Fix trailing backslash in shell registry operations

This commit is contained in:
EclipseAditya
2026-02-21 06:13:23 +00:00
parent c249939bcd
commit 320effe9a1
13 changed files with 116 additions and 22 deletions
+4 -1
View File
@@ -680,6 +680,9 @@ protected
# 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/)
@@ -700,7 +703,7 @@ protected
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
#
@@ -134,7 +134,7 @@ class MetasploitModule < Msf::Exploit::Local
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')
@@ -72,7 +72,7 @@ class MetasploitModule < Msf::Exploit::Local
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')
@@ -110,7 +110,7 @@ class MetasploitModule < Msf::Exploit::Local
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')
@@ -118,7 +118,7 @@ class MetasploitModule < Msf::Post
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
@@ -81,8 +81,8 @@ class MetasploitModule < Msf::Post
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',
@@ -109,8 +109,8 @@ class MetasploitModule < Msf::Post
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*')
@@ -378,14 +378,14 @@ class MetasploitModule < Msf::Post
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
@@ -54,7 +54,7 @@ class MetasploitModule < Msf::Post
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.')
@@ -52,13 +52,13 @@ class MetasploitModule < Msf::Post
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]
@@ -48,15 +48,15 @@ class MetasploitModule < Msf::Post
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 == '')
+1 -1
View File
@@ -115,7 +115,7 @@ class MetasploitModule < Msf::Post
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
+1 -1
View File
@@ -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
@@ -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