Cómo filtrar direcciones con explotaciones de cadenas de formato

1

Al jugar varios juegos de guerra, me di cuenta de que seguía atorándome en las vulnerabilidades de las cadenas de formato, así que decidí dar un paso atrás y volver a aprenderlas desde cero. En el proceso, me di cuenta de que no podía explicarme por qué podemos leer / escribir en ubicaciones arbitrarias al proporcionar una dirección válida.

printf (\x41\x41\x41\x41_%08x_%08x)

Según mi comprensión de las cadenas de formato, se supone que esta llamada de función simplemente imprime AAAA + stack value + stack value y nada más. En su lugar, pierde dos direcciones comenzando por la dirección provista

De enlace

The format function now parses the format string ‘A’, by reading a
character a time. If it is not ‘%’, the character is copied to the output. In
case it is, the character behind the ‘%’ specifies the type of parameter that
should be evaluated. The string “%%” has a special meaning, it is used to print
the escape character ‘%’ itself. Every other parameter relates to data, which
is located on the stack

Si la declaración anterior es verdadera, y \x41\x41\x41\x41_%08x_%08x es el único argumento de printf () asignado en la pila, entonces ¿cómo podemos explicar la lectura / escritura desde / a las ubicaciones de memoria?

EDIT 1:

Esta respuesta sí especifica que podemos filtrar la dirección que queramos, pero no explica cómo comenzar a filtrar desde una ubicación de memoria arbitraria.

I esta otra respuesta

So you're asking how printf can find the string because there is a
different parameter count than the % signs say? Two thought problems here: a)
Before printf can count the % at all, it has to find the string. Wrong string
content can't prevent finding this string. b) Without attacks: printf supports
variable parameter counts, and it always can find the string. Last parameter
etc. doesn't matter.

Por alguna razón, el OP asume que la parte 'AAAA' es una dirección real.

    
pregunta shxdow 12.03.2017 - 01:10
fuente

1 respuesta

2

@LiveOverflow me ayudó a descubrir qué era lo que no podía obtener. Ambas suposiciones que tenía eran verdaderas

  1. printf simplemente imprime lo que nunca sea un '%' y trata de manera especial los caracteres que siguen a '%'
  2. Los formateadores (% x,% s, '% n, etc ...) SOLAMENTE usan las direcciones que se encuentran en la pila (lo que quiero decir es que si comenzamos a resaltar los valores usando% x, esos valores aparecerán en la pila siempre que las direcciones válidas estén disponibles

Ahora, en el código de la pregunta, no basta con proporcionar una dirección como primer argumento, de alguna manera tenemos que poner en la pila la dirección que queremos leer / escribir desde / a

ejemplo:

vuln.c (gcc -g vuln.c -m32 -o vuln):

#include <stdio.h>

int main (int argc, char ** argv) {

    buffer[32];

    fgets (buffer, sizeof(buffer), stdin);

    printf (buffer);

    return 0;
}

Podemos hacerlo llamando al programa con un argumento ./vuln AAAA . Cuando se le pida una entrada, podemos insertar allí nuestra cadena de formato. Aquí está el problema: tenemos que quitar los valores hasta que encontremos nuestro AAAA , después de que %s eliminará la referencia a la dirección AAAA y leeremos una cadena desde allí, también conocida como que filtra una dirección arbitraria. Escribir en una dirección funciona de la misma manera.

En aras de la simplicidad, lo compilé con -g para poder usar el símbolo * argv

pwndbg> x/4s *argv
0xffffd258: "/home/ncrntn/vu"...
0xffffd267: "ln"
0xffffd26a: "AAAA"
0xffffd26f: "XDG_CONFIG_DIRS"...

En este punto, sabemos dónde mirar

pwndbg> x/200wx $esp
. . .
0xffffd260: 0x6e746e72  0x6c75762f  0x4141006e  0x58004141
. . .

Y efectivamente encontramos nuestro AAAA (en hexadecimal \ x41 \ x41 \ x41 \ x41)

    
respondido por el shxdow 16.03.2017 - 15:44
fuente

Lea otras preguntas en las etiquetas