Switch to full style
Este es tu lugar para hablar de programación, compartir, crear y desarrollar nuevos proyectos
Publicar una respuesta

Las preguntas más básicas sobre el shellcoding

Lun Feb 14, 2011 12:20 am

Muy buenas gente, os vengo a dar el coñazo como siempre.

Tengo un par de preguntas muy básicas sobre el shellcoding. De aquellas que nunca se explican a fondo. Bueno, al meollo..

Primero de todo y la más complicada, alguien me puede explicar (casi) perfectamente porqué el código debe ser position-independent? Se que eso significa que las instrucciones a ejecutar no deben de tomar referencias relativas a alguna posición de memoria. Sin embargo, alguien me puede poner un ejemplo de alguna instrucción de este tipo y de porqué no funcionaria cuando se ejecuta en un shellcode? Si alguien me lo pudiera explicar con esmero me haría un gran favor.

Lo segundo es más simple, pero también necesitaría una de esas explicaciones concisas ^^. Porqué se utiliza la sintaxis \xaa\xll\xgg\xoo en C para insertar un shellcode en memoria? Imagino que el \x indica que el siguiente valor es un valor en hexadecimal, pero qué mecanismo utiliza el compilador para almacenar el valor de la variable que contiene la cadena \xAA\xBB\xCC? Como es que sólo almacena el valor de después del \x? Es cosa del compilador? Es por el caracter '\'? GCC procesa el '\' de cada variable? En fin, exactamente, no lo tengo muy claro y no sería capaz de explicarselo a mi abuela :badgrin:


Gracias! Y siento estas preguntas de novatillo :roll:

Re: Las preguntas más básicas sobre el shellcoding

Lun Feb 14, 2011 1:03 am

Hola :)

Primero de todo y la más complicada, alguien me puede explicar (casi) perfectamente porqué el código debe ser position-independent? Se que eso significa que las instrucciones a ejecutar no deben de tomar referencias relativas a alguna posición de memoria. Sin embargo, alguien me puede poner un ejemplo de alguna instrucción de este tipo y de porqué no funcionaria cuando se ejecuta en un shellcode? Si alguien me lo pudiera explicar con esmero me haría un gran favor.


El por que, es como bien dices para eliminar dependencias con un entorno de memoria concreto. Esto es necesario si queremos tener una shellcode reutilizable, ya que en otro caso la vamos a cagar ;). En general, cuando compilas un programa, el compilador sabe donde se mapean los datos (aunque esto cambia con ASLR, relocation y demas) y podria por ejemplo acceder a variables globales via un acceso a la direccion de memoria conocida. Si haces eso en tu shellcode (osea, creas un ELF o similar a partir del codigo de la shellcode) la estaras liando por que usara direcciones hardcoded.

No se si me explico bien o no :oops:

Lo segundo es más simple, pero también necesitaría una de esas explicaciones concisas ^^. Porqué se utiliza la sintaxis \xaa\xll\xgg\xoo en C para insertar un shellcode en memoria? Imagino que el \x indica que el siguiente valor es un valor en hexadecimal, pero qué mecanismo utiliza el compilador para almacenar el valor de la variable que contiene la cadena \xAA\xBB\xCC? Como es que sólo almacena el valor de después del \x? Es cosa del compilador? Es por el caracter '\'? GCC procesa el '\' de cada variable? En fin, exactamente, no lo tengo muy claro y no sería capaz de explicarselo a mi abuela :badgrin:


Esto es sencillo :) Puesto que ciertas secuencias de bytes son no-imprimibles y por tanto no las puedes escribir facilmente en tu editor, los lenguajes de programacion introducen secuencias de escape para incluir algunos de estos caracteres especiales en una cadena. Esto se hace con \ y el compilador (el pre-procesador me parece) busca dichas secuencias de escape y las interpreta. Esto puede ser por ejemplo un \n (que es un byte 0x0A) o un tabulador con \t, pero para mas flexibilidad se te ofrece el \xXX donde XX se interpreta como la representacion hexadecimal del byte a poner.

