13 minutes reading time (2502 words)

Only a Ninja can kill another Ninja

Only a Ninja can kill another Ninja

If you were to provide a short list of the threats against your site, which one would be the number one threat? For me, it's script kiddies. Those pesky individuals who don't have a programming bone inside them, but still can cause a great deal of harm to our sites by using pre-packaged attacks against them. Their success rate is amazingly high, mostly due to our fault. The purpose of this article is to demonstrate some trivial techniques to add a degree of stealth on your site so that script kiddies can't launch their attacks and even if they do, they will most likely be fended off successfully. Just like a ninja, you'll learn how to have your site lurk in plain sight without being spotted by those pesky attackers.

Before beginning with this article, I'd like to disclaim something. I am in no way convinced that Joomla! is a vulnerable application or that Joomla! developers lack a security mind. On the contrary, I think that Joomla! is one of the safest web applications built to date. It's framework gives all the necessary tools for developers to produce useful, stunning and safe extensions. Most of the security concerns I am about to present are more or less shared among all high-profile PHP applications, including the other two big CMS. It's just that I am writing for the Joomla! Community Magazine and my specific passion for Joomla! which makes me talk about those concerns in the context of Joomla!. Now sit back and start inconspicuously quacking because...

...your site is like a sitting duck. Quack!

I'm sorry to be the bearer of bad news, but your site is a sitting duck, merrily quacking while predators pass by it. The simple truth is that all of our sites have some interesting features, commonly used for debugging, which can be exploited by hackers to divulge information about our sites. This information all by itself doesn't create a security threat, but a malicious hacker can exploit it to decide if your site is vulnerable before launching an attack. Since the premise of this article is to add some ninja stealth to your site, let us take a look at how noisy your site is and what we can do about it.

Visual fingerprinting

One of the easiest ways for an attacker to decide if your site is a potential Joomla! target is to perform a rudimentary visual fingerprinting. As you know, appending the tp=1 query parameter to your site's URL will trigger the modules debugging mode, showing all module positions on your template. This provides a tell-tale sign that the site is running Joomla!. Example: https://www.joomla.org?tp=1.

One other, much less known, way to do that is using the template=foobar query parameter, where foobar is any template name. This will change your site's template to the specified template name. If you use a non-existent template name, it will try to revert to the default (Milkyway) template. Example: http://extensions.joomla.org/?template=foobar

Finally, we can trigger the display of a system sub-template by using the tmpl=something query parameter. One of the most useful system sub-templates which can never be turned off is the offline template, i.e. what appears when you put your site off-line. Look, mom, I can make joomla.org appear offline: https://www.joomla.org/?tmpl=offline

The way to avoid exposure to these nasty tricks is to block them by placing mod_rewrite .htaccess rules to cause all URLs including these query parameters to end up to a 404 page:

RewriteCond %{QUERY_STRING} (&|%3F){1,1}tp= [OR] 
RewriteCond %{QUERY_STRING} (&|%3F){1,1}template= [OR] 
RewriteCond %{QUERY_STRING} (&|%3F){1,1}tmpl= [NC] 
RewriteRule ^(.*)$ - [R=404,L] 

PHP has such a big mouth

PHP is a fine programming language, but do you want to tell the world exactly which version of PHP you've got so that they can hack you easier? I didn't think so, but PHP developers seem to disagree with you. What? You don't believe me? PHP developers decided to include hard-coded images inside all PHP executables which get displayed when a special, very long query parameter is present in the URL. These images change from one version of PHP to the other and can be used to easily identify your PHP version. Collectively known as the PHP Easter Eggs, they create a gaping security hole on your site and have to be stopped, again with some .htaccess magic:

RewriteCond %{QUERY_STRING} ^%3F=PHPE9568F36-D428-11d2-A769-00AA001ACF42 [OR] 
RewriteCond %{QUERY_STRING} ^%3F=PHPE9568F34-D428-11d2-A769-00AA001ACF42 [OR] 
RewriteCond %{QUERY_STRING} ^%3F=PHPE9568F35-D428-11d2-A769-00AA001ACF42 [OR] 
RewriteCond %{QUERY_STRING} ^%3F=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000 [OR] 
RewriteRule ^(.*)$ - [R=404,L] 

Blind the elephant before it stomps you

Have you ever heard of BlindElephant? It's a very neat script which can be used to identify if your site is running Joomla! and even tell you the exact version with very high accuracy. It doesn't do any magic at all. All it does is download and process the well-known static resources of your site (CSS, Javascript and images). Each Joomla! version has slightly different files and, by deduction, it can figure out which Joomla! version you are using. It is certainly not the first tool to do that, but it's the only open source one which you can download without joining the digital underground.

