DDexec / EverythingExec
Πλαίσιο
Στο Linux, για να εκτελεστεί ένα πρόγραμμα πρέπει να υπάρχει ως ένα αρχείο, πρέπει να είναι προσβάσιμο με κάποιον τρόπο μέσω της ιεραρχίας του συστήματος αρχείων (αυτό είναι απλώς πώς λειτουργεί η execve()
). Αυτό το αρχείο μπορεί να βρίσκεται στο δίσκο ή στη μνήμη (tmpfs, memfd) αλλά χρειάζεστε ένα διαδρομή αρχείου. Αυτό έχει καταστήσει πολύ εύκολο τον έλεγχο του τι εκτελείται σε ένα σύστημα Linux, καθιστά εύκολο τον εντοπισμό απειλών και εργαλείων εισβολέα ή την αποτροπή τους από το να προσπαθήσουν να εκτελέσουν οτιδήποτε δικό τους εντελώς (π.χ. να μην επιτρέπεται σε μη προνομιούχους χρήστες να τοποθετήσουν εκτελέσιμα αρχεία οπουδήποτε).
Αλλά αυτή η τεχνική είναι εδώ για να αλλάξει όλα αυτά. Αν δεν μπορείτε να ξεκινήσετε τη διαδικασία που θέλετε... τότε αρπάξτε μια που υπάρχει ήδη.
Αυτή η τεχνική σάς επιτρέπει να παρακάμψετε κοινές τεχνικές προστασίας όπως read-only, noexec, λευκή λίστα ονομάτων αρχείων, λευκή λίστα κατακευής...
Εξαρτήσεις
Το τελικό σενάριο εξαρτάται από τα ακόλουθα εργαλεία για να λειτουργήσει, πρέπει να είναι προσβάσιμα στο σύστημα που επιτίθεστε (από προεπιλογή θα τα βρείτε παντού):
Η τεχνική
Εάν μπορείτε να τροποποιήσετε αυθαίρετα τη μνήμη ενός διεργασίας τότε μπορείτε να την αναλάβετε. Αυτό μπορεί να χρησιμοποιηθεί για να απαγάγετε μια ήδη υπάρχουσα διεργασία και να την αντικαταστήσετε με ένα άλλο πρόγραμμα. Μπορούμε να το επιτύχουμε είτε χρησιμοποιώντας την κλήση συστήματος ptrace()
(η οποία απαιτεί να έχετε τη δυνατότητα να εκτελέσετε κλήσεις συστήματος ή να έχετε το gdb διαθέσιμο στο σύστημα) ή, πιο ενδιαφέρον, γράφοντας στο /proc/$pid/mem
.
Το αρχείο /proc/$pid/mem
είναι μια αντιστοίχιση ενός προς ένα ολόκληρου του χώρου διεύθυνσης μιας διεργασίας (π.χ. από 0x0000000000000000
έως 0x7ffffffffffff000
σε x86-64). Αυτό σημαίνει ότι η ανάγνωση ή η εγγραφή σε αυτό το αρχείο σε μια θέση x
είναι το ίδιο με την ανάγνωση ή την τροποποίηση των περιεχομένων στην εικονική διεύθυνση x
.
Τώρα, έχουμε τέσσερα βασικά προβλήματα που πρέπει να αντιμετωπίσουμε:
Γενικά, μόνο ο ριζικός χρήστης και ο ιδιοκτήτης του προγράμματος μπορούν να το τροποποιήσουν.
ASLR.
Εάν προσπαθήσουμε να διαβάσουμε ή να γράψουμε σε μια διεύθυνση που δεν έχει αντιστοιχιστεί στον χώρο διεύθυνσης του προγράμματος, θα λάβουμε σφάλμα εισόδου/εξόδου.
Αυτά τα προβλήματα έχουν λύσεις που, αν και δεν είναι τέλειες, είναι καλές:
Τα περισσότερα διερμηνευτές κελύφους επιτρέπουν τη δημιουργία περιγραφέων αρχείων που στη συνέχεια θα κληρονομηθούν από διεργασίες-παιδιά. Μπορούμε να δημιουργήσουμε έναν περιγραφέα που δείχνει στο αρχείο
mem
του κελύφους με δικαιώματα εγγραφής... έτσι οι διεργασίες-παιδιά που χρησιμοποιούν αυτόν τον περιγραφέα θα μπορούν να τροποποιήσουν τη μνήμη του κελύφους.Το ASLR δεν είναι καν πρόβλημα, μπορούμε να ελέγξουμε το αρχείο
maps
του κελύφους ή οποιοδήποτε άλλο από το procfs για να αποκτήσουμε πληροφορίες σχετικά με τον χώρο διεύθυνσης της διεργασίας.Έτσι χρειάζεται να κάνουμε
lseek()
στο αρχείο. Από το κελύφους αυτό δεν μπορεί να γίνει εκτός αν χρησιμοποιήσουμε τον περίφημοdd
.
Λεπτομερειακά
Τα βήματα είναι σχετικά εύκολα και δεν απαιτούν καμία ειδική εμπειρία για να τα κατανοήσετε:
Αναλύστε το δυαδικό που θέλουμε να εκτελέσουμε και τον φορτωτή για να βρούμε ποιες αντιστοιχίσεις χρειάζονται. Στη συνέχεια δημιουργήστε ένα "shell"code που θα εκτελέσει, γενικά μιλώντας, τα ίδια βήματα που κάνει το πυρήνας κάθε φορά που καλείται η
execve()
:Δημιουργήστε τις εν λόγω αντιστοιχίσεις.
Διαβάστε τα δυαδικά σε αυτές.
Διαμορφώστε τα δικαιώματα.
Τέλος, αρχικοποιήστε τη στοίβα με τα ορίσματα για το πρόγραμμα και τοποθετήστε τον βοηθητικό διάνυσμα (απαραίτητο από τον φορτωτή).
Μπείτε στον φορτωτή και αφήστε τον να κάνει τα υπόλοιπα (φόρτωση βιβλιοθηκών που χρειάζεται το πρόγραμμα).
Αποκτήστε από το αρχείο
syscall
τη διεύθυνση στην οποία θα επιστρέψει η διεργασία μετά την κλήση συστήματος που εκτελεί.Αντικαταστήστε αυτό το σημείο, το οποίο θα είναι εκτελέσιμο, με το shellcode μας (μέσω του
mem
μπορούμε να τροποποιήσουμε σελίδες που δεν είναι εγγράψιμες).Περάστε το πρόγραμμα που θέλουμε να εκτελέσουμε στην είσοδο της διεργασίας (θα το διαβάσει το εν λόγω "shell"code).
Σε αυτό το σημείο είναι υπό τον φορτωτή να φορτώσει τις απαραίτητες βιβλιοθήκες για το πρόγραμμά μας και να μπει σε αυτό.
Ελέγξτε το εργαλείο στο https://github.com/arget13/DDexec
EverythingExec
Υπάρχουν αρκετές εναλλακτικές για το dd
, μία εκ των οποίων, το tail
, είναι επί του παρόντος το προεπιλεγμένο πρόγραμμα που χρησιμοποιείται για το lseek()
μέσω του αρχείου mem
(που ήταν ο μοναδικός σκοπός για τον οποίο χρησιμοποιούνταν το dd
). Οι εναλλακτικές αυτές είναι:
Με την ρύθμιση της μεταβλητής SEEKER
μπορείτε να αλλάξετε τον ψάχτη που χρησιμοποιείται, π.χ.:
Αν βρείτε έναν άλλο έγκυρο seeker που δεν έχει εφαρμοστεί στο script, μπορείτε ακόμα να το χρησιμοποιήσετε ρυθμίζοντας τη μεταβλητή SEEKER_ARGS
:
Φράξτε αυτό, EDRs.
Αναφορές
Last updated