[go: up one dir, main page]

Μετάβαση στο περιεχόμενο

Υπερχείλιση προσωρινής μνήμης

Από τη Βικιπαίδεια, την ελεύθερη εγκυκλοπαίδεια

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

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

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

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

Στο ακόλουθο παράδειγμα (κώδικας σε γλώσσα C), ένα πρόγραμμα έχει δύο μεταβλητές, οι οποίες είναι γειτονικές στην μνήμη: μία συμβολοσειρά με μήκος 8 bytes ονόματι Α και ένας ακέραιος μεγάλου άκρου (big-endian) μήκους 2 bytes ονόματι Β.

char           A[8] = "";
unsigned short B    = 1979;

Αρχικά, η μεταβλητή Α περιέχει μονάχα μηδενικά bytes, ενώ η μεταβλητή Β περιέχει τον αριθμό 1979.

όνομα μεταβλητής A B
τιμή [null συμβολοσειρά] 1979
δεκαεξαδική τιμή 00 00 00 00 00 00 00 00 07 BB

Έστω, ότι το πρόγραμμα επιχειρεί να αποθηκεύσει στην περιοχή προσωρινής μνήμης που βρίσκεται η μεταβλητή Α την μηδενικά-τερματισμένη συμβολοσειρά “excessive”, η οποία είναι κωδικοποιημένη σε ASCII.

strcpy(A, "excessive");

Η συμβολοσειρά “excessive” έχει μήκος 9 χαρακτήρες και η κωδικοποίησή της αποτελείται από 10 bytes (περιλαμβάνοντας και το null στο τέλος). Όμως, στην περιοχή Α η μέγιστη χωρητικότητα είναι 8 bytes. Έτσι, εάν επιχειρηθεί η αποθήκευση της συμβολοσειράς στην περιοχή αυτή, δίχως να προηγηθεί έλεγχος ορίων, θα αντικατασταθεί και η τιμή της Β:

όνομα μεταβλητής A B
τιμή 'e' 'x' 'c' 'e' 's' 's' 'i' 'v' 25856
δεκαεξαδική τιμή 65 78 63 65 73 73 69 76 65 00

Η τιμή της μεταβλητής Β έχει τροποποιηθεί χάρη στο τμήμα της συμβολοσειράς “excessive” που περίσσευε. Έτσι, ο χαρακτήρας “e” ακολουθούμενος από ένα μηδενικό byte (ο χαρακτήρας NUL σε κωδικοποίηση ASCII) αποδίδεται ως 28856 και συντελεί στην διαμόρφωση της μνήμης όπως φαίνεται παραπάνω.

Ένας απλός τρόπος να αποφευχθεί η υπερχείλιση αυτή είναι η αντικατάσταση της μεθόδου strcpy με την strlcpy. Αυτό γιατί η strlcpy λαμβάνει μία επιπλέον παράμετρο: την μέγιστη χωρητικότητα του προορισμού αντιγραφής (συμπεριλαμβανομένου και του χαρακτήρα τερματισμού NULL) και διασφαλίζει ότι τα δεδομένα που θα εγγραφούν δεν θα την υπερβούν. Έτσι, στο παραπάνω παράδειγμα, η αντίστοιχη κλήση θα ήταν:

strlcpy(A, "excessive", sizeof(A));

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

Υπερχείλιση στοίβας

[Επεξεργασία | επεξεργασία κώδικα]

Ένας επιτιθέμενος θα μπορούσε να εκμεταλλευτεί μία υπερχείλιση στοίβας με έναν από τους ακόλουθους τρόπους:

  1. Αντικαθιστώντας μια τοπική μεταβλητή η οποία βρίσκεται κοντά στην ευπαθή προσωρινή μνήμη ώστε να αλλάξει η εκτέλεση και κατά συνέπεια η συμπεριφορά του προγράμματος.
  2. Αντικαθιστώντας την διεύθυνση επιστροφής ενός πλαισίου στοίβας, ώστε να δείχνει σε κώδικα επιλεγμένο από τον επιτιθέμενο, ο οποίος συνήθως ονομάζεται κώδικας κελύφους (shellcode). Μόλις η συνάρτηση επιστρέψει, η εκτέλεση θα συνεχιστεί με τον κώδικα του επιτιθέμενου.
  3. Αντικαθιστώντας έναν δείκτη συνάρτησης (function pointeerer),[1] ώστε να δείχνει σε κώδικα κελύφους, ο οποίος εκτελείται ακολούθως.
  4. Αντικαθιστώντας μία τοπική μεταβλητή (ή έναν δείκτη) ενός διαφορετικού πλαισίου στοίβας, η οποία θα χρησιμοποιηθεί αργότερα από την συνάρτηση στην οποία αντιστοιχεί αυτό το πλαίσιο.[2]

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

