栈溢出漏洞的基本原理
栈溢出漏洞简单来说就是,因为程序向栈中写入了超过栈空间锁规定的大小,导致数据覆盖了 call 指令执行后压入栈中的返回地址。因此攻击者可以通过精心构造输入数据,使得程序在执行返回指令时跳转到攻击者设定的指令序列上,以达到劫持程序、控制程序执行流程的目的。
案例演示
1 | /*程序名:overflow.c*/ |
堆栈示意图:
从上图可以看到,这里函数 overflow 的返回地址已经被覆盖了。如果这个地址被改成其他函数的地址,那么我们就可以修改程序,执行任意恶意代码。
案例一
编写代码
1 |
|
gets函数可无限读取输入的字符串,不会判断上线,以回车键结束读取。当我们向 buf 数组输入超过其大小的数据时,就会发生栈溢出漏洞。
编译程序
gcc -g -no-pie -z execstack -z norelro -m64 overflow1.c -o overflow1
-g -no-pie:关闭 PIE 进程空间地址随机化
-z execstack:禁用 NX 保护
-z norelro:关闭 RELRO
动态调试查看程序
- kali中使用指令
edb --run overflow1
来动态调试程序
amd64位的系统编译的64位程序默认是 16 位对齐。从上面的栈区可以确认我们构造的 payload=(24位垃圾数据)+(backdoor地址)
编写 payload
1 | from pwn import * |
执行脚本时出现报错,未能成功获取 shell
调试修改 payload
在 paylaod 中增加 gdb 调试,查看是哪里出错
1 | from pwn import * |
- 输入 fini 指令:运行程序直到当前函数返回。
- 输入 n 指令,执行到 main 函数为止
- 继续输入 n ,返回到 backdoor 函数
- 继续输入 n,此时程序报错断在了
movaps xmmword ptr [rsp + 0x50], xmm0
指令处
出现这个问题主要原因: movaps xmmword ptr [rsp + 0x50], xmm0
指令是验证内存地址是否 16 位对齐,如果 rsp + 0x50 不是 0x10 的整数倍就会报错。(0x7ffcb5cf13f8 + 0x50) 不能整除 0x10,正好多了 8 字节,也就是多执行了一个 push 指令。64位程序的栈空间是 8 字节。
解决方案: backdoor+1,就是把 backdoor 的值改为 0x00401157 就行。
从下图中可以看到,当进入函数后都会指令 push rbp 压入栈的基地址,那我们 ret 返回时跳过该指令,不就可以少执行一个 push 指令,正确运行程序了。
修改后的 payload
1 | from pwn import * |
执行后正常获得shell
案例二:rip
- 查看程序基本信息
- IDA 分析程序,可以看到 main 函数中有 gets 函数,可造成栈溢出漏洞
- 其次查看左侧函数列表,寻找可疑函数
- 找到 fun 函数的地址
- 和我们上面自己编译的程序差不多,这里直接使用 payload 尝试在本地测试运行。
1 | from pwn import * |
注:这里数组 s 是 15 个字节,不要写入数据写多了,导致 ret 返回到错误的地址。
可以看到程序报了同样的错误,我们修改 payload 后重新测试运行,成功 getshell
1 | from pwn import * |
- 修改 payload,getshell 远程服务器,获取 flag
1 | from pwn import * |
参考
- 本文标题:PWN基础入门 - 栈溢出
- 本文作者:9unk
- 创建时间:2024-05-01 10:30:00
- 本文链接:https://9unkk.github.io/2024/05/01/pwn-ji-chu-ru-men-zhan-yi-chu/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!