Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion lib/msf/core/post/windows/registry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,9 @@ def meterpreter_registry_key_exist?(key)
# Normalize the supplied full registry key string so the root key is sane. For
# instance, passing "HKLM\Software\Dog" will return 'HKEY_LOCAL_MACHINE\Software\Dog'
#
# Any trailing backslash is stripped to prevent cmd.exe argument escaping
# issues when the normalized key is interpolated into a quoted shell command.
#
def normalize_key(key)
keys = split_key(key)
if (keys[0] =~ /HKLM|HKEY_LOCAL_MACHINE/)
Expand All @@ -700,7 +703,7 @@ def normalize_key(key)
raise ArgumentError, "Cannot normalize unknown key: #{key}"
end
# print_status("Normalized #{key} to #{keys.join("\\")}")
return keys.compact.join("\\")
return keys.compact.join("\\").chomp("\\")
end

#
Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/windows/persistence/registry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def create_cleanup(root_path, blob_reg_key, blob_reg_name, cmd_reg, new_key)
end

def check
return Msf::Exploit::CheckCode::Safe('System does not have powershell') unless registry_enumkeys('HKLM\\SOFTWARE\\Microsoft\\').include?('PowerShell')
return Msf::Exploit::CheckCode::Safe('System does not have powershell') unless registry_enumkeys('HKLM\\SOFTWARE\\Microsoft').include?('PowerShell')

vprint_good('Powershell detected on system')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def writable_dir
end

def check
return Msf::Exploit::CheckCode::Safe('System does not have powershell') unless registry_enumkeys('HKLM\\SOFTWARE\\Microsoft\\').include?('PowerShell')
return Msf::Exploit::CheckCode::Safe('System does not have powershell') unless registry_enumkeys('HKLM\\SOFTWARE\\Microsoft').include?('PowerShell')

vprint_good('Powershell detected on system')

Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/windows/persistence/wsl/registry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def create_cleanup(root_path, blob_reg_key, blob_reg_name, cmd_reg, new_key)
def check
# /tmp seems to persist on *some* Ubuntu WSL (wsl v1 it did, v2 it didnt)
print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if datastore['WritableDir'].start_with?('/tmp')
return Msf::Exploit::CheckCode::Safe('System does not have powershell') unless registry_enumkeys('HKLM\\SOFTWARE\\Microsoft\\').include?('PowerShell')
return Msf::Exploit::CheckCode::Safe('System does not have powershell') unless registry_enumkeys('HKLM\\SOFTWARE\\Microsoft').include?('PowerShell')

vprint_good('Powershell detected on system')

Expand Down
2 changes: 1 addition & 1 deletion modules/post/windows/gather/credentials/domain_hashdump.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def ntds_exists?
end

def ntds_location
@ntds_location ||= registry_getvaldata('HKLM\\SYSTEM\\CurrentControlSet\\services\\NTDS\\Parameters\\', 'DSA Working Directory')
@ntds_location ||= registry_getvaldata('HKLM\\SYSTEM\\CurrentControlSet\\services\\NTDS\\Parameters', 'DSA Working Directory')
end

def ntdsutil_method
Expand Down
8 changes: 4 additions & 4 deletions modules/post/windows/gather/credentials/enum_picasa_pwds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ def decrypt_password(data)
def get_registry
print_status('Looking in registry for stored login passwords by Picasa ...')

username = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa2\\Preferences\\', 'GaiaEmail') || ''
password = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa2\\Preferences\\', 'GaiaPass') || ''
username = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa2\\Preferences', 'GaiaEmail') || ''
password = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa2\\Preferences', 'GaiaPass') || ''

