Skip to main content

Weak CAPTCHA

Description

The system uses an insecure CAPTCHA implementation that allows the usage of optical recognition tools to automatically pass it.

Impact

Bypass security mechanisms to perform automated attacks.

Recommendation

Ensure that captchas response is at servers level and is not exposed on the HTML web pages code, also, ensure that captcha can not be read by an OCR.

Threat

Anonymous attacker from the Internet.

Expected Remediation Time

⌚ 30 minutes.

Score

Default score using CVSS 3.1. It may change depending on the context of the vulnerability.

Base

  • Attack vector: N
  • Attack complexity: L
  • Privileges required: N
  • User interaction: N
  • Scope: U
  • Confidentiality: L
  • Integrity: N
  • Availability: N

Temporal

  • Exploit code madurity: X
  • Remediation level: X
  • Report confidence: X

Result

  • Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N/E:X/RL:X/RC:X
  • Score:
    • Base: 5.3
    • Temporal: 5.3
  • Severity:
    • Base: Medium
    • Temporal: Medium

Code Examples

Compliant code

The 3rd party captcha service is securely configured on the server side

<?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 = md5( $pass_new );
$pass_conf = $_POST[ 'password_conf' ];
$pass_conf = stripslashes( $pass_conf );
$pass_conf = md5( $pass_conf );
$pass_curr = $_POST[ 'password_current' ];
$pass_curr = stripslashes( $pass_curr );
$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();
// Check passwords and update database
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>There was a mistake</pre>";
$hide_form = false;
}
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>

Non compliant code

There is an insecure configuration of the captcha functionality

<?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 ) {
$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
$hide_form = false;
return;
}
else {
//The step value can be modified on the client side and the captcha can be bypassed
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' ];
// Code to check if both password match
}
}
?>

Requirements