macOS Process Abuse

Μάθετε το χάκινγκ AWS από το μηδέν μέχρι τον ήρωα με το htARTE (Ειδικός Red Team του HackTricks AWS)!

Άλλοι τρόποι υποστήριξης του HackTricks:

Βασικές Πληροφορίες Διεργασιών

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

Παραδοσιακά, οι διεργασίες ξεκινούσαν μέσα σε άλλες διεργασίες (εκτός από το PID 1) καλώντας το fork το οποίο θα δημιουργούσε έναν ακριβή αντίγραφο της τρέχουσας διεργασίας και στη συνέχεια η παιδική διεργασία θα καλούσε γενικά το execve για να φορτώσει το νέο εκτελέσιμο και να το εκτελέσει. Στη συνέχεια, εισήχθη η vfork για να κάνει αυτή τη διαδικασία πιο γρήγορη χωρίς καμία αντιγραφή μνήμης. Στη συνέχεια εισήχθη το posix_spawn συνδυάζοντας τα vfork και execve σε μία κλήση και δεχόμενο σημαίες:

  • POSIX_SPAWN_RESETIDS: Επαναφορά των αναγνωριστικών σε πραγματικά αναγνωριστικά

  • POSIX_SPAWN_SETPGROUP: Ορισμός συσχετισμού ομάδας διεργασιών

  • POSUX_SPAWN_SETSIGDEF: Ορισμός προεπιλεγμένης συμπεριφοράς σήματος

  • POSIX_SPAWN_SETSIGMASK: Ορισμός μάσκας σήματος

  • POSIX_SPAWN_SETEXEC: Εκτέλεση στην ίδια διεργασία (όπως το execve με περισσότερες επιλογές)

  • POSIX_SPAWN_START_SUSPENDED: Έναρξη σε κατάσταση αναστολής

  • _POSIX_SPAWN_DISABLE_ASLR: Έναρξη χωρίς ASLR

  • _POSIX_SPAWN_NANO_ALLOCATOR: Χρήση του Nano allocator του libmalloc

  • _POSIX_SPAWN_ALLOW_DATA_EXEC: Επιτρέπεται το rwx στα τμήματα δεδομένων

  • POSIX_SPAWN_CLOEXEC_DEFAULT: Κλείσιμο όλων των περιγραφών αρχείων κατά το exec(2) από προεπιλογή

  • _POSIX_SPAWN_HIGH_BITS_ASLR: Τυχαία ανακατάταξη υψηλών bits του ASLR slide

Επιπλέον, το posix_spawn επιτρέπει την καθορισμό ενός πίνακα posix_spawnattr που ελέγχει κάποιες πτυχές της διεργασίας που δημιουργήθηκε, και posix_spawn_file_actions για την τροποποίηση της κατάστασης των περιγραφέων.

Όταν μια διεργασία πεθαίνει, στέλνει τον κωδικό επιστροφής στη γονική διεργασία (αν η γονική διεργασία πέθανε, η νέα γονική είναι το PID 1) με το σήμα SIGCHLD. Η γονική διεργασία πρέπει να λάβει αυτή την τιμή καλώντας wait4() ή waitid() και μέχρι να συμβεί αυτό, το παιδί παραμένει σε κατάσταση zombie όπου εξακολουθεί να είναι καταχωρημένο αλλά δεν καταναλώνει πόρους.

PIDs

Τα PIDs, αναγνωριστικά διεργασιών, αναγνωρίζουν μια μοναδική διεργασία. Στο XNU τα PIDs είναι 64bit αυξάνονται μονοτονικά και ποτέ δεν τυλίγονται (για να αποφευχθούν οι καταχρήσεις).

Ομάδες Διεργασιών, Συνεδρίες & Συναλλαγές

