Class: Msf::Exe::ElfInjector

Inherits:
Object
  • Object
show all
Defined in:
lib/msf/core/exe/elf_injector.rb,
lib/msf/core/exe/elf_injector/x64.rb,
lib/msf/core/exe/elf_injector/x86.rb,
lib/msf/core/exe/elf_injector/a_arch64.rb

Overview

Injects a forked payload into an ELF executable while preserving its original entry point.

Code-cave injection extends the file and memory sizes of an executable PT_LOAD into zero-filled, unallocated padding. The existing segment becomes writable because injected payloads may need writable memory. If no suitable cave exists, a PT_NULL or an unprotected PT_NOTE is replaced by a new RWX PT_LOAD. Segment and section handling follows the System V ABI program-loading rules: https://refspecs.linuxfoundation.org/elf/gabi4+/ch5.pheader.html

Defined Under Namespace

Classes: AArch64, X64, X86

Constant Summary collapse

ET_EXEC =
ELFTools::Constants::ET::ET_EXEC
ET_DYN =
ELFTools::Constants::ET::ET_DYN
PT_NULL =
ELFTools::Constants::PT::PT_NULL
PT_LOAD =
ELFTools::Constants::PT::PT_LOAD
PT_NOTE =
ELFTools::Constants::PT::PT_NOTE
PT_GNU_PROPERTY =
ELFTools::Constants::PT::PT_GNU_PROPERTY
SHT_NOBITS =
ELFTools::Constants::SHT::SHT_NOBITS
PF_X =
ELFTools::Constants::PF::PF_X
PF_W =
ELFTools::Constants::PF::PF_W
PF_R =
ELFTools::Constants::PF::PF_R
FINGERPRINT_BYTES =
2080
MAX_ALIGNMENT =
0x200000
MACHINE_ARCHITECTURES =
{
  [32, ELFTools::Constants::EM::EM_386] => :x86,
  [64, ELFTools::Constants::EM::EM_X86_64] => :x64,
  [64, ELFTools::Constants::EM::EM_AARCH64] => :aarch64
}.freeze
EXPECTED_PROGRAM_HEADER_SIZES =
{
  32 => 32,
  64 => 56
}.freeze
EXPECTED_SECTION_HEADER_SIZES =
{
  32 => 40,
  64 => 64
}.freeze
EXPECTED_HEADER_SIZES =
{
  32 => 52,
  64 => 64
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(template:, payload: ''.b) ⇒ ElfInjector

Returns a new instance of ElfInjector.

Parameters:

  • template (String) —

    Contents of the ELF executable to modify.

  • payload (String) (defaults to: ''.b) —

    Position-independent Linux shellcode to inject.



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/msf/core/exe/elf_injector.rb', line 61

def initialize(template:, payload: ''.b)
  raise ArgumentError, 'template must be a String' unless template.is_a?(String)
  raise ArgumentError, 'payload must be a String' unless payload.is_a?(String)

  @template = template.b
  @payload = payload.b
  parse_header
  parse_program_headers
  parse_section_headers
rescue ELFTools::ELFError => e
  raise ArgumentError, e.message
end

Instance Attribute Details

#technique ⇒ Symbol? (readonly)

Returns Injection technique used by the last call to generate.

Returns:

  • (Symbol, nil) —

    Injection technique used by the last call to generate.



57
58
59
# File 'lib/msf/core/exe/elf_injector.rb', line 57

def technique
  @technique
end

Instance Method Details

#architecture ⇒ Symbol

Returns The ELF architecture.

Returns:

  • (Symbol) —

    The ELF architecture.



75
76
77
# File 'lib/msf/core/exe/elf_injector.rb', line 75

def architecture
  MACHINE_ARCHITECTURES.fetch([@bits, @machine])
end

#fingerprint ⇒ String

Returns SHA-1 fingerprint of the first 2080 bytes of the .text section, or of a canonicalized executable prefix for sectionless ELFs.

Returns:

  • (String) —

    SHA-1 fingerprint of the first 2080 bytes of the .text section, or of a canonicalized executable prefix for sectionless ELFs.



85
86
87
# File 'lib/msf/core/exe/elf_injector.rb', line 85

def fingerprint
  @fingerprint ||= Digest::SHA1.hexdigest(fingerprint_data).b
end

#generate ⇒ String

Returns A modified ELF that forks the payload and resumes the original entry point.

Returns:

  • (String) —

    A modified ELF that forks the payload and resumes the original entry point.

Raises:

  • (ArgumentError)


90
91
92
93
94
95
96
97
98
# File 'lib/msf/core/exe/elf_injector.rb', line 90

def generate
  raise ArgumentError, 'ELF is already injected' if injected?
  raise ArgumentError, 'payload must not be empty' if @payload.empty?

  code_cave = find_code_cave
  return inject_code_cave(code_cave) if code_cave

  inject_new_segment
end

#injected? ⇒ Boolean

Returns Whether this injector's marker is present.

Returns:

  • (Boolean) —

    Whether this injector's marker is present.



80
81
82
# File 'lib/msf/core/exe/elf_injector.rb', line 80

def injected?
  @template.include?(fingerprint)
end