DVWA-Insecure CAPTCHA靶场

逻辑漏洞

准备环境:

多数DVWA不安全验证这个模块报错,需要修改配置,需要添加如下配置:
配置文件位置:
DVWA-Insecure CAPTCHA靶场_第1张图片

$_DVWA[ 'recaptcha_public_key' ]  = '6LdK7xITAAzzAAJQTfL7fu6I-0aPl8KHHieAT_yJg';
$_DVWA[ 'recaptcha_private_key' ] = '6LdK7xITAzzAAL_uw9YXVUOPoIHPZLfw2K1n5NVQ';

DVWA-Insecure CAPTCHA靶场_第2张图片
注意:
服务器将改密操作分成了两步,第一步检查用户输入的验证码,验证通过后,服务器返回表单,第二步客户端提交post请求,服务器完成更改密码的操作。但是由于部署环境的原因,这里无法正常显示验证码,但是没有关系,通常我们可以绕过这个验证码。下面我们只对第二部进行分析。

低级

代码:

 

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     .= "

The CAPTCHA was incorrect. Please try again.
"
; $hide_form = false; return; } else { // CAPTCHA was correct. Do both new passwords match? if( $pass_new == $pass_conf ) { // Show next stage for the user echo "

You passed the CAPTCHA! Click the button to confirm your changes.
{$pass_new}\" /> {$pass_conf}\" />
"
; } else { // Both new passwords do not match. $html .= "
Both passwords must match.
"
; $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( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Feedback for the end user echo "
Password Changed.
"
; } else { // Issue with the passwords matching echo "
Passwords did not match.
"
; $hide_form = false; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>

分析:第二步客户端提交post请求,服务器完成更改密码的操作,这其中存在明显的逻辑漏洞,服务器仅仅通过检查Change、step 参数来判断用户是否已经输入了正确的验证码。if( isset( $_POST[ ‘Change’ ] ) && ( $_POST[ ‘step’ ] == ‘2’ ) )
利用:对post表单抓包,更改step即可绕过
DVWA-Insecure CAPTCHA靶场_第3张图片

中级

源代码:



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     .= "

The CAPTCHA was incorrect. Please try again.
"
; $hide_form = false; return; } else { // CAPTCHA was correct. Do both new passwords match? if( $pass_new == $pass_conf ) { // Show next stage for the user echo "

You passed the CAPTCHA! Click the button to confirm your changes.
{$pass_new}\" /> {$pass_conf}\" />
"
; } else { // Both new passwords do not match. $html .= "
Both passwords must match.
"
; $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 .= "

You have not passed the CAPTCHA.
"
; $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( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Feedback for the end user echo "
Password Changed.
"
; } else { // Issue with the passwords matching echo "
Passwords did not match.
"
; $hide_form = false; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>

相对于初级代码,中级增加了对参数passed_captcha的检查,如果参数值为true,则认为用户已经通过了验证码检查,然而用户依然可以通过伪造参数绕过验证,本质上来说,这与Low级别的验证没有任何区别。我们只需在请求中增加passed_captcha=true
即可

step=2&password_new=666&password_conf=666&Change=Change&passed_captcha=true

DVWA-Insecure CAPTCHA靶场_第4张图片

高级



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( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Feedback for user echo "
Password Changed.
"
; } else { // Ops. Password mismatch $html .= "
Both passwords must match.
"
; $hide_form = false; } } else { // What happens when the CAPTCHA was entered incorrectly $html .= "

The CAPTCHA was incorrect. Please try again.
"
; $hide_form = false; return; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?>

分析:可以看到,服务器的验证逻辑是当$resp(浏览器验证的返回结果)是对的,或者参数recaptcha_response_field等于hidd3n_valu3并且http包头的User-Agent参数等于reCAPTCHA时,就认为验证码输入正确,满足其一即可,验证码这里肯定是我们无法修改,所以我们只要构造参数即可。
DVWA-Insecure CAPTCHA靶场_第5张图片
DVWA-Insecure CAPTCHA靶场_第6张图片

Impossible

 

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
        echo "

The CAPTCHA was incorrect. Please try again.
"
; $hide_form = false; return; } 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! echo "
Password Changed.
"
; } else { // Feedback for the end user - failed! echo "
Either your current password is incorrect or the new passwords did not match.
Please try again.
"
; $hide_form = false; } } } // Generate Anti-CSRF token generateSessionToken(); ?>

分析:
相对与高级别Impossible级别的代码增加了Anti-CSRF token 机制防御CSRF攻击,利用PDO技术防护sql注入,验证过程终于不再分成两部分了,验证码无法绕过,同时要求用户输入之前的密码,进一步加强了身份认证。

你可能感兴趣的:(DVWA靶场,验证码绕过逻辑漏洞,安全)