Οι διεργασίες μπορούν να εισαχθούν σε ομάδες για να είναι πιο εύκολο να τις χειριστεί κανείς. Για παράδειγμα, εντολές σε ένα σενάριο κελιού θα είναι στην ίδια ομάδα διεργασιών, έτσι ώστε να είναι δυνατό να τους στείλει σήματα μαζί χρησιμοποιώντας για παράδειγμα την εντολή kill. Είναι επίσης δυνατό να ομαδοποιούνται διεργασίες σε συνεδρίες. Όταν μια διεργασία ξεκινά μια συνεδρία (setsid(2)), οι διεργασίες-παιδιά τίθενται μέσα στη συνεδρία, εκτός αν ξεκινήσουν τη δική τους συνεδρία.

Η συναλλαγή είναι ένας άλλος τρόπος να ομαδοποιούνται διεργασίες στο Darwin. Μια διεργασία που εντάσσεται σε μια συναλλαγή της επιτρέπει να έχει πρόσβαση σε κοινούς πόρους, να μοιράζεται ένα λογιστικό ή να αντιμετωπίζει το Jetsam. Οι συναλλαγές έχουν διαφορετικούς ρόλους: Ηγέτη, XPC υπηρεσία, Επέκταση.

Διαπιστεύσεις & Προσωπικότητες

Κάθε διεργασία διαθέτει διαπιστεύσεις που ταυτοποιούν τα προνόμιά της στο σύστημα. Κάθε διεργασία θα έχει έναν κύριο uid και έναν κύριο gid (αν και ενδέχεται να ανήκει σε πολλές ομάδες). Είναι επίσης δυνατό να αλλάξετε το αναγνωριστικό χρήστη και ομάδας αν το δυαδικό έχει το bit setuid/setgid. Υπάρχουν αρκετές συναρτήσεις για ορισμό νέων αναγνωριστικών χρήστη/ομάδας.

Η κλήση συστήματος persona παρέχει ένα εναλλακτικό σύνολο διαπιστεύσεων. Η υιοθέτηση μιας προσωπικότητας υποθέτει το uid, gid και τα μέλη ομάδας της ταυτόχρονα. Στο πηγαίο κώδικα είναι δυνατό να βρείτε τη δομή:

struct kpersona_info { uint32_t persona_info_version;
uid_t    persona_id; /* overlaps with UID */
int      persona_type;
gid_t    persona_gid;
uint32_t persona_ngroups;
gid_t    persona_groups[NGROUPS];
uid_t    persona_gmuid;
char     persona_name[MAXLOGNAME + 1];

/* TODO: MAC policies?! */
}

Βασικές Πληροφορίες Νημάτων

  1. Νήματα POSIX (pthreads): Το macOS υποστηρίζει τα POSIX threads (pthreads), τα οποία αποτελούν μέρος μιας προτύπου διεργασίας για τη γλώσσα C/C++. Η υλοποίηση των pthreads στο macOS βρίσκεται στο /usr/lib/system/libsystem_pthread.dylib, το οποίο προέρχεται από το δημόσια διαθέσιμο έργο libpthread. Αυτή η βιβλιοθήκη παρέχει τις απαραίτητες λειτουργίες για τη δημιουργία και διαχείριση νημάτων.

  2. Δημιουργία Νημάτων: Η συνάρτηση pthread_create() χρησιμοποιείται για τη δημιουργία νέων νημάτων. Εσωτερικά, αυτή η συνάρτηση καλεί την bsdthread_create(), η οποία είναι μια χαμηλότερου επιπέδου κλήση συστήματος ειδική για τον πυρήνα XNU (ο πυρήνας στον οποίο βασίζεται το macOS). Αυτή η κλήση συστήματος παίρνει διάφορες σημαίες που προέρχονται από το pthread_attr (χαρακτηριστικά) που καθορίζουν τη συμπεριφορά του νήματος, συμπεριλαμβανομένων των πολιτικών προγραμματισμού και του μεγέθους της στοίβας.

  • Προεπιλεγμένο Μέγεθος Στοίβας: Το προεπιλεγμένο μέγεθος στοίβας για νέα νήματα είναι 512 KB, το οποίο είναι επαρκές για τις τυπικές λειτουργίες αλλά μπορεί να προσαρμοστεί μέσω των χαρακτηριστικών του νήματος αν χρειάζεται περισσότερος ή λιγότερος χώρος.

  1. Αρχικοποίηση Νήματος: Η συνάρτηση __pthread_init() είναι κρίσιμη κατά την εγκατάσταση του νήματος, χρησιμοποιώντας το όρισμα env[] για να αναλύσει μεταβλητές περιβάλλοντος που μπορεί να περιλαμβάνουν λεπτομέρειες σχετικά με την τοποθεσία και το μέγεθος της στοίβας.

