macOS Thread Injection via Task port

Support HackTricks

Code

1. Thread Hijacking

Αρχικά, η task_threads() συνάρτηση καλείται στην θύρα εργασίας για να αποκτήσει μια λίστα νημάτων από την απομακρυσμένη εργασία. Ένα νήμα επιλέγεται για hijacking. Αυτή η προσέγγιση αποκλίνει από τις συμβατικές μεθόδους έγχυσης κώδικα καθώς η δημιουργία ενός νέου απομακρυσμένου νήματος απαγορεύεται λόγω της νέας μείωσης που μπλοκάρει το thread_create_running().

Για να ελέγξει το νήμα, καλείται η thread_suspend(), σταματώντας την εκτέλεσή του.

Οι μόνοι επιτρεπόμενοι χειρισμοί στο απομακρυσμένο νήμα περιλαμβάνουν σταμάτημα και εκκίνηση αυτού, ανάκτηση και τροποποίηση των τιμών των καταχωρητών του. Οι απομακρυσμένες κλήσεις συναρτήσεων ξεκινούν με την ρύθμιση των καταχωρητών x0 έως x7 στις παραμέτρους, ρυθμίζοντας το pc για να στοχεύσει τη επιθυμητή συνάρτηση και ενεργοποιώντας το νήμα. Η διασφάλιση ότι το νήμα δεν θα καταρρεύσει μετά την επιστροφή απαιτεί ανίχνευση της επιστροφής.

Μια στρατηγική περιλαμβάνει την καταχώριση ενός χειριστή εξαιρέσεων για το απομακρυσμένο νήμα χρησιμοποιώντας το thread_set_exception_ports(), ρυθμίζοντας τον καταχωρητή lr σε μια μη έγκυρη διεύθυνση πριν από την κλήση της συνάρτησης. Αυτό προκαλεί μια εξαίρεση μετά την εκτέλεση της συνάρτησης, στέλνοντας ένα μήνυμα στην θύρα εξαίρεσης, επιτρέποντας την επιθεώρηση της κατάστασης του νήματος για την ανάκτηση της τιμής επιστροφής. Εναλλακτικά, όπως υιοθετήθηκε από την εκμετάλλευση triple_fetch του Ian Beer, ο lr ρυθμίζεται να επαναλαμβάνεται άπειρα. Οι καταχωρητές του νήματος παρακολουθούνται συνεχώς μέχρι το pc να δείχνει σε αυτή την εντολή.

2. Mach ports for communication

Η επόμενη φάση περιλαμβάνει την εγκαθίδρυση Mach ports για να διευκολύνει την επικοινωνία με το απομακρυσμένο νήμα. Αυτές οι θύρες είναι καθοριστικές για τη μεταφορά αυθαίρετων δικαιωμάτων αποστολής και λήψης μεταξύ εργασιών.

Για αμφίδρομη επικοινωνία, δημιουργούνται δύο δικαιώματα λήψης Mach: ένα στην τοπική και ένα στην απομακρυσμένη εργασία. Στη συνέχεια, ένα δικαίωμα αποστολής για κάθε θύρα μεταφέρεται στην αντίστοιχη εργασία, επιτρέποντας την ανταλλαγή μηνυμάτων.

Εστιάζοντας στην τοπική θύρα, το δικαίωμα λήψης κατέχεται από την τοπική εργασία. Η θύρα δημιουργείται με το mach_port_allocate(). Η πρόκληση έγκειται στη μεταφορά ενός δικαιώματος αποστολής σε αυτή τη θύρα στην απομακρυσμένη εργασία.

Μια στρατηγική περιλαμβάνει την εκμετάλλευση του thread_set_special_port() για να τοποθετήσει ένα δικαίωμα αποστολής στην τοπική θύρα στο THREAD_KERNEL_PORT του απομακρυσμένου νήματος. Στη συνέχεια, το απομακρυσμένο νήμα καθοδηγείται να καλέσει το mach_thread_self() για να ανακτήσει το δικαίωμα αποστολής.

Για την απομακρυσμένη θύρα, η διαδικασία είναι ουσιαστικά αντίστροφη. Το απομακρυσμένο νήμα καθοδηγείται να δημιουργήσει μια θύρα Mach μέσω του mach_reply_port() (καθώς το mach_port_allocate() δεν είναι κατάλληλο λόγω του μηχανισμού επιστροφής του). Μετά τη δημιουργία της θύρας, καλείται το mach_port_insert_right() στο απομακρυσμένο νήμα για να καθιερώσει ένα δικαίωμα αποστολής. Αυτό το δικαίωμα αποθηκεύεται στη μνήμη χρησιμοποιώντας το thread_set_special_port(). Επιστρέφοντας στην τοπική εργασία, χρησιμοποιείται το thread_get_special_port() στο απομακρυσμένο νήμα για να αποκτήσει ένα δικαίωμα αποστολής στη νεοδημιουργημένη θύρα Mach στην απομακρυσμένη εργασία.

