概要
类型:Web-SQL注入
来源:BUUCTF
知识点:堆叠注入;MySQL系统变量;逻辑运算符;
思路
首先能看到页面中提供了一个比较简单的查询,查看页面源代码,没有发现有效的其他信息。
很明显这个查询框就是唯一的注入点。先随意输入一些东西提交查询,发现当输入任何的非零数字时,页面总是回显一个相同的查询结果。
但是当我们输入的是0,或其他的字母、字符时,页面没有任何的回显。
再尝试输入一些MySQL中的关键字,如union、sleep,发现页面都会回显“Nonono”,大概是这些关键字被过滤了,也就是说盲注、联合查询在这里用不到了。
分析一下该注入点的闭合方式,发现不论是单引号还是双引号都没能引起语法层面的错误,结合前面发现的只有查询数字才有回显,可以判断就是数字型注入了。
在这里可以试试堆叠注入,我们可以先查询一下当前的表名:
1;show tables#
现在我们知道当前数据库下只有一个叫作为“Flag”的表了,我们想要的flag或许就在其中的某一条记录中。
回忆一下MySQL中是如何对表“Flag”进行查询的:
select * from Flag where unknown=xxx;
其中,unknown是Flag的某个字段,并且它的数据类型是整型。但我们无法使用“show columns from…”来获取这个表的任何字段名,因为我们发现“flag”这个字符串也被后端过滤了。
那么是否能换一种思路,有没有可能后端在查询时本就没有带任何的条件?
select xxx from Flag;
但这又难以解释为什么“xxx”为字符、字母、0时无回显,而为任意非零数时有回显。
因此我们认为后端一定对“xxx”做了变换。不知道0、1能不能让您想起什么,在一般的逻辑运算中,0代表假值,1代表真值。而在MySQL中,0被视为假值,非零数被视为真值。输入0时无回显,输入非零数时有回显,那么很可能存在一个或运算符“OR”,让我们的输入和一个假值进行了一次或运算。因此,可以猜测查询的语句如下:
select xxx OR false from Flag;
当然,这个假值,可以是0(false),也可以是这个表的某个字段名,因为在MySQL中,字符串在进行逻辑运算时,不能被正确地转换了类型,一般会被视为假值0。
根据我们猜测的查询语句,有以下两种方法可以获得flag。
法一
在select中,可以使用逗号来连接待查询的字段,即:
select name1,name2 from Flag;
我们的目的是消除或运算符的影响。利用这一点,可以构造出一种查询语句如下(方法不唯一):
select *,0 OR false from Flag;
根据逻辑运算符,该语句等价于:
select *,0 from Flag;
这里的0,实际上是在查询结果中增加了一列,该列的名称是“0”,每条记录在该字段的值也都是0,这一列并不属于表Flag,只是将查询的结果进行了拼接。
这样就能获取该表的所有记录了。
法二
该方法建立在已知Flag表的字段名为“flag”,且后端所使用的逻辑运算符为“||”的情况。
事实上,在MySQL中,管道符“||“也可以作为逻辑运算符,因此后端不一定用的就是”OR“。在这种情况下,MySQL有一种机制可以切换”||“的作用:
sql_mode=pipes_as_concat;
该语句通过系统变量sql_mode,赋予“||”以CONCAT()函数的作用,将查询结果按字段连接成一个字符串,而不再用于逻辑或运算。这就能破坏后端查询语句的语义。对此,可以构造以下语句获取flag(方法不唯一):
select 0;set sql_mode=pipes_as_concat;select 0||flag from Flag;
这等价于分别执行了三条语句:
select 0;
set sql_mode=pipes_as_concat;
select concat(0,flag) from Flag;
第一句并不重要;第二句则是切换了“||”的功能;最后一句对Flag表进行查询,将每条记录中flag字段的值和0进行拼接后再返回,因此如下图中flag前面会有一个“0”字符。
总结
这道SQL注入主要考验猜测、分析后端查询代码结构的能力。笔者在看其他作者对于这道题的WP时,发现大部分文章对猜测“select xxx||flag from Flag”的分析过程,都没有讲解得很清楚,往往都是一笔带过,用”显然可能应该是这样“等等,来搪塞读者,使人理解起来非常困难。事实上如何猜测得出这个查询语句,是关键所在。因此,我希望我自己浅薄的思考、分析的过程,能够帮助各位更好地来进行理解,理解“为什么能这样猜”。
在本题中,法二对大家也有一定的启示,有时我们可以修改MySQL的系统变量以达成一些目的。