Case Study: Analyzing a WordPress Attack – Dissecting the webr00t cgi shell – Part I
November 1st started like any other day on the web. Billions of requests were being shot virtually between servers in safe and not so safe attempts to access information. After months of waiting, finally one of those not so safe request hit one of our honeypots.
We won’t get into the location of the site because it really doesn’t matter, a fact that most critics don’t realize. As is often the case, the honeypot site was quiet without much traffic and the weakness was access control.
We intentionally left the password to the site to one of the top 10 passwords, with continuous attempts it took about 3 months before it was accessed.
This time though we were ready and this is how it went..
|Content Management System||WordPress 3.6.1|
|Host||Popular Shared Host|
|VPS / Dedicated Box||No|
|Server Level Hardening||No|
|Security Plugins||Sucuri Premium Plugin [Honeypot Mode]|
|Custom Hardening||Kill PHP Execution via .htaccess|
|Strong, Unique Password||No|
|Time To Hack||3 months|
All in all, it was set up to be like an everyday website install. No special configurations, outside of the one hardening on wp-content to kill PHP execution.
Order of events
On November 6th, as I was enjoying my fine afternoon, I was greeted with the following message from the Sucuri Premium plugin:
If you’re not aware with what it is, it’s telling me that someone is logging into one of our test sites.
A quick lookup and you see that the incoming IP, 22.214.171.124, is coming from a Turkey source:
role: Koc Net NCC address: Koc.net Haberlesme Teknolojileri ve Iletisim address: Hizmetleri A.S address: Ayazma Cad. Unalan Mah. address: Camlica Is Merkezi B3 Blok address: 34700 Uskudar Istanbul address: Turkey
Obviously not anyone on our development or research team, so it was time to investigate further.
Next step was to understand what else the attacker did. We first started with the auditing feature in the Sucuri plugin, there we found the following line items:
With this we were able to build a timeline for what the attacker was doing, but it was only part of the puzzle.
You can see that the first thing the attacker did was modify the 404.php on the Twenty Twelve theme using the built in Theme Editor. The attacker then switched the active theme to Twenty Thirteen, and proceed to modify the 404.php and index.php files for that theme.
Although interesting, we couldn’t begin to speculate why they switched the active theme. You’d think they’d want to leave the existing theme as to not arise suspicion, but then again, based on what they did, maybe they didn’t care.
Unfortunately, these audit logs weren’t enough to fully understand what the attacker was doing, but it was good enough to start the analysis. With this we were able to dive into the raw access logs, here is what we saw:
Confirm Known Actions
First we want to sync up the audit logs in the plugin with the raw access logs, do things make sense? Are they in sync?
Correlation between logs:
The following confirms the log in times:
[01/Nov/2013:12:53:36 -0700] "POST /wp-login.php HTTP/1.1" 302 925 [01/Nov/2013:13:22:07 -0700] "POST /wp-login.php HTTP/1.1" 302 971
We then see them making the modifications to the 404.php on TwentyTwelve:
[01/Nov/2013:13:22:32 -0700] "GET /wp-admin/theme-editor.php?file=404.php&theme=twentytwelve HTTP/1.1" 200 7750 [01/Nov/2013:13:22:38 -0700] "POST /wp-admin/theme-editor.php HTTP/1.1" 302 482 [01/Nov/2013:13:22:47 -0700] "GET /wp-admin/theme-editor.php?file=404.php&theme=twentytwelve&scrollto=8896&updated=true HTTP/1.1" 200 66793
The next step is to verify whether he was successful, so they try to access the 404.php page. They first try defining the path, then try the location at root:
Step 1: [01/Nov/2013:13:23:02 -0700] "GET /wp-content/themes/twentytwelve/404.php HTTP/1.1" 403 527 Step 2: [01/Nov/2013:13:23:09 -0700] "GET /404.php HTTP/1.1" 404 491 "-"
What you should notice is the two server notices they get when they try, 403 and 404. The first, 403 is saying Access is forbidden. The next, 404, is saying that the File does not exist on the server
The 403 is being generated from our hardening in .htaccess within wp-content, that kills all PHP execution.
The second, 404 is because the theme is not the active theme.
This actually explains why they go on to switch the active themes, but it doesn’t make sense as they could have just worked off the already active theme.
Here they go making the changes, first the theme switch:
[01/Nov/2013:13:23:48 -0700] "GET /wp-admin/theme-editor.php?file=404.php&theme=twentythirteen&scrollto=8896&updated=true HTTP/1.1" 200 66718 [01/Nov/2013:13:24:04 -0700] "GET /wp-admin/theme-editor.php?file=index.php&theme=twentythirteen HTTP/1.1" 200 7810 [01/Nov/2013:13:24:14 -0700] "POST /wp-admin/theme-editor.php HTTP/1.1" 302 486 [01/Nov/2013:13:24:20 -0700] "GET /wp-admin/theme-editor.php?file=index.php&theme=twentythirteen&scrollto=8896&updated=true HTTP/1.1" 200 66725
Then the verification things are running:
[01/Nov/2013:13:24:27 -0700] "GET / HTTP/1.1" 200 3001 "-"
This one renders them successful, see the 200.
You’re probably wondering why you killed PHP execution. Well, the attackers are abusing an otherwise benign feature. To understand what they are doing, you have to understand how WordPress and many other CMS applications function.
They have a load hierarchy that will execute the PHP files associated with active themes and plugins. So in this instance, as the attacker injected the payload into 404.php and index.php files of the active theme, they were now operational. Good times! Because they put it into the index.php file, they were able to test it by going directly to “/” which is what you see above.
Being this was successful, the attacker was able to proceed passing variables to their payload, each variable causing some level of annoyance to our afternoon.
First variable to be passed:
[01/Nov/2013:13:24:32 -0700] "GET /?webr00t=telnet HTTP/1.1" 200 2805
In part II of this post, I’ll provide you a cheat sheet of the various options the shell offers, but for now, here is what ?webr00t=telnet does at a high level:
?webr00t=telnet creates a .htaccess file that allows to run .root files as cgi scripts and then creates web.root perl file that has a login and logout, can execute shell commands and upload/download files from the server.
Understanding this helps explain the next step here:
[01/Nov/2013:13:24:33 -0700] "GET /cgiweb/web.root HTTP/1.1" 200 963 [01/Nov/2013:13:24:39 -0700] "POST /cgiweb/web.root HTTP/1.1" 200 887 [01/Nov/2013:13:24:44 -0700] "POST /cgiweb/web.root HTTP/1.1" 200 23310
If you’re wondering why the files are .root, that’s because they added elements to the .htaccess files that treat any .root file as a CGI file. Here is what the new .htaccess file looked like, the one inside the cgiweb directory that was created by ?webr00t=telnet:
From that variable, they jumped to /?webr00t=config, which does this:
Creates a .htaccess file that allows to run .root files as cgi scripts and then creates config.root perl file that creates a bunch of symlinks for reading all the config files on the server.
Here was the call:
[01/Nov/2013:13:24:59 -0700] “GET /?webr00t=config HTTP/1.1″ 200 2828 “http://www.[honeypot].com/?webr00t=telnet”
The next step was to access the newly created files in the newly created directory to start doing their work:
[01/Nov/2013:13:25:00 -0700] "GET /configweb/config.root HTTP/1.1" 200 980 [01/Nov/2013:13:25:05 -0700] "POST /configweb/config.root HTTP/1.1" 200 771
Using this variable they were able to use the file uploader and create a new shell backdoor here:
[01/Nov/2013:13:26:18 -0700] "GET /Sadrazam.php HTTP/1.1" 200 6120 [01/Nov/2013:13:26:21 -0700] "POST /Sadrazam.php HTTP/1.1" 200 2525
/?webr00t=config also created over a thousand symlinks at the root of the account, all to predefined configuration files. If the file existed, it created a text file and made it accessible to the attacker so that they were able to do a quick dump of each one.
In the end, the attacker was able to use the techniques we described in earlier posts about hacking servers with FTP, and were able to download dumps from the shared server, things like /etc/passwd and other files. Each of the variables were designed to create and automate the entire attack sequence, expediting and streamlining the attack to a few clicks. When the attacker was done, they left us a little present, a dead site:
They did this two ways:
First, they deleted our wp-includes and wp-admin killing the site, and then, icing on the cake, they added a new .htaccess file at the root that disabled all PHP in our root account:
If you’re wondering, our only hypothesis as to why they killed the site was likely nothing more than a need to show off. The name of the honeypot domain is a bit of a tease as well, leading us to think they did it as a virtual LOL. The other option is they really didn’t care.
Based on the variables they executed in the shell, their focus seemed to be to acquire server level information. Things like existing users in the shared account, and killing the site seemed to be nothing more than a big FU at the end of the day. Either way, it’s always fun and exciting to watch as attacks are happening, there is always so much to learn.
In the second part we’ll take a closer look at the shell the attacker used and see if we can’t better understand what all the attacker could have done.
In the interim, if you think or suspect you’ve been hacked but can’t find the issues, be sure to let us know at firstname.lastname@example.org.