sqli-labs学习教程(二)

来源:互联网 发布:财神软件下载 编辑:程序博客网 时间:2024/06/11 12:03

上一篇链接:sqli-labs学习教程(一)
第二节:GET – Error based – Intiger based 
这一节跟前面几乎一样,只是$id没用单引号引着,因为sql语句对于数字型的数据可以不加单引号。不写单引号的注入就更简单了。



第三节:GET – Error based – Single quotes with twist – string
首先加个单引号看看。

将near和at之间字符串的左右引号去掉,得到'-1'') LIMIT 0,1。-1的右边多了一个',后面还有个括号,代码应该是id=('$id')。看一下代码,确实是这样。



第四节:GET – Error based – Double Quotes – String
直接上单引号,发现没有报错。这里是因为php中双引号可以包含单引号。


所以在判断注入时,要加入双引号进行判断。

看一下代码。

第五节:GET – Double Injection – Single Quotes – String
还是先加一个单引号,发现和第一节的结果是一样的。


于是采用和第一节同样的方法注入,但是网页却显示的是You are in...........。


看一下代码。这里登录成功以后没有像以前一样返回用户名和密码,只是返回了提示信息You are in...........。


和前面一样,为了方便学习查看,可以在源码中的$sql下一句语句写以下PHP语句(就是输出拿到数据库查询的完整语句是怎么样的)。

echo "your sql statement is ".$sql."<br>";   
这里唯一的方法就是让mysql_error打印出我们想要的信息。在继续尝试注入之前,需要先学习一些基础知识。我在mysql中建了一张表new_table,表有两列Cno和Cname,一共有12项。


下面是执行select floor(rand(0)*2) from test.new_table;的结果。


看起来很正常,对吧?但是无论执行多少次,都会是这个结果,不会变化。如果我们给rand()指定了一个种子,那么这个序列在任何时间任何地点是固定的;如果我们没有给rand()指定种子,那么这个序列是随机的,每次执行的结果都不同。mysql的文档中提到,RAND() in a WHERE clause is re-evaluated every time the WHERE is executed.You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times. 也就是说where子句中的rand()在每次执行where时重新求值。不能在ORDER BY子句中使用具有RAND()值的列,因为ORDER BY将对列进行多次计算。在实际注入中,我们更多使用的group by。那么为什么rand()会被多次计算呢?我们先把表中除了第一项以外的数据全部删除,再执行一下select count(*),floor(rand(0)*2) as a from test.new_table group by a;试试。


按照我们前面的结论,rand(0)*2第一次的值一定是0的,这里却是1。我们在表中添加一项数据,再执行一下select count(*),floor(rand(0)*2) as a from test.new_table group by a;试试。


按照我们前面的结论,rand(0)*2第一次和第二次的值一定是0和1,这里却还是只有1。我们在表中添加一项数据,再执行一下select count(*),floor(rand(0)*2) as a from test.new_table group by a;试试。


这一次直接报错,select count(*),floor(rand(0)*2) as a from test.new_table group by a LIMIT 0, 1000Error Code: 1062. Duplicate entry '1' for key '<group_key>'0.000 sec。
原来,mysql在group by时,会先建立一张虚拟表。


取第一条记录,执行floor(rand(0)*2),发现结果为0(第一次计算),查询虚拟表,发现0的键值不存在,则在虚拟表插入新的数据时floor(rand(0)*2)会被再计算一次,结果为1(第二次计算)。


取第二条记录,执行floor(rand(0)*2),发现结果为1(第三次计算),查询虚拟表,发现1的键值存在,所以floor(rand(0)*2)不会被计算第二次,直接count(*)加1,第二条记录查询完毕。


取第三条记录,再次计算floor(rand(0)*2),发现结果为0(第4次计算),查询虚拟表,发现0的键值不存在,则在虚拟表插入新的数据时floor(rand(0)*2)会被再计算一次,结果为1(第5次计算),然而1这个主键已经存在于虚拟表中,而新计算的值也为1。主键键值必须唯一,所以插入的时候就直接报错了。如果不给rand()指定种子呢?前面的记录如果使得虚拟表成了这个样子,那么后面有再多的数据也不会报错了。不指定种子时有时报错有时不报错,需要多试几次。


如果没有count(*),那么就不可能报错了,因为这个时候没有使用虚表。还是让表中只有一项,执行select floor(rand(0)*2) as a from test.new_table group by a;看看。


好了,基础知识讲完了,现在我们回到正题。尝试使用(select count(*),concat(0x3a,0x3a,(select database()),0x3a,0x3a,floor(rand()*2)) as a from information_schema.columns group by a)进行注入。


返回的错误信息是Operand should contain 1 column(s),也就是说只能返回一列。尝试使用(select 1 from(select count(*),concat(0x3a,0x3a,(select database()),0x3a,0x3a,floor(rand()*2)) as a from information_schema.columns group by a))进行注入。

返回的错误信息是Every derived table must have its own alias,也就是说每个派生出来的表都必须有一个自己的别名。尝试使用(select 1 from(select count(*),concat(0x3a,0x3a,(select database()),0x3a,0x3a,floor(rand()*2)) as a from information_schema.columns group by a)b)进行注入。

我们得到了当前使用的数据库名。继续爆当前的用户和版本信息。


爆表名。




爆列名,不再一张一张截图了。

爆用户名和密码。

这一课的本意就是让我们使用这种双注入的方法。对于基于错误的SQL注入来说,还有其它办法。
1.使用extractvalue
extractvalue(xml_frag,xpath_expr)
extractvalue()接受两个字符串参数,一个xml标记xml_frag的片段和一个xpath表达式xpath_expr(也称为定位符)。这个函数返回第一个文本节点的文本。在mysql 5.6.6及更早版本中,xpath表达式最多可以包含127个字符。这个限制在mysql 5.6.7中解除。我们可以在xpath中填写获得我们想要的信息的语句。

2.使用updatexml
updatexml(xml_target,xpath_expr,new_xml)
此函数用新的xml片段new_xml替换xml标记xml_target的给定片段的单个部分,然后返回更改的xml。被替换的xml_target的部分与用户提供的xpath表达式xpath_expr匹配。在 mysql 5.6.6及更早版本中,xpath表达式最多可以包含127个字符。这个限制在mysql 5.6.7中解除。如果没有找到匹配xpath_expr的表达式,或者找到多个匹配项,函数将返回原始的xml_target片段。 所有三个参数应该是字符串。我们可以在xpath中填写获得我们想要的信息的语句。

3.使用name_const
name_const(name,value)
用于生成结果时,name_const()会使列具有给定的名称。参数应该是常量。它和select value as name是等价的。我们可以构造两个列使得它们名字一样并在列名中填写获得我们想要的信息的语句。

第五课的内容就到这里。
参考资料:mysql中floor,ExtractValue,UpdateXml三种报错模式注入利用方法、通过sqli-labs学习sql注入——基础挑战之less1-10、youtube上的视频教程、Mysql报错注入原理分析(count()、rand()、group by)


0 0
原创粉丝点击