Skip to content

Added a bad CAPTCHA vulnerability #69

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

martingalloar
Copy link

This added vulnerability is aimed at playing with image recognition/OCR to guess/identify bad CAPTCHA codes. As opposite to "Insecure CAPTCHA", there's no vulnerability on the validation logic but instead the CAPTCHA is generated using weak configurations.

It also has the advantage that can be used in isolated environments where the DVWA doesn't have Internet access and ReCaptcha can't be used. The library used is https://github.com/claviska/simple-php-captcha (MIT license).

Let me know if you think it would be a good addition or if it need some aspect to be worked on. Otherwise I left it here for if someone else has a requirement similar to this one.

Martin Gallo added 3 commits April 4, 2016 13:03
This added vulnerability is aimed at playing with image recognition/OCR to guess bad CAPTCHA codes.
@digininja
Copy link
Owner

Anyone got any time to go through this and have a look at it? Would need updating to include impossible level.

@anshika-panwar-05-code
Copy link

Please review the following code:

	$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'badcaptcha', 'name' => 'Bad CAPTCHA', 'url' => 'vulnerabilities/badcaptcha/' );

.DS_Store
simple-php-captcha.sublime-project
simple-php-captcha.sublime-workspace
{
"name": "abeautifulsite/simple-php-captcha",
"description": "A simple PHP CAPTCHA script",
"version": "1.0.0",
"homepage": "http://www.abeautifulsite.net/",
"license": "MIT"
}

<title>Example » A simple PHP CAPTCHA script</title> <style type="text/css"> pre { border: solid 1px #bbb; padding: 10px; margin: 2em; }
    img {
        border: solid 1px #ccc;
        margin: 0 2em;
    }
</style>

CAPTCHA Example

<h2>Usage</h2>

<p>
    The following code will prepare a CAPTCHA image and keep the code in a session
    variable for later use:
</p>
<?php
session_start();
include("simple-php-captcha.php");
?>
<p>
    After the call to <code>simple_php_captcha()</code> above,
    <code>$_SESSION['captcha']</code> will be something like this:
</p>

<p>
    To display the CAPTCHA image, create an HTML <code>&lt;img&gt;</code> using
    <code>$_SESSION['captcha']['image_src']</code> as the <code>src</code> attribute:
</p>

<p>
    <?php
    echo '<img src="' . $_SESSION['captcha']['image_src'] . '" alt="CAPTCHA code">';

    ?>
</p>

<p>
    To verify the CAPTCHA value on the next page load (or in an AJAX request), test
    against  <code>$_SESSION['captcha']['code']</code>. You can use
    <code>strtolower()</code> or <code>strtoupper()</code> to perform a
    case-insensitive match.
</p>

<h2>Configuration</h2>
<p>
    Configuration is easy and all values are optional. To specify one or more options,
    do this:
</p>
<?php

    'min_length' => 5,
    'max_length' => 5,
    'backgrounds' => array(image.png', ...),
    'fonts' => array('font.ttf', ...),
    'characters' => 'ABCDEFGHJKLMNPRSTUVWXYZabcdefghjkmnprstuvwxyz23456789',
    'min_font_size' => 28,
    'max_font_size' => 28,
    'color' => '#666',
    'angle_min' => 0,
    'angle_max' => 10,
    'shadow' => true,
    'shadow_color' => '#fff',
    'shadow_offset_x' => -1,
    'shadow_offset_y' => 1
));

>
<h2>Notes</h2>
<ul>
    <li>
        <strong>Important!</strong> Make sure you call <code>session_start()</code> before
        calling the <code>simple_php_captcha()</code> function
    </li>
    <li>
        Requires PHP GD2 library
    </li>
    <li>
        Backgound images must be in PNG format
    </li>
    <li>
        Fonts must be either TTF or OTF
    </li>
    <li>
        Backgrounds and fonts must be specified using their full paths (tip: use
        <code>$_SERVER['DOCUMENT_ROOT'] . '/' . [path-to-file]</code>)
    </li>
    <li>
        Angles should not exceed approximately 15 degrees, as the text will sometimes
        appear outside of the viewable area
    </li>
    <li>
        Creates a function called <code>simple_php_captcha()</code> in the global namespace
    </li>
    <li>
        Uses the <code>$_SESSION['simple-php-captcha']</code> session variable
    </li>
</ul>
# A simple PHP CAPTCHA script