Hope it helps.
Saludos!

Re: Las preguntas más básicas sobre el shellcoding

Lun Feb 14, 2011 10:34 am

Jajaja, vale, lo que me has comentado más o menos lo sabía. Más lo segundo, menos lo primero :embudito: .

Sobre las secuencias de escape. Entiendo que en java un System.out.println interprete por ejemplo un '\\' como un '\'. Y que en C un printf interprete un \n como un 'enter'. Pero imagino que son las funciones en si las que interpretan esos caracteres. Sin embargo, en un exploit el shellcode se enchufa en memoria con funciones, por ejemplo, como memcpy que en teoría no tendrían ni que procesar la cadena, ya que para estas funciones les bastaría copiar byte a byte lo que hay en el búfer. Significa que estas funciones también procesan el caracter '\' aunque el búfer sea de tipo, por ejemplo, void * que no tiene nada que ver con una cadena?
Por otro lado, como comentas, si es cuestión del preprocesador, imagino que antes de que se compile el programa, allí donde se encuentre un carácter de escape ('\') lo substituye por su correspondiente.

En resumen, la pregunta vendría a ser si el tema de la substitución de las secuencias de escape lo hace el preprocesador o las funciones en si. Imagino que no lo sabrás al 100%.


Sobre el primer tema:
Si haces eso en tu shellcode (osea, creas un ELF o similar a partir del codigo de la shellcode) la estaras liando por que usara direcciones hardcoded.

Qué problema habría con eso? Quiero decir que mientras la dirección esté hardcodeada... Las cosas iran bien. El problema vendría cuando se ejecuta alguna instrucción que hace, por ejemplo, un jmp 'relativo' y se elige un offset concreto suponiendo que esa instrucción jmp se ubicará en cierta posición de memoria. Eso ''lo entendería''.
En fin, el tema no me queda muy claro, se que pido lo que nunca he visto en ningún texto, pero sería posible poner un ejemplo práctico sobre este error?

Gracias TuXeD! Por responder y por hacerlo tan rápido!

Re: Las preguntas más básicas sobre el shellcoding

Lun Feb 14, 2011 5:10 pm

Sobre las barras de C, es simplemente sintaxis del compilador. No hay mas. Por ejemplo, recuerdo que en turbo pascal los bytes se ponian de otra forma mediante un inline. Mira: http://www.bsdg.org/swag/INTERRUP/0006.PAS.html

Sobre el PIC yo creo que lo esencial es que añade una indireccion. Aqui lo explican bastante bien, con codigos de ejemplo como dices.

Suerte,

Re: Las preguntas más básicas sobre el shellcoding

Mar Feb 15, 2011 10:19 am

Qué bueno el:
InLine( $8B/$E5/ { mov sp,bp }
$5D/$07/$1F/$5F/$5E/ { pop bp,es,ds,di,si }
$5A/$59/$5B/$58/ { pop dx,cx,bx,ax }
$06/ { push es }
$2B/$C0/ { sub ax,ax }
$8E/$C0/ { mov es,ax }
$26/$A0/$F0/$04/ { mov al,es:[4F0h] }
$07/ { pop es }
$CF);

:badgrin:


Gracias por el link! Me parece que será perfecto!

Ya editaré el post para comentar si ha sido perfecto o no ;)

Re: Las preguntas más básicas sobre el shellcoding

Mar Feb 15, 2011 10:47 am

Uy! lo del inline era con el Turbo Pascal 3 con el Turbo Pascal 5 ya podías meter la definición ASM y a partir de aquí podías poner código ASM.

Que tiempos aquellos del turbo pascal y el turbo c que aún no "existía" la programación orientada a objetos y pensar que hacia juegos y demos con el turbo pascal...

Re: Las preguntas más básicas sobre el shellcoding

Mar Mar 15, 2011 2:51 pm

Buenas,