Τερματισμός Νημάτων στο macOS

  1. Έξοδος Νημάτων: Τα νήματα τερματίζονται συνήθως καλώντας την pthread_exit(). Αυτή η συνάρτηση επιτρέπει σε ένα νήμα να τερματίσει καθαρά, εκτελώντας την απαραίτητη καθαριότητα και επιτρέποντας στο νήμα να στείλει έναν τιμή επιστροφής σε οποιονδήποτε συνδέοντα.

  2. Καθαρισμός Νήματος: Κατά την κλήση της pthread_exit(), ενεργοποιείται η συνάρτηση pthread_terminate(), η οποία χειρίζεται την αφαίρεση όλων των σχετικών δομών νήματος. Απελευθερώνει τις θύρες Mach thread (το Mach είναι το υποσύστημα επικοινωνίας στον πυρήνα XNU) και καλεί την bsdthread_terminate, μια κλήση συστήματος που αφαιρεί τις δομές σε επίπεδο πυρήνα που σχετίζονται με το νήμα.

Μηχανισμοί Συγχρονισμού

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

  1. Κλειδώματα (Mutexes):

  • Κανονικό Κλείδωμα (Υπογραφή: 0x4D555458): Κανονικό κλείδωμα με μνήμη 60 bytes (56 bytes για το κλείδωμα και 4 bytes για την υπογραφή).

  • Γρήγορο Κλείδωμα (Υπογραφή: 0x4d55545A): Παρόμοιο με ένα κανονικό κλείδωμα αλλά βελτιστοποιημένο για ταχύτερες λειτουργίες, επίσης μεγέθους 60 bytes.

  1. Μεταβλητές Συνθήκης (Condition Variables):

  • Χρησιμοποιούνται για την αναμονή συγκεκριμένων συνθηκών να συμβούν, με μέγεθος 44 bytes (40 bytes συν 4-byte υπογραφή).

  • Χαρακτηριστικά Μεταβλητής Συνθήκης (Υπογραφή: 0x434e4441): Χαρακτηριστικά διαμόρφωσης για μεταβλητές συνθήκης, μεγέθους 12 bytes.

  1. Μία Φορά Μεταβλητή (Once Variable) (Υπογραφή: 0x4f4e4345):

  • Βεβαιώνει ότι ένα τμήμα κώδικα αρχικοποιείται μόνο μία φορά. Το μέγεθός του είναι 12 bytes.

  1. Κλειδώματα Ανάγνωσης-Εγγραφής (Read-Write Locks):

  • Επιτρέπει πολλαπλούς αναγνώστες ή έναν συγγραφέα ταυτόχρονα, διευκολύνοντας την αποτελεσματική πρόσβαση σε κοινά δεδομένα.

  • Κλείδωμα Ανάγνωσης-Εγγραφής (Υπογραφή: 0x52574c4b): Μέγεθος 196 bytes.

  • Χαρακτηριστικά Κλειδώματος Ανάγνωσης-Εγγραφής (Υπογραφή: 0x52574c41): Χαρακτηριστικά για τα κλειδώματα ανάγνωσης-εγγραφής, μεγέθους 20 bytes.

Τα τελευταία 4 bytes αυτών των αντικειμένων χρησιμοποιούνται για την ανίχνευση υπερχείλισης.

Τοπικές Μεταβλητές Νήματος (TLV)

