Class: OneGadget::Fetcher::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/one_gadget/fetchers/base.rb

Overview

Define common methods for gadget fetchers.

Direct Known Subclasses

AArch64, X86

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file) ⇒ Base

Instantiate a fetcher object.

Parameters:

  • file (String)

    Absolute path to the target libc.



16
17
18
19
20
21
# File 'lib/one_gadget/fetchers/base.rb', line 16

def initialize(file)
  @file = file
  arch = self.class.name.split('::').last.downcase.to_sym
  @objdump = Objdump.new(file, arch)
  @objdump.extra_options = objdump_options
end

Instance Attribute Details

#fileString (readonly)

The absolute path to glibc.

Returns:

  • (String)

    The filename.



12
13
14
# File 'lib/one_gadget/fetchers/base.rb', line 12

def file
  @file
end

Instance Method Details

#candidates {|cand| ... } ⇒ Array<String>

Fetch candidates that end with call exec*.

Provide a block to filter gadget candidates.

Yield Parameters:

  • cand (String)

    Is this candidate valid?

Yield Returns:

  • (Boolean)

    True for valid.

Returns:

  • (Array<String>)

    Each String returned is multi-lines of assembly code.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/one_gadget/fetchers/base.rb', line 51

def candidates(&)
  call_regexp = "#{call_str}.*<(exec[^+]*|posix_spawn[^+]*)>$"
  cands = []
  `#{@objdump.command}|grep -E '#{call_regexp}' -B 30`.split('--').each do |cand|
    lines = cand.lines.map(&:strip).reject(&:empty?)
    # split with call_regexp
    loop do
      idx = lines.index { |l| l =~ /#{call_regexp}/ }
      break if idx.nil?

      cands << lines.shift(idx + 1).join("\n")
    end
  end
  # remove all jmps
  cands = slice_prefix(cands, &method(:branch?))
  cands.select!(&) if block_given?
  cands
end

#findArray<OneGadget::Gadget::Gadget>

Do find gadgets in glibc.

Returns:



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/one_gadget/fetchers/base.rb', line 25

def find
  candidates.map do |cand|
    lines = cand.lines
    # use processor to find which can lead to a valid one-gadget call.
    gadgets = []
    (lines.size - 2).downto(0) do |i|
      processor = emulate(lines[i..])
      options = resolve(processor)
      next if options.nil? # impossible to be a gadget

      offset = offset_of(lines[i])
      gadgets << OneGadget::Gadget::Gadget.new(offset, **options)
    end
    gadgets
  end.flatten
end