目錄
一、reCAPTCHA
二、代碼審計(Medium級別)
1、滲透準備
(1)配置security為Medium級別。
(2)配置RECAPTCHA參數
(3)再次打開靶場
2、源碼分析
(1)index.php
(2)Medium.php
(3)功能函數
(4)總結
三、滲透實戰
1、修改密碼并提交
(1)第一次點擊change
(2)第二次點擊change
(3)總結
2、bp修改密碼
本系列為通過《DVWA靶場通關筆記》的reCAPTCHA關卡(low,medium,high,impossible共4關)滲透集合,通過對相應關卡源碼的代碼審計找到講解滲透原理并進行滲透實踐,本文為reCAPTCHA關卡Medium級別關卡的滲透部分。
一、reCAPTCHA
reCAPTCHA關卡模擬了網站驗證碼系統的實現,在通過繞過驗證碼的安全驗證來實現密碼修改等操作,不同安全等級存在不同的繞過方法,本小節對中等級別關卡進行滲透實戰。
二、代碼審計(Medium級別)
1、滲透準備
(1)配置security為Medium級別。
進入到reCAPTCHA關卡Medium頁面,完整URL地址具體如下所示。
http://127.0.0.1/DVWA/vulnerabilities/captcha/
(2)配置RECAPTCHA參數
進入到DVWA的config目錄,如下所示找到config.inc.php文件。
修改config.inc.php文件中的如下參數,雖然頁面提示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)Medium.php
進入DVWA靶場源目錄,找到Medium.php源碼。
打開源碼Medium.php,分析可知這段代碼實現了一個兩步式的密碼修改功能,主要功能是處理用戶密碼修改請求,并通過 reCAPTCHA 驗證碼進行驗證。整個流程分為兩個步驟:
- 驗證碼驗證階段:驗證reCAPTCHA和密碼一致性(特別注意:由于本關卡這部分是亂填的,且會向https://www.google.com/recaptcha/api/siteverify提交請求,這個網站目前無法響應,故注釋掉這部分驗證,強制設置$resp=1,否則沒法向下繼續走)。
- 密碼修改階段:驗證碼通過后,用戶確認修改,確認驗證通過后執行數據庫更新
詳細注釋后的代碼如下所示。?
<?php// 第一步:處理初始密碼修改請求(包含CAPTCHA驗證)
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) {// 隱藏表單,準備顯示下一步或錯誤信息$hide_form = true;// 獲取用戶輸入的新密碼和確認密碼$pass_new = $_POST[ 'password_new' ];$pass_conf = $_POST[ 'password_conf' ];// 檢查第三方CAPTCHA驗證// $resp = recaptcha_check_answer(// $_DVWA[ 'recaptcha_private_key'], // reCAPTCHA私鑰// $_POST['g-recaptcha-response'] // 用戶輸入的CAPTCHA響應
//);
$resp=1;// CAPTCHA驗證失敗處理if( !$resp ) {// 顯示錯誤信息并重新顯示表單$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";$hide_form = false;return;}else {// CAPTCHA驗證成功,檢查兩次輸入的密碼是否匹配if( $pass_new == $pass_conf ) {// 顯示確認頁面,包含隱藏表單準備第二步提交$html .= "<pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre><form action=\"#\" method=\"POST\"><input type=\"hidden\" name=\"step\" value=\"2\" /><input type=\"hidden\" name=\"password_new\" value=\"{$pass_new}\" /><input type=\"hidden\" name=\"password_conf\" value=\"{$pass_conf}\" /><input type=\"submit\" name=\"Change\" value=\"Change\" /></form>";}else {// 密碼不匹配,顯示錯誤并重新顯示表單$html .= "<pre>Both passwords must match.</pre>";$hide_form = false;}}
}// 第二步:處理最終的密碼修改請求
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {// 隱藏表單$hide_form = true;// 獲取密碼(從隱藏表單字段)$pass_new = $_POST[ 'password_new' ];$pass_conf = $_POST[ 'password_conf' ];// 再次驗證密碼是否匹配(防御篡改)if( $pass_new == $pass_conf ) {// 密碼轉義防止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)) ? "" : ""));// 對密碼進行MD5哈希處理(注:MD5現在被認為不夠安全)$pass_new = md5( $pass_new );// 更新數據庫中的密碼$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );// 顯示成功信息$html .= "<pre>Password Changed.</pre>";}else {// 密碼不匹配(可能在第二步被篡改)$html .= "<pre>Passwords did not match.</pre>";$hide_form = false;}// 關閉數據庫連接((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?>
(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)總結
對于Medium關卡,兩者的代碼區別如下所示。
即第二步增加了一個參數passed_captcha,只有這個值為True(1)時,才可得到突破。代碼依賴客戶端提交的step參數來區分處理邏輯,攻擊者可能直接提交第二步請求繞過驗證碼驗證。
三、滲透實戰
1、修改密碼并提交
bp設置攔截報文,進入靶場,如下所示。
http://127.0.0.1/DVWA/vulnerabilities/captcha/
(1)第一次點擊change
將密碼改為1234,效果如下所示。
此時bursuite抓包,此時step=1,報文如下所示。
此時頁面也變為如下形式,提示“You passed the CAPTCHA! Click the button to confirm your changes”。
(2)第二次點擊change
再次點擊change,此時系統提示如下。
burpsuite抓包效果如下所示。
(3)總結
很明顯修改密碼共有兩個報文,基于源碼審計我們知道且第二個不依賴于第一個,故而滲透思路就是只對第二個報文進行修改重放,嘗試修改密碼。接下來我們將第2個報文發送到repeater如下所示。
2、bp修改密碼
在repeater中,通過修改如下紅框中的密碼0000來進行滲透,具體如下所示。
將如下紅框中的密碼0000均改為password,并點擊send,如下所示密碼修改成功,說明成功滲透。