Written by Cory LaViska for A Beautiful Site, LLC. (http://abeautifulsite.net/)

Licensed under the MIT license: http://opensource.org/licenses/MIT

Demo and Usage

http://labs.abeautifulsite.net/simple-php-captcha/

Attribution

'', 'min_length' => 5, 'max_length' => 5, 'backgrounds' => array( $bg_path . '45-degree-fabric.png', $bg_path . 'cloth-alike.png', $bg_path . 'grey-sandbag.png', $bg_path . 'kinda-jean.png', $bg_path . 'polyester-lite.png', $bg_path . 'stitched-wool.png', $bg_path . 'white-carbon.png', $bg_path . 'white-wave.png' ), 'fonts' => array( $font_path . 'times_new_yorker.ttf' ), 'characters' => 'ABCDEFGHJKLMNPRSTUVWXYZabcdefghjkmnprstuvwxyz23456789', 'min_font_size' => 28, 'max_font_size' => 28, 'color' => '#666', 'angle_min' => 0, 'angle_max' => 10, 'shadow' => true, 'shadow_color' => '#fff', 'shadow_offset_x' => -1, 'shadow_offset_y' => 1 ); // Overwrite defaults with custom config values if( is_array($config) ) { foreach( $config as $key => $value ) $captcha_config[$key] = $value; } // Restrict certain values if( $captcha_config['min_length'] < 1 ) $captcha_config['min_length'] = 1; if( $captcha_config['angle_min'] < 0 ) $captcha_config['angle_min'] = 0; if( $captcha_config['angle_max'] > 10 ) $captcha_config['angle_max'] = 10; if( $captcha_config['angle_max'] < $captcha_config['angle_min'] ) $captcha_config['angle_max'] = $captcha_config['angle_min']; if( $captcha_config['min_font_size'] < 10 ) $captcha_config['min_font_size'] = 10; if( $captcha_config['max_font_size'] < $captcha_config['min_font_size'] ) $captcha_config['max_font_size'] = $captcha_config['min_font_size']; // Generate CAPTCHA code if not set by user if( empty($captcha_config['code']) ) { $captcha_config['code'] = ''; $length = mt_rand($captcha_config['min_length'], $captcha_config['max_length']); while( strlen($captcha_config['code']) < $length ) { $captcha_config['code'] .= substr($captcha_config['characters'], mt_rand() % (strlen($captcha_config['characters'])), 1); } } // Generate HTML for image src if ( strpos($_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT']) ) { $image_src = substr(__FILE__, strlen( realpath($_SERVER['DOCUMENT_ROOT']) )) . '?_CAPTCHA&t=' . urlencode(microtime()); $image_src = '/' . ltrim(preg_replace('/\\\\/', '/', $image_src), '/'); } else { $_SERVER['WEB_ROOT'] = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['SCRIPT_FILENAME']); $image_src = substr(__FILE__, strlen( realpath($_SERVER['WEB_ROOT']) )) . '?_CAPTCHA&t=' . urlencode(microtime()); $image_src = '/' . ltrim(preg_replace('/\\\\/', '/', $image_src), '/'); } $_SESSION['_CAPTCHA']['config'] = serialize($captcha_config); return array( 'code' => $captcha_config['code'], 'image_src' => $image_src ); } if( !function_exists('hex2rgb') ) { function hex2rgb($hex_str, $return_string = false, $separator = ',') { $hex_str = preg_replace("/[^0-9A-Fa-f]/", '', $hex_str); // Gets a proper hex string $rgb_array = array(); if( strlen($hex_str) == 6 ) { $color_val = hexdec($hex_str); $rgb_array['r'] = 0xFF & ($color_val >> 0x10); $rgb_array['g'] = 0xFF & ($color_val >> 0x8); $rgb_array['b'] = 0xFF & $color_val; } elseif( strlen($hex_str) == 3 ) { $rgb_array['r'] = hexdec(str_repeat(substr($hex_str, 0, 1), 2)); $rgb_array['g'] = hexdec(str_repeat(substr($hex_str, 1, 1), 2)); $rgb_array['b'] = hexdec(str_repeat(substr($hex_str, 2, 1), 2)); } else { return false; } return $return_string ? implode($separator, $rgb_array) : $rgb_array; } } // Draw the image if( isset($_GET['_CAPTCHA']) ) { session_start(); $captcha_config = unserialize($_SESSION['_CAPTCHA']['config']); if( !$captcha_config ) exit(); unset($_SESSION['_CAPTCHA']); // Pick random background, get info, and start captcha $background = $captcha_config['backgrounds'][mt_rand(0, count($captcha_config['backgrounds']) -1)]; list($bg_width, $bg_height, $bg_type, $bg_attr) = getimagesize($background); $captcha = imagecreatefrompng($background); $color = hex2rgb($captcha_config['color']); $color = imagecolorallocate($captcha, $color['r'], $color['g'], $color['b']); // Determine text angle $angle = mt_rand( $captcha_config['angle_min'], $captcha_config['angle_max'] ) * (mt_rand(0, 1) == 1 ? -1 : 1); // Select font randomly $font = $captcha_config['fonts'][mt_rand(0, count($captcha_config['fonts']) - 1)]; // Verify font file exists if( !file_exists($font) ) throw new Exception('Font file not found: ' . $font); //Set the font size. $font_size = mt_rand($captcha_config['min_font_size'], $captcha_config['max_font_size']); $text_box_size = imagettfbbox($font_size, $angle, $font, $captcha_config['code']); // Determine text position $box_width = abs($text_box_size[6] - $text_box_size[2]); $box_height = abs($text_box_size[5] - $text_box_size[1]); $text_pos_x_min = 0; $text_pos_x_max = ($bg_width) - ($box_width); $text_pos_x = mt_rand($text_pos_x_min, $text_pos_x_max); $text_pos_y_min = $box_height; $text_pos_y_max = ($bg_height) - ($box_height / 2); if ($text_pos_y_min > $text_pos_y_max) { $temp_text_pos_y = $text_pos_y_min; $text_pos_y_min = $text_pos_y_max; $text_pos_y_max = $temp_text_pos_y; } $text_pos_y = mt_rand($text_pos_y_min, $text_pos_y_max); // Draw shadow if( $captcha_config['shadow'] ){ $shadow_color = hex2rgb($captcha_config['shadow_color']); $shadow_color = imagecolorallocate($captcha, $shadow_color['r'], $shadow_color['g'], $shadow_color['b']); imagettftext($captcha, $font_size, $angle, $text_pos_x + $captcha_config['shadow_offset_x'], $text_pos_y + $captcha_config['shadow_offset_y'], $shadow_color, $font, $captcha_config['code']); } // Draw text imagettftext($captcha, $font_size, $angle, $text_pos_x, $text_pos_y, $color, $font, $captcha_config['code']); // Output image header("Content-type: image/png"); imagepng($captcha); }