Μία τεχνική που χρησιμοποιείται συνήθως σε τέτοιες επιθέσεις είναι η “trampolining”. Χρησιμοποιώντας αυτή την τεχνική ο επιτιθέμενος επιχειρεί να βρει έναν δείκτη προς την ευάλωτη περιοχή προσωρινής μνήμης και να υπολογίσει την τοποθεσία του κώδικα κελύφους του συναρτήσει αυτού του δείκτη. Έπειτα, χρησιμοποιεί την αντικατάσταση δεδομένων, ώστε να μεταπηδήσει σε μία εντολή που βρίσκεται ήδη στην μνήμη από όπου θα γίνει ένα δεύτερο άλμα, το οποίο μεταφέρει την εκτέλεση του κώδικα στον κώδικα κελύφους. Κατάλληλες εντολές (instructions) εντοπίζονται συχνά σε κώδικα μεγάλης έκτασης, αν και πλέον, υπάρχουν εργαλεία αυτοματοποίησης της διαδικασίας. Για παράδειγμα, το Metsploit Project διαθέτει μία βάση δεδομένων με εντολές που μπορούν να χρησιμοποιηθούν σε τέτοιες περιπτώσεις.[3]

Υπερχείλιση σωρού

[Επεξεργασία | επεξεργασία κώδικα]

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

Πρακτικές εκμετάλλευσης

[Επεξεργασία | επεξεργασία κώδικα]

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

Τεχνική «έλκηθρο-NOP» (NOP-sled)

[Επεξεργασία | επεξεργασία κώδικα]

Πρόκειται για την αρχαιότερη και ευρύτερα γνωστή τεχνική εκμετάλλευσης μίας υπερχείλισης στοίβας.[4] Η χρησιμότητα της έγκειται στο γεγονός ότι ο ακριβής προσδιορισμός της διεύθυνσης εκκίνησης του κώδικα κελύφους δεν είναι πλέον απαραίτητος. Πιο συγκεκριμένα, ο κώδικας κελύφους τοποθετείται στο τέλος του προσωρινού χώρου αποθήκευσης, ενώ ο χώρος που προηγείται καταλαμβάνεται από εντολές NOP (no-operation), οι οποίες ουσιαστικά δεν εκτελούν κάποια λειτουργία. Έτσι, η διεύθυνση επιστροφής δεν χρειάζεται, πλέον, να είναι εκείνη του κώδικα κελύφους, αλλά κάποια διεύθυνση που αντιστοιχεί σε σημείο εντός του σώματος εντολών NOP. Από εκεί, η εκτέλεση του προγράμματος θα «ολισθήσει» (εξού και ο όρος έλκηθρο), εκτελώντας τις εντολές NOP, έως ότου συναντήσει την αρχή του κώδικα κελύφους.[5]

Η τεχνική αυτή είναι αρκετά δημοφιλής, με αποτέλεσμα πολλά Συστήματα Ανίχνευσης Εισβολής να αναζητούν για ακολουθίες εντολών no-op στην προσπάθειά τους να ανιχνεύσουν τον κακόβουλο κώδικα κελύφους. Ωστόσο, είναι σημαντικό να αναφερθεί πως ένα έλκηθρο-NOP δεν αποτελείται απαραίτητα, μονάχα από no-op εντολές, αλλά και από οποιαδήποτε άλλη εντολή δεν αλλοιώνει την κατάσταση του συστήματος σε σημείο που να μην επιτρέπει την εκτέλεση του κώδικα κέλυφους. Συνεπώς, είναι σύνηθες φαινόμενο, η ακολουθία των εντολών του «ελκήθρου» να περιλαμβάνει εντολές που πρακτικά ισοδυναμούν με no-op εντολές και δεν επιφέρουν κάποια σημαντική αλλαγή, όπως η αύξηση ή μείωση της τιμής μίας εγγραφής.[6]

