summaryrefslogtreecommitdiffstats
path: root/sploit/payload/payload.py
diff options
context:
space:
mode:
authorMalfurious <m@lfurio.us>2025-01-02 19:17:34 -0500
committerMalfurious <m@lfurio.us>2025-01-04 23:54:51 -0500
commit0f00627964a4b2e515108401fa2cfe94600ad648 (patch)
tree56da2ccaf393a1124220cc187a7225a4efcfbcba /sploit/payload/payload.py
parent640726aa11369d328c1cdfe00b4344b6a925729c (diff)
downloadnsploit-0f00627964a4b2e515108401fa2cfe94600ad648.tar.gz
nsploit-0f00627964a4b2e515108401fa2cfe94600ad648.zip
Rename sploit package to nsploit
Rename all affected files, references to file paths, and module imports within the code. Since this line of development represents a fork from the original sploit, a name change is seen as necessary to distinguish the projects, as well as allow them to be installed side by side. What does the "n" mean? Great question! You can think of it as meaning "new sploit" if you want, though that's not quite intended. The name is simply distinct and easy to pronounce. I had originally settled on "msploit" (something along the lines of "Malf's sploit"), but this name is too close to "metasploit" for me - and N is right next to it on the keyboard. Signed-off-by: Malfurious <m@lfurio.us>
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