Skip to content

Latest commit

 

History

History

wso_in_depth

WSO Web Shells in depth

WSO (sometimes "FilesMan") is a PHP program appearing in compromised WordPress installations. "WSO" stands for "Web Shell by Orb", a comment that appears in many variants' source code. It exists in lots of forms: it is a family of programs, modified in the wild by many programmers.

WSO phylogeny

WSO variant family tree. This is only the variants I have copies of. I'm certain that other variants exist.

What is a "web shell"?

A "web shell" is a program that presents a general purpose administrative interface to a human. The analog is to a Linux "shell", a programming language interpreter that specializes in manipulating files, and starting and stopping other programs.

If web shells were standalone, they'd be "remote access trojans", or if legitimately installed, they'd be "remote support software", like Dameware. But they're not standalone, they run by HTTP invocation, in the context of an HTTP (web) server. They're almost never legitimately installed, but rather surreptitiously placed on some compromised web server.

Origin

It appears that a Russian programmer with the handle of "oRb" wrote and upgraded WSO 2.0 through 2.5 in the second half of 2009.

I know the most primitive versions as "WSO_VERSION" of 2.0, I can't find a 1.x version.

oRb's avatar from xaker.name: oRb's avatar

oRb's avatar from antichat.ru: oRb's antichat avatar

The antichat.ru avatar may just be a placeholder.

Original Announcements

Timeline

This is a combined timeline from the 3 forums where oRb seems to have announced releases. It doesn't entirely line up.

  1. 2009-06-07 xaker.name WSO 2.1 announced
  2. 2009-07-16 antichat.ru WSO 2.2 announced
  3. 2009-08-20 xaker.name WSO 2.2 announced
  4. 2009-12-15 xaker.name WSO 2.3 announced
  5. 2010-12-31 antichat.ru WSO 2.5 announced
  6. 2010-12-31 rdot.org WSO 2.5.1 announced
  7. 2011-03-19 xaker.name WSO 2.4 and 2.5 announced

The dates from antichat.ru are all "last edited", so they may be later than when the post first appeared.

The rodot.org WSO 2.5.1 download is not the same as later WSO 2.5.1s, which all have a "phone home". The 2010-12-31 antichat.ru links to the rdot.org post for download.

Earliest web pages I can find referencing WSO or FilesMan:

Someone modified WSO 2.5 to get WSO 2.5.1: 2.5.1 has a "phone home", a small obscured piece of PHP that sends the URL of the WSO instance to the address "[email protected]" every time the 2.5.1 web shell executes. The earliest public reference to WSO has already been worked on in the wild.

Feature and bug fix progression

WSO 2.1

oRb says this is what WSO 2.1 featured:

  • Authorization
  • Info about the server
  • File manager (Copy, rename, move, delete, mod, touch, create files and folders)
  • View, hexview, editing, longload, file upload
  • Console
  • SQL manager (MySql, PostgreSql)
  • PHP code execution
  • Safe mode bypass
  • Work with strings + hash search in online databases
  • Bruteforce (FTP, MySql, PostgreSQL)
  • Bindports and back-connections in C and Perl
  • Self removal
  • Works under Unix and Windows

That's certainly true, but the big new feature is the "bindports and back-connections".

Relative to 2.0, 2.1 includes a lot of calls to printHeader and printFooter, so cleaning up the user interface as well.

WSO 2.2

The new feature in 2.2 is function actionRC, discussed in full below.

oRb added more calls to printHeader and printFooter, and cleaned up a few bugs, like deleting an extra break; in a switch-construct. Another telling bug fix: 2.1 used Windows "drive letters" A through Z. With 2.2, WSO uses drive letters C through Z.

WSO 2.3

oRb does more code cleanup, printLogin becomes WSOlogin, printFooter becomes wsoFooter, printHeader becomes wsoHeader, ex becomes wsoEx.

The C-language bind port and back shell disappear. Perl versions stay in place. This could mean that compromised servers don't often have the GNU C compiler installed. But the bind port and back shell in Perl means that even servers with PHP have Perl installed. It also seems to imply feedback from using WSO 2.2 in the field.

Some pieces of "embedded" HTML, between ?> and <?php tags, end up as PHP strings, output via the echo built-in.

This is a bug fix and tech-debt-reduction release.

WSO 2.4

The "Ajax" feature gets added. I think it was supposed to give immediate feedback when using the PHP Console. I don't think this works well, so I'm not sure why oRb put this in.

Improvements to function actionSecInfo: lists Apache web server loaded modules, for the web server it runs under. Lists interesting programs available, compilers and development tools like gcc and lcc, make, perl and python interpreters that exist on the compromised server. Lists infosec tools like root kit hunters, file modification detection, and antivirus. Changes from referencing milw0rm.com to exploit-db.com.

More bug fixes occur: file downloads get an HTTP header Content-Type: application/octet-stream, for example. Doesn't look like any lethal bugs get fixed (they may not exist), but certainly vexing bugs get squashed.

