pwnlib.shellcraft.i386
— Shellcode for Intel 80386¶
pwnlib.shellcraft.i386
¶
Shellcraft module containing generic Intel i386 shellcodes.
-
pwnlib.shellcraft.i386.
crash
()[source]¶ Crash.
Example
>>> run_assembly(shellcraft.crash()).poll(True) -11
-
pwnlib.shellcraft.i386.
epilog
(nargs=0)[source]¶ Function epilogue.
Parameters: nargs (int) – Number of arguments to pop off the stack.
-
pwnlib.shellcraft.i386.
function
(name, template_function, *registers)[source]¶ Converts a shellcraft template into a callable function.
Parameters: - template_sz (callable) – Rendered shellcode template. Any variable Arguments should be supplied as registers.
- name (str) – Name of the function.
- registers (list) – List of registers which should be filled from the stack.
>>> shellcode = '' >>> shellcode += shellcraft.function('write', shellcraft.i386.linux.write, ) >>> hello = shellcraft.i386.linux.echo("Hello!", 'eax') >>> hello_fn = shellcraft.i386.function(hello, 'eax').strip() >>> exit = shellcraft.i386.linux.exit('edi') >>> exit_fn = shellcraft.i386.function(exit, 'edi').strip() >>> shellcode = ''' ... push STDOUT_FILENO ... call hello ... push 33 ... call exit ... hello: ... %(hello_fn)s ... exit: ... %(exit_fn)s ... ''' % (locals()) >>> p = run_assembly(shellcode) >>> p.recvall() 'Hello!' >>> p.wait_for_close() >>> p.poll() 33
Notes
Can only be used on a shellcraft template which takes all of its arguments as registers. For example, the pushstr
-
pwnlib.shellcraft.i386.
getpc
(register='ecx')[source]¶ Retrieves the value of EIP, stores it in the desired register.
Parameters: return_value – Value to return
-
pwnlib.shellcraft.i386.
itoa
(v, buffer='esp', allocate_stack=True)[source]¶ Converts an integer into its string representation, and pushes it onto the stack.
Parameters: Example
>>> sc = shellcraft.i386.mov('eax', 0xdeadbeef) >>> sc += shellcraft.i386.itoa('eax') >>> sc += shellcraft.i386.linux.write(1, 'esp', 32) >>> run_assembly(sc).recvuntil('\x00') '3735928559\x00'
-
pwnlib.shellcraft.i386.
memcpy
(dest, src, n)[source]¶ Copies memory.
Parameters: - dest – Destination address
- src – Source address
- n – Number of bytes
-
pwnlib.shellcraft.i386.
mov
(dest, src, stack_allowed=True)[source]¶ Move src into dest without newlines and null bytes.
If the src is a register smaller than the dest, then it will be zero-extended to fit inside the larger register.
If the src is a register larger than the dest, then only some of the bits will be used.
If src is a string that is not a register, then it will locally set context.arch to ‘i386’ and use
pwnlib.constants.eval()
to evaluate the string. Note that this means that this shellcode can change behavior depending on the value of context.os.Parameters: Example
>>> print shellcraft.i386.mov('eax','ebx').rstrip() mov eax, ebx >>> print shellcraft.i386.mov('eax', 0).rstrip() xor eax, eax >>> print shellcraft.i386.mov('ax', 0).rstrip() xor ax, ax >>> print shellcraft.i386.mov('ax', 17).rstrip() xor ax, ax mov al, 0x11 >>> print shellcraft.i386.mov('edi', ord('\n')).rstrip() push 9 /* mov edi, '\n' */ pop edi inc edi >>> print shellcraft.i386.mov('al', 'ax').rstrip() /* moving ax into al, but this is a no-op */ >>> print shellcraft.i386.mov('al','ax').rstrip() /* moving ax into al, but this is a no-op */ >>> print shellcraft.i386.mov('esp', 'esp').rstrip() /* moving esp into esp, but this is a no-op */ >>> print shellcraft.i386.mov('ax', 'bl').rstrip() movzx ax, bl >>> print shellcraft.i386.mov('eax', 1).rstrip() push 1 pop eax >>> print shellcraft.i386.mov('eax', 1, stack_allowed=False).rstrip() xor eax, eax mov al, 1 >>> print shellcraft.i386.mov('eax', 0xdead00ff).rstrip() mov eax, -0xdead00ff neg eax >>> print shellcraft.i386.mov('eax', 0xc0).rstrip() xor eax, eax mov al, 0xc0 >>> print shellcraft.i386.mov('edi', 0xc0).rstrip() mov edi, -0xc0 neg edi >>> print shellcraft.i386.mov('eax', 0xc000).rstrip() xor eax, eax mov ah, 0xc000 >> 8 >>> print shellcraft.i386.mov('eax', 0xffc000).rstrip() mov eax, 0x1010101 xor eax, 0x1010101 ^ 0xffc000 >>> print shellcraft.i386.mov('edi', 0xc000).rstrip() mov edi, (-1) ^ 0xc000 not edi >>> print shellcraft.i386.mov('edi', 0xf500).rstrip() mov edi, 0x1010101 xor edi, 0x1010101 ^ 0xf500 >>> print shellcraft.i386.mov('eax', 0xc0c0).rstrip() xor eax, eax mov ax, 0xc0c0 >>> print shellcraft.i386.mov('eax', 'SYS_execve').rstrip() push SYS_execve /* 0xb */ pop eax >>> with context.local(os='freebsd'): ... print shellcraft.i386.mov('eax', 'SYS_execve').rstrip() push SYS_execve /* 0x3b */ pop eax >>> print shellcraft.i386.mov('eax', 'PROT_READ | PROT_WRITE | PROT_EXEC').rstrip() push (PROT_READ | PROT_WRITE | PROT_EXEC) /* 7 */ pop eax
-
pwnlib.shellcraft.i386.
push
(value)[source]¶ Pushes a value onto the stack without using null bytes or newline characters.
If src is a string, then we try to evaluate with context.arch = ‘i386’ using
pwnlib.constants.eval()
before determining how to push it. Note that this means that this shellcode can change behavior depending on the value of context.os.Parameters: value (int,str) – The value or register to push Example
>>> print pwnlib.shellcraft.i386.push(0).rstrip() /* push 0 */ push 1 dec byte ptr [esp] >>> print pwnlib.shellcraft.i386.push(1).rstrip() /* push 1 */ push 1 >>> print pwnlib.shellcraft.i386.push(256).rstrip() /* push 0x100 */ push 0x1010201 xor dword ptr [esp], 0x1010301 >>> print pwnlib.shellcraft.i386.push('SYS_execve').rstrip() /* push SYS_execve (0xb) */ push 0xb >>> print pwnlib.shellcraft.i386.push('SYS_sendfile').rstrip() /* push SYS_sendfile (0xbb) */ push 0x1010101 xor dword ptr [esp], 0x10101ba >>> with context.local(os = 'freebsd'): ... print pwnlib.shellcraft.i386.push('SYS_execve').rstrip() /* push SYS_execve (0x3b) */ push 0x3b
-
pwnlib.shellcraft.i386.
pushstr
(string, append_null=True)[source]¶ Pushes a string onto the stack without using null bytes or newline characters.
Example
>>> print shellcraft.i386.pushstr('').rstrip() /* push '\x00' */ push 1 dec byte ptr [esp] >>> print shellcraft.i386.pushstr('a').rstrip() /* push 'a\x00' */ push 0x61 >>> print shellcraft.i386.pushstr('aa').rstrip() /* push 'aa\x00' */ push 0x1010101 xor dword ptr [esp], 0x1016060 >>> print shellcraft.i386.pushstr('aaa').rstrip() /* push 'aaa\x00' */ push 0x1010101 xor dword ptr [esp], 0x1606060 >>> print shellcraft.i386.pushstr('aaaa').rstrip() /* push 'aaaa\x00' */ push 1 dec byte ptr [esp] push 0x61616161 >>> print shellcraft.i386.pushstr('aaaaa').rstrip() /* push 'aaaaa\x00' */ push 0x61 push 0x61616161 >>> print shellcraft.i386.pushstr('aaaa', append_null = False).rstrip() /* push 'aaaa' */ push 0x61616161 >>> print shellcraft.i386.pushstr('\xc3').rstrip() /* push '\xc3\x00' */ push 0x1010101 xor dword ptr [esp], 0x10101c2 >>> print shellcraft.i386.pushstr('\xc3', append_null = False).rstrip() /* push '\xc3' */ push -0x3d >>> with context.local(): ... context.arch = 'i386' ... print enhex(asm(shellcraft.pushstr("/bin/sh"))) 68010101018134242e726901682f62696e >>> with context.local(): ... context.arch = 'i386' ... print enhex(asm(shellcraft.pushstr(""))) 6a01fe0c24 >>> with context.local(): ... context.arch = 'i386' ... print enhex(asm(shellcraft.pushstr("\x00", False))) 6a01fe0c24
Parameters:
-
pwnlib.shellcraft.i386.
pushstr_array
(reg, array)[source]¶ Pushes an array/envp-style array of pointers onto the stack.
Parameters:
-
pwnlib.shellcraft.i386.
ret
(return_value=None)[source]¶ A single-byte RET instruction.
Parameters: return_value – Value to return
-
pwnlib.shellcraft.i386.
setregs
(reg_context, stack_allowed=True)[source]¶ Sets multiple registers, taking any register dependencies into account (i.e., given eax=1,ebx=eax, set ebx first).
Parameters: Example
>>> print shellcraft.setregs({'eax':1, 'ebx':'eax'}).rstrip() mov ebx, eax push 1 pop eax >>> print shellcraft.setregs({'eax':'ebx', 'ebx':'eax', 'ecx':'ebx'}).rstrip() mov ecx, ebx xchg eax, ebx
-
pwnlib.shellcraft.i386.
stackarg
(index, register)[source]¶ Loads a stack-based argument into a register.
Assumes that the ‘prolog’ code was used to save EBP.
Parameters:
-
pwnlib.shellcraft.i386.
stackhunter
(cookie = 0x7afceb58)[source]¶ Returns an an egghunter, which searches from esp and upwards for a cookie. However to save bytes, it only looks at a single 4-byte alignment. Use the function stackhunter_helper to generate a suitable cookie prefix for you.
The default cookie has been chosen, because it makes it possible to shave a single byte, but other cookies can be used too.
Example
>>> with context.local(): ... context.arch = 'i386' ... print enhex(asm(shellcraft.stackhunter())) 3d58ebfc7a75faffe4 >>> with context.local(): ... context.arch = 'i386' ... print enhex(asm(shellcraft.stackhunter(0xdeadbeef))) 583defbeadde75f8ffe4
-
pwnlib.shellcraft.i386.
strcpy
(dst, src)[source]¶ Copies a string
Example
>>> sc = 'jmp get_str\n' >>> sc += 'pop_str: pop eax\n' >>> sc += shellcraft.i386.strcpy('esp', 'eax') >>> sc += shellcraft.i386.linux.write(1, 'esp', 32) >>> sc += shellcraft.i386.linux.exit(0) >>> sc += 'get_str: call pop_str\n' >>> sc += '.asciz "Hello, world\\n"' >>> run_assembly(sc).recvline() 'Hello, world\n'
-
pwnlib.shellcraft.i386.
strlen
(string, reg='ecx')[source]¶ Calculate the length of the specified string.
Parameters: Example
>>> sc = 'jmp get_str\n' >>> sc += 'pop_str: pop eax\n' >>> sc += shellcraft.i386.strlen('eax') >>> sc += 'push ecx;' >>> sc += shellcraft.i386.linux.write(1, 'esp', 4) >>> sc += shellcraft.i386.linux.exit(0) >>> sc += 'get_str: call pop_str\n' >>> sc += '.asciz "Hello, world\\n"' >>> run_assembly(sc).unpack() == len('Hello, world\n') True
-
pwnlib.shellcraft.i386.
xor
(key, address, count)[source]¶ XORs data a constant value.
Parameters: - key (int,str) – XOR key either as a 4-byte integer, If a string, length must be a power of two, and not longer than 4 bytes. Alternately, may be a register.
- address (int) – Address of the data (e.g. 0xdead0000, ‘esp’)
- count (int) – Number of bytes to XOR, or a register containing the number of bytes to XOR.
Example
>>> sc = shellcraft.read(0, 'esp', 32) >>> sc += shellcraft.xor(0xdeadbeef, 'esp', 32) >>> sc += shellcraft.write(1, 'esp', 32) >>> io = run_assembly(sc) >>> io.send(cyclic(32)) >>> result = io.recvn(32) >>> expected = xor(cyclic(32), p32(0xdeadbeef)) >>> result == expected True
pwnlib.shellcraft.i386.linux
¶
Shellcraft module containing Intel i386 shellcodes for Linux.
-
pwnlib.shellcraft.i386.linux.
acceptloop_ipv4
(port)[source]¶ Parameters: port (int) – the listening port Waits for a connection. Leaves socket in EBP. ipv4 only
-
pwnlib.shellcraft.i386.linux.
cat
(filename, fd=1)[source]¶ Opens a file and writes its contents to the specified file descriptor.
Example
>>> f = tempfile.mktemp() >>> write(f, 'FLAG') >>> run_assembly(shellcraft.i386.linux.cat(f)).recvall() 'FLAG'
-
pwnlib.shellcraft.i386.linux.
connect
(host, port, network='ipv4')[source]¶ Connects to the host on the specified port. Leaves the connected socket in edx
Parameters: Examples
>>> l = listen(timeout=5) >>> assembly = shellcraft.i386.linux.connect('localhost', l.lport) >>> assembly += shellcraft.i386.pushstr('Hello') >>> assembly += shellcraft.i386.linux.write('edx', 'esp', 5) >>> p = run_assembly(assembly) >>> l.wait_for_connection().recv() 'Hello'
>>> l = listen(fam='ipv6', timeout=5) >>> assembly = shellcraft.i386.linux.connect('::1', l.lport, 'ipv6') >>> p = run_assembly(assembly) >>> assert l.wait_for_connection()
-
pwnlib.shellcraft.i386.linux.
connectstager
(host, port, network='ipv4')[source]¶ connect recvsize stager :param host, where to connect to: :param port, which port to connect to: :param network, ipv4 or ipv6? (default: ipv4)
-
pwnlib.shellcraft.i386.linux.
dir
(in_fd='ebp', size=2048, allocate_stack=True)[source]¶ Reads to the stack from a directory.
Parameters: You can optioanlly shave a few bytes not allocating the stack space.
The size read is left in eax.
-
pwnlib.shellcraft.i386.linux.
dupio
(sock='ebp')[source]¶ Args: [sock (imm/reg) = ebp] Duplicates sock to stdin, stdout and stderr
-
pwnlib.shellcraft.i386.linux.
dupsh
(sock='ebp')[source]¶ Args: [sock (imm/reg) = ebp] Duplicates sock to stdin, stdout and stderr and spawns a shell.
-
pwnlib.shellcraft.i386.linux.
echo
(string, sock='1')[source]¶ Writes a string to a file descriptor
Example
>>> run_assembly(shellcraft.echo('hello', 1)).recvall() 'hello'
-
pwnlib.shellcraft.i386.linux.
egghunter
(egg, start_address = 0)[source]¶ Searches memory for the byte sequence ‘egg’.
Return value is the address immediately following the match, stored in RDI.
Parameters:
-
pwnlib.shellcraft.i386.linux.
findpeer
(port=None)[source]¶ Args: port (defaults to any port) Finds a socket, which is connected to the specified port. Leaves socket in ESI.
-
pwnlib.shellcraft.i386.linux.
findpeersh
(port=None)[source]¶ Args: port (defaults to any) Finds an open socket which connects to a specified port, and then opens a dup2 shell on it.
-
pwnlib.shellcraft.i386.linux.
findpeerstager
(port=None)[source]¶ Findpeer recvsize stager :param port, the port given to findpeer: :type port, the port given to findpeer: defaults to any
-
pwnlib.shellcraft.i386.linux.
forkexit
()[source]¶ Attempts to fork. If the fork is successful, the parent exits.
-
pwnlib.shellcraft.i386.linux.
i386_to_amd64
()[source]¶ Returns code to switch from i386 to amd64 mode.
-
pwnlib.shellcraft.i386.linux.
killparent
()[source]¶ Kills its parent process until whatever the parent is (probably init) cannot be killed any longer.
-
pwnlib.shellcraft.i386.linux.
loader
(address)[source]¶ Loads a statically-linked ELF into memory and transfers control.
Parameters: address (int) – Address of the ELF as a register or integer.
-
pwnlib.shellcraft.i386.linux.
loader_append
(data=None)[source]¶ Loads a statically-linked ELF into memory and transfers control.
Similar to loader.asm but loads an appended ELF.
Parameters: data (str) – If a valid filename, the data is loaded from the named file. Otherwise, this is treated as raw ELF data to append. If None
, it is ignored.Example
>>> gcc = process(['gcc','-m32','-xc','-static','-Wl,-Ttext-segment=0x20000000','-']) >>> gcc.write(''' ... int main() { ... printf("Hello, %s!\\n", "i386"); ... } ... ''') >>> gcc.shutdown('send') >>> gcc.poll(True) 0 >>> sc = shellcraft.loader_append('a.out')
The following doctest is commented out because it doesn’t work on Travis for reasons I cannot diagnose. However, it should work just fine :-)
# >>> run_assembly(sc).recvline() == ‘Hello, i386!n’ # True
-
pwnlib.shellcraft.i386.linux.
mprotect_all
(clear_ebx=True, fix_null=False)[source]¶ Calls mprotect(page, 4096, PROT_READ | PROT_WRITE | PROT_EXEC) for every page.
It takes around 0.3 seconds on my box, but your milage may vary.
Parameters:
-
pwnlib.shellcraft.i386.linux.
pidmax
()[source]¶ Retrieves the highest numbered PID on the system, according to the sysctl kernel.pid_max.
-
pwnlib.shellcraft.i386.linux.
readfile
(path, dst='esi')[source]¶ Args: [path, dst (imm/reg) = esi ] Opens the specified file path and sends its content to the specified file descriptor.
-
pwnlib.shellcraft.i386.linux.
readn
(fd, buf, nbytes)[source]¶ Reads exactly nbytes bytes from file descriptor fd into the buffer buf.
Parameters: - fd (int) – fd
- buf (void) – buf
- nbytes (size_t) – nbytes
-
pwnlib.shellcraft.i386.linux.
recvsize
(sock, reg='ecx')[source]¶ Recives 4 bytes size field Useful in conjuncion with findpeer and stager :param sock, the socket to read the payload from.: :param reg, the place to put the size: :type reg, the place to put the size: default ecx
Leaves socket in ebx
-
pwnlib.shellcraft.i386.linux.
setregid
(gid='egid')[source]¶ Args: [gid (imm/reg) = egid] Sets the real and effective group id.
-
pwnlib.shellcraft.i386.linux.
setreuid
(uid='euid')[source]¶ Args: [uid (imm/reg) = euid] Sets the real and effective user id.
-
pwnlib.shellcraft.i386.linux.
sh
()[source]¶ Execute a different process.
>>> p = run_assembly(shellcraft.i386.linux.sh()) >>> p.sendline('echo Hello') >>> p.recv() 'Hello\n'
-
pwnlib.shellcraft.i386.linux.
socketcall
(socketcall, socket, sockaddr, sockaddr_len)[source]¶ Invokes a socket call (e.g. socket, send, recv, shutdown)
-
pwnlib.shellcraft.i386.linux.
stage
(fd=0, length=None)[source]¶ Migrates shellcode to a new buffer.
Parameters: Example
>>> p = run_assembly(shellcraft.stage()) >>> sc = asm(shellcraft.echo("Hello\n", constants.STDOUT_FILENO)) >>> p.pack(len(sc)) >>> p.send(sc) >>> p.recvline() 'Hello\n'
-
pwnlib.shellcraft.i386.linux.
stager
(sock, size, handle_error=False, tiny=False)[source]¶ Recives a fixed sized payload into a mmaped buffer Useful in conjuncion with findpeer. :param sock, the socket to read the payload from.: :param size, the size of the payload:
-
pwnlib.shellcraft.i386.linux.
syscall
(syscall=None, arg0=None, arg1=None, arg2=None, arg3=None, arg4=None, arg5=None)[source]¶ - Args: [syscall_number, *args]
- Does a syscall
Any of the arguments can be expressions to be evaluated by
pwnlib.constants.eval()
.Example
>>> print pwnlib.shellcraft.i386.linux.syscall('SYS_execve', 1, 'esp', 2, 0).rstrip() /* call execve(1, 'esp', 2, 0) */ push SYS_execve /* 0xb */ pop eax push 1 pop ebx mov ecx, esp push 2 pop edx xor esi, esi int 0x80 >>> print pwnlib.shellcraft.i386.linux.syscall('SYS_execve', 2, 1, 0, 20).rstrip() /* call execve(2, 1, 0, 0x14) */ push SYS_execve /* 0xb */ pop eax push 2 pop ebx push 1 pop ecx push 0x14 pop esi cdq /* edx=0 */ int 0x80 >>> print pwnlib.shellcraft.i386.linux.syscall().rstrip() /* call syscall() */ int 0x80 >>> print pwnlib.shellcraft.i386.linux.syscall('eax', 'ebx', 'ecx').rstrip() /* call syscall('eax', 'ebx', 'ecx') */ /* setregs noop */ int 0x80 >>> print pwnlib.shellcraft.i386.linux.syscall('ebp', None, None, 1).rstrip() /* call syscall('ebp', ?, ?, 1) */ mov eax, ebp push 1 pop edx int 0x80 >>> print pwnlib.shellcraft.i386.linux.syscall( ... 'SYS_mmap2', 0, 0x1000, ... 'PROT_READ | PROT_WRITE | PROT_EXEC', ... 'MAP_PRIVATE | MAP_ANONYMOUS', ... -1, 0).rstrip() /* call mmap2(0, 0x1000, 'PROT_READ | PROT_WRITE | PROT_EXEC', 'MAP_PRIVATE | MAP_ANONYMOUS', -1, 0) */ xor eax, eax mov al, 0xc0 xor ebp, ebp xor ebx, ebx xor ecx, ecx mov ch, 0x1000 >> 8 push -1 pop edi push (PROT_READ | PROT_WRITE | PROT_EXEC) /* 7 */ pop edx push (MAP_PRIVATE | MAP_ANONYMOUS) /* 0x22 */ pop esi int 0x80 >>> print pwnlib.shellcraft.open('/home/pwn/flag').rstrip() /* open(file='/home/pwn/flag', oflag=0, mode=0) */ /* push '/home/pwn/flag\x00' */ push 0x1010101 xor dword ptr [esp], 0x1016660 push 0x6c662f6e push 0x77702f65 push 0x6d6f682f mov ebx, esp xor ecx, ecx xor edx, edx /* call open() */ push SYS_open /* 5 */ pop eax int 0x80
pwnlib.shellcraft.i386.freebsd
¶
Shellcraft module containing Intel i386 shellcodes for FreeBSD.
-
pwnlib.shellcraft.i386.freebsd.
acceptloop_ipv4
(port)[source]¶ Args: port Waits for a connection. Leaves socket in EBP. ipv4 only