One common flaw among all those fingerprinting scripts is that they do not try to spoof the referrer URL, i.e. they do not try to pretend that a web page from your site is actually requesting the file. This allows us to write some simple anti-leach rules, i.e. rules which do not allow static files to be referenced from anywhere outside our site. However, we need to add an exception to this rule. We want our images to be indexed by search engines – provided that we have modified the robots.txt file to allow that – so we need to add an exception for images/stories. The rules look like that:

RewriteRule ^(images/stories/*\.(jpe[g,2]?|jpg|png|gif|bmp|css|js|swf|htm[l]?))$ $1 [L]
RewriteCond %{REQUEST_FILENAME} -f 
RewriteCond %{HTTP_REFERER} !^http[s]{0,1}://(.+\.)?www\.example\.com [NC] 
RewriteRule \.(jpe[g,2]?|jpg|png|gif|bmp|css|js|swf|htm[l]?)$ - [R=404,L] 

The first line instructs our web server to unconditionally serve all jpe, jpeg, jp2, jpg, png, gif, bmp, css, js, swf, htm and html files from images/stories and any of their subdirectories. If you don't care about your images being indexed by search engines you can safely remove it.

Please note that in the last line the URL to the site, in this case www.example.com, has to be hard-coded with the dots “escaped” as backslash dot. If you forget this part, the rule will not work properly.

If you really want to dodge fingerprinitng attacks with utilities like BlindElephant and you leave that first line intact, you should also remove the following files and directories from your images/stories directory:

  • Directories: food, fruit

  • Files: articles.jpg, clock.jpg, ext_com.png, ext_lang.png, ext_mod.png, ext_plugin.png, joomla-dev_cycle.png, key.jpg, pastarchives.jpg, powered_by.png, taking_notes.jpg, web_links.jpg

Nothing is served from my site unless I know about it

This is my very own rule when building web-sites, similar to Brian Teeman's rule “Nothing goes in my website unless I put it there” from his famous “Joomla! Hidden Secrets” presentation. The idea is that nothing should ever come out of my site's server unless I have previously positively authorized it. You might wonder why I am so picky, so let me explain my obsession with this rule.

For starters, all Joomla! extensions come with a handy XML file – their “installation manifest” if you like the tech-talk – which has a predictable file name and location, as well as invaluable information, such as the extension's name and the exact version. This information not only tells a potential hacker which extensions you have installed on your site, but also if they have known vulnerabilities which they can exploit to gain unauthorised entrance to your site. In other words, these XML files must be muted and never served to random web visitors.

Then, we have the language directories and their INI files with all the languages available to your site. But how can a language string be a security threat? All by itself it can't, but you might have noticed that newer versions of Joomla! introduce new translation strings or modify some of the existing ones. In plain English, if I can get hold of your site's INI files I can tell within a small margin of error which version of Joomla! you are using. If I happen to know of a specific security vulnerability in that version, your site is doomed.

Most importantly we have PHP files. All of the extensions' PHP files are supposed to have one handy little line in their head to prevent direct access. It looks like this:

defined('_JEXEC') or die('Restricted Access');

We have two problems to face here. First, if this line exists, trying to access such a PHP file directly spits out “Restricted Access” which tells an attacker that you are running Joomla!. If this line is not there, either nothing will happen or – depending on how the PHP file is written and your server settings – might spit out debug information, such as the absolute path to your site. This can be used by a resourceful attacker to fabricate a directory traversal attack against a vulnerable extension on your site to read the contents of your configuration.php file and gain full access to your site. Oops Finally, most common attacks are based on exploiting a vulnerable component to inject a PHP file with malicious code inside your site and have the attacker run it in order to do nasty things, like infect your site with XSS code or even gain access to your site's back-end.

All of these attacks can be prevented very easily, knowing how Joomla! works. Ideally, your site should have only a handful of entry points, namely the index.php and index2.php files inside your site's root and the administrator and xmlrpc subdirectories. Despite that, many extensions provide their own entry points. For example, JoomlaWorks AllVideos have a file plugins/content/jw_allvideos/includes/jw_allvideos_scripts.php to supply their Javscript to the browser. Any such scripts have to be added as exceptions to our rules which block everything by default. A complete rule set with a sample exception would look like this:

## Allow JoomlaWorks AllVideos 
RewriteCond %{REQUEST_FILENAME} -f 
RewriteRule ^(plugins/content/jw_allvideos/includes/jw_allvideos_scripts\.php) $1 [L] 

## Back-end protection 
RewriteRule ^(administrator[/]?)$ administrator/index.php [L] 
RewriteRule ^(administrator/index.htm[l]?)$ $1 [L] 
RewriteRule ^(administrator/index.php)$ $1 [L] 
RewriteRule ^(administrator/index[2,3].php)$ $1 [L] 
RewriteRule ^(administrator/(components|modules|templates|images|plugins)/.*\.(jpe[g,2]?|jpg|png|gif|bmp|css|js|swf|htm[l]?))$ $1 [L] 
RewriteRule ^administrator/(.*)$ - [R=404,L] 

## Explicitly allow access only to XML-RPC's xmlrpc/index.php or plain xmlrpc/ directory 
RewriteRule ^(xmlrpc/index\.php)$ $1 [L] 
RewriteRule ^xmlrpc/(.*)$ - [R=404,L] 

## Disallow front-end access for certain Joomla! system directories 
RewriteRule ^(includes/js/.*)$ $1 [L] 
RewriteRule ^(cache|includes|language|libraries|logs|tmp)/.*$ - [R=404,L] 

## Allow limited access for certain Joomla! system directories with client-accessible content 
RewriteRule ^((components|modules|plugins|templates)/.*\.(jp[g,2,eg]?|png|gif|bmp|css|js|swf|htm[l]?))$ $1 [L] 
RewriteRule ^((components|modules|plugins|templates)/.*index\.php(.*))$ $1 [L] 
RewriteRule ^(templates/.*\.php)$ $1 [L] 
RewriteRule ^(components|modules|plugins|templates)/.*$ - [R=404,L] 

## Disallow access to htaccess.txt and configuration.php-dist 
RewriteRule ^(htaccess\.txt|configuration\.php-dist)$ - [R=404,L] 

SQLi shield: engaged

Another common attack vector is SQL injection (commonly referred to as SQLi) attacks against vulnerable components. The best way to deal with them is to have all of our extensions sanitize their input before passing it to the database. Most developers are aware of that and conform to this rule, but sometimes an extension developer is either unaware of this basic rule, or unwittingly dropped the ball while developing the extension. Even though it's impossible to write a single rule to block all SQLi attacks, Radek Suski – of SOBI2 fame – has proposed a simple rule set to block the most common SQLi attacks. It's certainly better than nothing, but I still suggest keeping an eye on Joomla!'s Vulnerable Extensions List and uninstall or immediately update vulnerable extensions on your site.

RewriteCond %{QUERY_STRING} concat.*\( [NC,OR] 
RewriteCond %{QUERY_STRING} union.*select.*\( [NC,OR] 
RewriteCond %{QUERY_STRING} union.*all.*select.* [NC] 
RewriteRule ^(.*)$ - [R=404,L] 

The mother of all .htaccess files

Based on those simple rule sets we can come up with a master .htaccess file which can provide adequate protection against the most common “script kiddie” class of attacks against Joomla! sites. Do note that if you come up with an extension which no longer works after installing this .htaccess file, the easiest way to figure out why is using the Firefox browser together with its FireBug extension. Simply enable FireBug for the page which doesn't work properly and switch to FireBug's Net panel. Reload the page and look for entries marked in red. Those which result in a 404 error have been blocked by the protection rules and you have to supply exceptions in your .htaccess file. Sample exceptions for a few popular extensions have already been added, but it's up to you to supply the perfect mix of exceptions for your own site. As always, your mileage may vary.

Enough talking, here is the .htaccess file's contents, resulting from the mix of Joomla!'s standard htaccess.txt with all the rules we discused about: my master .htaccess.

A ninja is perfectly capable of killing another ninja

The techniques presented above are only good as a first line of defence – and only work on servers capable of understanding mod_rewrite rules. They can let your site remain cloaked against the less sophisticated attackers, like a ninja is virtually invisible to the untrained eye. But, as the title of this article implies, a ninja can and will kill another ninja. The hidden message in this simile is that if a real hacker targets your website there's little you can do besides having a good and tested backup. Real hackers will not be fooled by your cloaking techniques and will certainly not be stopped by the rudimentary defense we've put in place. A real world hacker might not even attack your site only on the Joomla! level. Most usually he'll combine a wealth of lower level attacks to gain access to your site.

However, I don't think this is likely. Why? All the advanced techniques of a real hacker cost him time. Serious attackers only try to break into a site for experience (hackers) or profit (crackers). If the mark does not guarantee a high return for the time invested in breaking into it, a real hacker will not even bother. He has more important things to do. So, unless you are a high-profile government agency, public service facility or a high profile target the chances of a ninja-like hacker attacking you are minimal. In this case, I deem the protection measures outlined more than adequate.

Thanks for all the fish

This article wraps up this series of basic Joomla! security articles. It has been a great pleasure sharing this information with you, our readers and community. I am now asking for your help. I want your feedback about this series and your ideas about the topic of my next article. All ideas are welcome and, most certainly, will be seriously evaluated. The most promising will be turned into articles for upcoming issues. Don't be shy! Tell me what you'd like to know about Joomla! and I promise I will do my best to share my experience with you.

Team EaSE Article: eCommerce - Will they pay...
Extending Joomla!'s MVC Architecture


Already Registered? Login Here
No comments made yet. Be the first to submit a comment

By accepting you will be accessing a service provided by a third-party external to https://magazine.joomla.org/