The PHP module backdoor II — The fallout

Luke Paris
Paradoxis
Published in
6 min readJun 23, 2017

--

Editors note: Before reading this post, please read the note at the beginning of the initial post.

A little over a week ago I published a post to my blog titled ‘Your interpreter isn’t safe anymore — The PHP module rootkit’.

Initially the post only got around thirty views and went mostly unnoticed until one of my colleagues, Rik van Duijn (amazing guy, go follow him on Twitter @rikvduijn, he has a great article on the Shadow Brokers dump here) decided to post a link to /r/netsec on Reddit, at which point the post gained some traction.

My project ended up getting tweeted out by a bunch of people including The Hacker News, made it to the trending page on GitHub (making it hit 138+ stars as of writing), and some people even wrote news articles about it.

Hitting the number 1 spot on the GitHub trending page for the C language

The post got mixed reactions, ranging from amazement, fear and, of course, criticism. In this post I want to clear up some misconceptions, answer some questions I saw, and explain what this project is and mostly what it isn’t.

Clearing up some misconceptions

Right after the post blew up online, some people asked how this could be used to hack their servers; by asking this question, they got one thing wrong:

The rootkit isn’t an exploit; it’s classified as a post-exploitation module which enables an attacker to maintain access to a server/network and intercept passwords which they could read as plain text at any moment in time.

Why call it a rootkit if it doesn’t give you root?

In hindsight, I’ll admit that this is true. However, my reason for calling it a rootkit is that the module mimics some of the traits that a traditional rootkit has, but simply at the user level.

While calling the project a ‘malicious PHP module’ would have been more technically correct, it would have been too broad and wouldn’t have given me the chance to explain the similarities between a traditional rootkit and a user-space rootkit. My goal was to write an easy-to-follow post (mainly targeted at managers/novice developers) outlining the dangers of not checking the integrity of your PHP modules.

Why would I ever install a PHP rootkit?

After reading some of the responses, I noticed that many people didn’t understand how they would go from a clean server to having the PHP module rootkit installed. As Volodymyr Kolesnykov pointed out:

Do you always install PHP / Zend extensions as binaries from unknown sources?

While this is a perfectly valid argument, social engineering (tricking a user into performing an action that is not in their best interests) isn’t the only way you could end up with a malicious PHP module on your system. Many servers that host PHP scripts get hacked through simple WordPress & Joomla exploits.

If you combine this with the fact that many servers don’t have the latest security patches installed for their OS, you could make a script that automatically hacks websites with an exploit and uses privilege escalation (eg: Dirty COW) to gain the rights to overwrite an existing extension rather than just drop a web shell in the public web root (which is far more likely to be detected). This would mean we’d be hiding in plain sight and an administrator would never even know their module got swapped out for a malicious one.

Furthermore, PHP modules are not the first place that forensic investigators would look if they detected that a server had been compromised. Many will start with scanning for kernel level rootkits, scan all files for well-known malware, and check authorized SSH keys, but due to the lack of popularity, your PHP interpreter is probably one of the last places an investigator will look for a backdoor.

DearBytes Remote Integrity Tool

After some careful consideration, the awesome guys at the company I work for (DearBytes B.V.) decided to release a fully-fledged tool which you can use to periodically check the integrity of your servers.

DearBytes B.V. on GitHub

The tool is incredibly effective at detecting changes on a server, and has built-in support to check the PHP module directory (much like the script I added to my last blog post). Moreover, the tool has the ability to notify one or more administrators through multiple means such as e-mail, syslog and telegram to let them know that one or more files have been added, deleted or modified.

DearBytes/Remote-Integrity-Tool on GitHub

The tool works by setting up a configuration file on a server you trust, and adding the public SSH key of that server to the one specified in the configuration. All you need to do then is add it to your crontab and you’re done!

Illustration showing how the tool works

Additional rootkit functionality

Since my last post, I’ve spent some time further developing the rootkit so it can do even more evil things. After brainstorming a little, I decided to add two core things that would seriously compromise the security of a server.

Execute shell commands

This is essentially a more stealthy version of uploading a web shell. I implemented it in such a way that it wouldn’t show up in the logs, by checking each request for a header named X-Rootkit-Exec, executing the (base64 encoded) command and returning the output.

This was done by adding the check in PHP_RINIT(rootkit) { ... }, which is executed before each request is passed the PHP script. I’ve omitted a screenshot of the code for the same reasons I didn’t show how the hashing methods were hooked in my previous post, as I don’t feel it’s right to give malicious developers code they could use to easily implement this.

An example of this would be logged in the server log like so:

However, in reality, the request looked like this:

Hiding modules from module listings

No rootkit is complete without being able to hide itself, so I added a feature that allows the module to hide itself (and other modules) from being listed. This was done by hijacking functions such as get_loaded_extensions and extension_loaded, which expose loaded modules.

See how the module curl doesn’t show up in the last command?

An even better way would be to hijack the module_registry that’s exported in the zend_modules.h header file, and ‘soft deleting’ the module from the hash table entirely (leaving the memory allocated). However, due to time constraints and my lack of experience in using the Zend engine, I haven’t had the chance to implement it this way.

Modifying return values before they’re sent back to the user

--

--

Dutch cyber security specialist with a passion for software & penetration testing, my weapons of choice are Python and Linux.