用一道bugku的CTF的题目来作为分析对象
https://ctf.bugku.com/challenges 里面的 分析类 里的 信息提取
初初看数据包。先过滤非HTTP的流量,便于分析。Wireshark中执行过滤
http
先看前面的可以看到。Sqlmap进行了试探性的注入点探测。从前面的几个数据包就可以知道Sqlmap请求的时候是进行了URL编码的。不易理解。不过还好接下来看响应包的时候发现,响应包直接将GET参数输出了。所以我们只用看相应包即可。
Sqlmap前几次的包都是在进行注入点探测。我们来分析一下
第一次 正常输入
我们可以看到。正常输入?id=1时。如果SQL语句执行没有问题。将返回
The quick brown fox jumps over the lazy dog
接着看第二个数据包。
这个数据包是特意将值改大。以便测试如果SQL语句执行为空返回的数据。可以看到之前的狐狸跳过懒狗的字样已经没有了。说明当SQL语句返回NULL时就不会出现字。
接着发送了一个待运算的数字。这个就有点精妙了。我们来看一个例子
可以看到。当没有单引号时。mysql会直接运算。得出1
但是如果有单引号。mysql就会当作一个字符串。但是因为有 - 减号的存在。所以mysql就只能读取到5,就无法继续读取了。所以便用5来作为运算结果。
所以。这样子就能巧妙的判断Mysql中是否使用了单引号。因为注入时第一个数字使用了很大的数组5432,之前探测的时候2586已经是没有数据了。所以如果有单引号的话。就不应该回显有字。
但是情况是回显了字。说明运算结果为1。这样子就用来判断之后的探测是否要加入单引号。
接下来来了两次带括号的注入。之所以后面还要加一个AND。是因为带括号的SQL语句。前面有一个左括号,右边还有一个左括号。在不进行注释的情况下将右括号闭合。
select xxx from xxx where id = ( 1) AND 3700=5811 AND (8309=8039 )
这两条数据的作用是:判断sql语句是否存在括号
如果存在的话
第一次的SQL执行结果应该为NULL。因为连接符是and。并且3700不等于5811。所以不应该有字
第二次的SQL执行结果应该为true。因为1922确实等于1922。所以应该有字。但是回显的是没有字的。说明是不带括号的。我们输入的参数进入SQL语句中就变成了
select xxx from xxx where id = 1) AND 3700=5811 AND (8309=8039
这样子引号没有闭合就报错了。所以就没有回显的字。
接着验证了一下SQL语句是不是不带括号的。这个注入原理和上一个一样。
Order by。获取一共有多少个字段。由此可见是两个字段
Order by是对记录集中的数据进行排序
但和获取多少个字段有什么关系呢。。。?
我们来做个小实验
这是对id进行正序和倒序输出。其实这里的id可以换成字段对应的顺序号。即id是1,content是2,title是3
可以看到,可以正常排序。根据这个顺序号的特点。我们注入时在order by中输入的数字,就可以从侧面反映我们成功查询的字段的顺序号,进而得知数据库中有多少个字段。
这个0x开头的表示是16进制。我们可以在网上搜索工具。将其转换成我们可以看懂的字符串。我用的是AscII及进制转换工具
http://www.pc6.com/softview/SoftView_3894.html
从上一个注入可以知道有两个字段。所以就测试一下它返回的时候,sql语句中只查询了多少个字段。这个很有必要的。一个例子说明一下。
第一次我们正常查询。查询了两个字段。第二次我们查的时候通过union联合查询模拟联合查询的注入。但是我只select了一个字段的位置。与主查询的两个字段数量不符合。所以就会报different number的错误。
这时候我们只能通过扩大我们的联合查询的字段数来确保能正常运行。
增加了一个字段数。就可以正常运行了。
接下来连续4个包都是用上面那个方式去进行注入
在分析之前。来一个小测试。以便更好的理解。
我们交换了一下aa和bb的位置。发现他们在输出的时候位置也换过来了。
sqlmap先是测试一下它能否一次输出两条数据。所以没有改id的值。交换位置是因为Web获取了两个字段。但是回显只有一个字段的值。sqlmap在测试它是读取哪一个字段的值来回显的。
前两条数据的主要作用是判断Web能否一次输出两条数据。显然不行。那么就发送了第三和第四个数据包。
这个主要的区别就是id的值变为了负数。这是什么意思呢。我们再来做个测试。
可以看到。当搜索的id值不存在时。返回了空。但是我们有union语句。在id值存在时union搜索出来的值在下面。但是如果id值不存在,union搜索出来的值就能在第一个了。在这个Web中它只显示第一条数据。这里交换了位置就是因为Web它拿的是第二个字段的值作为回显。我们这样就可以在页面中获得回显结果(我们自己输入的)。
接下来进行当前数据库的查询
一个个来分析
其实和union一样。唯一的区别就是union会把重复的记录删掉。但是union all就会全部返回。
是字符串拼凑。将其括号内所有通过逗号分隔的字符串拼接在一起。
判断第一个表达式是否为NULL。如果不为NULL返回第一个参数的值,如果是NULL返回第二个参数的值。
类型转换。把AS旁边的字段转成右边的类型
所以我们大概知道这个语句的意思了。通过字符串拼接把两个十六进制的和我们的子查询语句拼接在一起。子查询语句中用IFNULL来进行判断。如果是不是空就返回查询的值。是空就返回0x20
通过16进制转换器可知。
0x713636371 为 qsccq
0x716f757371 为 qousq
0x20 为 空格
所以中间那个就是数据库名。这样子做应该是为了干扰查询日志吧。。。
接着就是通过上面这种方式去找information_schema里面数据库,数据表的信息了。这样用的方法和上面的一样,就不多说了。我们直接了断。找到进行查询flag的语句。
发现他是进行了SQL盲注。通过比较ascii码的方式。
关于SQL盲注我之前也写过一篇博客
https://blog.csdn.net/xiaopan233/article/details/88093980
通过看这个语句我们可以知道。他在试探flag的数量。注意它用来ORD函数。将里面的字符转成了ascii码。所以这里的数字我们还要通过ascii码的转换器转换成真正的字符。ascii码为49的字符是1。
最后一个包,是它在测试是不是十位数。但是>1都没有正确回显。说明这是空的。结合前三个数据包我们可以知道这个flag表里面只有一条数据。
现在就是通过比较ascii码来进行盲注了。它通过MID来控制比较的flag字符。一个个数据包这样子看下去。就能得到flag值。前提是要有足够的耐心。毕竟这个flag值有33个字符。。。而我们要一个个看