引言
結合DVWA(Damn Vulberable Web Application)提供的各種漏洞環境,對各類漏洞進行一下攻擊,並且記錄一下怎么防范,其實在DVWA各個漏洞安全級別的不斷提升過程中,已經告訴我們一些防范各類漏洞的防范技巧,只要我們從源碼中分析,就可以得到我們想要的答案。模塊其中主要包括:Brute Force(暴力破解)、Command Injection(命令注入)、CSRF(Cross-site request forgery)、File Inclusion(文件包含)、File Upload(文件上傳)、Insecure CAPTCHA(不安全的驗證碼)、SQL Injection(SQL注入)、SQL Injection(Blind)(SQL盲注)、XSS(Reflected)(反射型跨站腳本)、XSS(Stored)(存儲型跨站腳本)。
環境
metasploitable2(虛擬機)
phpstudy
burpsuit
Brute Force(暴力破解)
low
對於某些需要進行用戶登錄的情況我們可以使用暴力破解的方法找到用戶名以及密碼。首先我們看一下源碼:
<?php if( isset( $_GET[ 'Login' ] ) ) { // Get username $user = $_GET[ 'username' ]; // Get password $pass = $_GET[ 'password' ]; $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 echo "<pre><br />Username and/or password incorrect.</pre>"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
low級別的暴力破解漏洞源碼比較簡單,就是GET傳參$user和$pass,后面直接執行Mysql語句查詢數據庫,驗證賬號密碼是否正確,如果正確,則直接登陸成功。我們直接上burp,抓包,進行暴力破解,找一個常規的字典就可以。線程數可以調整,數量越大,速度越快。
burp四種暴力破解類型:
sniper 一個字典,兩個參數,先匹配第一項再匹配第二項
Battering ram 一個字典,兩個參數,同用戶名同密碼
Pitchfork 兩個字典,兩個參數,同行匹配,短的截至
Cluster bomb 兩個字典,兩個參數,交叉匹配,所有可能
攻擊之后按照長度對響應包進行排列,查看異常的報文,如果攻擊成功就可以找到用戶名admin的密碼。
medium
首先我們看一下源碼和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); } ?>
分析源碼可以看到,用mysql_real_escape_string函數對參數進行過濾, 轉義在 SQL 語句中使用的字符串中的特殊字符(簡單防止SQL注入),而且如果登錄失敗,代碼將延遲執行2秒(sleep(2))。這時暴力破解的時間可能比較長,但是依然能夠破解成功。采用和low級別一樣的方法即可。
high
同樣的先看一下源碼:
<?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(); ?>
high級別的暴力破解源碼中加入了一個user_token驗證,每次請求報文時,都需要加上user_token參數,而且每次這個user_token參數都是會變化的。在HTML代碼里面可以看到一個生成user_token值的表單。
我們來看一下token的原理和作用機制。
什么是Token?
Token 是在服務端產生的。如果前端使用用戶名/密碼向服務端請求認證,服務端認證成功,那么在服務端會返回 Token 給前端。前端可以在每次請求的時候帶上 Token 證明自己的合法地位。如果這個 Token 在服務端持久化(比如存入數據庫),那它就是一個永久的身份令牌。
Token可以用來干什么?
- Token完全有應用管理,它可以避開同源策略。
- Token可以避免CSRF攻擊。
- Token是無狀態的,可以在多個應用間共享。
下面我們來對題目進行破解。破解步驟可以參考https://blog.csdn.net/liweibin812/article/details/86287645
1、首先可以對password和user_token兩個參數進行暴力破解,選用burp的intruder模塊,設置兩個參數 password和user_token為變量,攻擊類型選擇pitchfork,意思是草叉模式(Pitchfork )——它可以使用多組Payload集合,在每一個不同的Payload標志位置上(最多20個),遍歷所有的Payload。舉例來說,如果有兩個Payload標志位置,第一個Payload值為A和B,第二個Payload值為C和D,則發起攻擊時,將共發起兩次攻擊,第一次使用的Payload分別為A和C,第二次使用的Payload分別為B和D。
2、設置參數,在option選項卡中將攻擊線程thread設置為1,因為Recursive_Grep模式不支持多線程攻擊,然后選擇Grep-Extract,意思是用於提取響應消息中的有用信息,點擊Add,如下圖進行設置,最后將Redirections設置為Always。
3、設置payload,第一個參數就是常規設置,導入字典即可,第二個參數為user_token設置如圖:
4、之后start attack就可以進行常規檢查,找到真實用戶名和密碼。
從該方法我們就可以知道,增加token驗證機制並不能防止暴力破解攻擊,因為token可以在前端獲取,這樣防范措施就無效了,照樣可以傳參進行暴力破解。
除了使用上述burp繞過token驗證的方法,還可以編寫腳本,每次登陸前先獲取user_token然后進行登錄驗證,這樣也能實現暴力破解。
暴力破解的防范
結合前面不同級別源碼以及其他知識,我們可以總結一下防范暴力破解的方法。
- 對登陸失敗的情況做一些處理,比如失敗次數超過一定數量,則鎖定賬號或者ip一段時間。
- 設置安全的驗證碼
- 使用Token+驗證碼一起使用,這樣可以防止csrf攻擊。
- 限制登錄之間的時間限制(例如兩次登錄之間必須間隔10秒),當然這樣也會在一定程度上降低用戶體驗。