Οι Τοπικές Μεταβλητές Νήματος (TLV) στο πλαίσιο των αρχείων Mach-O (το μορφότυπο για εκτελέσιμα στο macOS) χρησιμοποιούνται για να δηλώσουν μεταβλητές που είναι συγκεκριμένες για κάθε νήμα σε μια εφαρμογή πολλαπλών νημάτων. Αυτό εξασφαλίζει ότι κάθε νήμα έχει τη δική του ξεχωριστή περίπτωση μιας μεταβλητής, παρέχοντας έναν τρόπο για να αποφευχθούν συγκρούσεις και να διατηρηθεί η ακεραιότητα των δεδομένων χωρίς την ανάγκη εμφανούς μηχανισμών συγχρονισμού όπως τα κλειδώματα.

Σε γλώσσες όπως η C και συναφείς, μπορείτε να δηλώσετε μια μεταβλητή τοπικού νήματος χρησιμοποιώντας τη λέξη-κλειδί __thread. Έτσι λειτουργεί στο παράδειγμά σας:

cCopy code__thread int tlv_var;

void main (int argc, char **argv){
tlv_var = 10;
}

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

Στο δυαδικό Mach-O, τα δεδομένα που σχετίζονται με τις τοπικές μεταβλητές νημάτων οργανώνονται σε συγκεκριμένες ενότητες:

  • __DATA.__thread_vars: Αυτή η ενότητα περιέχει τα μεταδεδομένα σχετικά με τις τοπικές μεταβλητές νημάτων, όπως οι τύποι τους και η κατάσταση αρχικοποίησης.

  • __DATA.__thread_bss: Αυτή η ενότητα χρησιμοποιείται για τοπικές μεταβλητές νημάτων που δεν αρχικοποιούνται ρητά. Είναι μέρος της μνήμης που διατίθεται για δεδομένα που αρχικοποιούνται με μηδενικές τιμές.

Το Mach-O παρέχει επίσης μια συγκεκριμένη διεπαφή API που ονομάζεται tlv_atexit για τη διαχείριση των τοπικών μεταβλητών νημάτων όταν ένα νήμα τερματίζεται. Αυτή η API σάς επιτρέπει να καταχωρίσετε καταστροφείς - ειδικές συναρτήσεις που καθαρίζουν τα δεδομένα τοπικών μεταβλητών όταν ένα νήμα τερματίζεται.

Python Ενσωμάτωση

Εάν η μεταβλητή περιβάλλοντος PYTHONINSPECT είναι ορισμένη, η διαδικασία python θα μεταβεί σε ένα python cli μόλις ολοκληρωθεί. Είναι επίσης δυνατόν να χρησιμοποιηθεί το PYTHONSTARTUP για να υποδείξει ένα σενάριο python που θα εκτελεστεί στην αρχή μιας διαδραστικής συνεδρίας. Ωστόσο, σημειώστε ότι το σενάριο PYTHONSTARTUP δεν θα εκτελεστεί όταν το PYTHONINSPECT δημιουργεί τη διαδραστική συνεδρία.

Άλλες μεταβλητές περιβάλλοντος όπως το PYTHONPATH και το PYTHONHOME θα μπορούσαν επίσης να είναι χρήσιμες για να κάνουν μια εντολή python να εκτελέσει αυθαίρετο κώδικα.

Σημειώστε ότι τα εκτελέσιμα που έχουν συνταχθεί με το pyinstaller δεν θα χρησιμοποιήσουν αυτές τις μεταβλητές περιβάλλοντος ακόμη κι αν εκτελούνται χρησιμοποιώντας ένα ενσωματωμένο python.

Συνολικά, δεν μπόρεσα να βρω έναν τρόπο για να κάνω την python να εκτελέσει αυθαίρετο κώδικα καταχρώμενη τις μεταβλητές περιβάλλοντος. Ωστόσο, οι περισσότεροι άνθρωποι εγκαθιστούν την python χρησιμοποιώντας το Hombrew, το οποίο θα εγκαταστήσει την python σε μια εγγράψιμη τοποθεσία για τον προεπιλεγμένο διαχειριστή χρήστη. Μπορείτε να το αρπάξετε με κάτι σαν:

