Feed Sign in with OpenID OpenID

Simon Willison’s Weblog

Hacked for Spam

From the New York Times:

Computer security researchers have been watching the evolution of remote-access rogue programs as they have become more common and have put more machines under the control of hackers. Programs like Sinit infect target machines and surreptitiously open back doors that allow outsiders to control the PC’s. The rings of infected computers have been used to send spam, to present online advertisements for pornographic Web sites or to trick people into giving up information like credit card numbers.

In fact, at least a third of all spam circulating on the Internet is now sent from or relayed by personal home computers that have been taken over, said Jesse Dougherty, director of development at Sophos, an antivirus and antispam company.

Emphasis mine. Of course, whether or not you want to believe a director from a company that directly profits from people’s fear of security attacks is up to you. That said, I’ve seen plenty of supporting evidence in the past few months that indicates that spamming is now the number one reason that a cracker would want to take over a PC, not least this Wired article.

Continuing on the same theme, The Rise of the Spammers is a fascinating article by David Barroso Berrueta describing how one of his servers was turned in to a spam relay after being compromised through a vulnerability in a PHP script. The technical details are intriguing; the attacker downloaded and uncompressed a daemon which then communicated with another host using an extended version of the SMTP protocol, receiving spam email bodies along with lists of addresses to send the spam on to.

Let’s talk about the PHP vulnerability in question: yet again, it was the classic problem where an attacker can instruct PHP to download and execute code from their own server by feeding in a query string parameter that is passed un-checked to an include() function call. While there are a number of steps that can be taken to deny this kind of attack, it unveils a fundamental problem with PHP itself—that it will execute code retrieved from a URL in the first place! This feature should be removed from PHP—it has almost no purpose in the real world aside from allowing servers to be cracked in to. The feature exists because PHP has the extremely useful ability to open remote files over HTTP. Unfortunately, this feature extends to the include() and require() functions which will execute any PHP code in the file passed to the functions. The most obvious solution to my mind would be for these functions to refuse to execute PHP in files that were opened via HTTP. I have no doubt that this would involve an ugly hack on behalf of PHP’s maintainers, but I believe the number of security problems it would solve would be well worth the trade-off.

Incidentally, I know you can disable opening files over HTTP and I know you shouldnt allow the direct creation of variables from the query string in the first place. The problems here are two-fold: firstly, opening files over HTTP is actually a very useful feature, one that would be all the more useful if it didn’t carry the risk of executing arbitrary code. Secondly, the problem is mainly down to third party software which often requires insecure PHP settings (such as register_globals) in order to work.

This is Hacked for Spam by Simon Willison, posted on 9th December 2003.

Tagged ,

View blog reactions

Next: YAGNI and DRY

Previous: How not to use OOP

10 comments

  1. As you say "you shouldnt allow the direct creation of variables from the query string in the first place". It comes down to developer taking care of what they do. Inluding a parameter from the url (or a POST for that matter) without any check is bad programming practice. I believe education is the key, the php people have a lot on their hands already ;)

    Arnaud - 9th December 2003 07:22 - #

  2. As for directly creating variables - I guess. But remember, PHP isn't about creating enterprise secure web applications all the time. It can be used in such a way, if you like. But it's also about creating hacky, insecure, personal apps for beginnners. Which is frankly not as bad as people make it out to be - a insecure, hacky personall app, is better than no app at all (people all need to start somewhere). PHP also offers funcitonality and settings to make PHP as secure as you want it to be, including input_filter handles (for CSS, also allowing you to implement a taint mode), register_globals = Off, and turning off URL opens, and URL includes. All good ideas, and all implemented by people who use PHP for apps that need security. At the end of the day, whether you have URL includes or not, beginners will shoot themselves in the foot. The same claim was infact frequently made about Perl years ago, when it was the most popular web development language, and I'm sure could be made about Python, if it was at all popular for web apps. Beginners do stupid things, and no amount of inconvience will stop them from doing those things...

    Sterling Hughes - 9th December 2003 08:15 - #

  3. Mmm... register_globals.

    Fredrik Lundh - 9th December 2003 11:53 - #

  4. Sterling, I don't go along with the view that PHP should be allowed to create "hacky, insecure, personal apps" In order for "beginners" to grasp it. I have no problem with beginners writing server side scripts that are "crappy, badly architected, monolithic etc etc" I do have an issue when they write scripts that can cause actual damage. I am sure PHP could be beginner friendly and more secure at the same time, they are largely orthogonal concerns (though not always)

    My grasp of what Simon was saying is that a newbie shouldn't need to worry about these security holes because they shouldn't be there! Security should be built in.

    Ben Meadowcroft - 9th December 2003 12:50 - #

  5. The problem isn't beginners - it's experienced developers who release scripts such as Gallery which are perfectly secure with register_globals Off but open up nasty and unexpected holes if it's turned on. The number one hole is caused by code loaded from an external server by include() being executed. If include() didn't execute code loaded from an external URL 90% of these exploits would stop working.

    Simon Willison - 9th December 2003 18:54 - #

  6. Okay, this is a new one on me. I didn't know require or include worked on remote files, people should be using file_get_contents() or a combination of fopen, fread and fclose for this. To me require() and include() are just for pulling in PHP classes/includes on the same server.

    Tim Fountain - 9th December 2003 19:18 - #

  7. Did you see this exploit?

    alanjstr - 10th December 2003 00:40 - #

  8. Actually in this case what register_globals is set to didn't matter. If you look at the Geeklog/Gallery integration plugin you will find this:
    if (!$gallery->register_globals) {
        if (is_array($HTTP_GET_VARS)) {
    	extract($HTTP_GET_VARS);
        }
    
        if (is_array($HTTP_POST_VARS)) {
    	extract($HTTP_POST_VARS);
        }
    
        if (is_array($HTTP_COOKIE_VARS)) {
    	extract($HTTP_COOKIE_VARS);
        }
    
        if (is_array($HTTP_POST_FILES)) {
    	foreach($HTTP_POST_FILES as $key => $value) {
    	    ${$key."_name"} = $value["name"];
    	    ${$key."_size"} = $value["size"];
    	    ${$key."_type"} = $value["type"];
    	    ${$key} = $value["tmp_name"];
    	}
        }
    }
    
    Which in effect replicates what register_globals=on would do. Don't think the Gallery script on its own suffers from this exploit.

    Kjartan Mannes - 10th December 2003 10:06 - #

  9. Think Simon's got a point. Can't say I've ever seen a need for include('http://...'). Disabling it seems like a smart move.

    Harry Fuecks - 11th December 2003 06:37 - #

  10. Thats what i've been doing too Harry.

    tbk - 15th January 2004 12:42 - #

Comments are closed.

Previously hosted at http://simon.incutio.com/archive/2003/12/09/hackedForSpam

A django site