Class: Pwnlib::ELF::ELF

Inherits:
Object
  • Object
show all
Includes:
Logger
Defined in:
lib/pwnlib/elf/elf.rb

Overview

Main class for using Pwnlib::ELF module.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, checksec: true) ⇒ ELF

Instantiate an Pwnlib::ELF::ELF object.

Will show checksec information to stdout.

Examples:

ELF.new('/lib/x86_64-linux-gnu/libc.so.6')
# RELRO:    Partial RELRO
# Stack:    No canary found
# NX:       NX enabled
# PIE:      PIE enabled
#=> #<Pwnlib::ELF::ELF:0x00559bd670dcb8>

Parameters:

  • path (String)

    The path to the ELF file.

  • checksec (Boolean) (defaults to: true)

    The checksec information will be printed to stdout after ELF loaded. Pass checksec: false to disable this feature.



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/pwnlib/elf/elf.rb', line 45

def initialize(path, checksec: true)
  @path = File.realpath(path)
  @elf_file = ELFTools::ELFFile.new(File.open(path, 'rb'))
  load_got
  load_plt
  load_symbols
  @address = base_address
  @load_addr = @address
  @one_gadgets = nil
  show_info(@path) if checksec
end

Instance Attribute Details

#addressInteger

Returns Base address.

Returns:

  • (Integer)

    Base address.



26
27
28
# File 'lib/pwnlib/elf/elf.rb', line 26

def address
  @address
end

#gotOpenStruct (readonly)

Returns GOT symbols.

Returns:

  • (OpenStruct)

    GOT symbols.



17
18
19
# File 'lib/pwnlib/elf/elf.rb', line 17

def got
  @got
end

#pltOpenStruct (readonly)

Returns PLT symbols.

Returns:

  • (OpenStruct)

    PLT symbols.



20
21
22
# File 'lib/pwnlib/elf/elf.rb', line 20

def plt
  @plt
end

#symbolsOpenStruct (readonly)

Returns All symbols.

Returns:

  • (OpenStruct)

    All symbols.



23
24
25
# File 'lib/pwnlib/elf/elf.rb', line 23

def symbols
  @symbols
end

Instance Method Details

#canary?Boolean

Is this ELF file has canary?

Actually judged by if __stack_chk_fail in got symbols.

Returns:

  • (Boolean)

    Yes or not.



126
127
128
# File 'lib/pwnlib/elf/elf.rb', line 126

def canary?
  @got.respond_to?('__stack_chk_fail') || @symbols.respond_to?('__stack_chk_fail')
end

#checksecString

Return the protection information, wrapper with color codes.

Returns:

  • (String)

    The checksec information.



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/pwnlib/elf/elf.rb', line 83

def checksec
  [
    'RELRO:'.ljust(10) + {
      full: Rainbow('Full RELRO').green,
      partial: Rainbow('Partial RELRO').yellow,
      none: Rainbow('No RELRO').red
    }[relro],
    'Stack:'.ljust(10) + {
      true => Rainbow('Canary found').green,
      false => Rainbow('No canary found').red
    }[canary?],
    'NX:'.ljust(10) + {
      true => Rainbow('NX enabled').green,
      false => Rainbow('NX disabled').red
    }[nx?],
    'PIE:'.ljust(10) + {
      true => Rainbow('PIE enabled').green,
      false => Rainbow(format('No PIE (0x%x)', address)).red
    }[pie?]
  ].join("\n")
end

#inspectString

There’s too many objects inside, let pry not so verbose.

Returns:

  • (String)


146
147
148
# File 'lib/pwnlib/elf/elf.rb', line 146

def inspect
  "#<Pwnlib::ELF::ELF:#{::Pwnlib::Util::Fiddling.hex(__id__)}>"
end

#nx?Boolean

Is stack executable?

Returns:

  • (Boolean)

    Yes or not.



133
134
135
# File 'lib/pwnlib/elf/elf.rb', line 133

def nx?
  !@elf_file.segment_by_type(:gnu_stack).executable?
end

#one_gadgetsArray<Integer>

Returns one-gadgets of glibc.

Examples:

ELF::ELF.new('/lib/x86_64-linux-gnu/libc.so.6').one_gadgets[0]
#=> 324293 # 0x4f2c5
libc = ELF::ELF.new('/lib/x86_64-linux-gnu/libc.so.6')
libc.one_gadgets[1]
#=> 324386 # 0x4f322

libc.address = 0x7fff7fff0000
libc.one_gadgets[1]
#=> 140735341130530 # 0x7fff8003f322
libc = ELF::ELF.new('/lib/x86_64-linux-gnu/libc.so.6')
context.log_level = :debug
libc.one_gadgets[0]
# [DEBUG] 0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
# constraints:
#   rcx == NULL
#=> 324293

Returns:

  • (Array<Integer>)

    Returns array of one-gadgets, see examples.



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/pwnlib/elf/elf.rb', line 221

def one_gadgets
  return @one_gadgets if @one_gadgets

  gadgets = OneGadget.gadgets(file: @path, details: true, level: 1)
  @one_gadgets = gadgets.map { |g| g.offset + address }
  @one_gadgets.instance_variable_set(:@gadgets, gadgets)

  class << @one_gadgets
    def [](idx)
      super.tap { log.debug(@gadgets[idx].inspect) }
    end

    def first
      self[0]
    end

    def last
      self[-1]
    end

    include ::Pwnlib::Logger
  end

  @one_gadgets
end

#pie?Boolean

Is this ELF file a position-independent executable?

Returns:

  • (Boolean)

    Yes or not.



140
141
142
# File 'lib/pwnlib/elf/elf.rb', line 140

def pie?
  @elf_file.elf_type == 'DYN'
end

#relro:full, ...

The method used in relro.

Returns:

  • (:full, :partial, :none)


108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/pwnlib/elf/elf.rb', line 108

def relro
  return :none unless @elf_file.segment_by_type(:gnu_relro)
  return :full if dynamic_tag(:bind_now)

  flags = dynamic_tag(:flags)
  return :full if flags && (flags.value & ::ELFTools::Constants::DF_BIND_NOW) != 0

  flags1 = dynamic_tag(:flags_1)
  return :full if flags1 && (flags1.value & ::ELFTools::Constants::DF_1_NOW) != 0

  :partial
end

#search(needle) ⇒ Enumerator<Integer> Also known as: find

Yields the ELF’s virtual address space for the specified string or regexp. Returns an Enumerator if no block given.

Examples:

ELF.new('/bin/sh', checksec: false).find('ELF')
#=> #<Enumerator: ...>

ELF.new('/bin/sh', checksec: false).find(/E.F/).each { |i| puts i.hex }
# 0x1
# 0x11477
# 0x1c84f
# 0x1d5ee
#=> true

Parameters:

  • needle (String, Regexp)

    The specified string to search.

Returns:

  • (Enumerator<Integer>)

    An enumerator for offsets in ELF’s virtual address space.



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/pwnlib/elf/elf.rb', line 169

def search(needle)
  return enum_for(:search, needle) unless block_given?

  load_address_fixup = @address - @load_addr
  stream = @elf_file.stream
  @elf_file.each_segments do |seg|
    addr = seg.header.p_vaddr
    memsz = seg.header.p_memsz
    offset = seg.header.p_offset

    stream.pos = offset
    data = stream.read(memsz).ljust(seg.header.p_filesz, "\x00")

    offset = 0
    loop do
      offset = data.index(needle, offset)
      break if offset.nil?

      yield (addr + offset + load_address_fixup)
      offset += 1
    end
  end
  true
end