Bilocating technology blogger Mark Maunder – he claims to live in Seattle and Cape Town concurrently, though I suspect he means consecutively, and I’ll wager he wisely avoids winter in both of them – recently wrote about an intrusion to his WordPress site.
It turns out the backdoor was a previously-unexploited, or at least a previously-undocumented, flaw in a useful little WordPress addon, shared by many WordPress themes, called timthumb.
Timthumb is an 864-line PHP script which assists with automatic image resizing, thumbmailing and so forth. (It doesn’t squeeze the image manipulation code into those 864 lines, but uses the third-party GD library.)
If you run WordPress and you have a file named timthumb.php, sometimes renamed to thumb.php, in your installation, you may be at risk.
Tracking down the mechanism behind his intrusion, Maunder identified three main problems with timthumb.php: poor default settings; poor verification of input data; and poor choice of file permissions for temporary files.
By default, the vulnerable version of timthumb allowed images from external sites to be accessed from your server. The default list is probably unsurprising:
// external domains that are allowed to be displayed on your website $allowedSites = array ( 'flickr.com', 'picasa.com', 'img.youtube.com', 'upload.wikimedia.org', );
But a better default would be an empty list, so that users who want to allow external files to be sourced by their own servers need to take steps to enable that capability.
If you use WordPress and timthumb and you don’t need this capability, Maunder suggests simply editing the timthumb.php code to say $allowedSites = array(); in order to prevent remote file trickery.
Secondly, timthumb.php checked the sanity of remote URLs – to verify they really were in the list of allowed sites – by looking for the permitted domains somewhere in the hostname part of the URL, rather than making sure they were the hostname part:
$isAllowedSite = false; foreach ($allowedSites as $site) { if (strpos (strtolower ($url_info['host']), $site) !== false) { $isAllowedSite = true; } }
This code meant that a dodgy website name such as picasa.com.badsite.example would pass the test, simply because it contains the string picasa.com. Clearly, that is not what was intended.
Lastly, timthumb.php stored the files it generated in a cache directory which is inside the PHP directory tree. This is bad, because files generated from untrusted external content – files only ever intended to be displayed – needlessly became executable.
So if the cached file isn’t an innocent image, but a remote access PHP Trojan (in Maunder’s case, the attacker used a malicious remote console tool called Alucar), you’re owned.
If you are a web developer:
* Don’t trust externally-sourced content by default. Force your users to think about what they really want.
* Check, test, check, test, check and test again your URL sanitisation code. Build a decent test suite and verify your code against it every time you release an update.
* Keep files which are only ever supposed to be used as data – especially remotely-sourced files – outside the directory tree where your server-side executable code lives.
If you run a WordPress installation:
Check if any of the blogs you host use timthumb.php, and upgrade to the latest version. The dodgy strpos above has been replaced with a tighter match based on a regular expression, like this:
$isAllowedSite = false; foreach ($allowedSites as $site) { if (preg_match ('/(?:^|\.)' . $site . '$/i', $url_info['host'])) { $isAllowedSite = true; } }
This doesn’t fix all of the issues Maunder describes, but it’s better than having a known hole in your site.
Many thanks to Mr Maunder for turning an attack on his site into a training tool to help the rest of us avoid a similar problem!
–
PS. WordPress.com VIP, which hosts Naked Security, doesn’t use timthumb.
Rad. Thanks mista.
For others who read this article, the vulnerable file in question is part of the WordPress plug-in called Tim Thumb. If you are not using that plug-in you do not have to worry about this particular exploit. No need to search through all your word press files like I did.
Always upgrade your WordPress core files to the latest version. WordPress is pretty good about fixing security issues.
Searching through all your WordPress files isn't terribly onerous, so you may as well do it. You might not even realise that you have timthumb if you acquired it as part of something else. If you read Mark Maunders' story, you'll notice that _he_ discovered he'd inherited the vulnerabiity when he purchased a theme which happens to have timthumb bundled into it.
So I'll stick to my phraseology, where I make specific mentione at first that the "flaw [is] in a useful little WordPress addon, shared by many WordPress themes, called timthumb", but later give generic advice to say "if you run WordPress and you have a file named timthumb.php, sometimes renamed to thumb.php, in your installation, you may be at risk."
If you know you aren't using timthumb, you are indeed safe. If you aren't sure, it's probably worth checking in case you are using it, and thus you aren't safe.
Indeed, I don't have a plug-in called Tim Thumb, but it came as part of my theme (from the very good wooThemes guys, or possibly with the wptouch plugin) though it was named thumbs.php.
I did note though that the code in my thumbs.php file didn't match either of the above, I've got:
if (ereg($site, $url_info['host']) == true) {
I removed my external sites anyway, so I've just got to check that's not broken anything (I only use one of those sites, so can always put that back if necessary once it's fixed up)
Seems like your version is rather old – the "ereg" functions in PHP were dropped (or deprecated) some time back.
The regexp also ought to be anchored to match at the _end_ of the hostname only (see the '$' in the regexp in the patched code above) so that you can't accidentally match at the start of a dodgy hostname which ends with a domain owned by a crook.
I'd suggest an update, and then reapplyling the external site list simplification you've already done…
"Keep files which are only ever supposed to be used as data – especially remotely-sourced files – outside the directory tree where your server-side executable code lives"
It has been some time since I played with WordPress plugins but when I wrote a few of them a couple of years ago, I found it hard to make use of a non-web directory to store files in: I doubt there is such a directory that works for all web hosts in there. (/tmp would be an obvious choice, but IIRC some web hosts don't give access to /tmp) Perhaps WordPress has found a way around this, but if not, using a directory inside the web tree and then disabling access to that directory using .htaccess is a good idea.
A simpler fix would be a .htaccess to prevent web access to the upload directory. And it would help if somehow bad data came from one of your allowed remote sites.