Bypassing the random image anti-spam feature

A friend of mine has been playing a game which you play through the browser, some tasks can be automated which allows the player to earn money or increase stats quickly, or while not at the computer (this particular action does not interact with other players). My friend then create a bookmarklet (?) which would automate this task. All was hunky dory until the game asked the user to read an image and copy the text down. This is done precisely to prevent these automated bots, still…. it provides an interesting problem. How could you read the image and continue the game automatically?

I couldn’t sleep the first night I was presented with this problem, I went down more dead ends than I thought existed in this kind of a problem. Eventually I decided to take a break and start again. Logically how could JavaScript read an image? It can’t, it would need some other technologies, these would have to reside either on a remote domain if they are web based or on the local machine. JavaScript cannot run either of these, so it seemed I came to a dead end, again. In fact, it would be impossible to solve this using JS at all, you would infact need a seperate program precisely because you need to call either a remote web site or a local program. Realising this decreased my enthusiasm as now it was merely an experiment to see if it could be done.

I remembered a certain web service that I’d used a while back, namely WhatTheFont (WTF). This service can read an image and tries to deduce the font used from the characters it can find. I figured I could use this to read the characters in an image.
I found a random image such as Tokoy which is the kind of image the user has to copy. I tried uploading the image to the WTF site, but it failed to read the image. I noticed the sample images they provide are much larger, so I scaled up my image and submitted it again, this time WTF could read the image perfectly.

Now… if only I could get some PHP code to read an image file, scale it up, submit it to WTF and read the response.

I should say that the code I provide is very untidy, this is because it’s the result of sleepless nights and at points I hacked certain bits, then edited them later again. I explain the code just below the code itself.


function doIt()
{
$r = rand(100000,999999);
if (@imagecreatefromgif($_GET['img']))
$ext = 'gif';
else
$ext = 'png';
if (!@copy ($_GET['img'],$r.$ext))
die("Error");
chmod($r.$ext,0777);
$img = up_size($r.$ext,5,$ext);
$lines = file("http://www.myfonts.com/WhatTheFont/Upload?url=http://www.whiteacid.org/img_reader/".$r.$ext);
parseInput($lines);

unlink($r.$ext);
}

The code initially determines what image type the image is. The script only allows PNG and GIF. BMP wouldn’t be used as no one really uses it any more and JPG wouldn’t be used as it would blur the lines making it difficult for humans to read the letters. It then saves the image to the same folder the script resides in under a random name (or quits if there’s a problem). I did this because for some reason the script seemed to work better when the image was in the same folder, or at least on the same domain. I then scale the image up (that function is below), perform the request and run parseInput (again, code coming below). Finally I remove the image (which up_size() creates).
The up_size function’s code is here:

function up_size($imageUrl,$ratio,$extension)
{
if ($extension == 'gif')
{
$src_img = imagecreatefromgif($imageUrl);
}
else
{
$src_img = @imagecreatefrompng($imageUrl);
}
$origw = imagesx($src_img);
$origh = imagesy($src_img);

$dst_img = imagecreatetruecolor($origw*$ratio,$origh*$ratio);
imagecopyresampled($dst_img,$src_img,0,0,0,0,$origw*$ratio,$origh*$ratio,imagesx($src_img),imagesy($src_img));

imagepng($dst_img, "$imageUrl");
//imagepng($dst_img);

return $dst_img;

}

It reads the file and creates an image object, reads it’s width and height, makes a new image with a larger canvas and copies the old smaller image onto this canvas streching it to fit. That’s how it scales up images. Finally it saves this in a file.

Now that the image had been scaled up it was sent off to WTF and the reponse was stored in a variable ready to be parsed. Now, before I give the code for the parsing section you should know how the outputted HTML looks. Very simply WTF prints out;

<input type=’text’ name=’ch[0]‘ id=’wtfchar0′ value=’T’ size=’2′ maxlength=’1′ style=’font-size:20; font-family:verdana; text-align:center;’>
<input type=’text’ name=’ch[1]‘ id=’wtfchar1′ value=’o’ size=’2′ maxlength=’1′ style=’font-size:20; font-family:verdana; text-align:center;’>
<input type=’text’ name=’ch[2]‘ id=’wtfchar2′ value=’k’ size=’2′ maxlength=’1′ style=’font-size:20; font-family:verdana; text-align:center;’>
<input type=’text’ name=’ch[3]‘ id=’wtfchar3′ value=’y’ size=’2′ maxlength=’1′ style=’font-size:20; font-family:verdana; text-align:center;’>
<input type=’text’ name=’ch[4]‘ id=’wtfchar4′ value=’o’ size=’2′ maxlength=’1′ style=’font-size:20; font-family:verdana; text-align:center;’>

There is more stuff and things in between those segments, but that’s what we’re after. The easiest thing to search for would be id=’wtfchar$n‘, then parse the value field after it. We’d have to note that if the character would not be identified the value attribute would be blank, so we could return a question mark instead, to let the user know that one character remained unknown. ok, the code

function parseInput($lines)
{
$c=0;
foreach ($lines as $line_num => $line)
{
if (strpos($line,"id='wtfchar$c'") != false)
{
$char = substr($line,strpos($line,"id='wtfchar$c' value='")+strlen("id='wtfchar$c' value='"),2);
if ($char == "' ")
$char = '?';
else
$char = substr($char,0,1);
echo $char;
$c++;
}
}
}

For each line of output search for “id=’wtfchar$c’” where $c is an incrementing integer which starts at 0. Essentially if found (then you’re on the right line of code), then parse out the value or echo a question mark.

One more line of code is also required, you need to run doIt(), then you’re done.

