1、第五章第五章 缓冲区溢出缓冲区溢出本章内容本章内容l5.1 缓冲区溢出相关概念缓冲区溢出相关概念l5.2 缓冲区溢出原理缓冲区溢出原理l5.3 溢出保护技术溢出保护技术l5.4 安全编程技术安全编程技术本章要求本章要求l了解缓冲区溢出的相关概念了解缓冲区溢出的相关概念l明确缓冲区溢出的危害明确缓冲区溢出的危害l理解栈溢出、堆溢出、整型溢出、格式化理解栈溢出、堆溢出、整型溢出、格式化字符串溢出及文件流溢出的原因字符串溢出及文件流溢出的原因l掌握安全编程技术掌握安全编程技术引子引子l1988 Morris蠕虫事件蠕虫事件lCERT统计数据统计数据5.1 缓冲区溢出相关概念缓冲区溢出相关概念l缓冲区
2、缓冲区l从程序的角度,缓冲区就是应用程序用来保从程序的角度,缓冲区就是应用程序用来保存用户输入数据、程序临时数据的内存空间存用户输入数据、程序临时数据的内存空间l缓冲区的本质缓冲区的本质l数组数组 l存储位置存储位置lStacklHeapl数据段数据段5.1 缓冲区溢出相关概念缓冲区溢出相关概念l缓冲区溢出缓冲区溢出l如果用户输入的数据长度如果用户输入的数据长度超出超出了程序为其分了程序为其分配的内存空间,这些数据就会配的内存空间,这些数据就会覆盖覆盖程序为程序为其其它数据它数据分配的内存空间,形成所谓的缓冲区分配的内存空间,形成所谓的缓冲区溢出溢出简单溢出实例简单溢出实例#include i
3、nt main()char name8=0;printf(“Your name:”);gets(name);printf(“Hello,%s!”,name);return 0;缓冲区溢出的危害缓冲区溢出的危害l应用程序异常应用程序异常l系统不稳定甚至崩溃系统不稳定甚至崩溃l程序跳转到恶意代码,控制权被窃程序跳转到恶意代码,控制权被窃5.2 缓冲区溢出原理缓冲区溢出原理l预备知识预备知识l理解程序内存空间理解程序内存空间l理解堆栈理解堆栈l理解函数调用过程理解函数调用过程l理解缓冲区溢出的原理理解缓冲区溢出的原理Windows环境下的堆栈环境下的堆栈l程序空间由何构成?程序空间由何构成?l堆栈是
4、什么堆栈是什么?l堆栈里面放的都是什么信息堆栈里面放的都是什么信息?l程序使用超过了堆栈默认的大小怎么办程序使用超过了堆栈默认的大小怎么办?l在一次函数调用中在一次函数调用中,堆栈是如何工作的堆栈是如何工作的?程序在内存中的映像程序在内存中的映像文本(代码)段文本(代码)段数据段数据段堆栈段堆栈段内存低地址内存低地址内存高地址内存高地址内存递增方向内存递增方向初始化数据段初始化数据段非初始化数据段非初始化数据段(BSS)堆堆(Heap)栈栈(stack)堆的增长方向堆的增长方向栈的增长方向栈的增长方向内核数据代码内核数据代码0 x800000000 x7FFFFFFFPEB&TEB系统系统DL
5、L代码段代码段栈栈l栈是一块连续的内存空间栈是一块连续的内存空间l先入后出先入后出l生长方向与内存的生长方向正好相反生长方向与内存的生长方向正好相反,从高地址向低从高地址向低地址生长地址生长l每一个线程有自己的栈每一个线程有自己的栈l提供一个暂时存放数据的区域提供一个暂时存放数据的区域 l使用使用POP/PUSH指令来对栈进行操作指令来对栈进行操作l使用使用ESP寄存器指向栈顶,寄存器指向栈顶,EBP指向栈帧底指向栈帧底栈内容栈内容l函数的参数函数的参数l函数返回地址函数返回地址lEBP的值的值l一些通用寄存器一些通用寄存器(EDI,ESI)的值的值l当前正在执行的函数的局部变量当前正在执行的
6、函数的局部变量三个重要的寄存器三个重要的寄存器lSP(ESP)l即栈顶指针,随着数据入栈出栈而发生变化即栈顶指针,随着数据入栈出栈而发生变化lBP(EBP)l即基地址指针,用于标识栈中一个相对稳定的位置。即基地址指针,用于标识栈中一个相对稳定的位置。通过通过BP,可以方便地引用函数参数以及局部变量可以方便地引用函数参数以及局部变量lIP(EIP)l即指令寄存器,在将某个函数的栈帧压入栈中时,即指令寄存器,在将某个函数的栈帧压入栈中时,其中就包含当前的其中就包含当前的IP值,即函数调用返回后下一个值,即函数调用返回后下一个执行语句的地址执行语句的地址函数调用过程函数调用过程l把参数压入栈把参数压
7、入栈l保存指令寄存器中的内容,作为返回地址保存指令寄存器中的内容,作为返回地址l放入堆栈当前的基址寄存器放入堆栈当前的基址寄存器l把当前的栈指针把当前的栈指针(ESP)拷贝到基址寄存器,拷贝到基址寄存器,作为新的基地址作为新的基地址l为本地变量留出一定空间,把为本地变量留出一定空间,把ESP减去适减去适当的数值当的数值函数调用中栈的工作过程函数调用中栈的工作过程l调用函数前调用函数前l压入栈压入栈l上级函数传给上级函数传给A函数的参数函数的参数l返回地址返回地址(EIP)l当前的当前的EBP l函数的局部变量函数的局部变量l调用函数后调用函数后l恢复恢复EBP l恢复恢复EIPl局部变量不作处
8、理局部变量不作处理例子例子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;int main()AFunc(5,6);return 0;6当前当前EBP当前当前ESPAFunc(5,6);push 6push 5call _AFuncadd esp+8语句执行前的语句执行前的EBP语句执行前的语句执行前的ESP函数调用中栈的工作过程函数调用中栈的工作过程5EIP_AFuncpush ebpmov ebp,
9、espsub esp,48h/压入环境变量压入环境变量/为局部变量分配空间为局部变量分配空间EBP48hEDIESIEBX3(m=3)4(n=4)6当前当前EBP当前当前ESPAFunc(5,6);call _AFuncadd esp+8语句执行前的语句执行前的EBP语句执行前的语句执行前的ESP函数调用中栈的工作过程函数调用中栈的工作过程5EIP_AFuncreturn 0;pop edipop esipop ebxadd esp,48h/栈校验栈校验pop ebpretEBP48hEDIESIEBX3(m=3)4(n=4)当缓冲区溢出发生时当缓冲区溢出发生时int AFunc(int i,
10、int j)int m=3;int n=4;char szBuf8=0;strcpy(szBuf,“This is a overflow buffer!”);m=i;n=j;BFunc(m,n);return 8;5.3 缓冲区溢出原理及其利用缓冲区溢出原理及其利用l缓冲区溢出种类缓冲区溢出种类l栈溢出栈溢出l堆溢出堆溢出l整型溢出整型溢出l格式化字符串溢出格式化字符串溢出l其他溢出其他溢出栈溢出栈溢出l特点特点l缓冲区在栈中分配缓冲区在栈中分配l拷贝的数据过长拷贝的数据过长l覆盖了函数的返回地址或其它一些重要数据覆盖了函数的返回地址或其它一些重要数据结构、函数指针结构、函数指针栈溢出实例栈溢
11、出实例int AFunc(int i,int j)int m=3;int n=4;char szBuf8=0;*(int*)(int)szBuf+20)=BFunc;m=i;n=j;BFunc(m,n);return 8;用用BFunc的地址替换正常的地址替换正常的的AFunc返回地址,使程返回地址,使程序运行至序运行至BFunc堆溢出堆溢出l堆和栈有何区别堆和栈有何区别l内存的动态分配与内存的动态分配与静态分配静态分配l堆溢出特点堆溢出特点l缓冲区在堆中分配缓冲区在堆中分配l拷贝的数据过长拷贝的数据过长l覆盖了堆管理结构覆盖了堆管理结构#define BUFLEN 32int main(in
12、t argc,char*argv)char*buf1;buf1=(char*)malloc(BUFLEN);strcpy(buf1,argv1);printf(%sn,buf1);free(buf1);return 0;整型溢出整型溢出l宽度溢出(宽度溢出(Widthness Overflow)l尝试存储一个超过变量表示范围的大数到变量中尝试存储一个超过变量表示范围的大数到变量中l运算溢出(运算溢出(Arithmetic Overflow)l如果存储值是一个运算操作,稍后使用这个结果的如果存储值是一个运算操作,稍后使用这个结果的程序的任何一部分都将错误的运行,因为这个计算程序的任何一部分都将错
13、误的运行,因为这个计算结果是不正确的。结果是不正确的。l符号溢出符号溢出(Signedness Bug)l一个无符号的变量被看作有符号,或者一个有符号一个无符号的变量被看作有符号,或者一个有符号的变量被看作无符号的变量被看作无符号宽度溢出示例宽度溢出示例void main(int argc,char*argv)unsigned short s;int i;char buf80;i=atoi(argv1);s=i;if(s=80)return;memcpy(buf,argv2,i);运算溢出示例运算溢出示例void CopyIntArray(int*array,int len)int*myarr
14、ay,i;myarray=malloc(len*sizeof(int);if(myarray=NULL)return;for(i=0;i size)return;memcpy(kbuf,buf,len);格式化字符串溢出格式化字符串溢出l关键字关键字l“%n”l产生原因产生原因lprintf()是不定参数输入是不定参数输入lprintf()不会检查输入参数的个数不会检查输入参数的个数其他溢出类型其他溢出类型l.data section溢出溢出lPEB/TEB溢出溢出l文件流溢出文件流溢出归纳归纳l溢出的共性溢出的共性l大大object向小向小object复制数据复制数据(字符串或整型字符串或整
15、型),容纳不下造成溢出容纳不下造成溢出l溢出会覆盖一些关键性数据(返回地址、管溢出会覆盖一些关键性数据(返回地址、管理数据、异常处理或文件指针等)理数据、异常处理或文件指针等)l利用程序的后续流程,得到程序的控制权利用程序的后续流程,得到程序的控制权缓冲区溢出缓冲区溢出的利用的利用char szBuf8=0;strcpy(szBuf,argv2);largv2的内容:的内容:l对对EIP的填充的填充lShellcode6szBuf5EIPEBPEDIESIEBX3(m=3)4(n=4)ShellcodeShellcodelShellcode其实就是一段可以完成某种特定其实就是一段可以完成某种特
16、定功能的二进制代码功能的二进制代码lShellcode的功能的功能l基本功能基本功能l添加添加administrator or root组用户组用户l远程可用远程可用shelll下载程序(下载程序(Trojan or Rootkit)执行)执行l高级功能高级功能l抗抗NIDS检测检测l穿透防火墙穿透防火墙Shellcode不通用不通用lShellcode为什么不通用为什么不通用l不同硬件平台不同硬件平台lIBM PC、Alpha,PowerPCl不同系统平台不同系统平台lUnix、Windowsl不同内核与补丁版本不同内核与补丁版本l不同漏洞对字符串限制不同不同漏洞对字符串限制不同利用缓冲区溢
17、出的攻击实例利用缓冲区溢出的攻击实例llogin:zchlPassword:lLast login:Fri Jan 12 15:21:34 from 210.34.6.82lSun Microsystems Inc.SunOS 5.6 Generic August 1997lYou have mail.l$wholzch pts/1 Jan 12 15:22 ()l$lpsetlUsage:lpset-n(system|xfn)-x-a key=value-d key(printer)#查看是否查看是否有有lpset程序程序l$./lpset2 944 1600 2lUsages:./lpse
18、t2 lUsing RET address=0 xefffff40 ,Offset=1600,Align=2l#idluid=0(root)gid=1(other)l#l入侵成功。入侵成功。lpset2源程序可在绿盟站点下载。源程序可在绿盟站点下载。5.3 溢出保护技术溢出保护技术l人人代码作者代码作者l编译器编译器l语言语言lRunTime保护保护l操作系统操作系统l硬件硬件人人代码作者代码作者l编写正确的代码编写正确的代码l方法方法l学习安全编程学习安全编程l软件质量控制软件质量控制l源码级纠错工具源码级纠错工具编译器编译器l数组边界检查数组边界检查l编译时加入条件编译时加入条件l例如例如
19、canary保护保护语言语言l为什么会出现缓冲区溢出?为什么会出现缓冲区溢出?lC/C+出于效率的考虑,不检查数组的边界出于效率的考虑,不检查数组的边界(语言固有缺陷)(语言固有缺陷)l类型非安全语言类型非安全语言类型安全语言类型安全语言lC,C+C#,Java?RunTime保护保护l二进制地址重写二进制地址重写lHook危险函数技术危险函数技术操作系统操作系统l非执行缓冲区非执行缓冲区l缓冲区是存放数据地方,我们可以在硬件或缓冲区是存放数据地方,我们可以在硬件或操作系统层次上强制缓冲区的内容不得执行操作系统层次上强制缓冲区的内容不得执行l许多内核补丁用来阻止缓冲区执行许多内核补丁用来阻止缓
20、冲区执行操作系统操作系统l堆栈不可执行内核补丁堆栈不可执行内核补丁lSolar designers nonexec kernel patchlSolaris/SPARC nonexec-stack protectionl数据段不可执行内核补丁数据段不可执行内核补丁lkNoX:Linux内核补丁,仅支持内核补丁,仅支持2.2内核。内核。lRSX:Linux内核模块。内核模块。lExec shieldl增强的缓冲区溢出保护及内核增强的缓冲区溢出保护及内核MAClOpenBSD security featurelPaX硬件硬件lX86 CPU上采用上采用4GB平坦模式,数据段和代码平坦模式,数据段和
21、代码段的线性地址是重叠的,页面只要可读就可以段的线性地址是重叠的,页面只要可读就可以执行,诸多内核补丁才会费尽心机设计了各种执行,诸多内核补丁才会费尽心机设计了各种方法来使数据段不可执行方法来使数据段不可执行.lAlpha、PPC、PA-RISC、SPARC、SPARC64、AMD64、IA64都提供了页执行都提供了页执行bit位。位。Intel及及AMD新增加的页执行新增加的页执行bit位称为位称为NX安全技术安全技术.lWindows XP SP2及及Linux Kernel 2.6都支持都支持NX缓冲区溢出漏洞挖掘缓冲区溢出漏洞挖掘lXcon 2004 l基于数据流分析的静态漏洞挖掘基于
22、数据流分析的静态漏洞挖掘lXcon 2005 l结构化的签名和签名的结构化结构化的签名和签名的结构化 5.4 安全编程技术安全编程技术l设计安全的系统设计安全的系统l代码的规范和风格代码的规范和风格l危险的函数危险的函数l安全测试安全测试设计安全的系统设计安全的系统l赖以生存的安全策略赖以生存的安全策略l建立一个安全步骤建立一个安全步骤l定义产品的安全目标定义产品的安全目标l将安全看作产品的一个功能将安全看作产品的一个功能l从错误中吸取教训从错误中吸取教训l使用最小权限使用最小权限l使用纵深防御使用纵深防御l假设外部系统是不安全的假设外部系统是不安全的l做好失效计划做好失效计划l使用安全的默认
23、值使用安全的默认值设计安全的系统设计安全的系统l威胁模型威胁模型lSTRIDE威胁模型威胁模型l欺骗标识欺骗标识 Spoofing identityl篡改数据篡改数据 Tampering with datal拒绝履约拒绝履约 Repudiationl信息泄露信息泄露 Information disclosurel拒绝服务拒绝服务 Denial of servicel特权提升特权提升 Elevation of privilege设计安全的系统设计安全的系统l部分威胁缓解方法部分威胁缓解方法l欺骗标识欺骗标识l篡改数据篡改数据l拒绝履约拒绝履约 l信息泄露信息泄露l拒绝服务拒绝服务 l特权提升特权
24、提升认证认证保护秘密保护秘密不存储秘密不存储秘密授权授权Hash消息认证代码消息认证代码数字签名数字签名抗篡改的协议抗篡改的协议数字签名数字签名时间戳时间戳审核跟踪审核跟踪授权授权加强保密的协议加强保密的协议加密加密保密存储保密存储认证认证授权授权过滤过滤扼杀扼杀服务质量服务质量以最小权限运行以最小权限运行代码的规范和风格代码的规范和风格l基本编程规范基本编程规范l成对编码原则成对编码原则l变量定义的规范变量定义的规范l代码对齐、分块、换行的规范代码对齐、分块、换行的规范l注释的规范注释的规范代码的规范和风格代码的规范和风格l目录与文件目录与文件危险的函数危险的函数lVS 2005危险的函数危险的函数lstrcpywcscpylstrcpy_tcscpy_mbscpylstrcatwcscatlstrcat_tcscat_mbscatlstrncpylmemcpylprintfsprintflgetslscanf