A feature release, concentrating on Linux security tools reporting. Again this suggests feedback from field use.

WSO 2.5

The big new feature in this release is to use HTTP cookies instead of PHP sessions to store persistent information. PHP sessions leave a file in /tmp/ with the persistent information in it, carrying the same information in a cookie leaves less on the compromised server to discover and possible attribute to an attacker. The cookie gets sent back-and-forty in HTTP requests and responses, which makes it liable to detection by any NIDS looking at traffic. I wonder if this change results from having WSO shell activity discovered in the field, or if it's just something oRb wanted to do.

There are a few bug fixes as well. WSO now says that the output of filectime() is file change time, not file creation time. Somebody's paying attention.

function actionSafeMode disappears. The corresponding ability to invoke actionSafeMode disappears from the "bread crumbs" menu. Given the grab-bag nature of this function, probably nobody used it. This is possibly more evidence of feedback affecting development.

4.x HardLinux variants

Russian-language developers starting with WSO 2.3 We know they started with at least WSO 2.3 based on the code used to issue a 404 or a login page, depending on User Agent string. Development was hosted by github.

4.x have function actionNetwork that includes base64-encoded C and Perl bind port and back connect shells. This is a bit odd, as the C-source shells were eliminated in v2.3.

Improvements

  • Xor-encrypted values of "a" and "p1" parameters
  • ???

Design

WSO is a PHP program. It executes on a HTTP server, in the context of some daemon process, usually an Apache HTTP server. It takes actions on the server because WSO is a "shell", or maybe a "remote access trojan", generates HTML appropriate for those actions, then sends the HTML back for a browser to display. Virtually all PHP programs do something like this.

It uses the _POST superglobal variable rather than _REQUEST, maybe in an effort to be compatible with past versions of PHP, or it was written by a coder that never learned about _REQUEST.

WSO's output HTML is composed as PHP strings, output using echo() instead of interleaving blocks of PHP code with blocks of HTML.

HTTP Parameters and action dispatch

Name Meaning
a Category of action
ajax
c Current working directory
charset character set to use in display
pass authentication password
p1 action's parameter 1
p2 action's parameter 2
p3 action's parameter 3

The parameter named "a" is the most important: it gets used to pick an "action", which gets called via PHP's call_user_func() builtin. I'd argue that the "a" parameter, action functions, and call_user_func() action dispatch are what makes a WSO webshell. This is a unique, distinctive feature of all WSO variants.

if (!empty($_POST['a']) && function_exists('action' . $_POST['a'])) {
    call_user_func('action' . $_POST['a']);
}
"a" value "p1" value
FilesMan
uploadFile
mkdir
delete
paste
Network
bpp
bpc
bcc
bcp

Which actions use c/p1/p2/p3?

I suspect that between call_user_func(), the modularity provided by the action functions, and keeping HTML in PHP strings (rather than interleaved code and HTML), the ease of modifying WSO has led to the explosion in variations.

Login Cookie

Most instances of WSO-family web shells ask for a password before they offer the user a point-n-click interface. Sending WSO a password causes WSO code to create an authentication cookie from the MD5 hash of the server's name, and the MD5 hash of the password. A copy of the MD5 hash of the desired password lives in WSO code.

Cookie Name Cookie Value
md5($_SERVER['HTTP_HOST']) md5($password)

Invoking with parameter "pass" sets a cookie for later access. setcookie($k, $v);

This feature allows attackers to invoke WSO instances with either a POST parameter named "pass" and the correct value, or with a cookie, no explicit login needed. Lots of attackers invoke WSO instances with the login cookie pre-set. This often happens when attackers invoke actionRC, using "a=RC" as POST parameter and value. See actionRC discussion below.

Concealing Login Page

WSO instances will put out a small piece of HTML for a mildly human-friendly login page. They sometimes attempt to conceal this login page from search engines. Instances of versions 2.0 - 2.2 usually have something like this:

if (strpos($_SERVER['HTTP_USER_AGENT'], 'Google') !== false) {
    header('HTTP/1.0 404 Not Found');
    die;
} 

This gets elaborated on beginning in version 2.3:

if (!empty($_SERVER['HTTP_USER_AGENT'])) {
    $userAgents = array('Google', 'Slurp', 'MSNBot', 'ia_archiver', 'Yandex', 'Rambler');
    foreach ($userAgents as $agent) {
        if (strpos($_SERVER['HTTP_USER_AGENT'], $agent) !== false) {
            header('HTTP/1.0 404 Not Found');
            die;
        }
    }
}

User agents for at least the major search engines and archive services get a 404, page not found. Presumably, this keeps people from using the search engines to find WSO instances.

"action" functions

The value of the POST parameter named "a" determines a category of things that WSO can do. The functions available vary by version.