credentials = Rex::Text::Table.new(
'Header' => 'Picasa Credentials',
Expand All @@ -109,8 +109,8 @@ def get_registry
end

# For early versions of Picasa3
username = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa3\\Preferences\\', 'GaiaEmail') || ''
password = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa3\\Preferences\\', 'GaiaPass') || ''
username = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa3\\Preferences', 'GaiaEmail') || ''
password = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa3\\Preferences', 'GaiaPass') || ''

if !username.empty? && !password.empty?
passbin = [password].pack('H*')
Expand Down
8 changes: 4 additions & 4 deletions modules/post/windows/gather/credentials/gpp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -378,14 +378,14 @@ def get_cached_domain_controller
def get_domain_reg
locations = []
# Lots of redundancy but hey this is quick!
locations << ['HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\', 'Domain']
locations << ['HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\', 'DefaultDomainName']
locations << ['HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History\\', 'MachineDomain']
locations << ['HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters', 'Domain']
locations << ['HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon', 'DefaultDomainName']
locations << ['HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History', 'MachineDomain']

domains = []

# Pulls cached domains from registry
domain_cache = registry_enumvals('HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\DomainCache\\')
domain_cache = registry_enumvals('HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\DomainCache')
if domain_cache
domain_cache.each { |ud| domains << ud }
end
Expand Down
2 changes: 1 addition & 1 deletion modules/post/windows/gather/credentials/idm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def run
print_status("Looking at Key #{k}")

begin
subkeys = registry_enumkeys("HKU\\#{k}\\Software\\DownloadManager\\Passwords\\")
subkeys = registry_enumkeys("HKU\\#{k}\\Software\\DownloadManager\\Passwords")

if subkeys.nil? || subkeys.empty?
print_status('IDM not installed for this user.')
Expand Down
6 changes: 3 additions & 3 deletions modules/post/windows/gather/credentials/imvu.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ def run
next if hive['HKU'].nil?

vprint_status("Looking at Key #{hive['HKU']}")
subkeys = registry_enumkeys("#{hive['HKU']}\\Software\\IMVU\\")
subkeys = registry_enumkeys("#{hive['HKU']}\\Software\\IMVU")
if subkeys.nil? || subkeys.empty?
print_status('IMVU not installed for this user.')
next
end
user = registry_getvaldata("#{hive['HKU']}\\Software\\IMVU\\username\\", '')
hpass = registry_getvaldata("#{hive['HKU']}\\Software\\IMVU\\password\\", '')
user = registry_getvaldata("#{hive['HKU']}\\Software\\IMVU\\username", '')
hpass = registry_getvaldata("#{hive['HKU']}\\Software\\IMVU\\password", '')
decpass = [ hpass.downcase.gsub(/'/, '').gsub(/\\?x([a-f0-9][a-f0-9])/, '\1') ].pack('H*')
print_good("User=#{user}, Password=#{decpass}")
creds << [user, decpass]
Expand Down
6 changes: 3 additions & 3 deletions modules/post/windows/gather/credentials/nimbuzz.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ def run
next if k.include?('_Classes')

vprint_status("Looking at Key #{k}")
subkeys = registry_enumkeys("HKU\\#{k}\\Software\\Nimbuzz\\")
subkeys = registry_enumkeys("HKU\\#{k}\\Software\\Nimbuzz")

if subkeys.nil? || (subkeys == '')
print_status('Nimbuzz Instant Messenger not installed for this user.')
next
end

user = registry_getvaldata("HKU\\#{k}\\Software\\Nimbuzz\\PCClient\\Application\\", 'Username') || ''
hpass = registry_getvaldata("HKU\\#{k}\\Software\\Nimbuzz\\PCClient\\Application\\", 'Password')
user = registry_getvaldata("HKU\\#{k}\\Software\\Nimbuzz\\PCClient\\Application", 'Username') || ''
hpass = registry_getvaldata("HKU\\#{k}\\Software\\Nimbuzz\\PCClient\\Application", 'Password')

next if hpass.nil? || (hpass == '')

Expand Down
2 changes: 1 addition & 1 deletion modules/post/windows/gather/outlook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def click_button(atrans, acftrans)

def outlook_installed?
key_base = 'HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles\\Outlook\\9375CFF0413111d3B88A00104B2A6676'
installed = registry_getvaldata("#{key_base}\\", 'NextAccountID')
installed = registry_getvaldata(key_base, 'NextAccountID')

if installed.blank? || installed == 0
return false
Expand Down
2 changes: 1 addition & 1 deletion scripts/meterpreter/gettelnet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def checkifinst()
# This won't work on windows 2000 since there is no sc.exe
print_status("Checking if Telnet is installed...")
begin
registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\services\\TlntSvr\\","Start")
registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\services\\TlntSvr","Start")
return true
rescue
return false
Expand Down
91 changes: 91 additions & 0 deletions spec/lib/msf/core/post/windows/registry_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# -*- coding: binary -*-

require 'spec_helper'

RSpec.describe Msf::Post::Windows::Registry do
subject do
context_described_class = described_class

klass = Class.new(Msf::Post) do
include context_described_class
end

klass.new
end

describe '#split_key' do
[
{ input: 'HKLM\\SOFTWARE\\Microsoft', expected: ['HKLM', 'SOFTWARE\\Microsoft'] },
{ input: 'HKLM\\SOFTWARE\\Microsoft\\', expected: ['HKLM', 'SOFTWARE\\Microsoft\\'] },
{ input: 'HKLM', expected: ['HKLM', nil] },
{ input: 'HKCU\\Environment', expected: ['HKCU', 'Environment'] },
{ input: 'HKU\\S-1-5-21-1234', expected: ['HKU', 'S-1-5-21-1234'] },
{ input: '', expected: ['', nil] },
].each do |test_case|
it "splits #{test_case[:input].inspect} into #{test_case[:expected].inspect}" do
expect(subject.send(:split_key, test_case[:input])).to eq(test_case[:expected])
end
end
end

describe '#normalize_key' do
context 'with standard key paths' do
[
{ input: 'HKLM\\SOFTWARE\\Microsoft', expected: 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft' },
{ input: 'HKCU\\Environment', expected: 'HKEY_CURRENT_USER\\Environment' },
{ input: 'HKU\\S-1-5-18', expected: 'HKEY_USERS\\S-1-5-18' },
{ input: 'HKCR\\.exe', expected: 'HKEY_CLASSES_ROOT\\.exe' },
{ input: 'HKCC\\System', expected: 'HKEY_CURRENT_CONFIG\\System' },
{ input: 'HKPD', expected: 'HKEY_PERFORMANCE_DATA' },
{ input: 'HKDD', expected: 'HKEY_DYN_DATA' },
].each do |test_case|
it "normalizes #{test_case[:input].inspect} to #{test_case[:expected].inspect}" do
expect(subject.send(:normalize_key, test_case[:input])).to eq(test_case[:expected])
end
end
end

context 'with trailing backslash' do
it 'strips the trailing backslash from the normalized key' do
result = subject.send(:normalize_key, 'HKLM\\SOFTWARE\\Microsoft\\')
expect(result).to eq('HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft')
expect(result).not_to end_with('\\')
end

it 'produces the same result as a key without trailing backslash' do
with_slash = subject.send(:normalize_key, 'HKLM\\SOFTWARE\\Microsoft\\')
without_slash = subject.send(:normalize_key, 'HKLM\\SOFTWARE\\Microsoft')
expect(with_slash).to eq(without_slash)
end
end

context 'with root-only keys' do
it 'returns the expanded root key without a trailing backslash' do
result = subject.send(:normalize_key, 'HKLM')
expect(result).to eq('HKEY_LOCAL_MACHINE')
expect(result).not_to end_with('\\')
end
end

context 'with already fully expanded root keys' do
it 'returns the key unchanged' do
expect(subject.send(:normalize_key, 'HKEY_LOCAL_MACHINE\\SOFTWARE')).to eq('HKEY_LOCAL_MACHINE\\SOFTWARE')
end
end

context 'with an unknown root key' do
it 'raises ArgumentError' do
expect { subject.send(:normalize_key, 'BOGUS\\Key') }.to raise_error(ArgumentError)
end
end

context 'idempotency' do
it 'returns the same result when called twice' do
key = 'HKLM\\SOFTWARE\\Microsoft\\'
first = subject.send(:normalize_key, key)
second = subject.send(:normalize_key, first)
expect(first).to eq(second)
end
end
end
end