Necesito visita con el Dr. Wadalberto, acabo de ver en mi lapiz USB que tenia redactado un ejemplo practico en el shellcoding de lo primero que preguntabas NewLog

Como mas vale tarde que nunca, ahi va:

Código:
[email protected]:~# nasm -f elf pic01.asm
[email protected]:~# ld -s -o pic01 pic01.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048060
[email protected]:~# ./pic01
Segmentation fault
[email protected]:~# cat pic01.asm
BITS 32

; int execve(const char *filename, char *const argv[], char *const envp[]);
push dword 11
pop eax
cdq
push edx

call next
db  "/bin/sh"
next:
mov ebx, [esp]
mov ecx, esp
int 0x80


El codigo de arriba produce una violacion de segmento. No es position-independent.

Código:
[email protected]:~# nasm -f elf pic02.asm
[email protected]:~# ld -s -o pic02 pic02.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048060
[email protected]:~# ./pic02
sh-3.2# exit
[email protected]:~# cat pic02.asm
BITS 32

; int execve(const char *filename, char *const argv[], char *const envp[]);
push dword 11
pop eax
cdq
push edx
jmp short down

back:
mov ebx, [esp]
mov ecx, esp
int 0x80
down:
call back
db  "/bin/sh"


Este segundo codigo funciona correctamente y nos devuelve la shell, es position-independent. ¿Por que? ...

pic01.asm no es position independent, ya que el call salta hacia direcciones mas altas de memoria que EIP (recordemos que call usa un offset relativo a EIP cuando pone en la pila la direccion de memoria de la siguiente instruccion), por lo que se producen bytes nulos que provocan la violacion de segmento.

pic02.asm si es position-independent, ya que el call salta hacia direcciones mas bajas de memoria que EIP, lo cual no produce bytes nulos y la llamada al sistema se llega a ejecutar correctamente, pues la shellcode se ejecuta "entera".

Mira:

Código:
[email protected]:~# objdump -d pic01 |grep call
 8048068:       e8 07 00 00 00          call   0x8048074
[email protected]:~# objdump -d pic02 |grep call
 8048071:       e8 f4 ff ff ff          call   0x804806a


Espero haberme explicado bien, si no no dudes en responder.

Suerte,

P.D. Veo Bebbop que tu tambien le dabas al Turbo Pascal :embudito: Si que molaba la programacion asi, el msdos era majo por su acceso libre al HW, habia peña que hacia autenticas virguerias...

Re: Las preguntas más básicas sobre el shellcoding

Mar Mar 15, 2011 8:17 pm

Hola,

En mi opinion lo que comenta vlan7 es incorrecto. Ambos codigos son perfectamente position-independent ya que si miras todos los opcodes que referencian otras partes del codigo lo hacen de forma relativa. Los bytes nulos no son problematicos en casos de test como el que comentas, el problema que tienen es cuando indican "aqui se acaba la cadena" (porque te cortan la shellcode) o cuando estan prohibidos en la entrada del programa vulnerable por la razon que sea (p.ej. solo acepta caracteres a-zA-Z).

La razon por la que el primer codigo peta es que no hay un byte nulo que termine la cadena pasada a execve() como argv[0] y como nombre del programa.Esto implica que la cadena se alarga hasta el proximo byte nulo (al final de la seccion .text en el ELF) lo cual no es una ruta correcta. Esto hace que el execve falle, y lo que hay detras del int 0x80 se ejecute como codigo. Y ahi viene el pete.

Si le anyades el nulo detras, funciona (probado en debian x86):

Código:
[email protected]:~$ sed 's/sh"/sh",0/' pic01.asm > pic01_fix.asm
[email protected]:~$ nasm -f elf pic01_fix.asm
[email protected]:~$ ld -s -o pic01_fix pic01_fix.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048060
[email protected]:~$ ./pic01_fix
$
[email protected]:~$


Lo que si es cierto es que el call 'hacia adelante' siempre te metera bytes nulos puesto que el desplazamiento es relativamente corto y se codifica en 16 o 32 bits si no me equivoco. En calls 'hacia atras' obtienes valores negativos que son del tipo 0xffffffXX o similares.