Ωστόσο, υπάρχουν φορές που είτε το μέγεθος της περιοχής προσωρινής μνήμης που επιχειρεί ο επιτιθέμενος να υπερχειλίσει είναι αρκετά μικρό για να χωρέσει ο κώδικας κελύφους είτε το μέγεθος του ελκήθρου είναι τόσο μικρό ώστε η πιθανότητα να μαντέψει κανείς μία διεύθυνσή αυτού είναι μηδαμινή. Βέβαια, ακόμα και υπό αυτές τις συνθήκες, μία επίθεση υπερχείλισης στοίβας είναι εφικτή (π.χ. με τοποθέτηση του κώδικα κελύφους σε μεταβλητή περιβάλλοντος).[5]

Τέλος, ένα ακόμη πρόβλημα που συναντά κανείς στην εφαρμογή της συγκεκριμένης τεχνικής είναι η δυσκολία εντοπισμού της απόστασης της θέσης της διεύθυνσης επιστροφής από την κορυφή της στοίβας (δηλαδή από το σώμα εντολών no-op).

Τεχνική «άλμα προς καταχωρητή»

[Επεξεργασία | επεξεργασία κώδικα]

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

Μία κλήση της ρουτίνας DgbPrint, η οποία περιέχει κώδικα μηχανής που ερμηνεύεται ως jmp esp.

Στην πράξη, ένας προγραμματιστής δεν θα περιλάβει από πρόθεση εντολές που θα οδηγήσουν σε έναν συγκεκριμένο καταχωρητή. Κατά συνέπεια, ένας επιτιθέμενος θα επιχειρήσει να εντοπίσει τυχαίες εμφανίσεις τέτοιων εντολών μέσα στην μνήμη. Μια τέτοια περίπτωση φαίνεται στην διπλανή εικόνα όπου τυχαία εμφανίζεται η jmp esp με μνημονική εντολή (opcode) το FF E4. Αυτή η δυάδα από bytes μπορεί να βρεθεί σε απόσταση ενός byte από την αρχή της εντολής call DbgPrint στη διεύθυνση 0x7C941EED. Έστω ότι ο κώδικας κελύφους βρίσκεται αμέσως μετά την διεύθυνση επιστροφής. Αυτό σημαίνει ότι μόλις η διεύθυνση επιστροφής αφαιρεθεί (pop) από την στοίβα, τότε ο καταχωρητής esp (δείχνει πάντοτε στην κορυφή της στοίβας) θα δείχνει στην αρχή του κώδικα κελύφους. Συνεπώς, για να εκτελεστεί ο κακόβουλος κώδικας αρκεί ένα «άλμα» από την διεύθυνση επιστροφής προς τον καταχωρητή esp. Αυτό το άλμα μπορεί να επιτευχθεί εύκολα μέσω της εντολής jmp esp. Εαν ένας κακόβουλος χρήστης καταφέρει να αντικαταστήσει την διεύθυνση επιστροφής της συνάρτησης με αυτή τη διεύθυνση θα είναι σε θέση να πετύχει την επίθεσή του.[7]

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

Επιλογή γλώσσας προγραμματισμού

[Επεξεργασία | επεξεργασία κώδικα]

Δημοφιλείς γλώσσες προγραμματισμού που είναι ευάλωτες σε μία υπερχείλιση προσωρινής αποθήκευσης είναι όπως αναφέραμε νωρίτερα οι C και C++.[8] Αυτό οφείλεται εν μέρει στο γεγονός ότι επιτρέπουν την απευθείας πρόσβαση στην μνήμη. Η C δεν παρέχει κάποιον ενσωματωμένο μηχανισμό προστασίας ενάντια στην πρόσβαση και αντικατάσταση των δεδομένων οποιουδήποτε μέρους της μνήμης. Πιο συγκεκριμένα, δεν ελέγχεται εάν το μέγεθος των δεδομένων που εγγράφονται είναι εντός των ορίων της περιοχής προσωρινής αποθήκευσης. Οι γλώσσες προγραμματισμού που βασίζονται σε ισχυρά συστήματα τύπων, όπως η Java και η Python δεν επιτρέπουν την απευθείας πρόσβαση στην μνήμη και έτσι, αποτρέπουν τις υπερχειλίσεις. Τέλος, οι περισσότερες γλώσσες που βασίζονται σε διερμηνείς (scripting languages) προσφέρουν και αυτές προστασία.[8]

