summaryrefslogtreecommitdiff
path: root/hypodermic
diff options
context:
space:
mode:
authorjakob <jakob@memeware.net>2017-09-10 14:12:54 -0400
committerjakob <jakob@memeware.net>2017-09-10 14:12:54 -0400
commitd801868006f94acc6e3313332c55331710171172 (patch)
tree9748047178f5503b198d52d07db75ded2e95c73c /hypodermic
parent81e47a4dba4a44624ec56708c1655206ae19cbfc (diff)
Initial invocation of _dl_open in the RTLD
Diffstat (limited to 'hypodermic')
-rw-r--r--hypodermic/main.py4
-rw-r--r--hypodermic/process.py74
-rw-r--r--hypodermic/shellcode.py44
3 files changed, 118 insertions, 4 deletions
diff --git a/hypodermic/main.py b/hypodermic/main.py
index cb17d3b..3cbb047 100644
--- a/hypodermic/main.py
+++ b/hypodermic/main.py
@@ -108,8 +108,8 @@ def main():
if args.create:
alert("Creating process at path '{}'...".format(args.create))
p = Process(path=args.create)
- p.continue_until_haulted()
else:
alert("Attaching to process with pid {}...".format(args.attach))
p = Process(pid=args.attach)
- p.continue_until_haulted()
+ print(p.dlopen("/usr/lib/libyggdrasil.so"))
+ p.continue_until_haulted()
diff --git a/hypodermic/process.py b/hypodermic/process.py
index e26978b..35b8c1d 100644
--- a/hypodermic/process.py
+++ b/hypodermic/process.py
@@ -18,11 +18,16 @@
"""ctypes wrapper for ptrace."""
import ctypes
-import os.path
+import os
import re
+from elftools.elf.elffile import ELFFile
+from elftools.elf.sections import SymbolTableSection
+
from hypodermic.memory import Region, maps
-from hypodermic.shellcode import assemble, open_shellcode
+from hypodermic.shellcode import (assemble, close_shellcode, dlopen_shellcode,
+ mmap_shellcode, munmap_shellcode,
+ open_shellcode)
_AMD64_INDICES = {
"r15": 0,
@@ -436,6 +441,35 @@ class Process(object):
else:
self.run_code(munmap_shellcode(addr, size, arch="i386"))
+ def dlopen(self, path: str) -> int:
+ """Maps a shared object into the process address space.
+
+ Args:
+ path (str): The path of the shared object to inject.
+
+ Raises:
+ OSError: If the process does not have a usable RTLD.
+
+ Returns:
+ The address at which the library was loaded.
+ """
+ if not self.rtld:
+ raise OSError("Process does not have a usable RTLD")
+
+ if self.arch == "x64":
+ old_rax = self.get_register("rax")
+ self.run_code(dlopen_shellcode(self.rtld_dl_open_addr, path),
+ preserve=["rax"])
+ addr = self.get_register("rax")
+ self.set_register("rax", old_rax)
+ else:
+ old_eax = self.get_register("eax")
+ self.run_code(dlopen_shellcode(self.rtld_dl_open_addr, path,
+ arch="i386"), preserve=["eax"])
+ addr = self.get_register("eax")
+ self.set_register("eax", old_eax)
+ return addr
+
def page_start(self, addr: int) -> int:
return addr & ~(self.page_size - 1)
@@ -467,6 +501,32 @@ 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.
@@ -475,6 +535,16 @@ class Process(object):
"""
return maps(self.pid)
+ # TODO: Return something more detailed than the list of open fds.
+ @property
+ def fds(self) -> list:
+ """Obtain currently open file descriptors for the process.
+
+ Returns:
+ A list of integer file descriptors.
+ """
+ return [int(fd) for fd in os.listdir("/proc/{}/fd/".format(self.pid))]
+
@property
def rtld(self) -> Region:
"""Obtain the base region of memory for the process' RTLD, if it
diff --git a/hypodermic/shellcode.py b/hypodermic/shellcode.py
index ceaf7a7..114a4bc 100644
--- a/hypodermic/shellcode.py
+++ b/hypodermic/shellcode.py
@@ -162,3 +162,47 @@ def munmap_shellcode(addr=0, size=0, arch="amd64"):
" movl ${}, %ecx;" \
" int $0x80;".format(addr, size)
return assemble(asm, arch)
+
+
+# FIXME: Relative addressing is untested in i386.
+def dlopen_shellcode(addr: int, path: str, arch="amd64"):
+ """Generates shellcode to invoke _dl_open in the RTLD.
+
+ Args:
+ addr (int): The absolute address of _dl_open.
+ path (str): The path of the library to open.
+
+ Returns:
+ The assembled shellcode, as a `bytes` object.
+ """
+ if arch == "amd64":
+ asm = " jmp __path_end;" \
+ "__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)
+ 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)
+ return assemble(asm, arch)