Espero haberme explicado.

Saludetes

Re: Las preguntas más básicas sobre el shellcoding

Mié Mar 16, 2011 4:20 pm

Ey se me fue la olla y no se por que crei que ese texto que tenia redactado en el USB iba aqui, y mira que lo repase despues de retocarlo y postearlo aps

El caso es que tal y como dice TuXeD ambos codigos son position independent, no hagais caso a mi respuesta. Ahi va un ejemplo adecuado:

En una ocasion antes de ser abierto este hilo escribi sobre ello aqui, donde mira tu por donde salis nombrados dos miembros de este foro. Lo enlazo porque acabo de comprobar de nuevo que hubiera algun ejemplo, y si no me equivoco ese si que es uno adecuado para responder a la pregunta inicial.

Suerte,

Re: Las preguntas más básicas sobre el shellcoding

Mié Mar 16, 2011 5:59 pm

vlan7 escribió:Ey se me fue la olla y no se por que crei que ese texto que tenia redactado en el USB iba aqui, y mira que lo repase despues de retocarlo y postearlo aps


No problem :)

vlan7 escribió:El caso es que tal y como dice TuXeD ambos codigos son position independent, no hagais caso a mi respuesta. Ahi va un ejemplo adecuado:

En una ocasion antes de ser abierto este hilo escribi sobre ello aqui, donde mira tu por donde salis nombrados dos miembros de este foro. Lo enlazo porque acabo de comprobar de nuevo que hubiera algun ejemplo, y si no me equivoco ese si que es uno adecuado para responder a la pregunta inicial.


En eso si que estoy de acuerdo. NewLog, si compilas y enlazas ese codigo, veras que tienes un push absoluto con lo que sirve para el ejemplo :)

Código:
 8048060:   31 c0                   xor    %eax,%eax
 8048062:   99                      cltd   
 8048063:   52                      push   %edx
 8048064:   68 72 80 04 08          push   $0x8048072
 8048069:   8b 1c 24                mov    (%esp),%ebx
 804806c:   89 e1                   mov    %esp,%ecx
 804806e:   b0 0b                   mov    $0xb,%al
 8048070:   cd 80                   int    $0x80
 8048072:   2f                      das   
 8048073:   62 69 6e                bound  %ebp,0x6e(%ecx)
 8048076:   2f                      das   
 8048077:   73 68                   jae    0x80480e1


Saludetes!

Re: Las preguntas más básicas sobre el shellcoding

Jue Mar 17, 2011 7:38 pm

Tengo lo que se dice... Muy mala memoria!

Primero, por olvidarme de este hilo, segundo por olvidarme del post en tu blog... En fin...

En la entrada de tu blog dices:
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 que no lo acabo de entender! Por pasos:
1) El db lo que hace es insertar en memoria la cadena definida.
2) ¿¿ El push sh lo que hace poner en memoria la dirección donde está ubicada la cadena ??

Si es así, no veo el problema. Ya que el push sh siempre insertará la dirección de la cadena ya sea código compilado o inyectado.

Por otro lado, si el push sh sólo pone la dirección donde se encuentra la instrucción db (ya que es lo que sigue a la etiqueta sh), MAL. Pero si es así, entonces no entiendo como el shellcode puede funcionar como shellcode in the wild o como shellcode compilado y lincado.


P.D.: TuXeD, en tu código ya veo que se hace un push de una dirección de memoria que contiene un 'das', cosa que no tiene mucho sentido.

Re: Las preguntas más básicas sobre el shellcoding

Vie Mar 18, 2011 12:09 am

1) El db lo que hace es insertar en memoria la cadena definida.


Si, el db inserta en esa posicion la cadena definida, tal cual.

2) ¿¿ El push sh lo que hace poner en memoria la dirección donde está ubicada la cadena ??