Η ολοκλήρωση αυτών των βημάτων έχει ως αποτέλεσμα την εγκαθίδρυση Mach ports, θέτοντας τα θεμέλια για αμφίδρομη επικοινωνία.

3. Basic Memory Read/Write Primitives

Σε αυτή την ενότητα, η εστίαση είναι στη χρήση του εκτελέσιμου primitive για την εγκαθίδρυση βασικών primitives ανάγνωσης και εγγραφής μνήμης. Αυτά τα αρχικά βήματα είναι κρίσιμα για την απόκτηση περισσότερου ελέγχου πάνω στη απομακρυσμένη διαδικασία, αν και τα primitives σε αυτό το στάδιο δεν θα εξυπηρετήσουν πολλούς σκοπούς. Σύντομα, θα αναβαθμιστούν σε πιο προηγμένες εκδόσεις.

Memory Reading and Writing Using Execute Primitive

Ο στόχος είναι να εκτελούνται αναγνώσεις και εγγραφές μνήμης χρησιμοποιώντας συγκεκριμένες συναρτήσεις. Για την ανάγνωση μνήμης, χρησιμοποιούνται συναρτήσεις που μοιάζουν με την παρακάτω δομή:

uint64_t read_func(uint64_t *address) {
return *address;
}

Και για την εγγραφή στη μνήμη, χρησιμοποιούνται συναρτήσεις παρόμοιες με αυτή τη δομή:

void write_func(uint64_t *address, uint64_t value) {
*address = value;
}

Αυτές οι συναρτήσεις αντιστοιχούν στις δοθείσες εντολές συναρμολόγησης:

_read_func:
ldr x0, [x0]
ret
_write_func:
str x1, [x0]
ret

Identifying Suitable Functions

A scan of common libraries revealed appropriate candidates for these operations:

  1. Reading Memory: Η συνάρτηση property_getName() από τη βιβλιοθήκη χρόνου εκτέλεσης Objective-C αναγνωρίζεται ως κατάλληλη συνάρτηση για την ανάγνωση μνήμης. Η συνάρτηση περιγράφεται παρακάτω:

const char *property_getName(objc_property_t prop) {
return prop->name;
}

Αυτή η συνάρτηση λειτουργεί αποτελεσματικά όπως η read_func επιστρέφοντας το πρώτο πεδίο του objc_property_t.

  1. Γράφοντας Μνήμη: Η εύρεση μιας προ-κατασκευασμένης συνάρτησης για τη γραφή μνήμης είναι πιο δύσκολη. Ωστόσο, η συνάρτηση _xpc_int64_set_value() από τη libxpc είναι κατάλληλος υποψήφιος με την παρακάτω αποσυναρμολόγηση:

__xpc_int64_set_value:
str x1, [x0, #0x18]
ret

Για να εκτελέσετε μια εγγραφή 64-bit σε μια συγκεκριμένη διεύθυνση, η απομακρυσμένη κλήση δομείται ως εξής:

_xpc_int64_set_value(address - 0x18, value)

Με αυτές τις βασικές αρχές καθορισμένες, η σκηνή είναι έτοιμη για τη δημιουργία κοινής μνήμης, σηματοδοτώντας μια σημαντική πρόοδο στον έλεγχο της απομακρυσμένης διαδικασίας.

4. Ρύθμιση Κοινής Μνήμης

Ο στόχος είναι να καθιερωθεί κοινή μνήμη μεταξύ τοπικών και απομακρυσμένων εργασιών, απλοποιώντας τη μεταφορά δεδομένων και διευκολύνοντας την κλήση συναρτήσεων με πολλαπλά επιχειρήματα. Η προσέγγιση περιλαμβάνει την εκμετάλλευση του libxpc και του τύπου αντικειμένου OS_xpc_shmem, ο οποίος βασίζεται σε καταχωρίσεις μνήμης Mach.

Επισκόπηση Διαδικασίας:

  1. Κατανομή Μνήμης:

  • Κατανομή της μνήμης για κοινή χρήση χρησιμοποιώντας mach_vm_allocate().

  • Χρησιμοποιήστε το xpc_shmem_create() για να δημιουργήσετε ένα αντικείμενο OS_xpc_shmem για την κατανεμημένη περιοχή μνήμης. Αυτή η συνάρτηση θα διαχειριστεί τη δημιουργία της καταχώρισης μνήμης Mach και θα αποθηκεύσει το δικαίωμα αποστολής Mach στη θέση 0x18 του αντικειμένου OS_xpc_shmem.

  1. Δημιουργία Κοινής Μνήμης στην Απομακρυσμένη Διαδικασία:

  • Κατανομή μνήμης για το αντικείμενο OS_xpc_shmem στην απομακρυσμένη διαδικασία με μια απομακρυσμένη κλήση στο malloc().

  • Αντιγραφή του περιεχομένου του τοπικού αντικειμένου OS_xpc_shmem στην απομακρυσμένη διαδικασία. Ωστόσο, αυτή η αρχική αντιγραφή θα έχει λανθασμένα ονόματα καταχωρίσεων μνήμης Mach στη θέση 0x18.

  1. Διόρθωση της Καταχώρισης Μνήμης Mach:

  • Χρησιμοποιήστε τη μέθοδο thread_set_special_port() για να εισάγετε ένα δικαίωμα αποστολής για την καταχώριση μνήμης Mach στην απομακρυσμένη εργασία.

  • Διορθώστε το πεδίο καταχώρισης μνήμης Mach στη θέση 0x18 αντικαθιστώντας το με το όνομα της καταχώρισης μνήμης της απομακρυσμένης διαδικασίας.

  1. Ολοκλήρωση Ρύθμισης Κοινής Μνήμης:

  • Επικυρώστε το απομακρυσμένο αντικείμενο OS_xpc_shmem.

  • Καθιερώστε τη χαρτογράφηση κοινής μνήμης με μια απομακρυσμένη κλήση στο xpc_shmem_remote().

Ακολουθώντας αυτά τα βήματα, η κοινή μνήμη μεταξύ των τοπικών και απομακρυσμένων εργασιών θα ρυθμιστεί αποτελεσματικά, επιτρέποντας απλές μεταφορές δεδομένων και την εκτέλεση συναρτήσεων που απαιτούν πολλαπλά επιχειρήματα.

Πρόσθετα Κωδικοποιημένα Αποσπάσματα

Για την κατανομή μνήμης και τη δημιουργία αντικειμένου κοινής μνήμης:

mach_vm_allocate();
xpc_shmem_create();

Για τη δημιουργία και διόρθωση του αντικειμένου κοινής μνήμης στη απομακρυσμένη διαδικασία:

malloc(); // for allocating memory remotely
thread_set_special_port(); // for inserting send right

Θυμηθείτε να χειριστείτε σωστά τις λεπτομέρειες των Mach ports και των ονομάτων εισόδου μνήμης για να διασφαλίσετε ότι η ρύθμιση της κοινής μνήμης λειτουργεί σωστά.

5. Επίτευξη Πλήρους Ελέγχου

Αφού καταφέρουμε να εγκαταστήσουμε κοινή μνήμη και να αποκτήσουμε ικανότητες αυθαίρετης εκτέλεσης, έχουμε ουσιαστικά αποκτήσει πλήρη έλεγχο της στοχευμένης διαδικασίας. Οι βασικές λειτουργίες που επιτρέπουν αυτόν τον έλεγχο είναι:

  1. Αυθαίρετες Λειτουργίες Μνήμης:

  • Εκτελέστε αυθαίρετες αναγνώσεις μνήμης καλώντας το memcpy() για να αντιγράψετε δεδομένα από την κοινή περιοχή.

  • Εκτελέστε αυθαίρετες εγγραφές μνήμης χρησιμοποιώντας το memcpy() για να μεταφέρετε δεδομένα στην κοινή περιοχή.

  1. Διαχείριση Κλήσεων Συναρτήσεων με Πολλαπλά Επιχειρήματα:

  • Για συναρτήσεις που απαιτούν περισσότερα από 8 επιχειρήματα, τοποθετήστε τα επιπλέον επιχειρήματα στη στοίβα σύμφωνα με τη σύμβαση κλήσης.

  1. Μεταφορά Mach Port:

  • Μεταφέρετε Mach ports μεταξύ διαδικασιών μέσω Mach μηνυμάτων μέσω προηγουμένως καθορισμένων ports.

  1. Μεταφορά Περιγραφέα Αρχείου:

  • Μεταφέρετε περιγραφείς αρχείων μεταξύ διαδικασιών χρησιμοποιώντας fileports, μια τεχνική που επισημαίνεται από τον Ian Beer στο triple_fetch.

Αυτός ο εκτενής έλεγχος είναι ενσωματωμένος στη βιβλιοθήκη threadexec, παρέχοντας μια λεπτομερή υλοποίηση και μια φιλική προς τον χρήστη API για αλληλεπίδραση με τη διαδικασία-στόχο.

Σημαντικές Σκέψεις:

  • Διασφαλίστε τη σωστή χρήση του memcpy() για λειτουργίες ανάγνωσης/εγγραφής μνήμης για να διατηρήσετε τη σταθερότητα του συστήματος και την ακεραιότητα των δεδομένων.

  • Όταν μεταφέρετε Mach ports ή περιγραφείς αρχείων, ακολουθήστε τους σωστούς πρωτοκόλλους και χειριστείτε τους πόρους υπεύθυνα για να αποτρέψετε διαρροές ή μη προγραμματισμένη πρόσβαση.

Ακολουθώντας αυτές τις οδηγίες και χρησιμοποιώντας τη βιβλιοθήκη threadexec, μπορεί κανείς να διαχειριστεί και να αλληλεπιδράσει με διαδικασίες σε λεπτομερές επίπεδο, επιτυγχάνοντας πλήρη έλεγχο της στοχευμένης διαδικασίας.

Αναφορές

Support HackTricks

Last updated