Wednesday, May 9, 2012

Nmap script to check PLESK compromised servers


Few days back I wrote about the PLESK compromised servers in www.my-audit.gr, at that time I made a script to perform manual checks for our clients in our IP ranges.  The script was slow and it was taking a lot of time to produce actual results at first, then I remembered about nmap scripting language (NSE).  I had never used it before but it seems rather easy to make a simple script, so after a couple of minutes I came up with the following script:
   1: description = [[
   2: Looks for signature of PLESK servers that were compromised earlier in 2012.
   3:  
   4: The script checks the existence of enterprise/control/psa/engine.php and 
   5: /enterprise/control/ctrl.php3 files that are not part of plesk distribution. 
   6: The files were added in most servers during the first 3 months of 2012 
   7: after a global scale attack on PLESK hosting servers. 
   8: More at: http://www.my-audit.gr/hacking/plesk-backdoors-a-very-large-number-of-servers-compromised/ ,
   9: http://forum.parallels.com/showthread.php?t=258101 and 
  10: http://0entropy.blogspot.com/2012_03_01_archive.html
  11: ]]
  12:  
  13: ---
  14: -- the result will be something like the following
  15: -- Interesting ports on somehost.someserver.com (xxx.xxx.193.64):
  16: -- PORT     STATE SERVICE
  17: -- 8443/tcp open  https-alt
  18: -- |_ http-plesk-backdoor: PLESK infected v2, please check: http://www.my-audit.gr/hacking/plesk-backdoors-a-very-large-number-of-servers-compromised/
  19: ---
  20:  
  21: author = "Nicolas Krassas"
  22: license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
  23: categories = {"malware","discovery","safe"}
  24:  
  25: require "http"
  26: require "shortport"
  27: require "stdnse"
  28:  
  29: -- This script will check on port 8443 only
  30: portrule = function(host, port)
  31:     local svc = { std = { ["https-alt"] = 1 } }
  32:     if port.protocol ~= 'tcp' or not svc.std[port.service] then
  33:         return false
  34:     end
  35:     return true
  36: end
  37:  
  38: -- Execute the check 
  39: action = function(host, port)
  40:  
  41:         -- Perform a GET request for v2 backdoor, this is the most common currently.
  42:         result = http.get_url("https://" .. host.ip .. ":" .. port.number .. "/enterprise/control/psa/engine.php")
  43:  
  44:         if(not(result)) then
  45:                 return stdnse.format_output(false, "Couldn't perform GET request")
  46:         end
  47:  
  48:         if(result.status == 200) then
  49:                 string = ("PLESK infected v2, please check: http://www.my-audit.gr/hacking/plesk-backdoors-a-very-large-number-of-servers-compromised/");
  50:                 return string
  51:         end
  52:  
  53:         -- Perform a GET request for v1 backdoor
  54:         result = http.get_url("https://" .. host.ip .. ":" .. port.number .. "/enterprise/control/ctrl.php3")
  55:  
  56:         if(not(result)) then
  57:                 return stdnse.format_output(false, "Couldn't perform GET request")
  58:         end
  59:  
  60:         if(result.status == 200) then
  61:                 string = ("PLESK infected v1, please check: http://www.my-audit.gr/hacking/plesk-backdoors-a-very-large-number-of-servers-compromised/");
  62:                 return string
  63:         end
  64: end

a sample output from the script,

root@host:~# nmap  --script http-plesk-backdoor xxx.xxx.xxx.xxx

Starting Nmap 5.00 ( http://nmap.org ) at 2012-05-09 14:20 EEST
Interesting ports on someserver.com (xxx.xxx.xxx.xxx):
Not shown: 979 closed ports
PORT     STATE    SERVICE
21/tcp   open     ftp
22/tcp   open     ssh
25/tcp   open     smtp
53/tcp   open     domain
80/tcp   open     http
106/tcp  open     pop3pw
110/tcp  open     pop3
135/tcp  filtered msrpc
139/tcp  filtered netbios-ssn
143/tcp  open     imap
443/tcp  open     https
445/tcp  filtered microsoft-ds
465/tcp  open     smtps
587/tcp  open     submission
646/tcp  filtered ldp
993/tcp  open     imaps
995/tcp  open     pop3s
1025/tcp filtered NFS-or-IIS
2000/tcp filtered callbook
3306/tcp open     mysql
8443/tcp open     https-alt
|_ http-plesk-backdoor: PLESK infected v1, please check: http://www.my-audit.gr/hacking/plesk-backdoors-a-very-large-number-of-servers-compromised/

Nmap done: 1 IP address (1 host up) scanned in 2.98 seconds

and scanning a larger range,

root@host:~# nmap  --script http-plesk-backdoor xxx.xxx.193.0/24 -p 8443
--snip--
Interesting ports on srv1.someserver.com (xxx.xxx.193.61):
PORT     STATE SERVICE
8443/tcp open  https-alt

Interesting ports on srv2.someserver.com (xxx.xxx.193.62):
PORT     STATE SERVICE
8443/tcp open  https-alt
|_ http-plesk-backdoor: PLESK infected v2, please check: http://www.my-audit.gr/hacking/plesk-backdoors-a-very-large-number-of-servers-compromised/

Interesting ports on srv3.someserver.com (xxx.xxx.193.63):
PORT     STATE SERVICE
8443/tcp open  https-alt
|_ http-plesk-backdoor: PLESK infected v2, please check: http://www.my-audit.gr/hacking/plesk-backdoors-a-very-large-number-of-servers-compromised/

Interesting ports on srv4.someserver.com (xxx.xxx.193.64):
PORT     STATE SERVICE
8443/tcp open  https-alt
|_ http-plesk-backdoor: PLESK infected v2, please check: http://www.my-audit.gr/hacking/plesk-backdoors-a-very-large-number-of-servers-compromised/
--snip--

 The script can be found here, http://chaos.deventum.com/research/nse/http-plesk-backdoor.nse