SQL-injection-blind

当攻击者执行 SQL 注入攻击时,服务器有时会响应来自数据库服务器的错误消息,报告 SQL 查询的语法不正确。SQL 盲注入与普通 SQL 注入相同,只是当攻击者试图利用应用程序进行攻击时,得到的不是有用的报错信息,而是开发人员指定的通用页面。这使得利用 SQL 注入攻击变得更加困难,但这并非是不可能的。攻击者仍然可以通过 SQL 语句询问一系列真假问题,并监视 web 应用程序的响应来窃取数据。

  1. 布尔盲注:顾名思义就是基于布尔运算特性的盲注,布尔盲注语句需要在涉及判断的功能才能使用,其中最常见的就是在查询条件的位置,分别拼接上一段结果为真和结果为假的判断语句,如果结果为真时显示效果与原来一致,结果为假时查询不到数据或与原来数据不一直,则认为存在布尔盲注。
  1. 时间盲注:同样也就是基于时间运算特性的盲注,时间盲注主要是对没有涉及判断的功能,如插入、更新等语句的数据为止(而非条件语句的位置),或者布尔盲注没有结果的类型(如显示均为正常或均为异常),可以尝试使用延迟注入进行测试,如果插入时间型盲注语句后服务器延迟响应,则可以认为存在SQL注入漏洞。

low

请求页面

1692261151176

http请求

输入 1,先看看情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GET /vulnerabilities/sqli_blind/?id=1&Submit=Submit HTTP/1.1
Host: localhost:4280
sec-ch-ua:
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: ""
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.199 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:4280/vulnerabilities/sqli_blind/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=56b6259296256464a178e043c6597894; security=low
Connection: close

响应页面

1692261278132

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<<?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);
}

?>
?>

攻击思路

  1. 布尔盲注
    通过分析源码,可以知道一些重要的信息,比如说这是数值型注入并且页面会有2种显。二分法分万物哈哈哈哈哈。

    1. 判断注入类型,结果数值型

      • 输入 1,返回 User ID exists in the database.
      • 输入 1‘,返回 User ID is MISSING from the database.
    2. 判断回显。只有以上两种回显。

    3. 获取其他信息。运用布尔盲注或者时间盲注,这里使用布尔盲注比较快捷

      • 获取数据库版本号。最后测试出版本为 10.1.26

        • 判断版本号第1位是否为1,1' and substr(version(),1,1) = '1' #
        • 判断版本号第2位是否为0,1' and substr(version(),2,1) = '0' #
        • 以此类推
      • 获取数据路名称。也可以用ASCII码来辅助判断,最后测试出名称为 dvwa

        字符 ASCII(十进制)
        a 97
        A 65
        0 48
        _ 95
        z 122
        Z 90
        9 57
        @ 64
    - 判断数据库名第1位是d,`1'and ascii(substr(database(),1,1))=100 #`
  1. 时间盲注(顺序类似布尔盲注)
    • 判断数据库版本第1位是1,。1' and if(substr(version(),1,1) = '1' , sleep(3), 1) #

medium

请求页面

请求页面变成了下拉选择框,限制用户输入
1692283885330

http请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
POST /vulnerabilities/sqli_blind/ HTTP/1.1
Host: localhost
Content-Length: 18
Cache-Control: max-age=0
sec-ch-ua:
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: ""
Upgrade-Insecure-Requests: 1
Origin: http://localhost
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.199 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost/vulnerabilities/sqli_blind/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=56b6259296256464a178e043c6597894; security=medium
Connection: close

id=1&Submit=Submit

源码

源码如下,源码使用了 mysql_real_escape_string() 函数转义字符串中的特殊字符。也就是说特殊符号 \x00、\n、\r、\、’、” 和 \x1a 都将进行转义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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();
}

?>

攻击思路

  1. 布尔盲注
    值得一提的是,单引号在中级别的代码中被过滤了,不过我们可以使用 ASCII 码的值来代替原来单引号括起来的字符。MySql 的 ASCII() 函数把字符转换成 ascii 码值,然后我们同样把版本号的各个字符提取出来,然后和 0 ~ 9 和 “.” 11 个字符的 ascii 码值作比较。
    • 获取数据库版本号
      • 判断第1位是不是1,1 and ascii(substr(version(),1,1)) = 49 #
    • 获取数据库名
      • 判断数据库名第1位是d,1 and ascii(substr(database(),1,1))=100 #
  2. 时间盲注(过程类似布尔盲注)
    • 获取数据库版本号
      • 判断第1位是不是1,1 and if(ascii(substr(version(),1,1)) = 49,sleep(3),1) #

high

源码

源码如下,High 级别的只是在 SQL 查询语句中添加了 LIMIT 1,这令服务器仅回显查询到的一个结果。同时源码利用了 cookie 传递参数 id,当 SQL 查询结果为空时会执行函数 sleep(),这是为了混淆基于时间的盲注的响应时间判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?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);
}

?>

攻击思路

由于当查询不到结果时,服务器会等待一段时间,这会对时间盲注造成混淆,因此我们使用 bool 盲注。虽然查询语句添加了 LIMIT 1,但是我们可以利用 “#” 把它注释掉,这种防御形同虚设,此时 bool 盲注的过程与 Low 级别基本一样。

  1. 布尔盲注
    • 判断数据库版本第1位是1,1' and substr(version(),1,1) = '1' #

impossible

源码

impossible 级别的代码采用了 PDO 技术,防止代码和查询数据的混杂,Anti-CSRFtoken 机制的加入了进一步提高了安全性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

if( isset( $_GET[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

// Get input
$id = $_GET[ 'id' ];

// Was a number entered?
if(is_numeric( $id )) {
// Check the database
$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();

// Get results
if( $data->rowCount() == 1 ) {
// 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>';
}
}
}

// Generate Anti-CSRF token
generateSessionToken();

?>

总结

SQL 注入攻击就是 Web 程序对用户的输入没有进行合法性判断,从而攻击者可以从前端向后端传入攻击参数,并且该参数被带入了后端执行。在很多情况下开发者会使用动态的 SQL 语句,这种语句是在程序执行过程中构造的,不过动态的 SQL 语句很容易被攻击者传入的参数改变其原本的功能。
当我们进行手工 SQL 注入时,往往是采取以下几个步骤:

  1. 判断是否存在注入,注入是字符型还是数字型
  2. 猜解SQL查询语句中的字段数;
  3. 获取当前数据库;
  4. 获取数据库中的表;
  5. 获取表中的字段名;

当开发者需要防御 SQL 注入攻击时,可以采用以下方法。

  1. 过滤危险字符:可以使用正则表达式匹配各种 SQL 子句,例如 select,union,where 等,如果匹配到则退出程序。
  2. 使用预编译语句:PDO 提供了一个数据访问抽象层,这意味着不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。使用 PDO 预编译语句应该使用占位符进行数据库的操作,而不是直接将变量拼接进去。

SQL-injection-blind
http://blog.lingyuanming.site/2022/06/05/dvwa-SQL-injection-blind/
作者
LYM
发布于
2022年6月5日
许可协议