El push pone la direccion donde se encuentra la etiqueta. El ensamblador cambia etiquetas por direcciones, si ensamblas el codigo en un fichero objeto simplemente tendras un offset desde el principio donde iba la etiqueta en el caso del push (para jmp's se hacen relativos, un desplazamiento desde el eip actual). Luego, al linkarlo y darle una base al objeto dentro de un ELF, se le metera una direccion absoluta.

De ahi que no puedas usar esta tecnica en una shellcode, puesto que lleva una direccion absoluta. En cuanto al codigo que puse, no es mas que el codigo del post de vlan7 ensamblado y linkado. El das que mencionas, si te fijas es simplemente la cadena /bin/sh que objdump trata como codigo puesto que esta en la seccion .code (y esta justo detras de codigo valido que en teoria puede volver a seguir ejecutando en la instruccion siguiente).

Saludos

Re: Las preguntas más básicas sobre el shellcoding

Sab Mar 19, 2011 12:55 pm

-
Última edición por vlan7 el Mié Mar 23, 2011 9:28 am, editado 1 vez en total

Re: Las preguntas más básicas sobre el shellcoding

Mar Mar 22, 2011 7:12 am

Buenas,

Este es el codigo relevante de objdump.

Código:
8048072:       2f                      das
8048073:       62 69 6e                bound  %ebp,0x6e(%ecx)
8048076:       2f                      das
8048077:       73 68                   jae    0x80480e1


Newlog, fijate en los opcodes como coinciden con los valores en ASCII de /bin/sh A la hora de armar el shellcode esos opcodes seran interpretados como cadena.

NewLog escribió:Por otro lado, si el push sh sólo pone la dirección donde se encuentra la instrucción db (ya que es lo que sigue a la etiqueta sh), MAL


Decir que db no es una instruccion, es una pseudoinstruccion para definir constantes que es lo que estara en memoria. El "push sh" pone en la pila la direccion calculada por nasm al ensamblar:

Código:
(gdb) disassemble _start
Dump of assembler code for function _start:
0x08048060 <_start+0>:  xor    %eax,%eax
0x08048062 <_start+2>:  cltd
0x08048063 <_start+3>:  push   %edx
0x08048064 <_start+4>:  push   $0x8048072
0x08048069 <_start+9>:  mov    (%esp),%ebx
0x0804806c <_start+12>: mov    %esp,%ecx
0x0804806e <_start+14>: mov    $0xb,%al
0x08048070 <_start+16>: int    $0x80
End of assembler dump.
(gdb) x/7b 0x08048072
0x8048072 <sh>: 0x2f    0x62    0x69    0x6e    0x2f    0x73    0x68


Como vemos se hace un push de la direccion donde se encuentra la cadena /bin/sh.

NewLog escribió:no entiendo como el shellcode puede funcionar como shellcode in the wild o como shellcode compilado y lincado.


El shellcode compilado y linkado devuelve una shell porque dentro de la seccion de tabla de simbolos del ELF se guarda la direccion tal y como esta referenciada por el push. Pero en una explotacion real, esa direccion ya no va a apuntar a /bin/sh, porque como atacante estas bajo ambito del programa que quieres explotar.

Un ejemplo, declarando otro string de nombre mas en el codigo para que se vea como con 0x8048072 ya no estarias apuntando a /bin/sh , con lo cual lo mas probable es que se produjera una violacion de segmento.

Código:
[email protected]:~# readelf -s sc |grep 08048072
     4: 08048072     0 NOTYPE  LOCAL  DEFAULT    1 sh
[email protected]:~# readelf -s sc2 |grep 08048072
     4: 08048072     0 NOTYPE  LOCAL  DEFAULT    1 mas


Para resolver este problema, tienes que referenciar todas las direcciones con respecto al EIP, por ejemplo con el jmp/call trick.

Bueno, espero que te haya quedado claro, a mi me ha servido para reescribir aquello del position-independent code enfocado al shellcoding. Dejo la la URL para el que pueda servirle.

Suerte,
Publicar una respuesta