WSO version SecInfo Php FilesMan StringTools FilesTools SafeMode Console Logout SelfRemove Bruteforce Sql Network RC Domain Framer Infect Mass
2.0 X X X X X X X X X X X
2.1 X X X X X X X X X X X X
waw X X X X X X X X X X X X X X
wew X X X X X X X X X X X X
2.2 X X X X X X X X X X X X X
2.3 X X X X X X X X X X X X X
2.4 X X X X X X X X X X X X X
bogel X X X X X X X X X X X X X
2.6 X X X X X X X X X X X X X
2.7 X X X X X X X X X X X X X
3.0 X X X X X X X X X X X X
3.1 X X X X X X X X X X X X X X
4.1.1 X X X X X X X X X X X X X X
4.2.5 X X X X X X X X X X X X X X
Jijle3 X X X X X X X X X X X X X X
Mystery%20Backdoor X X X X X X X X X X X X
2.5 X X X X X X X X X X X X
2.5.1 X X X X X X X X X X X X
2.8 X X X X X X X X X X X X
2.9 X X X X X X X X X X X X
WEBAPP X X X X X X X X X X X X
f4 X X X X X X
ws_ver2 X X X X X

"bogel" is just WSO 2.4 with the string "bogel" substituted for any string matching [Ww][Ss][Oo]. Several other string-substituted variants occur.

The Russian 4.x variants descend from 2.4 - they use a PHP session to keep state rather than keeping state in a cookie. Why did phylogeny indicate a 2.3 origin?

WSO 2.5.1 is WSO 2.5 with a "phone home" borrowed from fx29 web shells. WSO 2.8 is 2.5.1 with an additional "phone home", the previous phone home is preserved.

Conserved Features

Since WSO undergoes "evolution" in the wild, it might be worth looking at what features get conserved.

"a" and call_user_func.

Perl in shell and back connect shell

Methods of obfuscation

Can't be exhaustive - too numerous to list them all.

  • FOPO
  • mod_tumblr "plugin"
  • eval(gzinflate(base64_decode($something)));

actionRC

Most of the "action" functions are devoted to interactive use by humans. One exception is the actionRC function, which first appeared in WSO 2.2, and mostly conserved during subsequent evolution, although a few later variants have function actionRC edited out.

  • Called 2 ways: with and without value for parameter "p1"
  • Acts as an immediate eval backdoor if parameter named "p1" is present and contains PHP source code.
  • Returns a summary of system information if parameter "p1" is not present.

In the wild, attackers invoke WSO shells with HTTP parameter a=RC both with and without PHP code as the value of the parameter named "p1". It appears that invoking actionRC without "p1" contents is a convenient way to verify that a WSO URL allows the password or cookie the attacker has, and that Apache web server and PHP are correctly installed and work.

Attackers apparently invoke WSO with parameters a=RC and PHP code as the value of "p1" to use WSO as an immediate eval backdoor. My WSO emulator often catches this use. A few examples:

An intermediate use of actionRC shows up in this WSO access has a=RC, and p1=echo '67436';. This is almost certainly an attempt to validate that the URL so invoked constitutes a working WSO instance. The attacker(s) in that case had just attempted to send an obfuscated WSO instance to my WordPress honey pot. The file transfer attempt took place via WordPress plugin installation, which means a Zip file had to get unzipped, and WordPress had to put new files in place. Many things could go wrong, including running out of disk space, so it was probably prudent to try out the new WSO instance.

The attackers could vary the string echoed on every invocation. It would be next to impossible to anticipate all the variations with emulator code. This implies that a lot of WSO honey pots or emulators exist, and constitute enough of a problem that the attackers would check for emulation.

Why use "Php" or "Console" actions for this, which does happen.

actionPhp, actionConsole

actionNetwork

function actionNetwork first appears in version 2.1

Perl and C source code for "bind shells" and shell servers, all source kept in base64-encoded strings, C compiled and executed on demand. C shell and bind shell eliminated in version 2.3

Vigilante Malware Remover

My honey pot caught a vigilante malware remover. I've got evidence of this malware dating to 2015-09-22. Every version of this malware has a "detection" function that can find some instances of previously-installed WSO instances. They look for PHP files that contain one of the strings "FilesMan", "WSOsetcookie", "default_use_ajax", "default_action". This will only find unobfuscated WSO instances.

Should this malware find an existing WSO instance, it prepends PHP code that checks a special cookie. Should that cookie not have the correct value, the PHP code sets a 404 header and exits.

The special cookie has both name and value calculated from the well-known PHP variable $_SERVER['HTTP_HOST'] .

Any WSO instances the malware modifies now have an additional authorization check: modified WSO requires a cookie to arrive before even checking the password.

This doesn't entirely make sense, as WSO instances often have individualized passwords. The authors of the vigilante malware remover don't necessarily know that password, so their cookie check might only keep out the previous "owner" or farmer of the WSO instance.

Invocations

I wrote my WordPress honey pot to include a WSO emulator. That WSO emulator stores the passwords and login cookies of all the WSO login attempts. I have written an analysis of WSO passwords.

"root" appears to be the single most used passwords, but I believe there are trends over time, and possibly even vendors of access to WSO instances who use the same password for all of their shells.