An updated version of apikey.php file gateway, which gets used to receive another piece of malware, an immediate eval backdoor. The file gateway gets deleted after that, possibly in an attempt to conceal where the other piece of malware came from.
Another version of the bonus backdoor downloaded to my honey pot 2019-11-21. This other version is obfuscated in the same manner as this backdoor, with randomly-composed variable names different. All 3 of these backdoors are fairly similar.
This installation consisted of a single HTTP 1.1 session,
with 9 HTTP requests.
The updated version of apikey.php
got downloaded
via a WordPress plugin upload invocation.
After that, the attacker(s) used the version of apikey.php
to download a somewhat obfuscated immediate eval backdoor.
They invoked a self-delete feature of the apikey.php
variant.
45.132.192.22 has no reverse lookup in DNS.
45.132.192.22 looks like it belongs to a Netherlands company, WorldStream:
route: 45.132.192.0/23
origin: AS49981
mnt-by: mnt-nl-sennal-1
created: 2019-08-28T12:15:47Z
last-modified: 2019-08-28T12:15:47Z
AS49981 is:
organisation: ORG-WA106-RIPE
org-name: WorldStream B.V.
org-type: LIR
address: Postbus 223
address: 2670AE
address: Naaldwijk
address: NETHERLANDS
phone: +31174712117
fax-no: +31174512310
45.132.192.22 has never accessed my web site before this.
Remote port 64368 for all requests, outside Linux range for ephemeral ports. This is consistent with a single HTTP/1.1 session, using "Connection: keep-alive" headers.
p0f3 says "Windows 7 or 8"
User agent: Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14
Looks like the attackers used a Windows machine.
Timestamp | URI | Note |
---|---|---|
2019-10-05T01:23:52.854-0600 | /wp-login.php | WordPress login page access, no cookies, no password |
2019-10-05T01:23:53.096-0600 | /wp-login.php | WordPress login, admin/qwertg |
2019-10-05T01:23:53.303-0600 | /wp-admin/ | WordPress admin page access |
2019-10-05T01:23:54.002-0600 | /wp-admin/plugin-install.php?tab=upload | |
2019-10-05T01:23:54.326-0600 | /wp-admin/update.php?action=upload-plugin | plugin install page access |
2019-10-05T01:23:54.614-0600 | /wp-content/plugins/t_file_wp/t_file_wp.php?test=hello | apikey.php access check |
2019-10-05T01:23:54.867-0600 | /wp-content/plugins/t_file_wp/t_file_wp.php | apikey.php file download |
2019-10-05T01:23:55.073-0600 | /wp-content/plugins/t_file_wp/t_file_wp.php?delete_self=1 | apikey.php backdoor cleanup |
2.219 seconds elapsed time to do "cold" WordPress login, act a little bit like a human by retrieving WordPress admin page, and then plugin upload page, upload a Zip file, test that the Zip file got unpacked correctly, use the "apikey" file gateway to send another file "seo_script.php", and finally trigger the "apikey" immediate eval backdoor to delete itself and any other files that might have arrived in the Zip file.
This got done by some automation. No human is fast enough to do all that in 2.2 seconds.
The WordPress user ID and password, admin/qwertg, looks like it was first used 2019-07-31T06:19:16-06:00, by 212.129.7.167, when my honey pot deemed it a valid WordPress password. Since then, it's been used 2566 times, by 629 unique IP addresses. That user ID/password has been sold on the black market. The humans behind 45.132.192.22 bought it.
Deleting the file gateway after using it to download another piece
of malware seems like a lot of work.
Presumably, the attacker(s) try to throw people off by eliminating one of the installation step's evidence,
but they leave a PHP file containing obvious obscured code behind anyway.
I see people writing that their WordPress blog has mysterious
malware on it, but they never seem to figure out where
the mysterious malware came from.
The usual advice consists of reinstalling from backups.
Nobody ever says "read your log files to figure out how it got in".
That's apparently considered too much work for no return.
So why bother to delete the file gateway,
any files in the t_file_wp/
directory,
and that directory?
Why not just download the next stage directly?
The file gateway code looks like an updated
version of apikey.php.
They have the same sort of WordPress meaningful comment at
the top of the file.
Both echo "testtrue";
if you make an HTTP GET request of their
URL with a parameter named "test" that has a value "hello".
They both look in $_FILES["filename"]["tmp_name"]
for information about an uploaded file.
Both gateways use PHP's move_uploaded_file()
builtin to
get an uploaded file's contents to its final destination.
This updated version has slightly more capability, and it's been ruggedized.
The updated version can delete itself and all files in its directory, and then delete the directory, on receipt of an HTTP GET with a parameter "delete_self" that has a value of "1". This actually gets used, too.
Most or all of the places where an unset variable would cause
an ugly and perhaps revealing error message,
the code now uses isset()
.
It's actually a little boring to see so many isset()
calls.
One can only guess that the author of the gateway had some
bad experiences when trying to access un-initiallized variables.
The other added capabilites involve POST parameters named "folder", and a set of parameters named "home", "wp_admin", "wp_content", "wp_includes". If any or all of the set of parameters has a value of "1", the file gateway creates a copy of the uploaded file into the corresponding WordPress directory. If POST parameter "folder" has a value, that value gets used as a subdirectory of the corresponding WordPress directory, and the file gateway moves a copy of the uploaded file to it.
The code is consistenly indented with tabs, the author uses double-quote characters for all strings except one. The code has CRLF line endings, consistent with Windows text file formats. This is reasonably workman-like code.
I ran the improved file gateway through virustotal.com - nothing detected it This implies that the "delete_self" part is effective in keeping the fake plugin code off of people's disks. The question remains why go to all this work? Why not download the backdoor directly?
Unlike the updated apikey.php
file gateway,
the backdoor is obfuscated.
PHP functions that might be part of signatures for backdoors
or other malware, like "str_rot13", "strrev", get recreated
from pieces at run time.
All builtin functions get accessed through $GLOBALS
,
by setting $GLOBALS['_79565595_']
to an array of strings
that name the functions.
The author could have used references to $_79565595_
once
"79565595" got used as an index into $GLOBALS
,
so maybe not that subtle, but still, pretty subtle.
The backdoor assembles obfuscated code from 4 cookies, or POST parameters,
named "jweyc", "aeskoly", "owhggiku" and "callbrhy", in that order.
Any piece or pieces could be a cookie or a POST parameter.
the backdoor deobfuscates the concatenated cookies or parameter
by reversing the string, using packA('H*', ...)
to convert from a hex-digit-string,
and then ROT-13 transposing the characters.
The "H*" argument to pack()
means that instead of a more
common base64 all-ASCII representation, each byte of the
obfuscated code is represented by 2 ASCII characters,
the printable representation in hexadecimal of its numeric value.
I've written an example program that can send code to the backdoor in the correct format to get that code to execute.
virustotal.com has 11 malware engines detecting it under various names which seems to mean "some backdoor".
Alas, nobody made any subsequent accesses of seo_script.php
,
which would be the name of the backdoor.
I guess that this is because my "apikey.php" honey pot
did not answer correctly when the attacker(s)
sent it the backdoor.
My "apikey.php" honey pot merely emulated the other
instances of apikey.php
I had.
It did not answer with the same strings that the updated
version of apikey.php
does.
URLs that have the 4 cookie/parameter names in them somehow, 2019-11-24
- https://www.unphp.net/decode/ac41eec3a81cc4e0efaeac12e9b932f8/
- https://pastebin.com/9fffVzMe
- https://blog.sucuri.net/2019/11/vulnerable-versions-of-adminer-as-a-universal-infection-vector.html
- backdoor is a late-stage part of some larger campaign