Χρήση ασφαλών βιβλιοθηκών

[Επεξεργασία | επεξεργασία κώδικα]

Συνίσταται η αποφυγή χρήσης συναρτήσεων όπως oi gets, scanf, strcpy, sprintf, strcat, καθώς και όλων των συναρτήσεων που δεν πραγματοποιούν έλεγχο του μήκους των δεδομένων εισόδου. Το σκουλήκι Morris, για παράδειγμα, εκμεταλλευόταν μίας κλήση της μεθόδου gets στην υλοποίηση της μεθόδου fingerd του πρωτοκόλλου Finger.[9] Για τον λόγο αυτόν, συνίσταται η χρήση των ισοδύναμων συναρτήσεων: fgets, strncpy, snprintf, strncat κ.ο.κ.

Οι κύριοι τύποι δεδομένων που ευθύνονται για την υπερχείλιση μιας περιοχής προσωρινής αποθήκευσης είναι οι συμβολοσειρές (Strings) και οι πίνακες (arrays). Συνεπώς, οι βιβλιοθήκες που προλαμβάνουν μία υπερχείλιση κατά την χρήση των συγκεκριμένων τύπων παρέχουν ένα μεγάλο μέρος της απαιτούμενης προστασίας. Ορισμένες ασφαλείς βιβλιοθήκες συμβολοσειράς στην C είναι οι: “The Better String Library”[10], Vstr[11] και η safestringlib, που αναπτύσσεται από ομάδα της Intel.

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

Προστασία δεικτών

[Επεξεργασία | επεξεργασία κώδικα]

Μία υπερχείλιση προσωρινής μνήμης λειτουργεί χάρη στην χειραγώγηση ενός δείκτη, ο οποίος ουσιαστικά είναι μία διεύθυνση μνήμης που περιέχει σαν τιμή μία άλλη διεύθυνση μνήμης (στην οποία και «δείχνει»). Το PointGuard είχε προταθεί ως μία επέκταση του μεταγλωττιστή, η οποία στόχευε στην κρυπτογράφηση των δεικτών ενόσω αυτοί βρίσκονται στην μνήμη και στην αποκρυπτογράφησή τους προτού αποκτηθεί η διεύθυνση στην οποία «δείχνει» ο δείκτης (de-referencing). Η κρυπτογράφηση και αποκρυπτογράφηση επιτυγχάνεται μέσω της λογικής πράξης XOR («αποκλειστικό ή») και χρησιμοποιώντας κλειδιά των 32 bits.[12]

Το PointGuard, ωστόσο, δεν κυκλοφόρησε ποτέ, αν και η Microsoft υλοποίησε έναν παρόμοιο μηχανισμό που χρησιμοποιήθηκε στα Windows XP SP2 και τον Windows Server 2003 SP1. Η προστασία όμως σε αυτές τις περιπτώσεις, δεν παρέχεται αυτομάτως και ο προγραμματιστής θα πρέπει να καλέσει μία διαδικασία κάνοντας χρήση μιας Διεπαφής Προγραμματισμού Εφαρμογής. Έτσι, αν και δεν επιβαρύνεται η απόδοση του προγράμματος με διαρκείς ελέγχους, ο προγραμματιστής καθίσταται υπεύθυνος για την κλήση της διαδικασίας όποτε κρίνει πως είναι απαραίτητο.[13]

Προστασία εκτελέσιμου χώρου

[Επεξεργασία | επεξεργασία κώδικα]

Η εν λόγω τεχνική εφαρμόζεται για να αποτρέψει την εκτέλεση κώδικα στην στοίβα ή τον σωρό. Πιο συγκεκριμένα, ορισμένες περιοχές της μνήμης χαρακτηρίζονται ως μη εκτελέσιμες (“No eXecute” ή NX bit), με αποτέλεσμα ο εκάστοτε αυθαίρετος κώδικας κελύφους, που τυχόν βρεθεί σε κάποια από τις περιοχές αυτές λόγω υπερχείλισης, να μην μπορεί να εκτελεστεί.

Κάποια λειτουργικά συστήματα που βασίζονται στο Unix (όπως π.χ. το OpenBSD, το macOS) έχουν ενσωματωμένο έναν μηχανισμό προστασίας εκτελέσιμου χώρου (π.χ. το W^X).

