pwnlib.shellcraft.aarch64 — Shellcode for AArch64

pwnlib.shellcraft.aarch64

pwnlib.shellcraft.aarch64.breakpoint()[source]

Inserts a debugger breakpoint (raises SIGTRAP).

Example

>>> run_assembly(shellcraft.breakpoint()).poll(True)
-5
pwnlib.shellcraft.aarch64.crash()[source]

Crashes the process.

Example

>>> run_assembly(shellcraft.crash()).poll(True)
-11
pwnlib.shellcraft.aarch64.infloop()[source]

An infinite loop.

Example

>>> io = run_assembly(shellcraft.infloop())
>>> io.recvall(timeout=1)
''
>>> io.close()
pwnlib.shellcraft.aarch64.mov(dst, src)[source]

Move src into dest.

Support for automatically avoiding newline and null bytes has to be done.

If src is a string that is not a register, then it will locally set context.arch to ‘arm’ 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.

Examples

>>> print shellcraft.mov('x0','x1').rstrip()
    mov  x0, x1
>>> print shellcraft.mov('x0','0').rstrip()
    mov  x0, xzr
>>> print shellcraft.mov('x0', 5).rstrip()
    mov  x0, #5
>>> print shellcraft.mov('x0', 0x34532).rstrip()
    /* Set x0 = 214322 = 0x34532 */
    mov  x0, #17714
    movk x0, #3, lsl #16
Parameters:
  • dest (str) – The destination register.
  • src (str) – Either the input register, or an immediate value.
pwnlib.shellcraft.aarch64.push(value, register1='x14', register2='x15')[source]

Pushes a value onto the stack without using null bytes or newline characters.

If src is a string, then we try to evaluate 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.

Note

AArch64 requires that the stack remain 16-byte aligned at all times, so this alignment is preserved.

Parameters:
  • value (int,str) – The value or register to push
  • register1 (str) – Scratch register to use
  • register2 (str) – Second scratch register to use

Example

>>> print pwnlib.shellcraft.push(0).rstrip()
    /* push 0 */
    mov  x14, xzr
    str x14, [sp, #-16]!
>>> print pwnlib.shellcraft.push(1).rstrip()
    /* push 1 */
    mov  x14, #1
    str x14, [sp, #-16]!
>>> print pwnlib.shellcraft.push(256).rstrip()
    /* push 0x100 */
    mov  x14, #256
    str x14, [sp, #-16]!
>>> print pwnlib.shellcraft.push('SYS_execve').rstrip()
    /* push SYS_execve (0xdd) */
    mov  x14, #221
    str x14, [sp, #-16]!
>>> print pwnlib.shellcraft.push('SYS_sendfile').rstrip()
    /* push SYS_sendfile (0x47) */
    mov  x14, #71
    str x14, [sp, #-16]!
>>> with context.local(os = 'freebsd'):
...     print pwnlib.shellcraft.push('SYS_execve').rstrip()
...
    /* push SYS_execve (0x3b) */
    mov  x14, #59
    str x14, [sp, #-16]!
pwnlib.shellcraft.aarch64.pushstr(string, append_null=True, register1='x14', register2='x15', pretty=None)[source]

Pushes a string onto the stack.

r12 is defined as the inter-procedural scratch register ($ip), so this should not interfere with most usage.

Parameters:
  • string (str) – The string to push.
  • append_null (bool) – Whether to append a single NULL-byte before pushing.
  • register (str) – Temporary register to use. By default, R7 is used.

Examples

>>> print shellcraft.pushstr("Hello!").rstrip()
    /* push 'Hello!\x00' */
    /* Set x14 = 36762444129608 = 0x216f6c6c6548 */
    mov  x14, #25928
    movk x14, #27756, lsl #16
    movk x14, #8559, lsl #0x20
    str x14, [sp, #-16]!
>>> print shellcraft.pushstr("Hello, world!").rstrip()
    /* push 'Hello, world!\x00' */
    /* Set x14 = 8583909746840200520 = 0x77202c6f6c6c6548 */
    mov  x14, #25928
    movk x14, #27756, lsl #16
    movk x14, #11375, lsl #0x20
    movk x14, #30496, lsl #0x30
    /* Set x15 = 143418749551 = 0x21646c726f */
    mov  x15, #29295
    movk x15, #25708, lsl #16
    movk x15, #33, lsl #0x20
    stp x14, x15, [sp, #-16]!
>>> print shellcraft.pushstr("Hello, world, bienvenue").rstrip()
    /* push 'Hello, world, bienvenue\x00' */
    /* Set x14 = 8583909746840200520 = 0x77202c6f6c6c6548 */
    mov  x14, #25928
    movk x14, #27756, lsl #16
    movk x14, #11375, lsl #0x20
    movk x14, #30496, lsl #0x30
    /* Set x15 = 7593667296735556207 = 0x6962202c646c726f */
    mov  x15, #29295
    movk x15, #25708, lsl #16
    movk x15, #8236, lsl #0x20
    movk x15, #26978, lsl #0x30
    stp x14, x15, [sp, #-16]!
    /* Set x14 = 28558089656888933 = 0x65756e65766e65 */
    mov  x14, #28261
    movk x14, #25974, lsl #16
    movk x14, #30062, lsl #0x20
    movk x14, #101, lsl #0x30
    str x14, [sp, #-16]!
>>> print shellcraft.pushstr("Hello, world, bienvenue!").rstrip()
    /* push 'Hello, world, bienvenue!\x00' */
    /* Set x14 = 8583909746840200520 = 0x77202c6f6c6c6548 */
    mov  x14, #25928
    movk x14, #27756, lsl #16
    movk x14, #11375, lsl #0x20
    movk x14, #30496, lsl #0x30
    /* Set x15 = 7593667296735556207 = 0x6962202c646c726f */
    mov  x15, #29295
    movk x15, #25708, lsl #16
    movk x15, #8236, lsl #0x20
    movk x15, #26978, lsl #0x30
    stp x14, x15, [sp, #-16]!
    /* Set x14 = 2406458692908510821 = 0x2165756e65766e65 */
    mov  x14, #28261
    movk x14, #25974, lsl #16
    movk x14, #30062, lsl #0x20
    movk x14, #8549, lsl #0x30
    mov  x15, xzr
    stp x14, x15, [sp, #-16]!
pwnlib.shellcraft.aarch64.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({'x0':1, 'x2':'x3'}).rstrip()
    mov  x0, #1
    mov  x2, x3
>>> print shellcraft.setregs({'x0':'x1', 'x1':'x0', 'x2':'x3'}).rstrip()
    mov  x2, x3
    eor  x0, x0, x1 /* xchg x0, x1 */
    eor  x1, x0, x1
    eor  x0, x0, x1
pwnlib.shellcraft.aarch64.trap()[source]

Inserts a debugger breakpoint (raises SIGTRAP).

Example

>>> run_assembly(shellcraft.breakpoint()).poll(True)
-5
pwnlib.shellcraft.aarch64.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.
  • address (int) – Address of the data (e.g. 0xdead0000, ‘rsp’)
  • count (int) – Number of bytes to XOR.

Example

>>> sc  = shellcraft.read(0, 'sp', 32)
>>> sc += shellcraft.xor(0xdeadbeef, 'sp', 32)
>>> sc += shellcraft.write(1, 'sp', 32)
>>> io = run_assembly(sc)
>>> io.send(cyclic(32))
>>> result = io.recvn(32)
>>> expected = xor(cyclic(32), p32(0xdeadbeef))
>>> result == expected
True

pwnlib.shellcraft.aarch64.linux

pwnlib.shellcraft.aarch64.linux.cat(filename, fd=1)[source]

Opens a file and writes its contents to the specified file descriptor.

Example

>>> write('flag', 'This is the flag\n')
>>> shellcode = shellcraft.cat('flag') + shellcraft.exit(0)
>>> print disasm(asm(shellcode))
   0:   d28d8cce        mov     x14, #0x6c66                    // #27750
   4:   f2acec2e        movk    x14, #0x6761, lsl #16
   8:   f81f0fee        str     x14, [sp, #-16]!
   c:   d29ff380        mov     x0, #0xff9c                     // #65436
  10:   f2bfffe0        movk    x0, #0xffff, lsl #16
  14:   f2dfffe0        movk    x0, #0xffff, lsl #32
  18:   f2ffffe0        movk    x0, #0xffff, lsl #48
  1c:   910003e1        mov     x1, sp
  20:   aa1f03e2        mov     x2, xzr
  24:   aa1f03e3        mov     x3, xzr
  28:   d2800708        mov     x8, #0x38                       // #56
  2c:   d4000001        svc     #0x0
  30:   aa0003e1        mov     x1, x0
  34:   d2800020        mov     x0, #0x1                        // #1
  38:   aa1f03e2        mov     x2, xzr
  3c:   d29fffe3        mov     x3, #0xffff                     // #65535
  40:   f2afffe3        movk    x3, #0x7fff, lsl #16
  44:   d28008e8        mov     x8, #0x47                       // #71
  48:   d4000001        svc     #0x0
  4c:   aa1f03e0        mov     x0, xzr
  50:   d2800ba8        mov     x8, #0x5d                       // #93
  54:   d4000001        svc     #0x0
>>> run_assembly(shellcode).recvline()
'This is the flag\n'
pwnlib.shellcraft.aarch64.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 x12.

pwnlib.shellcraft.aarch64.linux.echo(string, sock='1')[source]

Writes a string to a file descriptor

Example

>>> run_assembly(shellcraft.echo('hello\n', 1)).recvline()
'hello\n'
pwnlib.shellcraft.aarch64.linux.forkexit()[source]

Attempts to fork. If the fork is successful, the parent exits.

pwnlib.shellcraft.aarch64.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.aarch64.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 :-)

# >>> gcc = process([‘aarch64-linux-gnu-gcc’,’-xc’,’-static’,’-Wl,-Ttext-segment=0x20000000’,’-‘]) # >>> gcc.write(‘’’ # ... int main() { # ... printf(“Hello, %s!\n”, “world”); # ... } # ... ‘’‘) # >>> gcc.shutdown(‘send’) # >>> gcc.poll(True) # 0 # >>> sc = shellcraft.loader_append(‘a.out’) # >>> run_assembly(sc).recvline() # ‘Hello, world!n’
pwnlib.shellcraft.aarch64.linux.open(filename, mode='O_RDONLY')[source]

Opens a file

pwnlib.shellcraft.aarch64.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.aarch64.linux.sh()[source]

Execute a different process.

>>> p = run_assembly(shellcraft.aarch64.linux.sh())
>>> p.sendline('echo Hello')
>>> p.recv()
'Hello\n'
pwnlib.shellcraft.aarch64.linux.socket(network='ipv4', proto='tcp')[source]

Creates a new socket

pwnlib.shellcraft.aarch64.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()
'Hello\n'
pwnlib.shellcraft.aarch64.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.aarch64.linux.syscall(11, 1, 'sp', 2, 0).rstrip()
    /* call syscall(11, 1, 'sp', 2, 0) */
    mov  x0, #1
    mov  x1, sp
    mov  x2, #2
    mov  x3, xzr
    mov  x8, #11
    svc 0
>>> print shellcraft.aarch64.linux.syscall('SYS_exit', 0).rstrip()
    /* call exit(0) */
    mov  x0, xzr
    mov  x8, #SYS_exit
    svc 0
>>> print pwnlib.shellcraft.openat(-2, '/home/pwn/flag').rstrip()
    /* openat(fd=-2, file='/home/pwn/flag', oflag=0) */
    /* push '/home/pwn/flag\x00' */
    /* Set x14 = 8606431000579237935 = 0x77702f656d6f682f */
    mov  x14, #26671
    movk x14, #28015, lsl #16
    movk x14, #12133, lsl #0x20
    movk x14, #30576, lsl #0x30
    /* Set x15 = 113668128124782 = 0x67616c662f6e */
    mov  x15, #12142
    movk x15, #27750, lsl #16
    movk x15, #26465, lsl #0x20
    stp x14, x15, [sp, #-16]!
    mov  x1, sp
    /* Set x0 = -2 = -2 */
    mov  x0, #65534
    movk x0, #65535, lsl #16
    movk x0, #65535, lsl #0x20
    movk x0, #65535, lsl #0x30
    mov  x2, xzr
    /* call openat() */
    mov  x8, #SYS_openat
    svc 0