mv /opt/homebrew/bin/python3 /opt/homebrew/bin/python3.old
cat > /opt/homebrew/bin/python3 <<EOF
#!/bin/bash
# Extra hijack code
/opt/homebrew/bin/python3.old "$@"
EOF
chmod +x /opt/homebrew/bin/python3

Ακόμα και ο root θα εκτελέσει αυτόν τον κώδικα όταν τρέχει την python.

Ανίχνευση

Shield

Shield (Github) είναι μια εφαρμογή ανοιχτού κώδικα που μπορεί να ανιχνεύσει και να μπλοκάρει ενέργειες εισαγωγής διεργασιών:

  • Χρησιμοποιώντας Μεταβλητές Περιβάλλοντος: Θα παρακολουθεί την ύπαρξη οποιασδήποτε από τις ακόλουθες μεταβλητές περιβάλλοντος: DYLD_INSERT_LIBRARIES, CFNETWORK_LIBRARY_PATH, RAWCAMERA_BUNDLE_PATH και ELECTRON_RUN_AS_NODE

  • Χρησιμοποιώντας κλήσεις task_for_pid: Για να βρει όταν μια διεργασία θέλει να πάρει τη θύρα εργασίας μιας άλλης που επιτρέπει την εισαγωγή κώδικα στη διεργασία.

  • Παράμετροι εφαρμογών Electron: Κάποιος μπορεί να χρησιμοποιήσει τις παραμέτρους γραμμής εντολών --inspect, --inspect-brk και --remote-debugging-port για να ξεκινήσει μια εφαρμογή Electron σε λειτουργία εντοπισμού σφαλμάτων και έτσι να εισάγει κώδικα σε αυτήν.

  • Χρησιμοποιώντας συμβολικούς συνδέσμους ή σκληρούς συνδέσμους: Συνήθως το πιο κοινό κακόβουλο είναι να τοποθετήσουμε ένα σύνδεσμο με τα δικαιώματα του χρήστη μας, και να τον κατευθύνουμε προς μια τοποθεσία με υψηλότερα δικαιώματα. Η ανίχνευση είναι πολύ απλή τόσο για σκληρούς όσο και για συμβολικούς συνδέσμους. Αν η διαδικασία που δημιουργεί τον σύνδεσμο έχει διαφορετικό επίπεδο δικαιωμάτων από το αρχείο-στόχο, δημιουργούμε μια ειδοποίηση. Δυστυχώς, στην περίπτωση των συμβολικών συνδέσμων, η αποκλειστική δράση δεν είναι δυνατή, καθώς δεν έχουμε πληροφορίες σχετικά με τον προορισμό του συνδέσμου πριν τη δημιουργία του. Αυτό είναι ένα περιορισμό του πλαισίου EndpointSecuriy της Apple.

Κλήσεις που γίνονται από άλλες διεργασίες

Σε αυτήν την ανάρτηση στο blog μπορείτε να βρείτε πώς είναι δυνατό να χρησιμοποιηθεί η συνάρτηση task_name_for_pid για να λάβετε πληροφορίες σχετικά με άλλες διεργασίες που εισάγουν κώδικα σε μια διεργασία και στη συνέχεια να λάβετε πληροφορίες σχετικά με αυτήν την άλλη διεργασία.

Σημειώστε ότι για να καλέσετε αυτήν τη συνάρτηση πρέπει να είστε το ίδιο uid με αυτόν που εκτελεί τη διεργασία ή root (και επιστρέφει πληροφορίες σχετικά με τη διεργασία, όχι έναν τρόπο για εισαγωγή κώδικα).

Αναφορές

Μάθετε το χάκινγκ στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι υποστήριξης του HackTricks:

Last updated