Skip to content

Latest commit

 

History

History

cscript

Extensible backdoor

An extensible backdoor.

  1. Plugins can be added, removed and executed.
  2. Immediate code eval.
  3. Some recon info: PHP version, its own version.
  4. Password authenticated access.

I got 71 downloads of essentially the same code from 2018-03-15 to 2018-05-30. All code purports to be version "1.0-2".

Higher-numbered versions exist. You can get version 2.0-1 from pastebin. I have reversed a version v2.0-1 instance, to see what changes people have made.

Version 2.0-1 is the earliest occurance on pastebin, at January 9, 2018.

I got another spin on version 2.0-1 via email. It's in the ico directory. A January, 2019 analysis of another, nearly identical, 2.0-1 installation.

On 2018-06-18, my WSO honey pot caught a batch of 5 similar, more primitive backdoors. Those primitive backdoors probably shared an ancestor with these.

A less specific analysis of apparently the version 2.0-1 backdoor. Apparently the attackers in this case actually used the plugin feature.

See also Backdoor installation campaign for what seems like an extension or continuation of the "more primitive" backdoor attacks.

On 2019-05-09, my honey pot caught a v3-01 instance, very reminiscent of v2-01 instances.

Origin

Download

Attacker wanted to download to the "RC" action of a WSO (Web Shell by oRb) instance. Code downloaded to the WSO part of my WordPress honey pot.

Every request made of the fake WSO arrives with a WSO cookie. The md5 hash in the cookie corresponds to "nhzgrf", a common WSO password.

The attacker did try a variety of possible WSO URIs:

/wordpress/wp-content/plugins/revslider/temp/update_extract/revslider/db.php
/wordpress/wp-content/plugins/wp-mobile-detector/cache/db.php
/wordpress/wp-content/uploads/wpallimport/uploads/f2af55ff3d3404c81a296c997348e8d1/db.php
/wp-content/plugins/revslider/temp/update_extract/revslider/info.php
/wp-content/plugins/wp-db-ajax-made/wp-ajax.php
/wp-content/plugins/wp_bing/system.php
/wp-content/themes/sketch/404.php

These are all URIs that attackers believe are WSO or other web shells.

Source IP Addresses

