pwnlib.shellcraft.thumb — Shellcode for Thumb Mode
pwnlib.shellcraft.thumb
Shellcraft module containing generic thumb little endian shellcodes.
- pwnlib.shellcraft.thumb.crash()[source]
Crash.
Example
>>> run_assembly(shellcraft.crash()).poll(True) < 0 True
- pwnlib.shellcraft.thumb.itoa(v, buffer='sp', allocate_stack=True)[source]
Converts an integer into its string representation, and pushes it onto the stack. Uses registers r0-r5.
- Parameters:
v (str, int) – Integer constant or register that contains the value to convert.
alloca
Example
>>> sc = shellcraft.thumb.mov('r0', 0xdeadbeef) >>> sc += shellcraft.thumb.itoa('r0') >>> sc += shellcraft.thumb.linux.write(1, 'sp', 32) >>> run_assembly(sc).recvuntil(b'\x00') b'3735928559\x00'
- pwnlib.shellcraft.thumb.memcpy(dest, src, n)[source]
Copies memory.
- Parameters:
dest – Destination address
src – Source address
n – Number of bytes
- pwnlib.shellcraft.thumb.mov(dst, src)[source]
Returns THUMB code for moving the specified source value into the specified destination register.
If src is a string that is not a register, then it will locally set context.arch to ‘thumb’ 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.Example
>>> print(shellcraft.thumb.mov('r1','r2').rstrip()) mov r1, r2 >>> print(shellcraft.thumb.mov('r1', 0).rstrip()) eor r1, r1 >>> print(shellcraft.thumb.mov('r1', 10).rstrip()) mov r1, #0xa + 1 sub r1, r1, 1 >>> print(shellcraft.thumb.mov('r1', 17).rstrip()) mov r1, #0x11 >>> print(shellcraft.thumb.mov('r1', 'r1').rstrip()) /* moving r1 into r1, but this is a no-op */ >>> print(shellcraft.thumb.mov('r1', 512).rstrip()) mov r1, #0x200 >>> print(shellcraft.thumb.mov('r1', 0x10000001).rstrip()) mov r1, #(0x10000001 >> 28) lsl r1, #28 add r1, #(0x10000001 & 0xff) >>> print(shellcraft.thumb.mov('r1', 0xdead0000).rstrip()) mov r1, #(0xdead0000 >> 25) lsl r1, #(25 - 16) add r1, #((0xdead0000 >> 16) & 0xff) lsl r1, #16 >>> print(shellcraft.thumb.mov('r1', 0xdead00ff).rstrip()) ldr r1, value_... b value_..._after value_...: .word 0xdead00ff value_..._after: >>> with context.local(os = 'linux'): ... print(shellcraft.thumb.mov('r1', 'SYS_execve').rstrip()) mov r1, #SYS_execve /* 0xb */ >>> with context.local(os = 'freebsd'): ... print(shellcraft.thumb.mov('r1', 'SYS_execve').rstrip()) mov r1, #SYS_execve /* 0x3b */ >>> with context.local(os = 'linux'): ... print(shellcraft.thumb.mov('r1', 'PROT_READ | PROT_WRITE | PROT_EXEC').rstrip()) mov r1, #(PROT_READ | PROT_WRITE | PROT_EXEC) /* 7 */
- pwnlib.shellcraft.thumb.popad()[source]
Pop all of the registers onto the stack which i386 popad does, in the same order.
- pwnlib.shellcraft.thumb.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 = ‘thumb’ 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.thumb.push('r0').rstrip()) push {r0} >>> print(pwnlib.shellcraft.thumb.push(0).rstrip()) /* push 0 */ eor r7, r7 push {r7} >>> print(pwnlib.shellcraft.thumb.push(1).rstrip()) /* push 1 */ mov r7, #1 push {r7} >>> print(pwnlib.shellcraft.thumb.push(256).rstrip()) /* push 0x100 */ mov r7, #0x100 push {r7} >>> print(pwnlib.shellcraft.thumb.push('SYS_execve').rstrip()) /* push 'SYS_execve' */ mov r7, #0xb push {r7} >>> with context.local(os = 'freebsd'): ... print(pwnlib.shellcraft.thumb.push('SYS_execve').rstrip()) /* push 'SYS_execve' */ mov r7, #0x3b push {r7}
- pwnlib.shellcraft.thumb.pushad()[source]
Push all of the registers onto the stack which i386 pushad does, in the same order.
- pwnlib.shellcraft.thumb.pushstr(string, append_null=True, register='r7')[source]
Pushes a string onto the stack without using null bytes or newline characters.
- Parameters:
string (str) – The string to push.
append_null (bool) – Whether to append a single NULL-byte before pushing.
Examples:
Note that this doctest has two possibilities for the first result, depending on your version of binutils.
>>> enhex(asm(shellcraft.pushstr('Hello\nWorld!', True))) in [ ... '87ea070780b4dff8047001e0726c642180b4dff8047001e06f0a576f80b4dff8047001e048656c6c80b4', ... '87ea070780b4dff8047001e0726c642180b4dff8047001e06f0a576f80b4dff8047001e048656c6c80b400bf', ... '87ea070780b4dff8067000f002b8726c642180b4dff8047000f002b86f0a576f80b4014f00f002b848656c6c80b4'] True >>> print(shellcraft.pushstr('abc').rstrip()) /* push b'abc\x00' */ ldr r7, value_... b value_..._after value_...: .word 0xff636261 value_..._after: lsl r7, #8 lsr r7, #8 push {r7} >>> print(enhex(asm(shellcraft.pushstr('\x00', False)).rstrip(b'\x00\xbf'))) 87ea070780b4
- pwnlib.shellcraft.thumb.pushstr_array(reg, array)[source]
Pushes an array/envp-style array of pointers onto the stack.
- Parameters:
reg (str) – Destination register to hold the pointer.
array (str,list) – Single argument or list of arguments to push. NULL termination is normalized so that each argument ends with exactly one NULL byte.
- pwnlib.shellcraft.thumb.ret(return_value=None)[source]
A single-byte RET instruction.
- Parameters:
return_value – Value to return
- pwnlib.shellcraft.thumb.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:
reg_context (dict) – Desired register context
stack_allowed (bool) – Can the stack be used?
Example
>>> print(shellcraft.setregs({'r0':1, 'r2':'r3'}).rstrip()) mov r0, #1 mov r2, r3 >>> print(shellcraft.setregs({'r0':'r1', 'r1':'r0', 'r2':'r3'}).rstrip()) mov r2, r3 eor r0, r0, r1 /* xchg r0, r1 */ eor r1, r0, r1 eor r0, r0, r1
- pwnlib.shellcraft.thumb.udiv_10(N)[source]
Divides r0 by 10. Result is stored in r0, N and Z flags are updated.
- Code is from generated from here:
https://raw.githubusercontent.com/rofirrim/raspberry-pi-assembler/master/chapter15/magic.py
- With code:
python magic.py 10 code_for_unsigned
pwnlib.shellcraft.thumb.linux
Shellcraft module containing THUMB shellcodes for Linux.
- pwnlib.shellcraft.thumb.linux.bindsh(port, network)[source]
Listens on a TCP port and spawns a shell for the first to connect. Port is the TCP port to listen on, network is either ‘ipv4’ or ‘ipv6’.
- pwnlib.shellcraft.thumb.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\n') >>> run_assembly(shellcraft.arm.to_thumb()+shellcraft.thumb.linux.cat(f)).recvline() b'FLAG\n'
- pwnlib.shellcraft.thumb.linux.cat2(filename, fd=1, length=16384)[source]
Opens a file and writes its contents to the specified file descriptor. Uses an extra stack buffer and must know the length.
Example
>>> f = tempfile.mktemp() >>> write(f, 'FLAG\n') >>> run_assembly(shellcraft.arm.to_thumb()+shellcraft.thumb.linux.cat2(f)).recvline() b'FLAG\n'
- pwnlib.shellcraft.thumb.linux.connect(host, port, network='ipv4')[source]
Connects to the host on the specified port. Network is either ‘ipv4’ or ‘ipv6’. Leaves the connected socket in R6.
- pwnlib.shellcraft.thumb.linux.connectstager(host, port, network='ipv4')[source]
connect recvsize stager :param host: :param where to connect to: :param port: :param which port to connect to: :param network: ipv4) :param ipv4 or ipv6? (default: ipv4)
- pwnlib.shellcraft.thumb.linux.dupio(sock='r6')[source]
Args: [sock (imm/reg) = r6] Duplicates sock to stdin, stdout and stderr
- pwnlib.shellcraft.thumb.linux.dupsh(sock='r6')[source]
Args: [sock (imm/reg) = r6] Duplicates sock to stdin, stdout and stderr and spawns a shell.
- pwnlib.shellcraft.thumb.linux.echo(string, sock='1')[source]
Writes a string to a file descriptor
Example
>>> run_assembly(shellcraft.echo('hello\n', 1)).recvline() b'hello\n'
- pwnlib.shellcraft.thumb.linux.findpeer(port)[source]
Finds a connected socket. If port is specified it is checked against the peer port. Resulting socket is left in r6.
Example
>>> enhex(asm(shellcraft.findpeer(1337))) '6ff00006ee4606f101064ff001074fea072707f11f07f54630461fb401a96a4601df0130efdd01994fea11414ff039024fea022202f105029142e4d1'
- pwnlib.shellcraft.thumb.linux.findpeersh(port)[source]
Finds a connected socket. If port is specified it is checked against the peer port. A dup2 shell is spawned on it.
- pwnlib.shellcraft.thumb.linux.findpeerstager(port=None)[source]
Findpeer recvsize stager :param port: :type port: defaults to any :param the port given to findpeer: :type the port given to findpeer: defaults to any
- pwnlib.shellcraft.thumb.linux.forkexit()[source]
Attempts to fork. If the fork is successful, the parent exits.
- pwnlib.shellcraft.thumb.linux.kill(pid, sig) str[source]
Invokes the syscall kill.
See ‘man 2 kill’ for more information.
- Parameters:
pid (pid_t) – pid
sig (int) – sig
- Returns:
int
- pwnlib.shellcraft.thumb.linux.killparent()[source]
Kills its parent process until whatever the parent is (probably init) cannot be killed any longer.
- pwnlib.shellcraft.thumb.linux.listen(port, network)[source]
Listens on a TCP port, accept a client and leave his socket in r6. Port is the TCP port to listen on, network is either ‘ipv4’ or ‘ipv6’.
Example
>>> enhex(asm(shellcraft.listen(1337, 'ipv4'))) '4ff001074fea072707f119074ff002004ff0010182ea020201df0646004901e00200053906b469464ff0100207f1010701df30464ff0010107f1020701df304681ea010182ea020207f1010701df0646'
- pwnlib.shellcraft.thumb.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.thumb.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:
The following doctest is commented out because it doesn’t work on Travis for reasons I cannot diagnose. However, it should work just fine :-)
>>> payload = shellcraft.echo(b'Hello, world!\n') + shellcraft.exit(0) >>> payloadELF = ELF.from_assembly(payload) >>> payloadELF.arch 'arm' >>> loader = shellcraft.loader_append(payloadELF.data) >>> loaderELF = ELF.from_assembly(loader, vma=0, shared=True) >>> loaderELF.process().recvall() b'Hello, world!\n'
- pwnlib.shellcraft.thumb.linux.readfile(path, dst='r6')[source]
Args: [path, dst (imm/reg) = r6 ] Opens the specified file path and sends its content to the specified file descriptor. Leaves the destination file descriptor in r6 and the input file descriptor in r5.
- pwnlib.shellcraft.thumb.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.thumb.linux.recvsize(sock, reg='r1')[source]
Recives 4 bytes size field Useful in conjuncion with findpeer and stager :param sock: :param the socket to read the payload from.: :param reg: :type reg: default ecx :param the place to put the size: :type the place to put the size: default ecx
Leaves socket in ebx
- pwnlib.shellcraft.thumb.linux.setresuid(ruid=None, euid=None, suid=None)[source]
Args: [ruid = geteuid(), euid = ruid, suid = ruid] Sets real, effective and saved user ids to given values
- pwnlib.shellcraft.thumb.linux.sh()[source]
Execute a different process.
>>> p = run_assembly(shellcraft.thumb.linux.sh()) >>> p.sendline(b'echo Hello') >>> p.recv() b'Hello\n'
- pwnlib.shellcraft.thumb.linux.sleep(seconds)[source]
Sleeps for the specified amount of seconds.
Uses SYS_nanosleep under the hood. Doesn’t check for interrupts and doesn’t retry with the remaining time.
- Parameters:
seconds (int,float) – The time to sleep in seconds.
- pwnlib.shellcraft.thumb.linux.stage(fd=0, length=None)[source]
Migrates shellcode to a new buffer.
- Parameters:
fd (int) – Integer file descriptor to recv data from. Default is stdin (0).
length (int) – Optional buffer length. If None, the first pointer-width of data received is the length.
Example
>>> p = run_assembly(shellcraft.stage()) >>> sc = asm(shellcraft.echo("Hello\n", constants.STDOUT_FILENO)) >>> p.pack(len(sc)) >>> p.send(sc) >>> p.recvline() b'Hello\n'
- pwnlib.shellcraft.thumb.linux.stager(sock, size)[source]
Read ‘size’ bytes from ‘sock’ and place them in an executable buffer and jump to it. The socket will be left in r6.
- pwnlib.shellcraft.thumb.linux.syscall(syscall=None, arg0=None, arg1=None, arg2=None, arg3=None, arg4=None, arg5=None, arg6=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(shellcraft.thumb.linux.syscall(11, 1, 'sp', 2, 0).rstrip()) /* call syscall(0xb, 1, 'sp', 2, 0) */ mov r0, #1 mov r1, sp mov r2, #2 eor r3, r3 mov r7, #0xb svc 0x41 >>> print(shellcraft.thumb.linux.syscall('SYS_exit', 0).rstrip()) /* call exit(0) */ eor r0, r0 mov r7, #SYS_exit /* 1 */ svc 0x41 >>> print(pwnlib.shellcraft.open('/home/pwn/flag').rstrip()) /* open(file='/home/pwn/flag', oflag=0, mode=0) */ /* push b'/home/pwn/flag\x00' */ mov r7, #(0x6761 >> 8) lsl r7, #8 add r7, #(0x6761 & 0xff) push {r7} ldr r7, value_... b value_..._after value_...: .word 0x6c662f6e value_..._after: push {r7} ldr r7, value_... b value_..._after value_...: .word 0x77702f65 value_..._after: push {r7} ldr r7, value_... b value_..._after value_...: .word 0x6d6f682f value_..._after: push {r7} mov r0, sp eor r1, r1 eor r2, r2 /* call open() */ mov r7, #SYS_open /* 5 */ svc 0x41