From 5e07a6fef39ac10d67aa42cca5ae58186a7e1516 Mon Sep 17 00:00:00 2001 From: Malfurious Date: Sat, 4 Sep 2021 21:04:00 -0400 Subject: sploit: Add payload builder module class Payload is a tool for constructing stack-smash payloads and ROP chains. Its design is intended to abstract away some of the more tedious details of crafting a payload. Payload utilizes mem.Symtbl internally to optionally manage a collection of named offsets into its own buffer (these are usually in reference to entities appended to the payload via its main API). Alternatively, the API calls to append any entity will return the address of that entity as well. Returned (and looked-up) addresses are relative to the beginning of the payload by default. However, when the payload is constructed with a known base address value, these become absolute. This is useful for reusing addresses later in the payload body. class Placeholder is designed to be functionally compatible with bytearrays and bytestrings. When constructed, they take the value of 'zero', according to the current arch config. This facility enables some API's to detect whether a dummy value was passed as a required argument when said argument _may_ be unnecessary in niche situations. Signed-off-by: Malfurious Signed-off-by: dusoleil --- sploit/__init__.py | 4 ++-- sploit/payload.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 sploit/payload.py diff --git a/sploit/__init__.py b/sploit/__init__.py index 5082cfa..7180910 100644 --- a/sploit/__init__.py +++ b/sploit/__init__.py @@ -1,2 +1,2 @@ -__all__ = ["log","comm","until","arch","mem"] -from sploit import log, comm, until, arch, mem +__all__ = ["log","comm","until","arch","mem","payload"] +from sploit import log, comm, until, arch, mem, payload diff --git a/sploit/payload.py b/sploit/payload.py new file mode 100644 index 0000000..49e0c04 --- /dev/null +++ b/sploit/payload.py @@ -0,0 +1,64 @@ +from sploit.arch import arch, itob +from sploit.mem import Symtbl + +# Users can set this to the (absolute) address of a 'ret' ROP gadget. Some +# features may require it. +RETGADGET : int = None + +class Placeholder(bytearray): + def __init__(self, text='_unnamed_'): + self += bytearray(itob(0)) + self.text = text + +class Payload: + def __init__(self, size=0, base=0, **kwargs): + self.payload = b'' + self.size = size + self.alignstart = None + self.tab = Symtbl(base=base, **kwargs) + + def __len__(self): + return len(self.payload) + + def __getattr__(self, sym): + return getattr(self.tab, sym) + + def data(self, x, sym='_'): + off = len(self) + self.payload += x + setattr(self.tab, sym, off) + return getattr(self.tab, sym) + + def value(self, x, sym='_', signed=False): + return self.data(itob(x, signed=signed), sym=sym) + + def ret(self, x, sym='_'): + self.align() + return self.value(x, sym=sym) + + def stuff(self, x, size, sym='_', *, explain=''): + if size >= 0: + if (size := size / len(x)) == int(size): + if size == 0 or not isinstance(x, Placeholder): + return self.data(x * int(size), sym=sym) + + raise Exception(explain+"Can not stuff payload: " + f"Placeholder for {x.text} detected") + raise Exception(explain+"Can not stuff payload: " + "Element does not divide the space evenly") + raise Exception(explain+"Can not stuff payload: " + "Available space is negative") + + def pad(self, x=None, sym='_'): + size = self.size - len(self) + return self.stuff((x or arch.nopcode), size, sym=sym, + explain='Error padding payload: ') + + def align(self, x=None, sym='_'): + if self.alignstart is None: + self.alignstart = len(self) + + retgad = (itob(RETGADGET) if RETGADGET else Placeholder('ret gadget')) + size = (self.alignstart - len(self)) % arch.alignment + return self.stuff((x or retgad), size, sym=sym, + explain='Error aligning payload: ') -- cgit v1.2.3