IP address Download time DNS name
212.63.109.204 2018-03-15T03:13:33.000-0600 dns109204.phdns10.es
85.128.142.46 2018-03-16T07:59:31.000-0600 akl46.rev.netart.pl
119.59.120.3 2018-03-17T08:16:53.000-0600 N/A
194.54.82.78 2018-03-18T02:01:56.000-0600 dolina-82-78.dolina.rx-name.net
162.241.218.136 2018-03-19T06:34:18.000-0600 box5566.bluehost.com
184.168.200.228 2018-03-20T02:06:41.000-0600 p3plcpnl0168.prod.phx3.secureserver.net
121.127.254.2 2018-03-21T06:43:55.000-0600 N/A
103.95.197.62 2018-03-22T02:34:12.000-0600 host62.cloudzone.vn
162.241.226.121 2018-03-23T05:26:53.000-0600 box5342.bluehost.com
173.201.196.148 2018-03-24T03:03:45.000-0600 p3nlhg290.shr.prod.phx3.secureserver.net
173.201.196.110 2018-03-25T04:27:29.000-0600 p3nlhg302.shr.prod.phx3.secureserver.net
118.123.16.54 2018-03-26T03:49:21.000-0600 N/A
148.72.232.52 2018-03-27T02:49:23.000-0600 sg2plcpnl0173.prod.sin2.secureserver.net
85.128.142.58 2018-03-28T03:11:08.000-0600 akl58.rev.netart.pl
198.71.239.47 2018-03-29T07:30:25.000-0600 a2nlwpweb045.prod.iad2.secureserver.net
113.212.162.149 2018-03-30T08:21:34.000-0600 mail.bias-samudra.com
66.147.240.198 2018-03-31T02:10:45.000-0600 host398.hostmonster.com
207.246.249.205 2018-04-01T05:19:51.000-0600 N/A
50.63.194.158 2018-04-02T03:56:41.000-0600 p3nlhg1432.shr.prod.phx3.secureserver.net
184.168.27.12 2018-04-03T04:14:59.000-0600 p3nlhg836.shr.prod.phx3.secureserver.net
91.200.60.68 2018-04-04T03:37:00.000-0600 wezom3.linevps.net
158.69.8.115 2018-04-04T01:10:37.000-0600 N/A
160.153.147.139 2018-04-05T07:28:33.000-0600 n3nlwpweb011.prod.ams3.secureserver.net
182.50.135.55 2018-04-06T03:45:10.000-0600 sg2plcpnl0107.prod.sin2.secureserver.net
212.174.107.137 2018-04-07T04:05:25.000-0600 lpm3-ppp137.verisoft.net.tr
178.210.90.90 2018-04-08T04:06:56.000-0600 tproxy1102.nic.ru
198.71.238.6 2018-04-09T05:56:10.000-0600 a2nlwpweb054.prod.iad2.secureserver.net
198.71.238.11 2018-04-10T01:23:34.000-0600 a2nlwpweb059.prod.iad2.secureserver.net
50.62.176.242 2018-04-11T05:51:13.000-0600 p3plcpnl0726.prod.phx3.secureserver.net
184.168.27.140 2018-04-12T04:20:50.000-0600 p3nlhg913.shr.prod.phx3.secureserver.net
50.62.208.38 2018-04-13T03:37:27.000-0600 p3nlwpweb053.shr.prod.phx3.secureserver.net
178.210.90.90 2018-04-14T04:25:48.000-0600 tproxy1102.nic.ru
112.78.2.202 2018-04-15T01:06:48.000-0600 N/A
42.98.72.36 2018-04-16T07:19:46.000-0600 42-98-72-036.static.netvigator.com
209.175.164.195 2018-04-17T07:50:11.000-0600 N/A
122.114.43.148 2018-04-18T04:28:21.000-0600 N/A
78.24.221.82 2018-04-19T08:46:54.000-0600 legendgroup.fvds.ru
162.241.216.242 2018-04-20T10:03:16.000-0600 box5442.bluehost.com
149.202.83.87 2018-04-21T07:12:55.000-0600 ns3019045.ip-149-202-83.eu
168.167.251.215 2018-04-22T08:32:53.000-0600 N/A
132.148.104.129 2018-04-23T01:29:39.000-0600 p3nlhg2080.shr.prod.phx3.secureserver.net
50.87.144.119 2018-04-25T07:23:11.000-0600 gator3084.hostgator.com
185.26.122.29 2018-04-25T05:55:34.000-0600 serv29-26.hostland.ru
107.180.120.64 2018-04-26T06:32:10.000-0600 a2nlwpweb145.prod.iad2.secureserver.net
151.1.184.134 2018-04-27T07:40:37.000-0600 N/A
95.58.31.174 2018-04-28T04:01:05.000-0600 N/A
210.61.49.127 2018-05-06T03:18:37.000-0600 210-61-49-127.hinet-ip.hinet.net
182.50.151.55 2018-05-07T03:13:32.000-0600 sg2plcpnl0074.prod.sin2.secureserver.net
45.40.166.153 2018-05-08T05:35:46.000-0600 p3nlhg2063.shr.prod.phx3.secureserver.net
213.142.130.42 2018-05-09T01:49:54.000-0600 lhost452.websahibi.com
62.210.185.4 2018-05-10T05:48:22.000-0600 nat-dc2-2.online.net
207.148.119.51 2018-05-11T05:03:21.000-0600 207.148.119.51.vultr.com
198.71.238.17 2018-05-12T06:42:15.000-0600 a2nlwpweb064.prod.iad2.secureserver.net
198.71.239.45 2018-05-13T06:55:18.000-0600 a2nlwpweb044.prod.iad2.secureserver.net
188.187.190.59 2018-05-14T01:08:57.000-0600 188x187x190x59.static-customer.yola.ertelecom.ru
34.197.246.236 2018-05-15T03:26:38.000-0600 ec2-34-197-246-236.compute-1.amazonaws.com
50.62.177.187 2018-05-16T03:29:19.000-0600 p3plcpnl0887.prod.phx3.secureserver.net
50.87.144.56 2018-05-17T01:58:28.000-0600 gator3037.hostgator.com
107.180.120.67 2018-05-18T05:23:55.000-0600 a2nlwpweb147.prod.iad2.secureserver.net
107.180.120.45 2018-05-19T08:28:42.000-0600 a2nlwpweb128.prod.iad2.secureserver.net
198.71.239.9 2018-05-20T04:18:36.000-0600 a2nlwpweb007.prod.iad2.secureserver.net
182.50.130.35 2018-05-21T05:26:24.000-0600 sg2nw8shg139.shr.prod.sin2.secureserver.net
81.91.86.129 2018-05-22T05:43:57.000-0600 rs29.web4u.cz
82.209.199.218 2018-05-23T03:06:19.000-0600 metropr.by
79.170.40.55 2018-05-24T04:11:03.000-0600 web55.extendcp.co.uk
176.31.236.164 2018-05-25T07:14:22.000-0600 tarkett-2013.hosting.clever-age.net
192.185.83.194 2018-05-26T03:15:28.000-0600 marzal.websitewelcome.com
198.71.238.9 2018-05-27T02:51:42.000-0600 a2nlwpweb056.prod.iad2.secureserver.net
184.168.46.128 2018-05-28T02:35:37.000-0600 p3nlhg738.shr.prod.phx3.secureserver.net
195.74.38.66 2018-05-29T10:27:34.000-0600 cl-05.atm.binero.net
184.168.152.99 2018-05-30T03:54:00.000-0600 p3nlhg663.shr.prod.phx3.secureserver.net

