1.1 概览样本数据流
分析:
可以观察到样本已经提取得很精炼并没有多少个包,协议只有http、tcp 所以我们不用协议分层、会话、端点等分析,直接流追踪就行
1.2 tcp流追踪
分析:
从上面得图中可以发现以下流程:
分析:
服务端第二次返回了一个html文档,里面包含了这样得内容:
分析:
此html文档包含了一个js 脚本 和一个<span>标签,在span标签里面有一个<iframe src = "/...gif"> ,并且在这个<iframe>加载的时候给了一个动作函数 "WisgEgTNEfaONekEqaMyAUALLMYW(event)" 将当前动作事件以参数的形式传递进去,目前这个函数可以猜测是上面的脚本来的。
但是上面的脚本里面没有这个函数,所系分析脚本:
脚本是根据当前请求链接上的第一个参数作为密钥,解密了这个数组内容,并且使用window["eval"].(Script)的方法执行了这个内容
那就能解释了,这个解密后是脚本,并且有WisgEgTNEfaONekEqaMyAUALLMYW(event)这个函数。
1.3 提取脚本并调试获取解密脚本
这里我用chrome浏览器调试,我在解密后执行前下一个断点,如下:
分析:
此时的 NqxAXnnXiILOBMwVnKoqnbp 即保存的是 解密后的脚本,我们通过chrome 的数据窗口保存数据到本地:
1.4 查看并分析解密后脚本
分析:
我们看到的确在这里面有 WisgEgTNEfaONekEqaMyAUALLMYW() 函数,概览了分析了一下整个脚本(详情请查看上面的注释)。总结如下:
1. gGyfqFvCYPRmXbnUWzBrulnwZVAJpUifKDiAZEKOqNHrfziGDtUOBqjYCtATBhClJkXjezUcmxBlfEX()
此函数填充了 0xd0000个栈溢出跳转地址和堆空间空间150个滑板指令+shellcode
lTneQKOeMgwvXaqCPyQAaDDYAkd
2. 创建了全局的变量事件触发event副本
把 <span>标签vhQYFCtoDnOzUOuxAflDSzVMIHYhjJojAOCHNZtQdlxSPFUeEthCGdRtiIY
的内容置空
3. 设置一个定时器,发作间隔为50ms,发作响应函数为nayjNuSncnxGnhZDJrEXatSDkpo
这个函数是将全局对象的空间填充为"\u0c0f\u0c0d\u0c0d\u0c0d\u0c0d\u0c0d...“,并访问了这个已经置空的lTneQKOeMgwvXaqCPyQAaDDYAkd.srcElement,即<iframe>触发事件对象,猜想这里应该就是触发了崩溃,因为已经置空了还在去访问。
2.1 获取崩溃点
使用windbg 附加ie 6.0 的进程,然后访问本地搭建的服务器(这里使用phpsudy搭建,根目录下放我们前面提取出的html文档),链接使用 xxx.html?rFfWELUjLJHpP,xxx为你存储的html文档名
分析:
如前面分析脚本中的验证,根据栈回溯分析,是mshtml!CEventObj::get_srcElement导致的崩溃,即脚本中的 lTneQKOeMgwvXaqCPyQAaDDYAkd.srcElement。
2.2 分析上下文 查看奔溃点的来源
> u mshtml!CEventObj::get_srcElement
> u mshtml!CEventObj::GenericGetElement l0x100
> u mshtml!CElement::GetDocPtr
崩溃点环境:
分析:
-
我们可以看到ecx是0x 00000054 所以产生了异常。
-
我往上找(上面第二张贴图)发现 在mshtml!CEventObj::GenericGetElement 中 ecx 源于 ebx,ebx 来源于.......可以追溯到 当前的局部变量 [ebp-0x8] 中。
-
简单的浏览观察到没有哪里有赋值[ebp-0x8],所以开始展开分析。
2.3 展开分析追溯崩溃源
展开 mshtml!CEventObj::GenericGetElement 函数 查看 局部变量 [ebp-8]
分析:
我们可以从上面找到如下语句:
可以看出,调用了GetParam函数,ebp-8是存储的参数
分析 mshtml!CEventObj::GetParam函数:
分析:
可以看出使用ecx调用数据,这大概是一个thiscall类型,ecx存储着一个对象指针。我门回到上面查看调用mshtml!CEventObj::GetParam之前ecx是什么。
可以看到是 mshtml!CEventObj::GenericGetElement 函数的 局部变量 [ebp-0ch]
可以看到 是 mshtml!CEventObj::GenericGetElement() 的 ecx 也就是 同一个对象参数。
2.4 查阅分析相关类和结构体
CEventObj 是一个event对象,但是并没有与event直接相关的属性。event直接相关的属性在 EVENTPARAM 结构中,一般来说 event 会有一个源元素(触发这个事件的元素节点),在event的srcElment 属性中即是对象,当调用CreateEventObject()创建事件event副本的时候,没有增加Element的引用计数,所以当释放原Element之后,事件副本eventcopy.CTreeNode是一个悬空指针,其下的Element元素内存已经被释放了。
使用查看相关IDA符号:
2.5 漏洞成因
综合上面的分析可以得出以下结论:
createEventObject创建了event的副本,但是此函数中EVENTPARAM::EVENTPARAM() 复制EVENTPARAM结构时并没有增加CTreeNode中srcElement即原对象的访问计数。所以在原Element被清空的时候,也对该内存进行了释放,造成了event副本中的EVENTPARAM.CtreeNode成了悬空指针。当使用的时候,会依次调用mshtml!CEventObj::get_srcElement()、mshtml!CEventObj::GenericGetElement()、mshtml!CElement::GetDocPtr(),会使得访问已经释放的内存(我们可以有意使用这块内存触发堆喷条件)
3.1 当释放Element的情况
在mshtml!CEventObj::get_srcElement()、mshtml!CEventObj::GenericGetElement()、mshtml!CElement::GetDocPtr()这三个函数下断点
分析:
我们一路跟下来可以看到此时 ecx = ebx = 0x0c0d0c0d是我们的滑板指令了。继续跟进去验证:
分析:
如我们预计的一样,此时已经来到了我们的滑板了
3.2 当没有释放Element的情况
在脚本中注释掉,释放对象的语句:
运行:
分析:
我们可以观察到这里CTreeNode的ECX和EBX恢复了正常
4.1 CShellCode 和 UnicodeShellCode的的转换
注意: 此脚本使用python2的环境,因为python3中没有 .encode('hex')
4.2 shellcode的编写
这里使用的是vs2017 -32- release,写完后直接放xdbg里面扣取shellcode
4.3 自定义js脚本,触发并实现堆喷
4.4 验证远程连接反弹shell
使用OD附加IE并使用IE 访问服务器 ip/test.html:
到达触发点:
来到堆喷滑板指令:
验证shellcode:
f9 继续运行,并使用物理机telnet虚拟机,成功反弹shell,并且在shellcode中使用exitprocess,增强隐蔽性: