Module: Msf::Util::WindowsRegistry::Security

Includes:
Msf::Util::WindowsCryptoHelpers
Defined in:
lib/msf/util/windows_registry/security.rb

Overview

This module include helpers for the SECURITY hive

Defined Under Namespace

Classes: CacheData, CacheEntry, CacheInfo

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Msf::Util::WindowsCryptoHelpers

#add_parity, #aes128_cts_hmac_sha1_96, #aes256_cts_hmac_sha1_96, #aes_cts_hmac_sha1_96, #convert_des_56_to_64, #decrypt_aes, #decrypt_hash, #decrypt_lsa_data, #decrypt_secret_data, #decrypt_user_hash, #decrypt_user_key, #des_cbc_md5, #fix_parity, #rid_to_key, #weak_des_key?

Instance Attribute Details

#lsa_vista_styleObject

Returns the value of attribute lsa_vista_style.


80
81
82
# File 'lib/msf/util/windows_registry/security.rb', line 80

def lsa_vista_style
  @lsa_vista_style
end

Instance Method Details

#cached_infos(nlkm_key) ⇒ Array

Returns the decrypted Cache data and information from HKLMCache. For this, the NLKM secret key must be provided, which can be retrieved with the #nlkm_secret_key method.

Parameters:

  • nlkm_key (String)

    The NLKM secret key

Returns:

  • (Array)

    An array of CacheInfo structures containing the Cache information


190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/msf/util/windows_registry/security.rb', line 190

def cached_infos(nlkm_key)
  values = enum_values('\\Cache')
  unless values
    elog('[Msf::Util::WindowsRegistry::Sam::cached_hashes] No cashed entries')
    return
  end

  values.delete('NL$Control')

  iteration_count = nil
  if values.delete('NL$IterationCount')
    _value_type, value_data = reg_parser.get_value('\\Cache', 'NL$IterationCount')
    iteration_count = value_data.to_i
  end

  values.map do |value|
    _value_type, value_data = get_value('\\Cache', value)
    cache = CacheEntry.read(value_data)

    cache_info = CacheInfo.new(name: value, entry: cache)

    next cache_info unless cache.user_name_length > 0

    enc_data = cache.enc_data.map(&:chr).join
    if @lsa_vista_style
      dec_data = decrypt_aes(enc_data, nlkm_key[16...32], cache.iv)
    else
      dec_data = decrypt_hash(enc_data, nlkm_key, cache.iv)
    end

    params = cache.snapshot.to_h.select { |key, _v| key.to_s.end_with?('_length') }
    params[:group_count] = cache.group_count
    cache_data = CacheData.new(params).read(dec_data)
    cache_info.data = cache_data

    if @lsa_vista_style
      cache_info.iteration_count = iteration_count ? iteration_count : cache.iteration_count
      if (cache_info.iteration_count > 10240)
        cache_info.real_iteration_count = cache_info.iteration_count & 0xfffffc00
      else
        cache_info.real_iteration_count = cache_info.iteration_count * 1024
      end
    end

    cache_info
  end
end

#lsa_secret_key(boot_key) ⇒ String

Retrieve the decrypted LSA secret key from a given BootKey. This also sets the @lsa_vista_style attributes according to the registry keys found under `HKLMSECURTYPolicy`. If set to `true`, the system version is Windows Vista and above, otherwise it is Windows XP or below.

Parameters:

  • boot_key (String)

    The BootKey

Returns:

  • (String)

    The decrypted LSA secret key


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/msf/util/windows_registry/security.rb', line 89

def lsa_secret_key(boot_key)
  # vprint_status('Getting PolEKList...')
  _value_type, value_data = get_value('\\Policy\\PolEKList')
  if value_data
    # Vista or above system
    @lsa_vista_style = true

    lsa_key = decrypt_lsa_data(value_data, boot_key)
    lsa_key = lsa_key[68, 32] unless lsa_key.empty?
  else
    # vprint_status('Getting PolSecretEncryptionKey...')
    _value_type, value_data = get_value('\\Policy\\PolSecretEncryptionKey')
    # If that didn't work, then we're out of luck
    return nil if value_data.nil?

    # XP or below system
    @lsa_vista_style = false

    md5x = Digest::MD5.new
    md5x << boot_key
    1000.times do
      md5x << value_data[60, 16]
    end

    rc4 = OpenSSL::Cipher.new('rc4')
    rc4.decrypt
    rc4.key = md5x.digest
    lsa_key = rc4.update(value_data[12, 48])
    lsa_key << rc4.final
    lsa_key = lsa_key[0x10..0x1F]
  end

  lsa_key
end

#lsa_secrets(lsa_key) ⇒ Hash

Returns the decrypted LSA secrets under HKLMSECURTYPolicySecrets. For this, the LSA secret key must be provided, which can be retrieved with the #lsa_secret_key method.

Parameters:

  • lsa_key (String)

    The LSA secret key

Returns:

  • (Hash)

    A hash containing the LSA secrets.


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/msf/util/windows_registry/security.rb', line 130

def lsa_secrets(lsa_key)
  keys = enum_key('\\Policy\\Secrets')
  return unless keys

  keys.delete('NL$Control')

  keys.each_with_object({}) do |key, lsa_secrets|
    # vprint_status("Looking into #{key}")
    _value_type, value_data = get_value("\\Policy\\Secrets\\#{key}\\CurrVal")
    encrypted_secret = value_data
    next unless encrypted_secret

    if @lsa_vista_style
      decrypted = decrypt_lsa_data(encrypted_secret, lsa_key)
      secret_size = decrypted[0, 4].unpack('<L').first
      secret = decrypted[16, secret_size]
    else
      encrypted_secret_size = encrypted_secret[0, 4].unpack('<L').first
      secret = decrypt_secret_data(encrypted_secret[(encrypted_secret.size - encrypted_secret_size)..-1], lsa_key)
    end
    lsa_secrets[key] = secret
  end
end

#nlkm_secret_key(lsa_key) ⇒ String

Returns the decrypted NLKM secret key from HKLMSECURTYPolicySecretsNL$KMCurrVal. For this, the LSA secret key must be provided, which can be retrieved with the #lsa_secret_key method.

Parameters:

  • lsa_key (String)

    The LSA secret key

Returns:

  • (String)

    The NLKM secret key


160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/msf/util/windows_registry/security.rb', line 160

def nlkm_secret_key(lsa_key)
  _value_type, value_data = get_value('\\Policy\\Secrets\\NL$KM\\CurrVal')
  return nil unless value_data

  if @lsa_vista_style
    nlkm_dec = decrypt_lsa_data(value_data, lsa_key)
  else
    value_data_size = value_data[0, 4].unpack('<L').first
    nlkm_dec = decrypt_secret_data(value_data[(value_data.size - value_data_size)..-1], lsa_key)
  end

  nlkm_dec
end