注意,這一關必須要使用Burpsuite來抓包
目錄
- Low
- 1.抓包
- 2.發送到爆破模塊
- 3.選擇爆破模式
- 爆破模式介紹
- 4.添加載荷
- 5.添加字典
- 6.爆破查看
- 查看源碼
- Medium
- 查看源碼
- High
- 1.抓包
- 2.在bp的`extensions`中找到`CSRF Token Tracker`,并安裝
- 3.構造字典
- 4.成功爆破
- 查看源碼
- Impossible
- 查看源碼
Low
1.抓包
打開代理,然后在登錄框隨便輸入賬號密碼
可以攔截抓包:
也可以在歷史中找到對應的包:
2.發送到爆破模塊
右鍵
3.選擇爆破模式
將Attack type的值設置為Cluster bomb
爆破模式介紹
4.添加載荷
選中需要爆破的地方,點擊add(在前后輸入§
也行)
5.添加字典
可以選擇導入字典也可以手動輸入
6.爆破查看
果然成功了:
查看源碼
<?phpif( isset( $_GET[ 'Login' ] ) ) {// 安全風險:使用GET方法傳遞用戶名和密碼,會暴露在URL中并可能被日志記錄// 建議:使用POST方法處理敏感信息// Get username$user = $_GET[ 'username' ];// 安全風險:未對用戶名進行任何過濾或轉義處理,直接用于SQL查詢// 存在嚴重的SQL注入漏洞// Get password$pass = $_GET[ 'password' ];// 安全風險:密碼通過GET傳輸,存在泄露風險// 安全風險:使用MD5哈希密碼,安全性極低,易被彩虹表破解// 安全風險:未使用鹽值增強密碼哈希安全性// 建議:使用password_hash()和password_verify()$pass = md5( $pass );// Check the database// 安全風險:直接拼接用戶輸入構建SQL查詢,存在嚴重SQL注入漏洞$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";// 安全風險:數據庫錯誤直接顯示給用戶,可能泄露數據庫結構等敏感信息$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>' );if( $result && mysqli_num_rows( $result ) == 1 ) {// Get users details$row = mysqli_fetch_assoc( $result );$avatar = $row["avatar"];// Login successfulecho "<p>Welcome to the password protected area {$user}</p>";// 安全風險:直接輸出用戶可控的$avatar變量,可能存在XSS攻擊// 示例:如果avatar存儲為javascript:alert('xss'),可能執行腳本echo "<img src=\"{$avatar}\" />";// 安全風險:缺少會話管理機制,無法在后續請求中保持登錄狀態// 建議:使用session_start()初始化會話并存儲用戶認證信息}else {// Login failedecho "<pre><br />Username and/or password incorrect.</pre>";}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?>
可以發現,這個登錄框甚至都沒有做sql注入防護,那么使用萬能密碼就可以直接登錄…
- 總的來說,這個只實現了驗證賬號密碼是否匹配的功能,幾乎沒有安全性可言
Medium
查看源碼
<?phpif( isset( $_GET[ 'Login' ] ) ) {// 安全風險:使用GET方法傳輸用戶名和密碼,數據會暴露在URL中,可能被日志記錄// 建議:使用POST方法傳輸敏感信息// Sanitise username input$user = $_GET[ 'username' ];// 安全風險:僅使用mysqli_real_escape_string()不足以完全防止SQL注入// 建議:使用參數化查詢(prepared statements)$user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));// Sanitise password input$pass = $_GET[ 'password' ];// 同樣存在SQL注入防護不足的問題$pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));// 安全風險:使用MD5哈希密碼,安全性不高,易被破解// 安全風險:未使用鹽值(salt)增強哈希安全性// 建議:使用password_hash()和password_verify()函數$pass = md5( $pass );// Check the database// 安全風險:通過字符串拼接構建SQL查詢,存在SQL注入風險$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";// 安全風險:查詢錯誤時直接輸出數據庫錯誤信息,可能泄露敏感信息// 建議:生產環境中不顯示具體錯誤信息,記錄到日志$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>' );if( $result && mysqli_num_rows( $result ) == 1 ) {// Get users details$row = mysqli_fetch_assoc( $result );$avatar = $row["avatar"];// Login successfulecho "<p>Welcome to the password protected area {$user}</p>";// 安全風險:直接輸出從數據庫獲取的avatar路徑,可能存在XSS攻擊風險echo "<img src=\"{$avatar}\" />";// 安全風險:缺少會話管理機制,無法在后續請求中保持身份驗證狀態// 建議:使用session_start()和$_SESSION存儲用戶認證狀態}else {// Login failed// 安全風險:登錄失敗時使用sleep(2),導致響應時間差異,可能被用于暴力破解// 建議:移除sleep()或對成功和失敗響應使用相同的延遲處理sleep( 2 );echo "<pre><br />Username and/or password incorrect.</pre>";}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?>
- 不難發現,相比于Low級別的代碼,Medium級別的代碼主要增加了
mysql_real_escape_string
函數,這個函數會對字符串中的特殊符號(x00,n,r,,’,",x1a)進行轉義,把其中的字符串給過濾掉了,勉強能夠抵御一般的sql注入攻擊,那Low等級時候用到的注入就失效了,需要注意的是中級的暴力破解相對來說較慢是因為有個sleep函數,在破解失敗后會使程序停止運行兩秒。所以我們直接用爆破方法即可,和low級的一樣。
High
1.抓包
發送到爆破模塊,發現登陸時有token
要么刪除token后發包;要么使用同一個token,重放;要么使用burp得插件CSRF Token Tracker,根據規則從reponse報文中找到token并使其他模塊發送報文時自動更新新的token。
2.在bp的extensions
中找到CSRF Token Tracker
,并安裝
其中host為包中的host,name為token字段名
ps:使用CSRF Token Tracker插件的原理:你提交用戶名密碼后,burp捕獲這個數據包,然后你將這個數據包
send to repeater
,send發送給服務端,服務端發送響應包, CSRF Token Tracker插件捕獲響應包中的user_token
。
3.構造字典
和low一樣添加字典
使用單線程
4.成功爆破
查看源碼
<?phpif( isset( $_GET[ 'Login' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );// 安全改進:添加了CSRF令牌驗證,有助于防止跨站請求偽造攻擊// 注意:需確認checkToken()實現是否安全,以及令牌生成邏輯是否可靠// Sanitise username input$user = $_GET[ 'username' ];// 安全風險:使用GET方法傳輸用戶名和密碼,敏感信息會暴露在URL中$user = stripslashes( $user );// 安全問題:stripslashes()僅移除反斜杠,不能有效防止SQL注入// 注意:與mysqli_real_escape_string()配合使用可能產生意外結果$user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));// 安全風險:仍依賴字符串拼接構建SQL查詢,mysqli_real_escape_string()防護有限// 建議:使用參數化查詢(prepared statements)徹底防止SQL注入// Sanitise password input$pass = $_GET[ 'password' ];$pass = stripslashes( $pass );$pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));// 安全風險:密碼哈希使用MD5算法,安全性極低,易被破解// 安全風險:未使用鹽值(salt)增強密碼哈希安全性// 建議:使用password_hash()和password_verify()函數$pass = md5( $pass );// Check database$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";// 安全風險:通過字符串拼接構建SQL查詢,仍存在SQL注入風險// 即使使用了轉義函數,在特定編碼或場景下仍可能被繞過$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>' );// 安全風險:數據庫錯誤直接顯示給用戶,可能泄露數據庫結構等敏感信息// 建議:生產環境中記錄錯誤日志,不向用戶展示具體錯誤信息if( $result && mysqli_num_rows( $result ) == 1 ) {// Get users details$row = mysqli_fetch_assoc( $result );$avatar = $row["avatar"];// Login successfulecho "<p>Welcome to the password protected area {$user}</p>";// 安全風險:直接輸出$user變量,未進行HTML轉義,可能存在XSS攻擊// 建議:使用htmlspecialchars($user, ENT_QUOTES)轉義輸出echo "<img src=\"{$avatar}\" />";// 安全風險:直接使用數據庫中的$avatar路徑,若該值用戶可控則存在XSS風險// 建議:驗證路徑合法性并使用htmlspecialchars()轉義// 安全風險:缺少會話管理機制,登錄狀態無法在后續請求中保持// 建議:使用session_start()初始化會話并存儲用戶認證信息}else {// Login failedsleep( rand( 0, 3 ) );// 安全改進:使用隨機延遲替代固定延遲,降低暴力破解效率// 仍存在:成功與失敗響應時間差異可能被利用的風險echo "<pre><br />Username and/or password incorrect.</pre>";}// 代碼問題:數據庫連接關閉方式過于復雜,可簡化為mysqli_close($GLOBALS["___mysqli_ston"])((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}// Generate Anti-CSRF token
generateSessionToken();
// 注意:需確認generateSessionToken()生成的令牌是否足夠隨機且安全?>
原理就是 token是前端生成的所以我們可以提前獲取他的值(利用的就是token的復用 我們上一次訪問失敗之后可以把他的token搞到下一次去使用 這樣就可以使用這個token去爆破)但是現實場景我們是不知道他的token的 無法提取獲取。總的來說就是下面兩點:
令牌暴露在前端: 無論后端如何生成,令牌最終會作為 HTML 內容返回給前端(否則前端無法提交),攻擊者可通過訪問頁面直接提取。
復用無限制:代碼未實現 “一次有效” 機制,同一令牌可在同一會話中反復使用,無需每次重新獲取,失敗不失效。
Impossible
查看源碼
<?phpif( isset( $_POST[ 'Login' ] ) && isset ($_POST['username']) && isset ($_POST['password']) ) {// 安全改進:使用POST方法傳輸登錄數據(用戶名、密碼)// 相比GET方法,POST數據在URL中不可見,避免了瀏覽器歷史、服務器日志泄露敏感信息的風險// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );// 保留并延續了CSRF令牌驗證機制,有效防御跨站請求偽造攻擊// 確保登錄請求來自當前用戶的合法會話,而非第三方偽造// Sanitise username input$user = $_POST[ 'username' ];$user = stripslashes( $user );$user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));// Sanitise password input$pass = $_POST[ 'password' ];$pass = stripslashes( $pass );$pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass = md5( $pass );// 注:MD5哈希密碼仍是安全短板,但本版代碼的核心改進在其他維度// Default values$total_failed_login = 3; // 設定最大失敗登錄次數(3次)$lockout_time = 15; // 設定賬戶鎖定時長(15分鐘)$account_locked = false;// 安全改進:新增賬戶鎖定機制的基礎配置,從源頭限制暴力破解頻率// Check the database (Check user information)$data = $db->prepare( 'SELECT failed_login, last_login FROM users WHERE user = (:user) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR );$data->execute();$row = $data->fetch();// 安全改進:使用PDO參數化查詢(prepare + bindParam)// 徹底杜絕SQL注入風險!參數化查詢將用戶輸入與SQL語句邏輯分離,輸入無法被解析為SQL命令// Check to see if the user has been locked out.if( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) ) {// 安全改進:實現賬戶鎖定邏輯——當失敗次數達到閾值時,觸發鎖定判斷// 注:此處雖有用戶枚舉風險(可通過返回信息判斷用戶名是否存在),但核心鎖定功能已生效// Calculate when the user would be allowed to login again$last_login = strtotime( $row[ 'last_login' ] );$timeout = $last_login + ($lockout_time * 60);$timenow = time();// Check to see if enough time has passed, if it hasn't locked the accountif( $timenow < $timeout ) {$account_locked = true;// 安全改進:鎖定邏輯生效——在鎖定時長內,即使密碼正確也無法登錄// 有效阻止“短時間高頻次暴力破解”,大幅提升破解成本}}// Check the database (if username matches the password)$data = $db->prepare( 'SELECT * FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR);$data->bindParam( ':password', $pass, PDO::PARAM_STR );$data->execute();$row = $data->fetch();// 再次使用PDO參數化查詢,確保密碼驗證環節無SQL注入風險// 同時通過LIMIT 1優化查詢效率,避免冗余數據返回// If its a valid login...if( ( $data->rowCount() == 1 ) && ( $account_locked == false ) ) {// Get users details$avatar = $row[ 'avatar' ];$failed_login = $row[ 'failed_login' ];$last_login = $row[ 'last_login' ];// Login successfulecho "<p>Welcome to the password protected area <em>{$user}</em></p>";echo "<img src=\"{$avatar}\" />";// Had the account been locked out since last login?if( $failed_login >= $total_failed_login ) {echo "<p><em>Warning</em>: Someone might of been brute forcing your account.</p>";echo "<p>Number of login attempts: <em>{$failed_login}</em>.<br />Last login attempt was at: <em>{$last_login}</em>.</p>";}// 安全改進:新增安全預警——當用戶登錄時,提示之前存在暴力破解嘗試// 提升用戶安全感知,便于用戶及時修改密碼等操作// Reset bad login count$data = $db->prepare( 'UPDATE users SET failed_login = "0" WHERE user = (:user) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR );$data->execute();// 安全改進:登錄成功后重置失敗次數// 確保合法用戶后續登錄不受之前失敗記錄影響,平衡安全性與用戶體驗} else {// Login failedsleep( rand( 2, 4 ) );// 保留隨機延遲機制,避免攻擊者通過響應時間差異判斷“用戶名/密碼是否正確”// 相比固定延遲,隨機延遲更難被暴力破解工具利用// Give the user some feedbackecho "<pre><br />Username and/or password incorrect.<br /><br/>Alternative, the account has been locked because of too many failed logins.<br />If this is the case, <em>please try again in {$lockout_time} minutes</em>.</pre>";// 安全改進:模糊錯誤提示——不明確告知“是用戶名錯”還是“密碼錯”,也不直接確認“賬戶是否存在”// 有效降低用戶枚舉風險,同時告知鎖定規則,提升用戶體驗// Update bad login count$data = $db->prepare( 'UPDATE users SET failed_login = (failed_login + 1) WHERE user = (:user) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR );$data->execute();// 安全改進:登錄失敗后累加失敗次數// 為后續賬戶鎖定邏輯提供數據支撐,形成“失敗-累加-鎖定”的完整防御鏈}// Set the last login time$data = $db->prepare( 'UPDATE users SET last_login = now() WHERE user = (:user) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR );$data->execute();// 安全改進:記錄每次登錄(無論成功/失敗)的時間// 一方面用于賬戶鎖定的超時計算,另一方面可作為審計日志,便于后續安全分析
}// Generate Anti-CSRF token
generateSessionToken();
// 延續令牌生成機制,確保每次頁面加載都有有效令牌,維持CSRF防御能力?>
- 徹底防御 SQL 注入:全面采用 PDO 參數化查詢,替代字符串拼接,從根源杜絕注入風險;
- 強化暴力破解防御:新增 “失敗次數累加 + 超時鎖定” 機制,大幅提升破解成本,同時保留隨機延遲;
- 優化敏感數據傳輸:改用 POST 方法傳輸用戶名 / 密碼,避免 URL 泄露;
- 降低信息泄露風險:模糊錯誤提示,減少用戶枚舉可能;
- 增強用戶安全感知:登錄成功時提示暴力破解預警,同時重置失敗次數,平衡安全與體驗;
- 完善審計與配置:記錄登錄時間,支持可配置的鎖定閾值與時長,便于維護與擴展。
對于制作靶場的作者當時來說md5已經十分牢固,但是隨著時代發展,md5變得不那么牢固了,但是這仍然是優秀代碼的典范