Οι νεότερες εκδόσεις των Windows παρέχουν και εκείνες προστασία εκτελέσιμου χώρου, η οποία αποκαλείται «Πρόληψη Εκτέλεσης Δεδοιμένων» (Data Execution Prevention).[14]

Βέβαια, ο εν λόγω μηχανισμός προστασίας δεν παρέχει προστασία ενάντια σε επιθέσεις που δεν βασίζονται στην εκτέλεση του κώδικα κελύφους που εισάγει ο επιτιθέμενος, όπως μία return-to-libc επίθεση. Τέτοιες επιθέσεις βασίζονται στην εκτέλεση κώδικα που υπάρχει σε διαφορετικό μέρος της μνήμης, το οποίο είναι εκτελέσιμο. Ωστόσο, σε 64-bit συστήματα που χρησιμοποιούν μεθόδους όπως ή «Τυχαία Διάταξη Χώρου Διευθύνσεων», η ύπαρξη προστασίας εκτελέσιμου χώρου καθιστά ιδιαίτερα δύσκολη μία επίθεση υπερχείλισης μνήμης.

Η λογική πίσω από αυτήν την μέθοδο είναι η διενέργεια ενός ελέγχου για τυχόν αλλοιώσεις στην στοίβα προτού χρησιμοποιηθεί η διεύθυνση επιστροφής. Αυτό επιτυγχάνεται με την χρήση μιας τιμής «καναρνιού», η οποία τοποθετείται στην στοίβα μετά τον δείκτη του προηγούμενου πλαισίου και κατ’ επέκταση μετά την διεύθυνση επιστροφής. Εφόσον, όμως, η στοίβα είναι μία LIFO (Last In - First Out) δομή δεδομένων, το «καναρίνι» θα εξέλθει νωρίτερα από την στοίβα συγκριτικά με την διεύθυνση επιστροφής. Αυτό σημαίνει ότι η τιμή του «καναρινιού» ελέγχεται πριν από την διεύθυνση επιστροφής και σε περίπτωση που έχει αλλοιωθεί, τότε το πρόγραμμα τερματίζεται, διότι έχει συμβεί μία επίθεση υπερχείλισης προσωρινής μνήμης. Ο αμυντικός αυτός μηχανισμός βασίζεται στην ιδέα ότι οποιαδήποτε προσπάθεια αντικατάστασης της διεύθυνσης επιστροφής θα έπρεπε πρώτα να αλλοιώσει την τιμή του «καναρινιού», αφού αυτή προηγείται. Η συγκεκριμένη μέθοδος προτάθηκε για πρώτη φορά το 1998 ως μέρος του StackGuard, μίας επέκτασης του μεταγλωττιστή gcc.[15][16] Αξίζει να αναφερθεί πως η τιμή «καναρινού» τοποθετούταν, αρχικά, ανάμεσα στην διεύθυνση επιστροφής και στον δείκτη προηγούμενου πλαισίου. Ωστόσο, αυτή η πρακτική δεν ισχύει από το StackGuard 3.0 και έπειτα, καθώς ήταν ευάλωτη σε επιθέσεις υπερχείλισης που στόχευαν τον δείκτη προηγούμενου πλαισίου.[17]

Τυχαία Διάταξη Χώρου Διευθύνσεων

[Επεξεργασία | επεξεργασία κώδικα]

