缓冲区溢出攻击原理
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.缓冲区溢出攻击原理
文本段(代码段) 文本区域是由程序确定的, 包括代码(指令)和只读数 一个进程的内存映像 堆栈
低
据。 该区域相当于可执行文件的文本段。 这个区域通常 被标记为只读, 任何对其写入的操作都会导致段错误 (segmentation violation 数据段 数据区域包含了已初始化和未初始化的数据。 静态变量储存在这个区域中
(已初始化数据) 数据段 (未初始化数据)
代码段
高
堆栈
用于函数调用,用于返回
1) 缓冲区溢出攻击(实例)
main() { char passwd[8] = {"2e4rfe"}; char yourpasswd[8] = {""}; again: puts("please input passwd?"); gets(yourpasswd); if (strcmp(yourpasswd, passwd)= =0) goto ok; puts("passwd error"); goto again; exit(-2); ok: puts("correct!"); // do work you want return 0; }
③释放局部变量 ④从堆栈中取出的 ESP指向返回地址 EIP,执行shell code
缓冲区溢出攻击
例子
int main() {AFunc(5,6); return 0;}
int AFunc(int i,int j) { int m = 3; int n = 4; m = i; n = j; BFunc(m,n); return 8; } int BFunc(int i,int j) { int m = 1; int n = 2; m = i; n = j; return m; }
}
程序运行结果:buffer、FP、RET、甚至Str本身等的值都变成了A
攻击原理:
改变RET的值; 用特殊的可执行指令来改变 这样就可以达到攻击目的。 RET的位置是可以被计算出来的(偏移值)
函数调用中栈的工作过程
AFunc(5,6);
push 6 push 5 call _AFunc add esp+8
EDI ESI EBX
48h 当前EBP 4(n=4) 3(m=3) EBP EIP 5 6
_AFunc
push ebp mov ebp,esp sub esp,48h //压入环境变量 //为局部变量分配空间
#include<iostream.h> #include<string.h> void input() { int access(0); //access为1时表示登录正确得到权限,初始为0 char password[4]; //用于存储用户输入的登录密码 cout<<"输入密码:"; cin>>password; if(strcmp(password,"1988")==0)//比较两个串是否相等,如果相等返回值为0 { access=1; //两串相等,将权限变量赋值1 } if(access!=0) //access非零,则登录成功 cout<<"登录成功"<<endl; else //access为零,登录失败 cout<<"error"; } void main() { input(); //函数调用 }
寄存器 EIP argc ESP→
寄存器 EIP argc argv
④释放局部变量 寄存器出栈
⑤返回
函数调用与堆栈
低 ESP → 缓 冲 区 寄存器 EIP 高 argc argv ①进入函数后的堆栈 ②拷贝超长字符 数组到缓冲区中 EIP’ ESP → EIP’ ESP → EIP’ ←buf → EIP’→
程序的设计功能: 输入正确的口令后 做某项工作(否则 重复要求输入口令) 演示:
输入精心计划好的 字串打乱设计期望 的执行逻辑,从而 绕过某些口令
2)栈溢出攻击(函数调用)
局部变量 基地址 栈 增 长 方 向 1) 首先把参数压入栈; 2) 然后保存命令寄存器(IP)中的内容作为返回地址 (RET); 3) 第三个放入堆栈的是基址寄存器(FP);
当前EBP
48h 4(n=4) 3(m=3) EBP EIP 5 6
语句执行前的ESP
语句执行前的EBP
当缓Leabharlann Baidu区溢出发生时……
int AFunc(int i,int j) { int m = 3; int n = 4; char szBuf[8] = {0}; strcpy(szBuf, “This is a overflow buffer!”); m = i; n = j; BFunc(m,n); return 8; }
返回地址
4) 然后把当前的栈指针(SP)拷贝到FP,作为新的基 地址; 5) 最后为本地变量留出一定空间
实在参数 栈底(内存高端)
低 ESP→ ←buf→
缓 冲 区
缓 冲 区
缓 冲 区
寄存器 ESP→ 高 ←→ EIP argc argv ESP→ ①调用之前 ②参数、EIP压栈 ③寄存器压栈 分配局部变量 EIP argc argv ESP→
当前ESP 语句执行前的ESP
语句执行前的EBP
函数调用中栈的工作过程
AFunc(5,6);
…… call _AFunc add esp+8
当前ESP EDI ESI EBX
_AFunc {……return 0;}
pop edi pop esi pop ebx add esp,48h //栈校验 pop ebp ret
example.c void function(char *str) { char buffer[16]; } strcpy(buffer,str);
buffer 基地址FP Ret (Function后的指令地址) *str 栈底(内存高端)
void main() { char large_string[256]; int i; for(i=0;i<255;i++) large_string[i] = ‘A’; function(large_string);
文本段(代码段) 文本区域是由程序确定的, 包括代码(指令)和只读数 一个进程的内存映像 堆栈
低
据。 该区域相当于可执行文件的文本段。 这个区域通常 被标记为只读, 任何对其写入的操作都会导致段错误 (segmentation violation 数据段 数据区域包含了已初始化和未初始化的数据。 静态变量储存在这个区域中
(已初始化数据) 数据段 (未初始化数据)
代码段
高
堆栈
用于函数调用,用于返回
1) 缓冲区溢出攻击(实例)
main() { char passwd[8] = {"2e4rfe"}; char yourpasswd[8] = {""}; again: puts("please input passwd?"); gets(yourpasswd); if (strcmp(yourpasswd, passwd)= =0) goto ok; puts("passwd error"); goto again; exit(-2); ok: puts("correct!"); // do work you want return 0; }
③释放局部变量 ④从堆栈中取出的 ESP指向返回地址 EIP,执行shell code
缓冲区溢出攻击
例子
int main() {AFunc(5,6); return 0;}
int AFunc(int i,int j) { int m = 3; int n = 4; m = i; n = j; BFunc(m,n); return 8; } int BFunc(int i,int j) { int m = 1; int n = 2; m = i; n = j; return m; }
}
程序运行结果:buffer、FP、RET、甚至Str本身等的值都变成了A
攻击原理:
改变RET的值; 用特殊的可执行指令来改变 这样就可以达到攻击目的。 RET的位置是可以被计算出来的(偏移值)
函数调用中栈的工作过程
AFunc(5,6);
push 6 push 5 call _AFunc add esp+8
EDI ESI EBX
48h 当前EBP 4(n=4) 3(m=3) EBP EIP 5 6
_AFunc
push ebp mov ebp,esp sub esp,48h //压入环境变量 //为局部变量分配空间
#include<iostream.h> #include<string.h> void input() { int access(0); //access为1时表示登录正确得到权限,初始为0 char password[4]; //用于存储用户输入的登录密码 cout<<"输入密码:"; cin>>password; if(strcmp(password,"1988")==0)//比较两个串是否相等,如果相等返回值为0 { access=1; //两串相等,将权限变量赋值1 } if(access!=0) //access非零,则登录成功 cout<<"登录成功"<<endl; else //access为零,登录失败 cout<<"error"; } void main() { input(); //函数调用 }
寄存器 EIP argc ESP→
寄存器 EIP argc argv
④释放局部变量 寄存器出栈
⑤返回
函数调用与堆栈
低 ESP → 缓 冲 区 寄存器 EIP 高 argc argv ①进入函数后的堆栈 ②拷贝超长字符 数组到缓冲区中 EIP’ ESP → EIP’ ESP → EIP’ ←buf → EIP’→
程序的设计功能: 输入正确的口令后 做某项工作(否则 重复要求输入口令) 演示:
输入精心计划好的 字串打乱设计期望 的执行逻辑,从而 绕过某些口令
2)栈溢出攻击(函数调用)
局部变量 基地址 栈 增 长 方 向 1) 首先把参数压入栈; 2) 然后保存命令寄存器(IP)中的内容作为返回地址 (RET); 3) 第三个放入堆栈的是基址寄存器(FP);
当前EBP
48h 4(n=4) 3(m=3) EBP EIP 5 6
语句执行前的ESP
语句执行前的EBP
当缓Leabharlann Baidu区溢出发生时……
int AFunc(int i,int j) { int m = 3; int n = 4; char szBuf[8] = {0}; strcpy(szBuf, “This is a overflow buffer!”); m = i; n = j; BFunc(m,n); return 8; }
返回地址
4) 然后把当前的栈指针(SP)拷贝到FP,作为新的基 地址; 5) 最后为本地变量留出一定空间
实在参数 栈底(内存高端)
低 ESP→ ←buf→
缓 冲 区
缓 冲 区
缓 冲 区
寄存器 ESP→ 高 ←→ EIP argc argv ESP→ ①调用之前 ②参数、EIP压栈 ③寄存器压栈 分配局部变量 EIP argc argv ESP→
当前ESP 语句执行前的ESP
语句执行前的EBP
函数调用中栈的工作过程
AFunc(5,6);
…… call _AFunc add esp+8
当前ESP EDI ESI EBX
_AFunc {……return 0;}
pop edi pop esi pop ebx add esp,48h //栈校验 pop ebp ret
example.c void function(char *str) { char buffer[16]; } strcpy(buffer,str);
buffer 基地址FP Ret (Function后的指令地址) *str 栈底(内存高端)
void main() { char large_string[256]; int i; for(i=0;i<255;i++) large_string[i] = ‘A’; function(large_string);