That’s about it, using that code you can parse text from an image. This allows you to complete some forms automatically. This obviously could be used for spamming reasons, which is why instead of using images like I’ve used them people should use ones like hotmail and gmail:

Hotmail random image

To see the script in action I’ve made one script which allows you to create images of text and the other one as described here. I used to host examples of this code in action but my new host doesn’t allow file-access from a URL.

Share
  • http://aviv.raffon.net Aviv Raff

    What you where trying to do is called CAPTCHA – Completely Automated Public Turing test to tell Computers and Humans Apart.

    The following site is a nice CAPTCHA project which tries to identify even obfuscated images of characters, like the one GMail uses.
    http://www.captcha.net/

  • http://www.whiteacid.org WhiteAcid

    Thanks for that link, it’s a very interesting site.

  • raccoon
  • http://www.BeyondSecurity.com aviram

    CAPTCHA images are getting more and more complicated in order to beat attacks such as what WhiteAcid describes here. This reaches a point where humans can barely pass this turing test!
    Here’s a post I wrote a while back about that:
    http://blogs.securiteam.com/?p=59

  • iLLeLogicaL

    MMM, i’ve been looking for this to a while to an program that could read an image from a game named ‘Kings of Chaos’ so that i could leave my pc while it clicks for me :)

  • http://www.wizard-ict.co.uk wizard

    quote ‘What you where trying to do is called CAPTCHA’
    This is wrong, what he is trying to do is actually the complete opposite!

  • Pingback: SecuriTeam Blogs » Defeating Voice Captchas

  • sunshine

    For my post on breaking voice Captchas:
    http://blogs.securiteam.com/index.php/archives/287

    For the post on new comment spam issues:
    http://blogs.securiteam.com/index.php/archives/285

  • Jean claude duce

    This is a very usefull introduction. But it still lack the most interesting idea :
    Bypassing a captcha is and will always be a race. As in many security fields, some try to break a secret or better to reverse an open alorithm that others constinuouly try to improve.
    In this particular and beautifull field, the game has a end. Guess what it is.

  • http://www.diverhaus.com Ivan

    Looks nice, but, linking to another page to do the work is not for me, i like to have all the package working compact and hard.

  • TwoD

    quote: “…in fact, it would be impossible to solve this using JS at all…”

    Nope, not if you’re using JScript and some ActiveX objects to read/write to files and make HTTP requests. You might have to write your own routines for resizing the images by parsing the raw bytestreams first, but it would still be possible.

    I once wrote a weird thing which cracked a CAPTCHA-light (single number, always the same images but with different filenames) test.
    On “boot” the JS script would write a number of patterns to a textfile. The patterns were lists where each entry had a list of pixel positions and color values, along with an id number.

    This file was continously read by a Java progam, which created a “KnowledgeBase” out of these patterns.

    When the test was encountered by JS, it grabbed the filename, wrote it to the file and waited for Java to find, parse, compare the cached image to the KB and return the id via the textfile. All this took about a second, given the textfile polls by JS and Java were in sync.

    Thanks to the Java library for manipulating .jpg files, I didn’t have to write my own in JS.

  • http://www.whiteacid.org Sid

    I guess I stand corrected

  • http://www.haan.net Jeroen Haan

    I have to say this on captchas and in general on preventing of abuse of submission forms:

    Why not mix numbers with letters or symbols and ask the human to type the numbers only.

    Of course we can invent numerous other variations on this theme, which require a deeper understanding of language and character recognition.

    So when every website developer makes his own version of this captcha it will almost not possible to effectively SPAM since the captchas will evolve rapidly and unpredictably.

    That’s why I built my own captchas…

    Last but not least;
    what about good filtering after the submit or the need the register first.
    Hints for filtering:

    - Check if only one @ is present in the header parameter of your mail function (probably the FROM address).

    - Check if there are “new lines / return” characters in the header parameter.
    Limit the length of the header parameter.

    - Convert special characters into html entities.

    - Or just use a fixed FROM address and change this somewhere on your server of on a client.

    Wouldn’t it be beautiful when we could subscribe to a random captcha service connected to a big captcha database with the newest and approved artistic captchas?
    Every visitor would see a totally different captcha and of course also would be able to generate a new one a few times and within a certain time span.

    Random image of a dog:
    What’s the name…
    The system should accept different languages “dog, perro, chien, cão, hond, hund, etc”.

    Map of USA
    Which country…

    What’s is the capital of…

    Etc, etc

    What about a captcha that consists of different images or FLASH or other active content?
    What about a special plugin?
    Or what about numerous checks on referrer, user agent, ability to load css and client side scripts…

    What about a check on IP address and listing on different spam databases like spamassasin?

    If we want we can give the spammers a real hard time and still give the most Internet users a chance to submit.
    Don’t say no, but lets develop!

    Cheers,
    Jeroen Haan
    website developer

  • wave

    Great article! But somehow this script doesn`t work! I always get the “Error”. What`s the problem?

    can you help me?
    nvd_5@hotmail.com

    greetzs

  • Stefano Capuzzimato

    If i can read what’s written on an image, and i know how i managed to read it, i can write software that does it. That’s the end of the game.

    If you manage to make images that are totally unreadable for a computer, in that case it will likely be unreadable for humans as well.

    This is the big problem with captchas: how to make it readable for some and unreadable for others?

    The main idea, as for most other security protections, is to make it painful and ultimately not worth the effort for you to break the code, i.e. to keep out 95% of the bots.

  • http://www.cooltoad.com jitendra

    plz send me a code in jsp/servlet which genrate random text image
    thanx

  • PAT

    I like