Προκειμένου να επιτύχει η κλασική επίθεση υπερχείλισης μνήμης, ο επιτιθέμενος χρειάζεται να προβλέψει μία διεύθυνση-στόχο, ούτως ώστε αυτή να τεθεί ως διεύθυνση επιστροφής και συνεπώς, να μεταβιβάσει την ροή εκτέλεσης στον κώδικα κελύφους (είτε απευθείας είτε μέσω ενός «ελκήθρου» από NOP εντολές). Η μέθοδος Τυχαίας Διάταξης Χώρου Διευθύνσεων (Address Space Layout Randomization ή ASLR εν συντομία) μπορεί να αναχαιτίσει αποτελεσματικά την παραπάνω διαδικασία, αλλάζοντας με τυχαίο τρόπο την διάταξη των διάφορων τμημάτων της μνήμης, συπεριλαμβανομένων των δεδομένων και του κώδικα.[18] Ακόμη, η μέθοδος αυτή συνδράμει σημαντικά ενάντια σε επιθέσεις που προσπαθούν να εκμεταλλευτούν τον υπάρχοντα κώδικα βιβλιοθηκών, ο οποίος φορτώνεται σε συγκεκριμένη διεύθυνση, εφόσον τυχαιοποιείται και αυτή.

  1. «SecurityFocus». www.securityfocus.com. Αρχειοθετήθηκε από το πρωτότυπο στις 26 Σεπτεμβρίου 2020. Ανακτήθηκε στις 24 Σεπτεμβρίου 2020. 
  2. Wimberley, Eric· Harrison, Nathan (24 Μαΐου 2013). «Modern Overflow Targets» (PDF). Ανακτήθηκε στις 24 Σεπτεμβρίου 2020. 
  3. «The Metasploit Opcode Database». metasploit. Αρχειοθετήθηκε από το πρωτότυπο στις 12 Μαΐου 2007. Ανακτήθηκε στις 24 Σεπτεμβρίου 2020. 
  4. «Stack-based Overflow Exploit». 8 Δεκεμβρίου 2004. Αρχειοθετήθηκε από το πρωτότυπο στις 18 Αυγούστου 2007. Ανακτήθηκε στις 24 Σεπτεμβρίου 2020. 
  5. 5,0 5,1 One, Aleph (1996-11-08). «Smashing The Stack For Fun And Profit». Phrack Magazine. http://phrack.org/issues/49/14.html. Ανακτήθηκε στις 2020-09-24. 
  6. Akritidis, Periklis & Markatos, Evangelos & Polychronakis, Michalis & Anagnostakis, Kostas. (2005). STRIDE: Polymorphic Sled Detection through Instruction Sequence Analysis.. International Federation for Information Processing Digital Library; Security and Privacy in the Age of Ubiquitous Computing;. 375-392. 10.1007/0-387-25660-1_25.
  7. Alvarez, Sergio (5 Σεπτεμβρίου 2004). «Win32 Stack BufferOverFlow Real Life Vuln-Dev Process» (PDF). Ανακτήθηκε στις 24 Σεπτεμβρίου 2020. 
  8. 8,0 8,1 «Buffer Overflow | OWASP». owasp.org (στα Αγγλικά). Ανακτήθηκε στις 24 Σεπτεμβρίου 2020. 
  9. Spafford, Eugene. (2000). The Internet Worm Program: An Analysis. ACM SIGCOMM Computer Communication Review. 19. 10.1145/66093.66095. Ανακτήθηκε στις 24 Σεπτεμβρίου 2020. Διαθέσιμο από: https://spaf.cerias.purdue.edu/tech-reps/823.pdf
  10. «The Better String Library». bstring.sourceforge.net. Ανακτήθηκε στις 24 Σεπτεμβρίου 2020. 
  11. «Vstr documentation -- overview». www.and.org. Ανακτήθηκε στις 24 Σεπτεμβρίου 2020. 
  12. Cowan, Crispin & Beattie, Steve & Johansen, John & Wagle, Perry. (2003). Pointguard TM : protecting pointers from buffer overflow vulnerabilities. 7-7. Ανακτήθηκε στις 24 Σεπτεμβρίου 2020.
  13. Howard, Michael (30 Ιανουαρίου 2006). «Protecting against Pointer Subterfuge (Kinda!)». 
  14. «Data Execution Prevention - Win32 apps». docs.microsoft.com (στα Αγγλικά). Ανακτήθηκε στις 24 Σεπτεμβρίου 2020. 
  15. Cowan, Crispin & Pu, Calton & Maier, Dave & Hintony, Heather & Walpole, Jonathan & Bakke, Peat & Beattie, Steve & Grier, Aaron & Wagle, Perry & Zhang, Qian. (1998). StackGuard: Automatic adaptive detection and prevention of buffer-overflow attacks. 98. 5-5.
  16. «Security Technologies: Stack Smashing Protection (StackGuard)». Red Hat Customer Portal (στα Αγγλικά). Ανακτήθηκε στις 24 Σεπτεμβρίου 2020. 
  17. Richarte, Gerardo. (2002). Four different tricks to bypass stackshield and stackguard protection.
  18. Szekeres, Laszlo & Payer, Mathias & Wei, Tao & Song, Dawn. (2013). Eternal War in Memory. IEEE Security & Privacy. 12. 48-62. 10.1109/SP.2013.13.