summaryrefslogtreecommitdiff
path: root/hypodermic
diff options
context:
space:
mode:
Diffstat (limited to 'hypodermic')
-rw-r--r--hypodermic/process.py85
-rw-r--r--hypodermic/shellcode.py40
2 files changed, 68 insertions, 57 deletions
diff --git a/hypodermic/process.py b/hypodermic/process.py
index 35b8c1d..4740062 100644
--- a/hypodermic/process.py
+++ b/hypodermic/process.py
@@ -456,20 +456,71 @@ class Process(object):
if not self.rtld:
raise OSError("Process does not have a usable RTLD")
+ self.path_caller_check()
if self.arch == "x64":
+ ret = self.get_register("rip")
old_rax = self.get_register("rax")
- self.run_code(dlopen_shellcode(self.rtld_dl_open_addr, path),
- preserve=["rax"])
+ shellcode = dlopen_shellcode(self.rtld_dlsym("_dl_open"), ret, path)
+ self.run_code(shellcode, preserve=["rax"])
addr = self.get_register("rax")
self.set_register("rax", old_rax)
else:
+ ret = self.get_register("eip")
old_eax = self.get_register("eax")
- self.run_code(dlopen_shellcode(self.rtld_dl_open_addr, path,
- arch="i386"), preserve=["eax"])
+ shellcode = dlopen_shellcode(self.rtld_dlsym("_dl_open"), ret, path,
+ arch="i386")
+ self.run_code(shellcode, preserve=["eax"])
addr = self.get_register("eax")
self.set_register("eax", old_eax)
return addr
+ def patch_caller_check(self):
+ """Patches out a caller check security measure in the RTLD.
+
+ Note:
+ This is requried before making any invocations to `dlopen`.
+
+ Raises:
+ OSError: If the process either has no RTLD, or the caller
+ check cannot be found.
+ """
+ if not self.rtld:
+ raise OSError("Process does not have a usable RTLD")
+
+ if self.arch == "x64":
+ caller_check = self.rtld_dlsym("_dl_check_caller")
+ shellcode = assemble("movq $0x00, %rax; ret;")
+ self.write_bytes(caller_check, shellcode)
+ else:
+ caller_check = self.rtld_dlsym("_dl_check_caller")
+ shellcode = assemble("movl $0x00, %eax; ret;")
+ self.write_bytes(caller_check, shellcode)
+
+ def rtld_dlsym(self, sym: str) -> int:
+ """Obtain the absolute address of an RTLD symbol in main memory.
+
+ Raises:
+ OSError: If either the process has no instance of the RTLD,
+ or the RTLD lacks sufficient symbols.
+
+ Returns:
+ An integer containing the address.
+ """
+ if self.rtld is None:
+ raise OSError("Process has no RTLD instance")
+
+ with open(self.rtld.path, "rb") as rtld:
+ elf = ELFFile(rtld)
+ symtab = elf.get_section_by_name(".symtab")
+
+ if not isinstance(symtab, SymbolTableSection):
+ raise OSError("RTLD has no usable symbol table")
+
+ res = symtab.get_symbol_by_name(sym)
+ if len(res) < 1:
+ raise OSError("RTLD has no {} symbol".format(sym))
+ return self.rtld.start + res[0].entry.st_value
+
def page_start(self, addr: int) -> int:
return addr & ~(self.page_size - 1)
@@ -501,32 +552,6 @@ class Process(object):
return "x64" if self._isamd64 else "x86"
@property
- def rtld_dl_open_addr(self) -> int:
- """Obtain the absolute address of _dl_open in main memory.
-
- Raises:
- OSError: If either the process has no instance of the RTLD,
- or the RTLD lacks sufficient symbols.
-
- Returns:
- An integer containing the address.
- """
- if self.rtld is None:
- raise OSError("Process has no RTLD instance")
-
- with open(self.rtld.path, "rb") as rtld:
- elf = ELFFile(rtld)
- symtab = elf.get_section_by_name(".symtab")
-
- if not isinstance(symtab, SymbolTableSection):
- raise OSError("RTLD has no usable symbol table")
-
- res = symtab.get_symbol_by_name("_dl_open")
- if len(res) < 1:
- raise OSError("RTLD has no _dl_open symbol")
- return self.rtld.start + res[0].entry.st_value
-
- @property
def maps(self) -> list:
"""Obtain the process' memory map.
diff --git a/hypodermic/shellcode.py b/hypodermic/shellcode.py
index 114a4bc..38aa841 100644
--- a/hypodermic/shellcode.py
+++ b/hypodermic/shellcode.py
@@ -164,12 +164,12 @@ def munmap_shellcode(addr=0, size=0, arch="amd64"):
return assemble(asm, arch)
-# FIXME: Relative addressing is untested in i386.
-def dlopen_shellcode(addr: int, path: str, arch="amd64"):
+# TODO: i386 not implemented.
+def dlopen_shellcode(dlopen: int, ret: int, path: str, arch="amd64"):
"""Generates shellcode to invoke _dl_open in the RTLD.
Args:
- addr (int): The absolute address of _dl_open.
+ dlopen (int): The absolute address of _dl_open.
path (str): The path of the library to open.
Returns:
@@ -180,29 +180,15 @@ def dlopen_shellcode(addr: int, path: str, arch="amd64"):
"__path:" \
" .asciz \"{}\";" \
"__path_end:" \
- " leaq (%rip), %rdi;" \
- " subq $. - __path, %rdi;" \
- " movq $0x80000101, %rsi;" \
- " movq $0x00, %rdx;" \
- " movq $0x00, %rcx;" \
- " movq $0x00, %r8;" \
- " movq $0x00, %r9;" \
- " pushq $0x00;" \
- " callq ${};".format(path, addr)
+ " leaq (%rip), %rdi;" \
+ " subq $. - __path, %rdi;" \
+ " movq $0x80000101, %rsi;" \
+ " movq ${}, %rdx;" \
+ " movq $0xfffffffffffffffe, %rcx;" \
+ " movq $0x00, %r8;" \
+ " movq $0x00, %r9;" \
+ " movq $0x00, %r10;" \
+ " callq ${};".format(path, ret, dlopen)
else:
- asm = " jmp __path_end;" \
- "__path:" \
- " .asciz \"{}\";" \
- "__path_end:" \
- " call $. + 5;" \
- " popl %ebx;" \
- " subl $. - 4 - __path, %ebx;" \
- " pushl %ebx;" \
- " pushl $0x80000101;" \
- " pushl $0x00;" \
- " pushl $0x00;" \
- " pushl $0x00;" \
- " pushl $0x00;" \
- " pushl $0x00;" \
- " calll ${};".format(path, addr)
+ asm = ""
return assemble(asm, arch)