目錄
一、reCAPTCHA
二、代碼審計(High級別)
1、滲透準備
(1)配置security為High級別。
(2)配置RECAPTCHA參數
(3)再次打開靶場
2、源碼分析
(1)index.php
(2)High.php
(3)功能函數
(4)總結
三、滲透實戰
1、滲透方法一
(1)源碼修改
(2)點擊change
2、滲透方法二
(1)源碼修改
(2)修改密碼
(3)bp改包
本系列為通過《DVWA靶場通關筆記》的reCAPTCHA關卡(low,medium,high,impossible共4關)滲透集合,通過對相應關卡源碼的代碼審計找到講解滲透原理并進行滲透實踐,本文為reCAPTCHA關卡High級別關卡的滲透部分。
一、reCAPTCHA
reCAPTCHA關卡模擬了網站驗證碼系統的實現,在通過繞過驗證碼的安全驗證來實現密碼修改等操作,不同安全等級存在不同的安全風險和繞過方法,本小節對高等級別的關卡進行滲透實戰。
二、代碼審計(High級別)
1、滲透準備
(1)配置security為High級別。
進入到reCAPTCHA關卡High頁面,完整URL地址具體如下所示。
http://127.0.0.1/DVWA/vulnerabilities/captcha/
(2)配置RECAPTCHA參數
進入到DVWA的config目錄,如下所示找到config.inc.php文件。
修改config.inc.php文件中如下內容,雖然在RECAPTCHA關卡的頁面提示api-key需要通過https://www.google.com/recaptcha/admin/create生成,但是實際上這部分可以填充為自己的內容,如下所示。
$_DVWA[ 'recaptcha_public_key' ]? = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXMOOYUAN';
$_DVWA[ 'recaptcha_private_key' ] = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXMOOYUAN';
修改后效果如下所示,記得修改后保存文件。
(3)再次打開靶場
如下所示,更新config.inc.php文件后,靶場可以正常打開,這是一個具有修改密碼功能的頁面。
2、源碼分析
(1)index.php
進入DVWA靶場源目錄,找到index.php源碼。
這段代碼實現了
?DVWA (Damn Vulnerable Web Application)?
中的
reCAPTCHA
關卡的演示頁面,主要功能包括:
DVWA的Insecure CAPTCHA模塊通過四個安全等級(低、中、高、不可能)演示驗證碼系統的安全演進,該模塊核心展示密碼修改場景下的驗證碼實現,包含密鑰檢查、表單動態生成(根據等級顯示不同字段)和安全警告提示,如客戶端驗證繞過、驗證碼重復使用等問題,并通過對比不同等級的實現差異,直觀呈現從脆弱到安全的演進過程,最終強調應使用專業驗證服務(如reCAPTCHA)配合多因素驗證的整體防護思路。
- 初始化與安全級別處理
- 設置頁面路徑和安全依賴。
- 根據用戶安全級別(低、中、高、不可能)加載不同的驗證碼實現。
- 驗證碼配置檢查
- 驗證是否配置了 reCAPTCHA API 密鑰。
- 若未配置則顯示警告并隱藏表單。
- 表單構建
- 生成密碼修改表單,包含當前密碼(僅 "不可能" 級別)、新密碼和確認密碼字段。
- 根據安全級別不同,集成不同的驗證碼機制(低級、中級、高級和不可能四個級別)。
- 安全措施
- "高" 和 "不可能" 級別包含 CSRF 令牌保護。
- "不可能" 級別增加了當前密碼驗證。
經過注釋后的詳細代碼如下所示。
<?php
/*** DVWA Insecure CAPTCHA 演示頁面* 演示不同安全等級下的驗證碼實現方式及潛在安全風險*/// 定義網站根目錄路徑
define( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );// 引入必要的庫文件
require_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php'; // DVWA核心頁面庫
require_once DVWA_WEB_PAGE_TO_ROOT . "external/recaptcha/recaptchalib.php"; // reCAPTCHA庫// 初始化頁面,要求認證并啟用PHPIDS防護
dvwaPageStartup( array( 'authenticated', 'phpids' ) );// 創建新頁面對象
$page = dvwaPageNewGrab();
// 設置頁面標題
$page[ 'title' ] = 'Vulnerability: Insecure CAPTCHA' . $page[ 'title_separator' ].$page[ 'title' ];
// 設置頁面ID
$page[ 'page_id' ] = 'captcha';
// 設置幫助按鈕
$page[ 'help_button' ] = 'captcha';
// 設置源代碼查看按鈕
$page[ 'source_button' ] = 'captcha';// 連接數據庫
dvwaDatabaseConnect();// 根據安全等級選擇對應的實現文件
$vulnerabilityFile = '';
switch( $_COOKIE[ 'security' ] ) {case 'low': // 低安全等級$vulnerabilityFile = 'low.php';break;case 'medium': // 中安全等級$vulnerabilityFile = 'medium.php';break;case 'high': // 高安全等級$vulnerabilityFile = 'high.php';break;default: // 默認(不可能等級)$vulnerabilityFile = 'impossible.php';break;
}// 控制表單是否顯示
$hide_form = false;
// 引入對應的實現文件
require_once DVWA_WEB_PAGE_TO_ROOT . "vulnerabilities/captcha/source/{$vulnerabilityFile}";// 檢查reCAPTCHA密鑰配置
$WarningHtml = '';
if( $_DVWA[ 'recaptcha_public_key' ] == "" ) {$WarningHtml = "<div class=\"warning\"><em>reCAPTCHA API key missing</em> from config file: " . realpath( getcwd() . DIRECTORY_SEPARATOR . DVWA_WEB_PAGE_TO_ROOT . "config" . DIRECTORY_SEPARATOR . "config.inc.php" ) . "</div>";$html = "<em>Please register for a key</em> from reCAPTCHA: " . dvwaExternalLinkUrlGet( 'https://www.google.com/recaptcha/admin/create' );$hide_form = true; // 密鑰缺失時隱藏表單
}// 構建頁面主體HTML
$page[ 'body' ] .= "
<div class=\"body_padded\"><h1>Vulnerability: Insecure CAPTCHA</h1>{$WarningHtml}<div class=\"vulnerable_code_area\"><form action=\"#\" method=\"POST\" ";// 密鑰缺失時隱藏表單
if( $hide_form )$page[ 'body' ] .= "style=\"display:none;\"";$page[ 'body' ] .= "><h3>Change your password:</h3><br /><input type=\"hidden\" name=\"step\" value=\"1\" />\n";// 不可能等級需要驗證當前密碼
if( $vulnerabilityFile == 'impossible.php' ) {$page[ 'body' ] .= "Current password:<br /><input type=\"password\" AUTOCOMPLETE=\"off\" name=\"password_current\"><br />";
}$page[ 'body' ] .= " New password:<br /><input type=\"password\" AUTOCOMPLETE=\"off\" name=\"password_new\"><br />Confirm new password:<br /><input type=\"password\" AUTOCOMPLETE=\"off\" name=\"password_conf\"><br />" . recaptcha_get_html( $_DVWA[ 'recaptcha_public_key' ] ); // 插入reCAPTCHA組件// 高安全等級下的開發者注釋提示
if( $vulnerabilityFile == 'high.php' )$page[ 'body' ] .= "\n\n <!-- **DEV NOTE** Response: 'hidd3n_valu3' && User-Agent: 'reCAPTCHA' **/DEV NOTE** -->\n";// 高和不可能等級添加CSRF令牌
if( $vulnerabilityFile == 'high.php' || $vulnerabilityFile == 'impossible.php' )$page[ 'body' ] .= "\n " . tokenField();$page[ 'body' ] .= "<br /><input type=\"submit\" value=\"Change\" name=\"Change\"></form>{$html} <!-- 顯示操作結果 --></div><h2>More Information</h2><ul><li>" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/CAPTCHA' ) . "</li><li>" . dvwaExternalLinkUrlGet( 'https://www.google.com/recaptcha/' ) . "</li><li>" . dvwaExternalLinkUrlGet( 'https://www.owasp.org/index.php/Testing_for_Captcha_(OWASP-AT-012)' ) . "</li></ul>
</div>\n";// 輸出完整HTML頁面
dvwaHtmlEcho( $page );?>
(2)High.php
進入DVWA靶場源目錄,找到High.php源碼。
打開源碼High.php,
打開源碼High.php,分析可知這段代碼實現了實現了帶有?CSRF?保護和?CAPTCHA?驗證的密碼更改功能,主要過程如下所示:
- 增加了Anti-CSRF令牌防護(特別注意:由于本關卡這部分是亂填的,且會向https://www.google.com/recaptcha/api/siteverify提交請求,這個網站目前無法響應,故需注釋掉這部分驗證,否則沒法向下繼續走,但是相對于low和meidium關卡,本次沒有必要強制設置$resp=1,默認情況下$resp=0)。
- 使用reCAPTCHA進行人機驗證
- 需要驗證當前密碼
- 使用PDO預處理語句防止SQL注入
- 對密碼進行MD5加密存儲
- 包含輸入清理和驗證
詳細注釋后的代碼如下所示。?
<?php// 檢查是否是密碼修改請求
if( isset( $_POST[ 'Change' ] ) ) {// 1. 首先檢查Anti-CSRF令牌,防止跨站請求偽造攻擊checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );// 隱藏表單,準備顯示結果$hide_form = true;// 2. 獲取并處理新密碼輸入$pass_new = $_POST[ 'password_new' ];$pass_new = stripslashes( $pass_new ); // 去除反斜線// 轉義特殊字符防止SQL注入$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_new = md5( $pass_new ); // MD5哈希(注:不夠安全)// 3. 獲取并處理確認密碼$pass_conf = $_POST[ 'password_conf' ];$pass_conf = stripslashes( $pass_conf );$pass_conf = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_conf ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_conf = md5( $pass_conf );// 4. 獲取并處理當前密碼$pass_curr = $_POST[ 'password_current' ];$pass_curr = stripslashes( $pass_curr );$pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_curr = md5( $pass_curr );// 5. 檢查CAPTCHA驗證//$resp = recaptcha_check_answer(//$_DVWA[ 'recaptcha_private_key' ], // reCAPTCHA私鑰//$_POST['g-recaptcha-response'] // 用戶輸入的驗證碼//);// CAPTCHA驗證失敗處理if( !$resp ) {$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";$hide_form = false;return;}else {// 6. 驗證當前密碼是否正確(使用PDO預處理語句)$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );$data->execute();// 7. 檢查:新密碼是否匹配且當前密碼正確if( ( $pass_new == $pass_conf) && ( $data->rowCount() == 1 ) ) {// 8. 更新密碼(使用PDO預處理語句)$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );$data->execute();// 9. 顯示成功信息$html .= "<pre>Password Changed.</pre>";}else {// 10. 顯示失敗信息(當前密碼錯誤或新密碼不匹配)$html .= "<pre>Either your current password is incorrect or the new passwords did not match.<br />Please try again.</pre>";$hide_form = false;}}
}// 11. 生成新的Anti-CSRF令牌供下次使用
generateSessionToken();?>
(3)功能函數
根據如下代碼可知,CheckCaptcha函數會像谷歌https://www.google.com/recaptcha/api/siteverify進行請求,CheckCaptcha和recaptcha_get_html函數的定義如下所示。
<?php/*** 驗證碼驗證函數(兼容舊版API)* * @param string $key 私鑰* @param string $response 用戶提交的驗證碼響應* @return bool|NULL 驗證成功返回true,失敗返回false,異常返回NULL*/
function recaptcha_check_answer($key, $response){return CheckCaptcha($key, $response);
}/*** 發送HTTP請求驗證驗證碼* * @param string $key 私鑰* @param string $response 用戶提交的驗證碼響應* @return bool|NULL 驗證成功返回true,失敗返回false,異常返回NULL*/
function CheckCaptcha($key, $response) {try {// Google reCAPTCHA驗證API地址$url = 'https://www.google.com/recaptcha/api/siteverify';// 準備POST數據$dat = array('secret' => $key, // 網站私鑰'response' => urlencode($response), // 用戶響應(由前端生成)'remoteip' => urlencode($_SERVER['REMOTE_ADDR']) // 用戶IP地址);// 配置HTTP請求選項$opt = array('http' => array('header' => "Content-type: application/x-www-form-urlencoded\r\n",'method' => 'POST','content' => http_build_query($dat) // 生成POST數據));// 創建HTTP上下文并發送請求$context = stream_context_create($opt);$result = file_get_contents($url, false, $context);// 解析JSON響應并返回驗證結果return json_decode($result)->success;} catch (Exception $e) {// 發生異常時返回NULLreturn null;}
}/*** 生成前端驗證碼HTML代碼* * @param string $pubKey 公鑰* @return string HTML代碼片段*/
function recaptcha_get_html($pubKey){return "<script src='https://www.google.com/recaptcha/api.js'></script><br /> <div class='g-recaptcha' data-theme='dark' data-sitekey='" . $pubKey . "'></div>";
}?>
?三個函數功能詳解,如下所示。
- recaptcha_check_answer
- 功能:驗證用戶提交的驗證碼是否有效(兼容舊版 API)。
- 流程:直接調用
CheckCaptcha
函數進行驗證。 - 安全作用:作為入口函數提供向后兼容性。
- CheckCaptcha
- 功能:向 Google 服務器發送驗證請求并處理響應。
- 流程:
- 構建 POST 請求參數(私鑰、用戶響應、IP 地址)。
- 配置 HTTP 請求上下文(設置請求頭、方法和內容)。
- 發送請求到 Google 驗證 API。
- 解析 JSON 響應并提取驗證結果。
- 安全作用:核心驗證邏輯,防止 CSRF 攻擊和機器人自動化操作。
- recaptcha_get_html
- 功能:生成前端驗證碼 UI 組件。
- 流程:
- 引入 Google reCAPTCHA JavaScript 庫。
- 創建帶有公鑰的驗證碼容器(暗色主題)。
- 安全作用:在頁面中正確渲染驗證碼組件,確保用戶交互。
(4)總結
相對而言,本關卡的判斷如下所示。
if ( $resp || ( $_POST[ 'g-recaptcha-response' ] == 'hidd3n_valu3' && $_SERVER[ 'HTTP_USER_AGENT' ] == 'reCAPTCHA' )
有兩種方法:
- 其一為resp=1,即通過token驗證
- 其二為g-recaptcha-response參數為'hidd3n_valu3'且HTTP_USER_AGENT參數為'reCAPTCHA'
三、滲透實戰
1、滲透方法一
(1)源碼修改
將resp=1,模擬通過token驗證的情況,如下所示。
(2)點擊change
bp設置攔截報文,進入靶場并將密碼改為123,如下所示。
http://127.0.0.1/DVWA/vulnerabilities/captcha/
此時bursuite抓包,發現step=1,報文如下所示。
此時頁面也變為如下形式,提示“Password Changed.”,具體如下所示。
很明顯修改密碼相對于前兩個關卡(low級別和medium級別有兩個step報文),本high關卡只有1個報文(step1),接下來我們將這個報文發送到repeater如下所示。?
在repeater中,通過修改如下紅框中的密碼0000來進行滲透。
2、滲透方法二
(1)源碼修改
需要配置g-recaptcha-response參數為'hidd3n_valu3'且HTTP_USER_AGENT參數為'reCAPTCHA'
(2)修改密碼
bp設置攔截報文,進入靶場http://127.0.0.1/DVWA/vulnerabilities/captcha/,將密碼改為321,如下所示。
點擊修改,頁面提示修改失敗,這是因為“( $_POST[ 'g-recaptcha-response' ] == 'hidd3n_valu3' && $_SERVER[ 'HTTP_USER_AGENT' ] == 'reCAPTCHA' )判斷失敗”,具體如下所示。
burpsuite抓包,報文顯示如下所示,很明顯post參數缺少g-recaptcha-response=hidd3n_valu3,而useragent需要配置為reCAPTCHA。接下來我們將報文發送到repeater,如下圖所示。
(3)bp改包
報文發送到repeater模塊如下所示。
將密碼修改為1234,同時POST增加參數g-recaptcha-response=hidd3n_valu3,useragent修改為reCAPTCHA,點擊發送,如下所示密碼修改成功。