ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Windows 用户态栈溢出原理:从最后一字节溢出到劫持程序流程(ctf-wiki 实战解析)

Windows 用户态栈溢出原理:从最后一字节溢出到劫持程序流程(ctf-wiki 实战解析) 文档网络安全教程【免费下载链接】ctf-wikiCome and join us, we need you!项目地址https://gitcode.com/gh_mirrors/ct/ctf-wiki点击查看免费下载导读本文以 ctf-wiki 仓库中 Windows 用户态 Pwn 实战文档为基础通过一个经典的密码校验程序完整演示 x86 Windows 下栈溢出的发生机理局部变量声明顺序与 buffer 大小如何诱发最后一字节溢出攻击者又是如何利用strcpy复制的字符串结束符覆盖strcmp的返回值从而在GS栈金丝雀开启的情况下改变程序执行流程。读完本文你将掌握用 VC6.0 编译 Windows 用户态目标、用 Winchecksec 检查防护机制、用 OllyDbg 下断点观察栈布局以及从栈内存转储中推导溢出点的完整技能。一、背景Windows 用户态漏洞利用的入门环节在 ctf-wiki 的 Windows 用户态章节中栈溢出是后续一切利用手法的地基。与 Linux 用户态 Pwn 不同Windows 用户态的利用需要考虑 PE 文件格式、导入导出表、GS 栈金丝雀、SafeSEH、DEP/NX 等机制的约束调试工具与栈布局也略有差异。本仓库中的 Windows 栈介绍 承接了 Linux 侧的 x86 栈介绍——那里详细讲述了栈的后进先出特性、压栈/出栈操作以及程序栈从进程地址空间的高地址向低地址增长这一关键事实。Windows 下的函数调用栈同样遵循这一模型函数参数、返回地址、保存的 EBP、局部变量在栈上依次排列局部变量越靠近栈顶低地址就越容易被不安全的字符串拷贝从低地址向高地址即返回地址方向覆盖。本仓库将 Windows 用户态栈溢出按难度拆解为三篇递进的文档文档核心内容stackoverflow-basic.md本文主体最后一字节溢出覆盖返回值shellcode-in-stack.md通过 padding 控制返回地址跳转到栈上布置的 shellcoderet2dll.md类似 Linux ret2libc泄漏 DLL 基址后调用 system 执行命令本文讲解第一层不需要覆盖返回地址、仅仅覆盖一个局部返回值就能让程序逻辑短路。二、示例程序与漏洞根因分析下面给出本节的典型例子完整源码位于 stackoverflow-basic.md#include stdio.h #include string.h #define PASSWORD 666666 int verify_password(char *password) { int authenticated; char buffer[8]; authenticated strcmp(password,PASSWORD); strcpy(buffer,password); return authenticated; } void main() { int valid_flag 0; char password[128]; while(1) { printf(please input password: ); scanf(%s,password); valid_flag verify_password(password); if (valid_flag !0) { printf(incorrect password!\n); } else { printf(Congratulation! You have passed the verification!\n); break; } } }这是一个简单的密码校验程序会判断输入的字符串是否与666666相等。程序的逻辑本身没有问题——verify_password先调用strcmp得到比较结果存入局部变量authenticated再用strcpy把用户输入复制进局部缓冲区buffer最后返回authenticated主函数根据返回值决定是输出incorrect password!还是Congratulation! You have passed the verification!。但漏洞恰恰隐藏在verify_password函数的局部变量布局里结合 ctf-wiki 的栈知识可以逐条拆解局部变量声明顺序源码中先声明int authenticated;后声明char buffer[8];。在 VC6.0x86的默认栈帧布局下后声明的局部变量位于更低地址先声明的位于更高地址。因此内存中buffer紧邻authenticated下方authenticated恰好位于buffer的上方更高地址处。buffer 的大小char buffer[8]只有 8 字节而strcpy(buffer, password)是一个典型的不检查目标缓冲区大小的危险函数会一直复制直到遇到源字符串的\0结束符。最后一字节溢出如果输入恰好是 8 个字节如 8 个astrcpy会把这 8 个字符填入buffer[0..7]随后把字符串结束符\0ASCII 0x00写入buffer的下一字节——这一字节正是authenticated这个局部变量的最低字节所在位置。由于strcmp返回值为非零输入不等于666666返回 1时其最低字节为 1被\0覆盖后整个返回值变成 0主函数的if (valid_flag ! 0)判断随即被绕过。需要强调的是这并不需要覆盖返回地址也不需要利用 EIP。它改写的是函数内部一个局部变量在栈上的存储属于最后一字节溢出off-by-one 的一种形态因此即便目标开启了 GS栈金丝雀也不妨碍此次利用——金丝雀保护的是返回地址附近的区域而这里被覆盖的是局部变量区。三、编译与防护机制检查使用VC6.0编译上述程序示例生成demo1.exe然后在命令行下用Winchecksec查看目标程序的防护机制C:\Users\CarlStar\Desktopwinchecksec.exe demo1.exe Dynamic Base : false ASLR : true High Entropy VA : false Force Integrity : false Isolation : true NX : true SEH : true CFG : false RFG : false SafeSEH : true GS : true Authenticode : false .NET : trueWinchecksec 是 Trail of Bits 出品的 Windows 二进制安全特性检查工具上面这份输出逐项说明了 demo1.exe 的防护状态检查项值含义Dynamic Basefalse未设置动态基址标志ASLRtrue启用地址空间布局随机化由系统级策略体现High Entropy VAfalse未启用高熵虚拟地址随机化64 位特性Force Integrityfalse未强制签名完整性Isolationtrue启用进程隔离相关机制NXtrue数据执行保护开启栈上代码不可执行SEHtrue启用结构化异常处理CFGfalse未启用控制流防护RFGfalse未启用返回流防护SafeSEHtrue启用 SafeSEH异常处理函数需在合法表内GStrue栈金丝雀缓冲区溢出检测开启Authenticodefalse未进行 Authenticode 签名.NETtrue程序与 .NET 运行时相关注意到最关键的一行GS 是开启的。许多初学者会认为开了 GS 就无法做栈溢出但本例证明GS 金丝雀只保护从局部变量区到返回地址之间的栈区域——当溢出只触及局部变量authenticated、尚未越过金丝雀触及返回地址时GS 的检测逻辑根本不会被触发。这正说明了**理解溢出边界可以覆盖到什么位置、不能覆盖到什么位置**在 Windows 栈利用中的核心价值。四、OllyDbg 动态调试观察正常执行流程接下来使用OllyDbg动态调试这个程序。先输入aaaaaa6 个a观察程序正常的执行流程。为了方便理解整个过程在strcmp函数和strcpy执行完后各下一个断点对应反汇编中00401041处的strcmp调用与00401059处的strcpy调用如下图所示让程序运行并输入aaaaaa后程序执行到第一个断点strcmp调用处。进入strcmp函数观察它的返回值因为a的 ASCII 码值0x61大于6的 ASCII 码值0x36不出意外函数会返回1。在 x86 下函数返回值保存在EAX 寄存器中。函数正常返回后由于程序完成其余功能还会继续使用这些寄存器所以这个返回值会先被保存到栈上——也就是地址ss:[0012FEA0]这个地方。当执行到第二个断点strcpy之后时查看栈结构。此时输入 6 个a时的栈如下0012FE90 CCCCCCCC 0012FE94 CCCCCCCC 0012FE98 61616161 0012FE9C CC006161 0012FEA0 00000001逐字节解读这份栈转储0012FE98处的61616161是输入前 4 个a的 ASCII 码0x610012FE9C处的CC006161中6161是第 5、6 个a00是字符串结束符CC是 VC6.0 调试版填充的栈初始化字节0xCC 同时也是 INT 3 指令的操作码用于捕捉非法执行0012FEA0处的00000001正是之前被保存下来的strcmp 返回值即authenticated 1。注意观察buffer从0012FE98开始8 字节到0012FE9F结束而authenticated恰好位于0012FEA0——正是buffer结束位置的下一个 4 字节单元。这印证了前面分析的局部变量布局。五、最后一字节溢出用\0覆盖返回值如果输入8 个a呢strcpy会把 8 个字符填满buffer0012FE980012FE9F随后把字符串结束符\0写入0012FEA0这一字节——也就是authenticated的最低字节。原值是0x00000001strcmp 返回值 1最低字节被覆盖为0x00后整个变量变成0x00000000。下图展示了输入长度逼近溢出边界时的临界状态输入 7 个a栈窗口仍显示ss:[0012FEA0]CCCCCCCC说明 7 字节尚未触及返回值再增加一个字符即发生覆盖首先让程序正常运行输入 6 个a确认结果是incorrect password!接着输入 8 个a验证我们的推断字符串的结束符会溢出到 strcmp 的返回值。程序运行到strcpy之后的第二个断点时strcmp的返回值已经成功由 1 溢出为 0栈转储如下0012FE90 CCCCCCCC 0012FE94 CCCCCCCC 0012FE98 61616161 0012FE9C 61616161 0012FEA0 00000000与 6 个a时的栈对比0012FE98与0012FE9C现在都是完整的616161618 个a填满了整个 8 字节buffer0012FEA0由00000001变成了00000000——strcmp 的返回值 1 被字符串结束符\0成功覆盖为 0。此时让程序继续运行verify_password返回 0主函数的if (valid_flag ! 0)判断为假程序输出预想中的成功提示至此一次典型的最后一字节栈溢出利用完整闭环用不安全的 strcpy 把多余的一个字节\0写进紧邻的局部变量篡改校验结果改变程序控制流。整个过程没有越过 GS 金丝雀、没有改写返回地址因此 GS、SafeSEH 等防护全部形同虚设。六、从返回值覆盖到真正劫持 EIP理解了最后一字节溢出的机理后可以将同样的思路延伸出本仓库中接下来的两个进阶主题执行 Shellcode见 shellcode-in-stack.md当需要真正劫持执行流时思路从覆盖局部变量升级为覆盖返回地址。示例程序使用memcpy(buffer, password, strlen(password))把输入原样布置到栈上通过 OllyDbg 动态调试确定padding 长度示例中先试探 50 BYTES最终确定返回地址距缓冲区起点为 60 BYTES把返回地址精确覆盖为栈中 shellcode 的起始地址如0012FAE4函数返回时EIP被置为该地址CPU 便按机器码执行栈中的指令示例演示了弹出内容为hackhack的消息框。前提是编译时关闭 ASLR、NX、CANARY并借助LoadLibrary(user32.dll)预先装载所需模块。ret2dll 利用见 ret2dll.md与 Linux 下的 ret2libc 原理类似但 Windows 侧pwntools目前无法直接提取 exe 文件中的地址需要手动提取关键地址。示例使用 MinGWgcc -Wl,--disable-reloc -g -o ret2dll.exe ret2dll.c编译通过ncat -l 8080 --keep-open --exec .\ret2dll.exe或win_server ./ret2dll.exe 8080搭建临时交互环境利用putsgot泄漏 DLL 基址再计算出system与cmd的实际地址完成调用链。七、参考阅读本仓库 Windows 用户态栈溢出系列stack-introduction.md、shellcode-in-stack.md、ret2dll.mdLinux 侧栈基础x86 stack-intro.md栈结构、x86/x64 调用约定的系统讲解书籍《0day安全软件漏洞分析技术》上述示例的思路来源之一WinchecksecTrail of Bits 出品的 Windows 二进制安全特性检测工具文中防护输出即来自该工具赞分享文档网络安全教程【免费下载链接】ctf-wikiCome and join us, we need you!项目地址https://gitcode.com/gh_mirrors/ct/ctf-wiki点击查看免费下载相关推荐ctf-wiki PWN 实战Windows 32 位栈溢出原理与一字节溢出绕过密码校验ctf wiki PWN 实战Windows 32 位栈溢出原理与一字节溢出绕过密码校验 本文基于 ctf wiki 中 Windows 用户态 PWN 章节文档网络安全教程CTF-Wiki Windows 栈溢出实战在栈中执行 Shellcode 的完整流程CTF Wiki Windows 栈溢出实战在栈中执行 Shellcode 的完整流程 本文基于 CTF Wiki 的 Windows 栈上执行 Shellc文档网络安全教程mistral.rs 部署 SmolLM3 HTTP 推理服务基于 OpenAI 兼容接口的思考模式动态控制实战mistral.rs 部署 SmolLM3 HTTP 推理服务基于 OpenAI 兼容接口的思考模式动态控制实战 SmolLM3 是 Hugging Face文档网络安全教程上一篇QuantsPlaybook重塑量化投资研究范式的下一代开源平台下一篇iOS性能优化终极指南如何使用Aspects实现应用后台刷新监控创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表