Help - Insecure CAPTCHA

About

A is a program that can tell whether its user is a human or a computer. You've probably seen

		them - colourful images with distorted text at the bottom of Web registration forms. CAPTCHAs are used by many websites to prevent abuse from
		"bots", or automated programs usually written to generate spam. No computer program can read distorted text as well as humans can, so bots
		cannot navigate sites protected by CAPTCHAs.</p>

	<p>CAPTCHAs are often used to protect sensitive functionality from automated bots. Such functionality typically includes user registration and changes,
		password changes, and posting content. In this example, the CAPTCHA is keeping the session active for the logged in user.</p>

	<br /><hr /><br />

	<h3>Objective</h3>
	<p>Your aim, keep the session active by guessing the bad CAPTCHA system using image recognition techniques.</p>

	<br /><hr /><br />

	<h3>Low Level</h3>
	size and without rotations.</p>

	<br />

	<h3>Medium Level</h3>
	<p>This CAPTCHA code is implemented by using 5 letters, that can be uppercase or lowercase. The code also applies some small rotations over the code and it has a
	 small shadow.</p>

	<br />

	<h3>High Level</h3>
	code.</p>

	<br />

	<h3>Impossible Level</h3>
	<p>In the impossible level, the CAPTCHA code is generated using the most advanced set of configuration. It uses 6 characters, variable font sizes, very variable
	angle rotations and a bigger shadow that should make the code difficult to guess using image recognition software.</p>

</div></td>
</tr>
</table>

</div>

<br />

<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'http://www.captcha.net/' ); ?></p>
define( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );
require_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';
require_once DVWA_WEB_PAGE_TO_ROOT . "external/simple-php-captcha/simple-php-captcha.php";

dvwaPageStartup( array( 'authenticated', 'phpids' ) );

dvwaDatabaseConnect();

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;
}

require_once DVWA_WEB_PAGE_TO_ROOT . "vulnerabilities/badcaptcha/source/{$vulnerabilityFile}";

<div class=\"body_padded\">
<h1>Vulnerability: Bad CAPTCHA</h1>

<div class=\"vulnerable_code_area\">
	<form action=\"#\" method=\"POST\" ";

if( $hide_form )
$page[ 'body' ] .= "style="display:none;"";

		<h3>Please enter the CAPTCHA code to continue logged in the web site:</h3>
		<br />

		<img src=\"" . $_SESSION['captcha']['image_src'] . "\" alt=\"CAPTCHA code\">
		CAPTCHA code:<br />
		<input type=\"captcha\" AUTOCOMPLETE=\"off\" name=\"captcha\"><br />
		";

		<br />

		<input type=\"submit\" value=\"Submit\" name=\"Submit\">
	</form>
	{$html}
