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 # 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' # 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) def normalize_key(key)
keys = split_key(key) keys = split_key(key)
if (keys[0] =~ /HKLM|HKEY_LOCAL_MACHINE/) if (keys[0] =~ /HKLM|HKEY_LOCAL_MACHINE/)
@@ -700,7 +703,7 @@ protected
raise ArgumentError, "Cannot normalize unknown key: #{key}" raise ArgumentError, "Cannot normalize unknown key: #{key}"
end end
# print_status("Normalized #{key} to #{keys.join("\\")}") # print_status("Normalized #{key} to #{keys.join("\\")}")
return keys.compact.join("\\") return keys.compact.join("\\").chomp("\\")
end end
# #
@@ -134,7 +134,7 @@ class MetasploitModule < Msf::Exploit::Local
end end
def check 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') vprint_good('Powershell detected on system')
@@ -72,7 +72,7 @@ class MetasploitModule < Msf::Exploit::Local
end end
def check 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') vprint_good('Powershell detected on system')
@@ -110,7 +110,7 @@ class MetasploitModule < Msf::Exploit::Local
def check def check
# /tmp seems to persist on *some* Ubuntu WSL (wsl v1 it did, v2 it didnt) # /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') 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') vprint_good('Powershell detected on system')
@@ -118,7 +118,7 @@ class MetasploitModule < Msf::Post
end end
def ntds_location 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 end
def ntdsutil_method def ntdsutil_method
@@ -81,8 +81,8 @@ class MetasploitModule < Msf::Post
def get_registry def get_registry
print_status('Looking in registry for stored login passwords by Picasa ...') print_status('Looking in registry for stored login passwords by Picasa ...')
username = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa2\\Preferences\\', 'GaiaEmail') || '' username = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa2\\Preferences', 'GaiaEmail') || ''
password = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa2\\Preferences\\', 'GaiaPass') || '' password = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa2\\Preferences', 'GaiaPass') || ''
credentials = Rex::Text::Table.new( credentials = Rex::Text::Table.new(
'Header' => 'Picasa Credentials', 'Header' => 'Picasa Credentials',
@@ -109,8 +109,8 @@ class MetasploitModule < Msf::Post
end end
# For early versions of Picasa3 # For early versions of Picasa3
username = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa3\\Preferences\\', 'GaiaEmail') || '' username = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa3\\Preferences', 'GaiaEmail') || ''
password = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa3\\Preferences\\', 'GaiaPass') || '' password = registry_getvaldata('HKCU\\Software\\Google\\Picasa\\Picasa3\\Preferences', 'GaiaPass') || ''
if !username.empty? && !password.empty? if !username.empty? && !password.empty?
passbin = [password].pack('H*') passbin = [password].pack('H*')
@@ -378,14 +378,14 @@ class MetasploitModule < Msf::Post
def get_domain_reg def get_domain_reg
locations = [] locations = []
# Lots of redundancy but hey this is quick! # Lots of redundancy but hey this is quick!
locations << ['HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\', 'Domain'] 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 NT\\CurrentVersion\\Winlogon', 'DefaultDomainName']
locations << ['HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History\\', 'MachineDomain'] locations << ['HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History', 'MachineDomain']
domains = [] domains = []
# Pulls cached domains from registry # 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 if domain_cache
domain_cache.each { |ud| domains << ud } domain_cache.each { |ud| domains << ud }
end end
@@ -54,7 +54,7 @@ class MetasploitModule < Msf::Post
print_status("Looking at Key #{k}") print_status("Looking at Key #{k}")
begin begin
subkeys = registry_enumkeys("HKU\\#{k}\\Software\\DownloadManager\\Passwords\\") subkeys = registry_enumkeys("HKU\\#{k}\\Software\\DownloadManager\\Passwords")
if subkeys.nil? || subkeys.empty? if subkeys.nil? || subkeys.empty?
print_status('IDM not installed for this user.') print_status('IDM not installed for this user.')
@@ -52,13 +52,13 @@ class MetasploitModule < Msf::Post
next if hive['HKU'].nil? next if hive['HKU'].nil?
vprint_status("Looking at Key #{hive['HKU']}") 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? if subkeys.nil? || subkeys.empty?
print_status('IMVU not installed for this user.') print_status('IMVU not installed for this user.')
next next
end end
user = registry_getvaldata("#{hive['HKU']}\\Software\\IMVU\\username\\", '') user = registry_getvaldata("#{hive['HKU']}\\Software\\IMVU\\username", '')
hpass = registry_getvaldata("#{hive['HKU']}\\Software\\IMVU\\password\\", '') hpass = registry_getvaldata("#{hive['HKU']}\\Software\\IMVU\\password", '')
decpass = [ hpass.downcase.gsub(/'/, '').gsub(/\\?x([a-f0-9][a-f0-9])/, '\1') ].pack('H*') decpass = [ hpass.downcase.gsub(/'/, '').gsub(/\\?x([a-f0-9][a-f0-9])/, '\1') ].pack('H*')
print_good("User=#{user}, Password=#{decpass}") print_good("User=#{user}, Password=#{decpass}")
creds << [user, decpass] creds << [user, decpass]
@@ -48,15 +48,15 @@ class MetasploitModule < Msf::Post
next if k.include?('_Classes') next if k.include?('_Classes')
vprint_status("Looking at Key #{k}") vprint_status("Looking at Key #{k}")
subkeys = registry_enumkeys("HKU\\#{k}\\Software\\Nimbuzz\\") subkeys = registry_enumkeys("HKU\\#{k}\\Software\\Nimbuzz")
if subkeys.nil? || (subkeys == '') if subkeys.nil? || (subkeys == '')
print_status('Nimbuzz Instant Messenger not installed for this user.') print_status('Nimbuzz Instant Messenger not installed for this user.')
next next
end end
user = registry_getvaldata("HKU\\#{k}\\Software\\Nimbuzz\\PCClient\\Application\\", 'Username') || '' user = registry_getvaldata("HKU\\#{k}\\Software\\Nimbuzz\\PCClient\\Application", 'Username') || ''
hpass = registry_getvaldata("HKU\\#{k}\\Software\\Nimbuzz\\PCClient\\Application\\", 'Password') hpass = registry_getvaldata("HKU\\#{k}\\Software\\Nimbuzz\\PCClient\\Application", 'Password')
next if hpass.nil? || (hpass == '') next if hpass.nil? || (hpass == '')
+1 -1
View File
@@ -115,7 +115,7 @@ class MetasploitModule < Msf::Post
def outlook_installed? def outlook_installed?
key_base = 'HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles\\Outlook\\9375CFF0413111d3B88A00104B2A6676' 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 if installed.blank? || installed == 0
return false 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 # This won't work on windows 2000 since there is no sc.exe
print_status("Checking if Telnet is installed...") print_status("Checking if Telnet is installed...")
begin begin
registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\services\\TlntSvr\\","Start") registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\services\\TlntSvr","Start")
return true return true
rescue rescue
return false 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