summaryrefslogtreecommitdiffstats
path: root/sploit/payload/payload.py
diff options
context:
space:
mode:
Diffstat (limited to 'sploit/payload/payload.py')
-rw-r--r--sploit/payload/payload.py224
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