</div>

<h2>More Information</h2>
<ul>
	<li>" . dvwaExternalLinkUrlGet( 'http://www.captcha.net/' ) . "</li>
	<li>" . dvwaExternalLinkUrlGet( 'https://www.owasp.org/index.php/Testing_for_Captcha_(OWASP-AT-012)' ) . "</li>
</ul>
\n";

dvwaHtmlEcho( $page );

?>


The CAPTCHA was incorrect. Please try again."; $hide_form = true; dvwaLogout(); } else { // CAPTCHA was correct. $html .= "
You can continue logged in into the Web site.
"; $hide_form = true; return; } } // Generate a new CAPTCHA 'min_length' => 5, 'max_length' => 5, 'characters' => 'ABCDEFGHJKLMNPRSTUVWXYZabcdefghjkmnprstuvwxyz23456789', 'min_font_size' => 20, 'max_font_size' => 28, 'color' => '#666', 'angle_min' => 0, 'angle_max' => 30, 'shadow' => true, 'shadow_color' => '#fff', 'shadow_offset_x' => -1, 'shadow_offset_y' => 1 )); ?>
The CAPTCHA was incorrect. Please try again."; $hide_form = true; dvwaLogout(); } else { // CAPTCHA was correct. $html .= "
You can continue logged in into the Web site.
"; $hide_form = true; return; } } // Generate a new CAPTCHA 'min_length' => 6, 'max_length' => 6, 'characters' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 'min_font_size' => 12, 'max_font_size' => 30, 'color' => '#444', 'angle_min' => 0, 'angle_max' => 60, 'shadow' => true, 'shadow_color' => '#fff', 'shadow_offset_x' => -2, 'shadow_offset_y' => 2 )); ?>
The CAPTCHA was incorrect. Please try again."; $hide_form = true; dvwaLogout(); } else { // CAPTCHA was correct. $html .= "
You can continue logged in into the Web site.
"; $hide_form = true; return; } } // Generate a new CAPTCHA 'min_length' => 3, 'max_length' => 3, 'backgrounds' => array(DVWA_WEB_PAGE_TO_ROOT . "external/simple-php-captcha/backgrounds/" . "grey-sandbag.png"), 'characters' => '1234567890', 'min_font_size' => 28, 'max_font_size' => 28, 'color' => '#666', 'angle_min' => 0, 'angle_max' => 0, 'shadow' => false, )); ?>
The CAPTCHA was incorrect. Please try again."; $hide_form = true; dvwaLogout(); } else { // CAPTCHA was correct. $html .= "
You can continue logged in into the Web site.
"; $hide_form = true; return; } } // Generate a new CAPTCHA 'min_length' => 5, 'max_length' => 5, 'backgrounds' => array(DVWA_WEB_PAGE_TO_ROOT . "external/simple-php-captcha/backgrounds/" . "45-degree-fabric.png", DVWA_WEB_PAGE_TO_ROOT . "external/simple-php-captcha/backgrounds/" . "cloth-alike.png", DVWA_WEB_PAGE_TO_ROOT . "external/simple-php-captcha/backgrounds/" . "grey-sandbag.png"), 'characters' => 'ABCDEFGHJKLMNPRSTUVWXYZabcdefghjkmnprstuvwxyz', 'min_font_size' => 28, 'max_font_size' => 28, 'color' => '#666', 'angle_min' => 0, 'angle_max' => 10, 'shadow' => true, 'shadow_color' => '#fff', 'shadow_offset_x' => -1, 'shadow_offset_y' => 1 )); ?>

elseif( $id == 'badcaptcha' ) {
$vuln = 'Bad CAPTCHA';
}
elseif ( $id == 'badcaptcha' ) {
$vuln = 'Bad CAPTCHA';
}
elseif ( $id == 'captcha' ) {
$vuln = 'Insecure CAPTCHA';
}
elseif ( $id == 'b' ) {
$vuln = 'Insecure CAPTCHA';
}
elseif ( $id == 'o' ) {
$vuln = 'Insecure CAPTCHA';
}
elseif ('db2 {
$vuln = 'SQL Injection';
}
static {
$vuln = 'SQL Injection';
}

$string ); } elseif ( $what == 'check' ) { // Verify whether the entered CAPTCHA is correct if( $user_ans == $_SESSION['_CAPTCHA']['code'] ) { return true; } else { return false; } } } ?>

@digininja
Copy link
Owner

@anshika-panwar-05-code I'm not sure what this is supposed to be, but if you are submitting this as some new code, please do it as a standard pull request rather than trying to add code to a description.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants