diff options
Diffstat (limited to 'sploit/payload/payload.py')
-rw-r--r-- | sploit/payload/payload.py | 224 |
1 files changed, 0 insertions, 224 deletions
diff --git a/sploit/payload/payload.py b/sploit/payload/payload.py deleted file mode 100644 index 2a9521f..0000000 --- a/sploit/payload/payload.py +++ /dev/null @@ -1,224 +0,0 @@ -from sploit.arch import itob -from sploit.payload.payload_entry import PayloadEntry -from sploit.types.indextbl import IndexTbl -from sploit.types.index_entry import IndexEntry -from sploit.types.lict import Lict - -_REPR_DATA_LEN = 64 - -class Payload(IndexTbl): - """ - Binary payload builder - - This class provides an API for fluently specifying structured payloads from - an assortment of input data. Payload "indices" are any bytes-like data, - which includes some supported IndexEntry types as well as nested Payloads. - - Payload is an IndexTbl based on a Lict and features two main use-cases or - syntaxes for interacting with data. - - The first method (the formal method) is through the use of normal index - access via attributes or subscripts. In this case, element keys are usually - given. When a new index is defined, it is inserted at the end of the - payload. Modifications to existing indices change the data in-place, and - this causes the content of the payload to shift around if the replaced data - is of a different length. - - The second method (the quick method) is through the use of Payload's __call__ - method. This is a general purpose "quick action" method that, among other - things, will insert data to the payload. If the Payload object is called - with 1 or more arguments, the values of these arguments are appended to the - payload in the order given. There is no way to specify keys using this - option, so the data simply occupies unkeyed elements in the underlying Lict. - - In either case, the data inserted must be bytes-like. In some common cases, - the data will be coerced into bytes. See the method __prep_insertion for - details on how this is handled. See the PayloadEntry module for some - additional features. - - When retrieving indices from the payload, instead of the element's value, - either the element offset or (for IndexEntries) the value based at that - offset is returned to you. If the payload has a non-zero base, this is - interpreted as the element's address in memory. This is useful for any - exploit that requires pointers to other crafted data. - - The binary output of a payload is simply the binary output of each of its - elements, concatenated together - there are no gaps. If you need to space - or separate two elements, you need to insert padding bytes between them. - The element binary content is either the object itself (for bytes elements), - the output from `payload_bytes()` (for PayloadEntries), or the output from - `bytes(obj)` for everything else. - - The following is a simple example using the Payload module to perform a - hypothetical stack buffer overrun "ret2win" with both of the build syntaxes: - - # 100 bytes from the start of the buffer to the saved frame pointer - # call (return into) the function "pwned", given by an ELF Symtbl - # 3 arguments, which are given on the stack - - # formal method - p = Payload() - p.smash = padlen(100) - p.fp = placeholder() - p.ret = elf.sym.pwned - p.ret2 = placeholder() - p.arg1 = 0 - p.arg2 = 1 - p.arg3 = 2 - io.write(bytes(p)) - - # quick method - p = Payload()(padlen(100), placeholder()) - p(elf.sym.pwned, placeholder(), 0, 1, 2) - io.write(p()) - """ - - def __init__(self, base=0, entries=None): - """Construct new Payload with optional base and content.""" - super().__init__(base) - if not isinstance(entries, Lict): - entries = Lict(entries) - object.__setattr__(self, "__entries__", entries) - - def __repr__(self): - """Return human-readable Payload.""" - FMT = "\n{:<20} {:<20} {:<20}" - s = f"{len(self.__entries__)} items, {len(self)} bytes @ {hex(self)}" - memo = {} - - if len(self.__entries__) > 0: - s += FMT.format("ADDRESS", "SYMBOL", "DATA") - - for i, value in enumerate(self.__entries__): - key = self.__entries__.idx2key(i) - key = "(unkeyed)" if key is None else str(key) - key = f"[{key}]" if isinstance(value, IndexEntry) else key - - addr = self.__addrof(i, memo) - data = str(self.__bytesof(i, memo)) - if len(data) > _REPR_DATA_LEN: - data = data[:_REPR_DATA_LEN] + " ..." - - s += FMT.format(hex(addr), key, data) - - return s - - def __bytes__(self): - """Return calculated payload bytes.""" - memo = {} - x = [ self.__bytesof(i, memo) for i in range(len(self.__entries__)) ] - return b"".join(x) - - def __call__(self, *args): - """ - Payload quick-action call operator. - - If called with arguments, append these values to the payload in the - order given. The payload (self) is returned for easily chaining calls. - - If called without arguments, return the rendered payload content as if - `bytes(payload)` was called. - """ - if len(args) == 0: - return bytes(self) - - for value in args: - value = self.__prep_insertion(value, self.end()) - self.__entries__.append(value) - - return self - - def end(self): - """Return the offset or address of the end of the payload.""" - return self.base + len(self) - - # IndexTbl abstract methods - - def __copy__(self): - """Return copy of object with shared data entries.""" - return Payload(self.base, self.__entries__) - - def __iter__(self): - """Iterate over data entries.""" - return iter(self.__entries__) - - def __len__(self): - """Return the size of the payload content in bytes.""" - memo = {} - x = [ self.__lenof(i, memo) for i in range(len(self.__entries__)) ] - return sum(x) - - def __getindex__(self, index): - """Return payload index value or address.""" - value, _ = self.__valueof(index, {}) - return value - - def __setindex__(self, index, value): - """Set payload index value.""" - try: - addr = self.__addrof(index, {}) - except KeyError: - addr = self.end() - value = self.__prep_insertion(value, addr) - self.__entries__[index] = value - - def __delindex__(self, index): - """Delete payload index.""" - del self.__entries__[index] - - # Payload helpers - - def __valueof(self, index, memo): - """Return a tuple (addr of value, literal value) for index.""" - value = self.__entries__[index] - addr = self.__addrof(index, memo) - if isinstance(value, IndexEntry): - value @= addr - return value, value - return addr, value - - def __addrof(self, index, memo): - """Return address (base + offset) for index.""" - index = self.__entries__.key2idx(index) - try: - return memo[index] - except KeyError: - sizes = [ self.__lenof(i, memo) for i in range(index) ] - addr = self.base + sum(sizes) - memo[index] = addr - return addr - - def __lenof(self, index, memo): - """Return element length for index.""" - _, value = self.__valueof(index, memo) - if isinstance(value, PayloadEntry): - return value.payload_len(self) - return len(value) - - def __bytesof(self, index, memo): - """Return byte output for index.""" - _, value = self.__valueof(index, memo) - if isinstance(value, PayloadEntry): - return value.payload_bytes(self) - return bytes(value) - - def __prep_insertion(self, value, addr): - """Initialize or type coerce input value for payload insert.""" - if isinstance(value, PayloadEntry): - value @= addr - value.payload_insert(self) - return value - - if type(value) is str: - value = value.encode() + b"\x00" - elif type(value) is int: - value = itob(value) - - try: - # Confirm value supports our required operations - len(value) - bytes(value) - except TypeError as ex: - raise TypeError(f"Payload: Bad type {type(value)} given") from ex - - return value |