Looks like they have a fondness for GoDaddy (secureserver.net) machines.

p0f3 says that most of these addresses were Linux machines at the time of download, but there's a sprinkling of Windows and FreeBSD, too.

Deobfuscation

The script extract contains the entire process, which goes something like this:

  1. For each file named files/*.php.file:

    1. Create a file with <?php at the beginning, and the contents of the original file, with "print" substituted for "eval"
    2. Append a line with "rawurldecode()" or "base64_decode()", depending on what the encoding in files/*.php.file
  2. Execute the files created in step 1, substituting "print" for "eval" in the output.

  3. Execute the files from step 2, saving the contents in final/

The dropper is the obfuscated code in files named files/*.php.file

The example final code is in extendable.php

Analysis

I'd give this code a thumbs-up. It tries to hide mostly in plain sight, but with enought obfuscation that visual inspection by a human would fail. Network traffic can be inobvious, as it is is XOR-ed and base64-encoded. Command traffic can arrive via HTTP cookie, or HTTP POST. The use of a cookie isn't unprecedented, but it would obscure the traffic.

The plugin architecture allows for maximum flexibility. It does have downsides, in that an attacker must install a plugin first, then execute it, causing more than one burst of suspicious traffic.

Dropper

Any of the files named files/*.php.file contain similar PHP. This PHP would get eval'ed by function actionRC() in a real WSO web shell.

Stylistically, the dropper code seems very consistent. The dropper has function names prefixed with "fr_". All function names are something like "fr_CamelCase" Every variable name is snake_case. Braces placement is mostly regular, albeit a little unusual. Left- and right-braces mostly exist on their own lines, rather than appearing at the end of an "if" or "while" statement line. A few instances of if (some condition) { do exist, possibly indicating a second author.

The code eval'ed by function actionRC() should detect if either Joomla, Drupal or WordPress exists on the host running WSO. The code contains names of a few files that exist in any install of each of the 3 CMS, for instance WordPress always has wp-settings.php and wp-config.php. Finding one of the file names indicates the corresponding CMS is installed.

For each of the files of the CMS that the dropper decides it finds, it first tries to put a PHP include(); directive in the CMS file, creating a randomly-named file to include. That randomly named file contains the obfuscated backdoor code.

If it did not succeed in adding "include" directives to any of the files of the CMS files, it tries to put the obfuscated backdoor code in the files with an "eval" surrounding it. Very thorough!

It looks like the dropper code output would constitute something like:

URL#http://example.com#FULL

for successful install(s), either with an include or with an eval, and it would report

URL#http://example.com#RESTRICTED

for failed installs. It outputs nothing if it finds no CMS it recognizes, or if it can't write to the CMS files it finds.

Backdoor

The extensible backdoor has function names prefixed with "cs_". There are some apparent duplications with the dropper, such as fr_GetHost in dropper, cs_GetHost in the back door code. The back door has a mix of function name styles, some in camel case (cs_GetCommonStorage()) some in snake case (cs_plugin_load()). Variable names are all "snake_case". Left- and right-bracket placement is completely consistent throughout. It looks maybe like the dropper and back door had independent, but cooperating, authors. Or maybe the back door author just borrowed available code for the dropper, but did some rewriting to conform to their coding standard.

The backdoor has 5 clearly delineated operations:

  1. Return host info: PHP version, backdoor version, XOR-key
  2. Eval: immediate eval of PHP code sent to the backdoor. The most traditional backdoor function.
  3. Add a plugin.
  4. Remove a plugin.
  5. Run all the plugins. There is no way to run just one plugin, it's all or nothing.

You need to supply a password/XOR key for every operation except running all the plugins.

The code looks like the author maybe had an idea of running just one plugin, but it never got written, even in version 2.0-1: function cs_plugin_load() has a formal argument, $name, used to decide what plugin to run. Unfortunately, cs_plugin_load() does not get invoked with a plugin name, nor does the code support getting a plugin name to the back door. This wasn't fixed in the 2.0-1 code.

Plugin code is stored encrypted, one file per plugin, in a directory created by the back door. The directory name is one of a list ("options", "views", "pages", "sessions", "stats", "users", "articles", "dump", "headers", "libs") in the back door code, chosen by string length of the host name the back door exists on. Plugin code gets XOR-ed with the host name, so it's not immediately obvious that file options/0fea6_b90f2694d4fbf770be56dbe9ba1e5fa0 contains PHP code.

Either way the back door code gets installed (include(random file name) or inside an eval()), the plugin code would seem fairly innocuous.

Test Client

I wrote a client to understand the cipher used, to verify that the backdoors work, and understand the code better. This client can invoke any of the backdoor functions. Any immediate-eval code or plugin code gets taken from a command line parameter, so it's inconvenient to add plugins. It should have an option to read plugins from files.

Pasword/XOR key

Out of 71 install attempts, the attacker sent me 41 different password/XOR keys. Just in case this is interesting to anyone:

08daac77-cdf8-4a48-bdaf-3c0e852c89b8
1a306d05-103d-4aac-952e-008871d6017a
1e87ab0f-acf1-4257-91fd-327300af749e
208842cd-e247-4882-aaa3-c881ee68e6b8
265c2857-4559-48e7-bf55-8991a1ecefdb
2802a388-982b-485a-a95a-32935c85945b
2c327d6b-188a-4cc1-9f51-099c5ceaf0f6
34d11daa-f6b5-4605-93f3-b8646febbd91
39da6ea2-8eab-4da6-bcae-0c3bee011999
557a307c-67b4-4c5b-9b73-bf8cbccc674c
615be3f0-a7d4-4bfc-946b-88fbc69f41c9
68468faf-3870-4b43-80e8-2988631799c2
69557b65-8b17-4f7f-b125-7ee49fe550f1
6ae4dfcd-ed62-42c7-80c2-b243de73efaf
6fd124d9-030f-418a-bfe6-9387dfa6e1c9
7018d16b-3efc-4a51-9426-4ac14509454b
70aa4fe9-b7d4-4f3a-a7bc-d38fecfffc99
728abe65-22d5-4a65-90ea-708ecb84af0c
72bff547-acd6-4a7e-9e3a-08f17d7259dd
7375f6b0-11a5-4e32-88d1-a35f30c5cf0b
863257b6-f98d-4e7a-bbba-773fda43c2e3
8dbdf9e9-d81d-48d5-8e2f-8e3658a65059
8f98f4d8-072e-4aa3-93a9-50bbb64a34a4
9a2fc75d-6ae2-42c0-9b70-1cce3d291bd9
9b3d3f5d-680a-4184-90f2-57b8985c188f
9d77d409-8a82-4adf-9407-9debffedab9d
a5d4ba8f-1065-423f-b9cb-f26351d33019
a801fcd0-c240-42a1-8ee9-396d1e89e06d
b405656c-7687-4672-9f30-6b4642901f97
b6f6b857-a137-4fe4-9f6e-0aa7bba96738
b95ef13a-be29-47bb-ac93-bd99740fbc6f
bfda478b-0412-41ef-8dfe-5510aa57ecd6
cca7f80a-a7a8-45e1-9c30-578704560790
d2a77a85-6712-4c43-bc0d-492e8f127b0f
dd8a5d6f-320e-4bbf-b625-decdd0a941c6
e340cca1-52db-41d1-a20f-a12ec7ec189e
ee8a7011-79ad-40f4-90af-91a7be1b7999
ee909dc0-3cbc-4e60-8d26-897fbe30a870
f722eee1-755e-4f1f-a999-410d0dbad878
f8f4d6f3-279a-438c-a89f-2283ac374cb7
f9cd46d4-75a9-4ef5-85ae-96f278b3724f