LOW等級
我們先用burpsuite抓包,因為burpsuite提供了暴力破解模塊
我們先創建一個1.txt文件夾,把正確的賬號密碼寫進去
我們輸入 Username:1 Password:1 進行抓包,然后發送到intruder(攻擊)模塊
Sniper標簽這個是我們最常用的,Sniper是狙擊手的意思。這個模式會使用單一的payload【就是導入字典的payload】組。它會針對每個position中$$位置設置payload。這種攻擊類型適合對常見漏洞中的請求參數單獨地進行測試。攻擊中的請求總數應該是position數量和payload數量的乘積。
Battering ram – 這一模式是使用單一的payload組。它會重復payload並且一次把所有相同的payload放入指定的位置中。這種攻擊適合那種需要在請求中把相同的輸入放到多個位置的情況。請求的總數是payload組中payload的總數。簡單說就是一個playload字典同時應用到多個position中
Pitchfork – 這一模式是使用多個payload組。對於定義的位置可以使用不同的payload組。攻擊會同步迭代所有的payload組,把payload放入每個定義的位置中。比如:position中A處有a字典,B處有b字典,則a【1】將會對應b【1】進行attack處理,這種攻擊類型非常適合那種不同位置中需要插入不同但相關的輸入的情況。請求的數量應該是最小的payload組中的payload數量
Cluster bomb – 這種模式會使用多個payload組。每個定義的位置中有不同的payload組。攻擊會迭代每個payload組,每種payload組合都會被測試一遍。比如:position中A處有a字典,B處有b字典,則兩個字典將會循環搭配組合進行attack處理這種攻擊適用於那種位置中需要不同且不相關或者未知的輸入的攻擊。攻擊請求的總數是各payload組中payload數量的乘積。

果然爆出了正確的賬號跟密碼
同樣,我們也可以用python進行暴力破解:

Medium等級
經驗證發現用LOW等級的方法依然可以進行暴力破解,但是明顯可以感覺用的時間比LOW等級長
我們能來看一下源代碼:
<?php if( isset( $_GET[ 'Login' ] ) ) { // Sanitise username input $user = $_GET[ 'username' ]; $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' ]; $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 ); // Check the database $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 successful echo "<p>Welcome to the password protected area {$user}</p>"; echo "<img src=\"{$avatar}\" />"; } else { // Login failed sleep( 2 ); echo "<pre><br />Username and/or password incorrect.</pre>"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
中間有個sleep(2)的php函數,即是如果賬號或者密碼錯誤,程序停止運行兩秒,導致medium等級的爆破所用時間更長
High等級
我們先來抓包看一下,輸入username:1 password:1 ,抓到的包如圖:
多了一個user_token的驗證
我們來看一下源代碼:
<?php if( isset( $_GET[ 'Login' ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Sanitise username input $user = $_GET[ '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 = $_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)) ? "" : "")); $pass = md5( $pass ); // Check database $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 successful echo "<p>Welcome to the password protected area {$user}</p>"; echo "<img src=\"{$avatar}\" />"; } else { // Login failed sleep( rand( 0, 3 ) ); echo "<pre><br />Username and/or password incorrect.</pre>"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?>

這里利用burp來爆破帶有規律性的token驗證:
1.抓包,選擇Pitchfork(草叉模式),添加爆破的參數

2.在Options中找到Request Engine模塊,把線程數設為1

3.在Options中找到Rediections模塊,選擇always,允許重定向

4.在Options中找到Grep-Extract模塊,點擊Add,並設置篩選條件,得到user_token。

5.在Payloads中為選擇的參數設置字典



6.開始爆破

根據返回長度的大小,可以得到正確的用戶密碼
除了burpsuite爆破,也可以通過python腳本實現,鄙人較菜,代碼不好看,但是經實驗可以運行:

代碼執行結果:

impossible等級
impossible幾乎是不可能注入,我們來看一下代碼
<?php if( isset( $_POST[ 'Login' ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // 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 ); // Default values $total_failed_login = 3; $lockout_time = 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(); // Check to see if the user has been locked out. if( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) ) { // User locked out. Note, using this method would allow for user enumeration! //echo "<pre><br />This account has been locked due to too many incorrect logins.</pre>"; // Calculate when the user would be allowed to login again $last_login = strtotime( $row[ 'last_login' ] ); $timeout = $last_login + ($lockout_time * 60); $timenow = time(); /* print "The last login was: " . date ("h:i:s", $last_login) . "<br />"; print "The timenow is: " . date ("h:i:s", $timenow) . "<br />"; print "The timeout is: " . date ("h:i:s", $timeout) . "<br />"; */ // Check to see if enough time has passed, if it hasn't locked the account if( $timenow < $timeout ) { $account_locked = true; // print "The account is locked<br />"; } } // 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(); // 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 successful echo "<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 failed sleep( rand( 2, 4 ) ); // Give the user some feedback echo "<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(); ?>
我們嘗試輸入錯誤的用戶名跟密碼:
發現再次嘗試要等到15分鍾后,果然是impossible等級,限制了暴力破解,多次嘗試輸入
所以說要防止暴力破解:
