I just added in Aarch64 support for pwntools. There is no sys_sigreturn in Aarch64, instead there is a sys_rt_sigreturn implementation. In a lot of ways writing the SROP frame was similar to my ARM experience; there is a magic flag value(FPSIMD_MAGIC) that needs to be present.
Quick note : When setting up QEMU images for an architecture, do not test network connectivity using ping. ICMP might be disabled.
There is something else that is curious about Aarch64 - regardless of the gcc optimization level, the local variables are allocated first and later on, the return address and the frame pointer are pushed onto the stack. I found this quite interesting, and I don't think I've seen this on any other architectures.
eg:
At the prologue
0x000000000040063c <+0>:subsp, sp, #0x200
0x0000000000400640 <+4>:stpx29, x30, [sp,#-16]!
and at the epilogue,
0x000000000040067c <+64>:ldpx29, x30, [sp],#16
0x0000000000400680 <+68>:addsp, sp, #0x200
0x0000000000400684 <+72>:ret
For a PoC we can get away with something like this. So we end up overwriting the return address of stub(and not of read_input). The make_space makes sure that the "access_ok" function inside the kernel(it checks if there is a frame that can be accessed from the stack) does not fail. The frame is about 4704 bytes in size ; so when access_ok runs ; we need sp to sp+4704 to be mapped in as valid addresses.
The registers for the SROP frame are named as `regs[31]` in the kernel source; so I used forktest.c, set the breakpoint at handler, the stack state before the "svc 0x0" and the register state after it and found the offsets.
You can view the PR for the same here.
Quick note : When setting up QEMU images for an architecture, do not test network connectivity using ping. ICMP might be disabled.
There is something else that is curious about Aarch64 - regardless of the gcc optimization level, the local variables are allocated first and later on, the return address and the frame pointer are pushed onto the stack. I found this quite interesting, and I don't think I've seen this on any other architectures.
eg:
At the prologue
0x000000000040063c <+0>:subsp, sp, #0x200
0x0000000000400640 <+4>:stpx29, x30, [sp,#-16]!
and at the epilogue,
0x000000000040067c <+64>:ldpx29, x30, [sp],#16
0x0000000000400680 <+68>:addsp, sp, #0x200
0x0000000000400684 <+72>:ret
For a PoC we can get away with something like this. So we end up overwriting the return address of stub(and not of read_input). The make_space makes sure that the "access_ok" function inside the kernel(it checks if there is a frame that can be accessed from the stack) does not fail. The frame is about 4704 bytes in size ; so when access_ok runs ; we need sp to sp+4704 to be mapped in as valid addresses.
The registers for the SROP frame are named as `regs[31]` in the kernel source; so I used forktest.c, set the breakpoint at handler, the stack state before the "svc 0x0" and the register state after it and found the offsets.
You can view the PR for the same here.