Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/msf/util/windows_registry/security.rb
Views: 11784
require 'ruby_smb'12module Msf3module Util4module WindowsRegistry56#7# This module include helpers for the SECURITY hive8#9module Security1011include Msf::Util::WindowsCryptoHelpers1213# All of these structures were taken from Impacket secretsdump.py14class CacheData < BinData::Record15mandatory_parameter :user_name_length16mandatory_parameter :domain_name_length17mandatory_parameter :dns_domain_name_length18mandatory_parameter :upn_length19mandatory_parameter :effective_name_length20mandatory_parameter :full_name_length21mandatory_parameter :logon_script_length22mandatory_parameter :profile_path_length23mandatory_parameter :home_directory_length24mandatory_parameter :home_directory_drive_length25mandatory_parameter :group_count26mandatory_parameter :logon_domain_name_length2728endian :little2930string :enc_hash, length: 1631string :unknown, length: 5632string16 :username, length: -> { user_name_length }, byte_align: 433string16 :domain_name, length: -> { domain_name_length }, byte_align: 434string16 :dns_domain_name, length: -> { dns_domain_name_length }, byte_align: 435string16 :upn, length: -> { upn_length }, byte_align: 436string16 :effective_name, length: -> { effective_name_length }, byte_align: 437string16 :full_name, length: -> { full_name_length }, byte_align: 438string16 :logon_script, length: -> { logon_script_length }, byte_align: 439string16 :profile_path, length: -> { profile_path_length }, byte_align: 440string16 :home_directory, length: -> { home_directory_length }, byte_align: 441string16 :home_directory_drive, length: -> { home_directory_drive_length }, byte_align: 442array :groups, initial_length: -> { group_count }, byte_align: 4 do43uint32 :relative_id44uint32 :attributes45end46string16 :logon_domain_name, length: -> { logon_domain_name_length }, byte_align: 447end4849class CacheEntry < BinData::Record50endian :little5152uint16 :user_name_length53uint16 :domain_name_length54uint16 :effective_name_length55uint16 :full_name_length56uint16 :logon_script_length57uint16 :profile_path_length58uint16 :home_directory_length59uint16 :home_directory_drive_length60uint32 :user_id61uint32 :primary_group_id62uint32 :group_count63uint16 :logon_domain_name_length64uint16 :logon_domain_id_length65file_time :last_access66uint32 :revision67uint32 :sid_count68uint16 :valid69uint16 :iteration_count70uint32 :sif_length71uint32 :logon_package72uint16 :dns_domain_name_length73uint16 :upn_length74string :iv, length: 1675string :ch, length: 1676array :enc_data, type: :uint8, read_until: :eof77end7879attr_accessor :lsa_vista_style8081def normalize_key(key)82@root.blank? ? key : key.delete_prefix(@root)83end8485# Retrieve the decrypted LSA secret key from a given BootKey. This also sets86# the @lsa_vista_style attributes according to the registry keys found87# under `HKLM\SECURITY\Policy`. If set to `true`, the system version is88# Windows Vista and above, otherwise it is Windows XP or below.89#90# @param boot_key [String] The BootKey91# @return [String] The decrypted LSA secret key92def lsa_secret_key(boot_key)93# vprint_status('Getting PolEKList...')94_value_type, value_data = get_value(normalize_key('HKLM\\SECURITY\\Policy\\PolEKList'))95if value_data96# Vista or above system97@lsa_vista_style = true9899lsa_key = decrypt_lsa_data(value_data, boot_key)100lsa_key = lsa_key[68, 32] unless lsa_key.empty?101else102# vprint_status('Getting PolSecretEncryptionKey...')103_value_type, value_data = get_value(normalize_key('HKLM\\SECURITY\\Policy\\PolSecretEncryptionKey'))104# If that didn't work, then we're out of luck105return nil if value_data.nil?106107# XP or below system108@lsa_vista_style = false109110md5x = Digest::MD5.new111md5x << boot_key1121000.times do113md5x << value_data[60, 16]114end115116rc4 = OpenSSL::Cipher.new('rc4')117rc4.decrypt118rc4.key = md5x.digest119lsa_key = rc4.update(value_data[12, 48])120lsa_key << rc4.final121lsa_key = lsa_key[0x10..0x1F]122end123124lsa_key125end126127# Returns the decrypted LSA secrets under HKLM\SECURITY\Policy\Secrets. For128# this, the LSA secret key must be provided, which can be retrieved with129# the #lsa_secret_key method.130#131# @param lsa_key [String] The LSA secret key132# @return [Hash] A hash containing the LSA secrets.133def lsa_secrets(lsa_key)134keys = enum_key(normalize_key('HKLM\\SECURITY\\Policy\\Secrets'))135return unless keys136137keys.delete('NL$Control')138139keys.each_with_object({}) do |key, lsa_secrets|140_value_type, value_data = get_value(normalize_key("HKLM\\SECURITY\\Policy\\Secrets\\#{key}\\CurrVal"))141encrypted_secret = value_data142next unless encrypted_secret143144if @lsa_vista_style145decrypted = decrypt_lsa_data(encrypted_secret, lsa_key)146secret_size = decrypted[0, 4].unpack('L<').first147secret = decrypted[16, secret_size]148else149encrypted_secret_size = encrypted_secret[0, 4].unpack('L<').first150secret = decrypt_secret_data(encrypted_secret[(encrypted_secret.size - encrypted_secret_size)..-1], lsa_key)151end152lsa_secrets[key] = secret153end154end155156# Returns the decrypted NLKM secret key from157# HKLM\SECURITY\Policy\Secrets\NL$KM\CurrVal. For this, the LSA secret key158# must be provided, which can be retrieved with the #lsa_secret_key method.159#160# @param lsa_key [String] The LSA secret key161# @return [String] The NLKM secret key162def nlkm_secret_key(lsa_key)163_value_type, value_data = get_value(normalize_key('HKLM\\SECURITY\\Policy\\Secrets\\NL$KM\\CurrVal'))164return nil unless value_data165166if @lsa_vista_style167nlkm_dec = decrypt_lsa_data(value_data, lsa_key)168else169value_data_size = value_data[0, 4].unpack('L<').first170nlkm_dec = decrypt_secret_data(value_data[(value_data.size - value_data_size)..-1], lsa_key)171end172173nlkm_dec174end175176# This structure consolidates Cache data and information, as retrieved by the #cached_infos method177CacheInfo = Struct.new(178:name,179:iteration_count,180:real_iteration_count,181:entry, # CacheEntry structure182:data, # CacheData structure183keyword_init: true184)185186# Returns the decrypted Cache data and information from HKLM\Cache. For187# this, the NLKM secret key must be provided, which can be retrieved with188# the #nlkm_secret_key method.189#190# @param nlkm_key [String] The NLKM secret key191# @return [Array] An array of CacheInfo structures containing the Cache information192def cached_infos(nlkm_key)193values = enum_values(normalize_key('HKLM\\SECURITY\\Cache'))194unless values195elog('[Msf::Util::WindowsRegistry::Sam::cached_hashes] No cashed entries')196return197end198199values.delete('NL$Control')200201iteration_count = nil202if values.delete('NL$IterationCount')203_value_type, value_data = reg_parser.get_value(normalize_key('HKLM\\SECURITY\\Cache'), 'NL$IterationCount')204iteration_count = value_data.to_i205end206207values.map do |value|208_value_type, value_data = get_value(normalize_key('HKLM\\SECURITY\\Cache'), value)209cache = CacheEntry.read(value_data)210211cache_info = CacheInfo.new(name: value, entry: cache)212213next cache_info unless cache.user_name_length > 0214215enc_data = cache.enc_data.map(&:chr).join216if @lsa_vista_style217dec_data = decrypt_aes(enc_data, nlkm_key[16...32], cache.iv)218else219dec_data = decrypt_hash(enc_data, nlkm_key, cache.iv)220end221222params = cache.snapshot.to_h.select { |key, _v| key.to_s.end_with?('_length') }223params[:group_count] = cache.group_count224cache_data = CacheData.new(params).read(dec_data)225cache_info.data = cache_data226227if @lsa_vista_style228cache_info.iteration_count = iteration_count ? iteration_count : cache.iteration_count229if (cache_info.iteration_count > 10240)230cache_info.real_iteration_count = cache_info.iteration_count & 0xfffffc00231else232cache_info.real_iteration_count = cache_info.iteration_count * 1024233end234end235236cache_info237end238end239240end241end242end243end244245246247