**Η SQL injection μπορεί να χωριστή σε 3 κατηγορίες**
INBAND:
Τα δεδομένα εξάγονται χρησιμοποιώντας το ίδιο κανάλι με αυτό που χρησιμοποιείτε για το injection στην SQL. Αυτός είναι ο πιο απλός τύπος επιθέσεις SQL όπου τα δεδομέναπαρουσιάζονται απευθείας στην ιστοσελίδα.
OUT_OF_BAND:
Τα δεδομένα εξάγονται χρησιμοποιώντας διαφορετικό κανάλι (π.χ κάποιο email) δηλαδή τα δεδομένα από το injection στέλνονται σε ένα email που έχει προκαθοριστεί.
INFERENTIAL:
Δεν υπάρχει πραγματική μεταφορά δεδομένων αλλα ο επιτιθέμενος είναι σε θέσει να ανακατασκευάσει τις πληροφορίες με την αποστολή συγκεκριμένου αιτήματος προς την βάση δεδομένων και παρατηρώντας την “συμπεριφορά” αντίδραση του website.
**ΤΥΠΟΙ SQL INJECTION**
ERROR-BASED: Ρωτάμε την Database κάτι που θα προκαλέσει κάποιο error
UNION-BASED:Το SQL union χρησιμοποιείτε για να συνδυάσει τα αποτελέσματα δυο η περισσοτέρων SELECT SQL σε ένα και μονο αποτέλεσμα
#παράδειγμα: http://example.com/page.asp?id=1UNION SELECT ALL 1,2,3,4--
http://example.com/page.asp?id=1UNION SELECT ALL 1,USER,3,4–
BLIND-BASED:Κάνουμε στην Database μια true/false ερώτηση και περιμένουμε εάν θα πάρουμε θετική απαντήσει, δηλαδή εάν θα εμφανιστεί το αποτέλεσμα που ρωτήσαμε, η αλλιώςχρησιμοποιώντας τον χρόνο ως μια παράμετρο
Υπάρχουν δυο τύποι injection που βασίζονται στο εάν ο τύπος του ευπαθές site είναι βασισμένο σε Integer η σε String. Στην περίπτωση του Integer για το injection δεν χρειαζόμαστε αυτό που λέμε single quote(‘)
Στην άλλη περίπτωση όμως του String τότε το single quote(‘) είναι απαραίτητο
Ο Αλέξανδρος είναι ο ιδρυτής του hacks.gr και η κινητήρια δύναμη πίσω από το όραμά μας.
Με πολυετή εμπειρία στον κόσμο του hacking, έχει διαμορφώσει μια κοινότητα που είναι πηγή έμπνευσης και μάθησης για όλους.
Με τον προσωπικό του χαρακτήρα και την τεχνογνωσία του, έχει δημιουργήσει έναν χώρο όπου οι λάτρεις του hacking μπορούν να συναντιούνται, να μοιράζονται γνώσεις και να εξελίσσονται.
Η Pizza Hut της Αυστραλίας προειδοποιεί 193.000 πελάτες για παραβίαση δεδομένων
Η Pizza Hut της Αυστραλίας, στέλνει ειδοποιήσεις παραβίασης δεδομένων στους πελάτες της, προειδοποιώντας ότι μια κυβερνοεπίθεση επέτρεψε σε χάκερς να αποκτήσουν πρόσβαση στις προσωπικές τους πληροφορίες.
Η ειδοποίηση προειδοποιεί ότι ο χάκερ απέκτησε μη εξουσιοδοτημένη πρόσβαση σε συστήματα της Pizza Hut Australia που αποθηκεύουν ευαίσθητες πληροφορίες για πελάτες που έκαναν online παραγγελίες, καθώς και επιμέρους οικονομικά δεδομένα και κρυπτογραφημένους κωδικούς πρόσβασης λογαριασμών.
“Στις αρχές Σεπτεμβρίου αντιληφθήκαμε ένα περιστατικό κυβερνοασφάλειας, κατά το οποίο ένας μη εξουσιοδοτημένος τρίτος είχε πρόσβαση σε ορισμένα δεδομένα της εταιρείας”, αναφέρεται στην ειδοποίηση που εστάλη στους πελάτες.
“Επιβεβαιώσαμε ότι τα δεδομένα που επηρεάστηκαν αφορούν τα στοιχεία του αρχείου πελατών και τις συναλλαγές ηλεκτρονικών παραγγελιών που τηρούνται στη βάση δεδομένων πελατών της Pizza Hut Australia”.
Οι πληροφορίες που έχουν εκτεθεί στους εισβολείς του δικτύου περιλαμβάνουν τα εξής:
Ονοματεπώνυμο
Διεύθυνση αποστολής
Οδηγίες παράδοσης
Διεύθυνση ηλεκτρονικού ταχυδρομείου
Αριθμός τηλεφώνου
Δεδομένα πιστωτικών καρτών
Κρυπτογραφημένοι κωδικοί πρόσβασης για διαδικτυακούς λογαριασμούς
Η αλυσίδα εστιατορίων, η οποία λειτουργεί σε 260 τοποθεσίες στην Αυστραλία, αναφέρει ότι οι παραλήπτες των ειδοποιήσεών της “ενδέχεται να επιθυμούν να εξετάσουν” την ενημέρωση του κωδικού πρόσβασής τους παρά το γεγονός ότι είναι “μονόδρομος κρυπτογραφημένος” στη βάση δεδομένων.
Επιπλέον, η ειδοποίηση καλεί τους πελάτες να επαγρυπνούν για επιθέσεις phishing και ύποπτους συνδέσμους που τους αποστέλλονται μέσω μη ζητηθέντων επικοινωνιών.
Τελικά, η Pizza Hut αναφέρει ότι το περιστατικό επηρεάζει μόνο έναν μικρό αριθμό πελατών της και ότι το Γραφείο του Επιτρόπου Πληροφοριών της Αυστραλίας (OAIC) έχει ενημερωθεί πλήρως για την κατάσταση.
Ο ακριβής αριθμός των επηρεαζόμενων πελατών γνωστοποιήθηκε μέσω δήλωσης εκπροσώπου της Pizza Hut στον Guardian, ο οποίος ανέφερε ότι το περιστατικό επηρέασε 193.000 άτομα.
Προηγούμενα περιστατικά
Στις αρχές Σεπτεμβρίου 2023, το DataBreaches ανέφερε ότι ο διαβόητος μεσίτης δεδομένων “ShinyHunters” ισχυρίστηκε ότι έκλεψε τα δεδομένα 1 εκατομμυρίου πελατών της Pizza Hut Australia.
Ο φορέας απειλών ισχυρίστηκε ότι απέκτησε πρόσβαση μέσω ενός απροστάτευτου τελικού σημείου των Amazon Web Services (AWS) μεταξύ Ιουλίου και Αυγούστου 2023, αποκτώντας πρόσβαση σε μια βάση δεδομένων με 30 εκατομμύρια παραγγελίες.
Η Pizza Hut Australia δεν απάντησε ποτέ σε αυτούς τους ισχυρισμούς, οπότε δεν είναι σαφές αν τα δύο περιστατικά σχετίζονται με οποιονδήποτε τρόπο.
Νωρίτερα φέτος, τον Ιανουάριο του 2023, ο ιδιοκτήτης της Pizza Hut, η Yum! Brands, έγινε στόχος επίθεσης ransomware που ανάγκασε το κλείσιμο τριακοσίων τοποθεσιών στο Ηνωμένο Βασίλειο.
Τον Απρίλιο του 2023, η εταιρεία επιβεβαίωσε ότι οι απειλητές είχαν κλέψει πληροφορίες εργαζομένων από τα δίκτυά της, αν και δεν βρήκε στοιχεία ότι οι πελάτες επηρεάστηκαν από την παραβίαση δεδομένων.
Το XSS (Cross-Site Scripting) είναι μια επίθεση κατά της ασφάλειας των ιστοσελίδων, κατά την οποία ο επιτιθέμενος ενσωματώνει κακόβουλο κώδικα (συνήθως JavaScript) σε μια ιστοσελίδα που ανοίγει σε έναν web browser. Ο κακόβουλος κώδικας εκτελείται στον browser του θύματος, όχι στον διακομιστή, και μπορεί να έχει πολλές επιπτώσεις, συμπεριλαμβανομένης της κλοπής δεδομένων χρηστών, όπως cookies ή συνόδους, την αλλοίωση του περιεχομένου της ιστοσελίδας ή την εκτέλεση επιπλέον επιθέσεων σε βάρος των χρηστών.
Οι βασικές μορφές του XSS περιλαμβάνουν:
Stored XSS (Αποθηκευμένο XSS): Όπου ο κακόβουλος κώδικας αποθηκεύεται στη βάση δεδομένων ή σε ένα αρχείο, και εκτελείται κάθε φορά που ο χρήστης ζητάει να δει τη σελίδα.
Reflected XSS (Ανακλιμένο XSS): Όπου ο κακόβουλος κώδικας περνά από τον browser του θύματος μέσω μιας επικίνδυνης URL ή ενός παραμέτρου σε μια σελίδα.
DOM-based XSS (DOM XSS): Όπου ο κακόβουλος κώδικας τροποποιεί το Document Object Model (DOM) στον browser του θύματος, και η επίθεση εκτελείται κατά την προβολή της σελίδας.
Blind XSS: Όπου ο κακόβουλος κώδικας εκτελείται χωρίς να αφήνει άμεσα αντίδραση στον browser του θύματος. Ο επιτιθέμενος δεν βλέπει την έξοδο, αλλά μπορεί να συλλέγει δεδομένα.
Non-persistent XSS: Όπου ο κακόβουλος κώδικας δεν αποθηκεύεται, αλλά παραδίδεται στο θύμα μέσω κακόβουλων συνδέσμων ή μηνυμάτων. Εκτελείται κατά την προβολή της σελίδας.
Το Cross-Site Scripting (XSS) λειτουργεί με τον εξής τρόπο:
Ενσωμάτωση κακόβουλου κώδικα: Ο επιτιθέμενος ενσωματώνει κακόβουλο κώδικα (συνήθως JavaScript) σε μια ιστοσελίδα, συχνά μέσω εισόδων χρήστη όπως φόρμες, παραμέτρους URL ή σχόλια.
Αποστολή της σελίδας προς το θύμα: Η τροποποιημένη σελίδα στέλνεται στο θύμα, συχνά μέσω κακόβουλων συνδέσμων ή ηλεκτρονικών μηνυμάτων.
Εκτέλεση του κακόβουλου κώδικα: Ο κακόβουλος κώδικας εκτελείται στον web browser του θύματος κατά την προβολή της τροποποιημένης σελίδας. Αυτό συμβαίνει επειδή ο browser εκτελεί όλο τον JavaScript που βρίσκεται στο περιεχόμενο της σελίδας.
Κλοπή δεδομένων ή επιθέσεις: Ο κακόβουλος κώδικας μπορεί να προκαλέσει πολλά διαφορετικά προβλήματα, όπως την κλοπή των cookies σύνδεσης του χρήστη, την αποστολή αιτημάτων εξ’ αποστάσεως εξ ονόματος του χρήστη, την αλλοίωση του περιεχομένου της σελίδας, την απόκτηση προσωπικών πληροφοριών, και πολλά άλλα.
Ο κίνδυνος με το XSS είναι ότι ο κακόβουλος κώδικας εκτελείται με τα δικαιώματα του χρήστη στον browser του, και αυτό μπορεί να έχει επιπτώσεις σε προσωπικά δεδομένα, ευαίσθητες πληροφορίες και την ασφάλεια της σελίδας.
Υπάρχουν διάφορα εργαλεία που μπορείτε να χρησιμοποιήσετε για την εντοπισμό και τον έλεγχο των ευπαθειών Cross-Site Scripting (XSS) σε ιστοσελίδες και εφαρμογές. Αυτά τα εργαλεία σάρωσης και ελέγχου ασφάλειας μπορούν να σας βοηθήσουν να εντοπίσετε και να αποτρέψετε επιθέσεις XSS. Εδώ είναι μερικά από αυτά:
OWASP Zed Attack Proxy (ZAP): Το OWASP ZAP είναι ένα ανοιχτού κώδικα εργαλείο εξερεύνησης ασφαλείας που προσφέρει ανίχνευση και αντιμετώπιση των ευπαθειών XSS, μεταξύ άλλων.
Burp Suite: Το Burp Suite είναι ένα εργαλείο συναχωσίνωσης και ασφαλείας που μπορεί να χρησιμοποιηθεί για τον έλεγχο της ασφάλειας εφαρμογών, συμπεριλαμβανομένης της ανίχνευσης ευπαθειών XSS.
Vega: Το Vega είναι ένα ανοιχτού κώδικα εργαλείο ασφαλείας που μπορεί να χρησιμοποιηθεί για τον έλεγχο της ασφάλειας των ιστοσελίδων και την ανίχνευση ευπαθειών XSS.
Για παράδειγμα. Αν πάτε στην σελίδα http://testphp.vulnweb.com/ (έχει δημιουργηθεί για να εξασκούνται οι νέοι σε θέματα ασφάλειας ) και αναζητήσετε κάτι παράξενο όπως αδσαδσδσζψσσαδσα θα σας εμφανίσει το παρακάτω μήνυμα
searched for: αδσαδσδσζψσσαδσα
Παρατηρούμε δηλαδή ότι το μήνυμα που πληκτρολογήσαμε εμφανίστηκε στην ιστοσελίδα. Τώρα αν αντικαταστήσουμε αυτό το μήνυμα με κώδικα μπορούμε να πετύχουμε πολύ διαφορετικά αποτελέσματα για παράδειγμα αν γράψουμε
<script>alert("This site is vulnerable to xss")</script>
Τότε θα παρατηρήσουμε ότι ο κώδικας μας εκτελείτε και έτσι μπορούμε να πετύχουμε αποτελέσματα που δεν είχαν προβλεφθεί από τους δημιουργούς του site
Όπως ανέφερα δεν χρησιμοποιείται τόσο για επίθεση στην σελίδα όσο για τους χρήστες που υπάρχουν σε αυτήν.
Πως όμως μπορεί αυτός ο τρόπος να βλάψει τους απλούς χρήστες?
Λοιπόν ο επιτιθέμενος έχει την επιλογή να στείλει το url που περιέχει την ευπάθεια σε άλλους χρήστες που χρησιμοποιούν αυτήν την σελίδα και ο κώδικας θα εκτελεστή στον υπολογιστή τους. Στην σελίδα που κοιτάμε εμείς δεν είναι ορατή η μεταβλητή που περιέχει τα δεδομένα που πληκτρολογήσαμε. Αρά ο επιτιθέμενος σε αυτήν την περίπτωση θα έβλεπε μέσο προγραμμάτων η κώδικα τι μεταβλητές υπάρχουν στο url 🙂
και θα έβρισκε ότι μπορούσε να στείλει κάτι τέτοιο στο θύμα του. (Δεν δουλεύει στην περίπτωση μας)
testphp.vulnweb.com/search.php?test=query&searchFor=<script>alert("this site is vulnerable to xss")</script>
Αυτό όμως φαίνεται ότι είναι πειραγμένο και ο χρήστης θα μπορούσε να το καταλάβει εύκολα. Αν όμως το κωδικοποιούσαμε ? ο χρήστης θα έβλεπε κάτι τέτοιο στο facebook/skype κλπ
testphp.vulnweb.com/search.php?test=query&searchFor=<script>alert("Test")</script></script>
Δεν θα έμπαινε στον κόπο να το αποκρυπτογραφήσει και απλά θα το άνοιγε για να δει τη είναι.
Ένας άλλος τρόπος είναι να βρει ευπάθεια σε πράγματα που μένουν για πάντα στο site. πχ σε ένα φόρουμ. Θα μπορούσε να κάνει xss σε κάποιο ποστ και έτσι θα έπεφταν στην παγίδα όλοι όσοι άνοιγαν το θέμα για να το δουν.
Φυσικά δεν θα ήταν τέτοιες εντολές. Η γλώσσα η οποία χρησιμοποιήσαμε λέγετε javascript… Ένας από τους λόγους είναι πως η γλώσσα είναι πιο πλούσια από την html και δίνει την δυνατότητα στον επιτιθέμενο να κλέψει τα cookies και να τα εκμεταλλευτή για να βρει τον κωδικό κάποιου χρήστη
Ο Αλέξανδρος είναι ο ιδρυτής του hacks.gr και η κινητήρια δύναμη πίσω από το όραμά μας. Με πολυετή εμπειρία στον κόσμο του hacking, έχει διαμορφώσει μια κοινότητα που είναι πηγή έμπνευσης και μάθησης για όλους. Με τον προσωπικό του χαρακτήρα και την τεχνογνωσία του, έχει δημιουργήσει έναν χώρο όπου οι λάτρεις του hacking μπορούν να συναντιούνται, να μοιράζονται γνώσεις και να εξελίσσονται.
Το συγκεκριμένο άρθρο είναι το πρώτο μέρος μιας σειράς που θα περιγράψει την αδυναμία Buffer Overflow. Σε αυτό το πρώτο μέρος, θα δώσουμε την απαιτούμενη (στοιχειώδη) γνώση ή σε απλά Ελληνικά: “το απαιτούμενο background”, που χρειάζεται σε κάποιον, ώστε να μπορέσει κατανοήσει τον βαθύτερο λόγο που μπορεί να συμβεί μια τέτοια επίθεση, ώστε να μπορέσει να εφαρμόσει μέτρα (ακόμα και ο ίδιος) μήπως και καταφέρει να μειώσει την πιθανότητα υλοποίησης αυτής της απειλής.
Κάθε εφαρμογή που τρέχουμε στον υπολογιστή μας όσο απλή ή σύνθετη κι αν είναι γράφτηκε από κάποιον προγραμματιστή. Οι αρχές εκτέλεσης ενός προγράμματος είτε πρόκειται για το ίδιο το λειτουργικό σύστημα είτε για ένα ταπεινό πρόγραμμα πρόσθεσης δύο αριθμών είναι παρόμοιες ή σχεδόν παρόμοιες.
Πρώτα απ’ όλα έχουμε το πρόγραμμα που φτιάχνει ο προγραμματιστής το οποίο αποτελείται από εντολές κατανοητές μόνο από ανθρώπους και ονομάζεται πηγαίος κώδικας ή απλά κώδικας. Αυτός ο κώδικας λοιπόν περνάει από μια ειδική επεξεργασία από άλλα προγράμματα που ονομάζονται μεταφραστές (compilers) ή διερμηνευτές (interpreters) για να μεταφραστεί σε κάτι που είναι κατανοητό μόνο (μόνο; Χμ, τέλος πάντων) από τον επεξεργαστή του υπολογιστή μας.
Θα μας πείτε τώρα ποια η διαφορά ενός compiler από έναν interpreter. Χμ, αρκετά μεγάλη: Οι compilers μεταφράζουν όλο τον πηγαίο κώδικα και παράγουν ένα νέο πρόγραμμα που ονομάζεται εκτελέσιμο (το γνωστό exe ή com). Το εκτελέσιμο αρχείο αποτελείται από εντολές μηχανής (όπως λέγονται) και που αντιστοιχούν σε αυτές που γράφτηκαν στον πηγαίο κώδικα. Είναι αυτό το αρχείο που όταν εκτελεστεί θα υλοποιήσει τις εντολές του αντίστοιχου πηγαίου του κώδικα. Μεταγλωττιστές χρησιμοποιούνται συνήθως για να μεταφράσουν κώδικα σε γλώσσες όπως οι C, C++, Pascal, κλπ.
Οι διερμηνευτές (interpreters) από την άλλη, μεταφράζουν τον πηγαίο κώδικα εντολή-εντολή: Τον διαβάζουν στην μνήμη και τον εκτελούν (συνήθως) γραμμή – γραμμή. Δεν παράγουν (…πάντα) κάποιο εκτελέσιμο αρχείο, αφού ο ίδιος ο πηγαίος κώδικας μεταφράζεται και εκτελείτε εκείνη την χρονική στιγμή που διαβάζεται. Διερμηνευτές υπάρχουν για τις γνωστές γλώσσες ανάπτυξης web εφαρμογών όπως η PHP και η ASP.
Η κάθε μια προσέγγιση φυσικά έχει τα καλά της και τα κακά της: Συνήθως τα προγράμματα που έχουν προέλθει από κάποιον compiler είναι πολύ πιο γρήγορα και απαλλαγμένα από συντακτικά λάθη που μπορεί να έκανε ο προγραμματιστής όταν τα έφτιαχνε. Αυτό το τελευταίο ισχύει διότι η συντακτικός έλεγχος γίνεται όταν παράγεται το εκτελέσιμο και αν βρεθεί λάθος, εκτελέσιμο δεν έχει! 😉 Επίσης το εκτελέσιμο είναι (λέμε τώρα…!! πολύ δύσκολο να διαβαστεί από κάποιον τρίτο ο οποίος θα προσπαθήσει (για οποιονδήποτε λόγο) να «κλέψει» τον κώδικα που έγραψε ο προγραμματιστής. Από την άλλη μεριά τα προγράμματα που περνάνε από διερμηνευτές είναι πολύ πιο εύκολα στην συντήρηση, αφού δεν απαιτείται η διαδικασία του compilation (όπως λέγεται) ούτε και απαιτείται κάποιο ξεχωριστό εκτελέσιμο. Για μικρές αλλαγές στον κώδικα είναι ιδανικά και γρήγορα!
Υπάρχει όμως και μια τρίτη κατηγορία που βρίσκεται κάπου στη μέση. Πρόκειται για τις λεγόμενες εικονικές μηχανές (Virtual Machines – όχι δεν εννοούμε το VMWare ή το Virtual Box, μην το μπερδέψετε!) που παράγουν ένα ψευτο-εκτελέσιμο κώδικα (intermediate code), ο οποίος απαιτεί την ύπαρξη μιας «εικονικής μηχανής» για να τρέξει. Τέτοιες προσεγγίσεις έχουν φτιαχτεί για τις γλώσσες Java και για το γνωστό και μη εξαιρετέο Microsoft .Net. Βέβαια μη νομίζετε ότι αυτή η ιστορία είναι και τόσο πολύ καινούρια! Την 10ετία του 1980 υπήρχε το περίφημο P-System της Pascal, και είχαν φτιαχτεί γι’ αυτό ουκ-ολίγες εφαρμογές! Τα πλεονεκτήματα της virtual machine είναι η φορητότητα, η ασφάλεια κλπ. Για την ταχύτητα θα έλεγε κανείς ότι σίγουρα είναι καλύτερα από τον interpreter αλλά ίσως λίγο χειρότερα από τον compiler.
Ας έρθουμε όμως στην εκτέλεση του προγράμματος, που είναι και αυτό που μας ενδιαφέρει. Θα ασχοληθούμε με την εκτέλεση ενός προγράμματος που έχει μεταγλωττιστεί από κάποιον compiler χωρίς αυτό να σημαίνει ότι οι υπόλοιπες προσεγγίσεις (interpreters και virtual machines) διαφέρουν πολύ σε υλοποίηση. Να πούμε οτι σε αυτό το άρθρο (τουλάχιστον) για αναφερθούμε για λόγους απλότητας σε υλοποιήσεις που βασίζονται στους επεξεργαστές της Intel (AMD και συμβατούς) και σε αρχιτεκτονική 32-bit.
Κάθε πρόγραμμα που εκτελείται στην μνήμη του υπολογιστή μας χρησιμοποιεί τρία βασικά μέρη της μνήμης RAM:
Το μέρος του Κώδικα (code section).
Το μέρος των Δεδομένων (data section).
Το μέρος της Στοίβας (stack).
Πριν αναλύσουμε ένα-ένα τα μέρη αυτά θα θέλαμε να σας πούμε λίγα λόγια για την μνήμη. Η μνήμη του υπολογιστή είναι σαν τις κλειδοθήκες στην reception ενός ξενοδοχείου. Οι κλειδοθήκες λοιπόν, έχουν απ’ έξω γραμμένο ένα αριθμό που είναι ο αριθμός δωματίου και μέσα περιέχουν (ή δεν περιέχουν) το κλειδί. Έτσι ακριβώς λειτουργεί και η μνήμη του υπολογιστή μας: Περιέχει εκατομμύρια κουτάκια με νούμερα τα οποία νούμερα τα ονομάζουμε διευθύνσεις και μέσα σε αυτές φυλάσσονται τα δεδομένα μας. Κάθε κουτάκι μπορεί να δεχτεί συγκεκριμένου μεγέθους δεδομένα. Αν τα δεδομένα που θέλουμε να αποθηκεύσουμε στην μνήμη είναι πολλά (που σχεδόν πάντα είναι) τότε μοιράζονται σε πολλά κουτάκια. Όπως θα φαντάζεστε, πάρα πολλά κουτάκια παραμένουν άδεια διότι απλά δεν έχουν τοποθετηθεί ακόμα μέσα τους δεδομένα. Αυτό όμως δεν σημαίνει ότι δεν έχουν και διεύθυνση! Κρατήστε αυτές τις πληροφορίες διότι θα μας χρειαστούν παρακάτω.
Μέρος του Κώδικα (code section)
Σε αυτό το κομμάτι της μνήμης αποθηκεύονται όλες οι εντολές του προγράμματός μας. Κατά την διάρκεια εκτέλεσης του προγράμματος κανένα πρόγραμμα δεν μπορεί να γράψει δεδομένα σε αυτό το μέρος. Είναι μόνο για διάβασμα (Read Only).
Για παράδειγμα, όλες οι εντολές μηχανής που αντιστοιχούν στο παρακάτω κομμάτι πηγαίου κώδικα (σε γλώσσα C στο παράδειγμα μας) θα τοποθετηθούν στην μνήμη στο Code Section:
/* Θέσε τα στοιχεία της 1ης διαγώνιου ενός πίνακα 100×100 με 1, και τα υπόλοιπα με 0 */
for (i = 0; i < 100; i++)
for (j = 0; j < 100; j++)
if (i<>j)
a[i][j] = 0
else
a[i][j] = 1;
Τα σχόλια /*…*/ φυσικά δεν περιλαμβάνονται στον εκτελέσιμο κώδικα, δηλαδή δεν θα μεταφραστούν σε κώδικα μηχανής αφού αφορούν μόνο αυτόν που διαβάζει το πρόγραμμα και όχι τον επεξεργαστή που το εκτελεί.
Μέρος των Δεδομένων (data section)
Στο μέρος αυτό τοποθετούνται όλες οι καθολικές μεταβλητές (global variables) του προγράμματος μας. Καθολικές μεταβλητές είναι εκείνες που είναι προσβάσιμες από όλες τις συναρτήσεις (functions) και τα υποπρογράμματα (procedures) του τρέχοντος προγράμματος. Εδώ, μπορεί να γράψει και φυσικά να διαβάσει δεδομένα το πρόγραμμα μας (non Read-Only). Για παράδειγμα, οι παρακάτω μεταβλητές i, j και a θα τοποθετηθούν στο data section:
int i;
int j=0;
int a[100][100];
Μέρος της Στοίβας (stack)
Όλες οι τοπικές μεταβλητές, δηλαδή αυτές που δηλώνονται στις συναρτήσεις ή στα υπο-προγράμματα καθώς επίσης και κάποιες διευθύνσεις μνήμης που χρησιμοποιεί το πρόγραμμα μας καταχωρούνται στην λεγόμενη στοίβα. Το μέρος αυτό της μνήμης αποτελεί στην πραγματικότητα μια δομή δεδομένων τύπου στοίβας. Για να γίνει κατανοητή η δομή αυτή θα αναφέρουμε το κλασικό παράδειγμα με τα πιάτα: Σκεφτείτε ότι πρέπει να πλύνουμε 10 πιάτα. Καθώς τα πλένουμε ένα-ένα τα τοποθετούμε σε μια στοίβα, το ένα επάνω στο άλλο. Μόλις τελειώσουμε και θέλουμε να τα σκουπίσουμε (λέμε τώρα…!) τότε θα πάρουμε πρώτα εκείνο που μπήκε τελευταίο στην στοίβα. Η μέθοδος αυτή που χρησιμοποιούμε την στοίβα ονομάζεται Last In First Out (LIFO) και πρόκειται για μια πολύ συνηθισμένη “κατάσταση” στον προγραμματισμό (και όχι μόνο – απ’ όσο είδαμε και στο παράδειγμα μας…). Το κύριο χαρακτηριστικό της είναι πως το στοιχείο που μπαίνει τελευταίο, βγαίνει πρώτο.
Να πούμε οτι σε αυτό το μέρος της μνήμης επιτρέπεται το γράψιμο, δηλαδή είναι κι αυτό (όπως και το data segment) Writable. Αντί για… πιάτα όμως, το πρόγραμμα μας τοποθετεί εδώ της μεταβλητές που χρησιμοποιούμε στις συναρτήσεις του προγράμματος μας. Βέβαια, πρέπει να έχει ένα τρόπο να γνωρίζει ποια μεταβλητή είναι η τελευταία στην στοίβα, αυτή δηλαδή που θα ληφθεί πρώτη, όταν χρειαστεί. Για να το γνωρίζει αυτό, χρησιμοποιεί έναν από τους λεγόμενους δείκτες. Σκεφτείτε τους δείκτες σαν θέσεις μνήμης αλλά μέσα στον επεξεργαστή: άμεσα και γρήγορα προσβάσιμους. Ο δείκτης που χρησιμοποιείται για να ξέρουμε ποιο είναι το τελευταίο στοιχείο (μεταβλητή) της στοίβας ονομάζεται Δείκτης Στοίβας (extended stack pointer – ESP ή σκέτο SP). Στην πραγματικότητα ο ESP κρατάει την διεύθυνση της μεταβλητής που βρίσκεται κάθε στιγμή στην κορυφή της στοίβας.
Στην στοίβα μπορούμε να βάζουμε (push) ή να παίρνουμε (pop) στοιχεία κατά βούληση. Είναι πολύ σημαντικό να γνωρίζετε δυο μικρά μυστικά:
Εξ’ αιτίας της αρχιτεκτονικής του 32μπιτου επεξεργαστή της Intel (ή των συμβατών με αυτόν όπως o AMD), οι μεταβλητές που καταχωρούνται αποτελούνται από μέρη των 4ων ψηφίων ή αλλιώς των 4ων bytes. Γιατί; Διότι το bus είναι 32 bits (binary digits). Στα 32 bits χωράνε 4 bytes αφού το 1 byte = 8 bits, 4 x 8 = 32bits.
Η στοίβα αυξάνεται προς τα κάτω. Δηλαδή ξεκινάει από ψηλές διευθύνσεις στην μνήμη και όσο βάζουμε στοιχεία αυτή “μεγαλώνει” τόσο “κατεβαίνει” προς τα κάτω. Δείτε για παράδειγμα το εξής:
Έστω οτι ο καταχωρητής SP = 256. Δείχνει, δηλαδή, στο κουτάκι 256 στην μνήμη. Αν δώσουμε την εντολή “push 34” (βάλε στο stack το 34) τότε ο ΕSP αυτόματα θα μειωθεί κατά 4 και θα γίνει 252 και στο κουτάκι 256 θα μπει ο αριθμός 34.
Έχουμε λοιπόν:
PUSH 34
Διεύθυνση
Τιμή
256
34
252
248
…
ESP=256
Αν μετά δώσουμε την εντολή:
PUSH 50
θα έχουμε:
Διεύθυνση
Τιμή
256
34
252
50
248
…
ESP=248
Για να πάρει το πρόγραμμα μας από το stack, θα δώσει την εντολή:
POP Χ
Αυτό σημαίνει οτι ο επεξεργαστής θα πάρει από το STACK την πρώτη τμή και θα την απονείμει στην μεταβλητή Χ και αμέσως μετά ο ESP θα γίνει 252 και η μεταβλητή Χ θα έχει την τιμή 34.
Εδώ, να αναφέρουμε ένα μικρό μυστικό. Αν θέλαμε να πάρουμε από το STACK την τιμή 50 και όχι την 34 τότε θα έπρεπε να δώσουμε δύο φορές POP αφού δεν έχουμε κατευθείαν πρόσβαση στο 50. Δηλαδή:
POP Χ
POP Χ Εδώ, το Χ θα έχει την τιμή 50 και ο ESP=248.
Πως εκτελούνται οι εντολές (instructions)
Για να καταλάβουμε αυτή την λειτουργία πρέπει πρώτα να μιλήσουμε για ένα καταχωρητή: Τον EIP (Extended Instruction Pointer ή απλά Instruction Pointer). Οι καταχωρητές είναι ακριβώς όπως και οι δείκτες που αναφέραμε πιο πάνω: Είναι θέσεις μνήμης μέσα στον επεξεργαστή και χρησιμοποιούνται από αυτόν για να εκτελεί της εντολές των προγραμμάτων μας. Αυτός ο καταχωρητής χρησιμοποιείται για να “κρατάει” πάντα την διεύθυνση που βρίσκεται η επόμενη προς εκτέλεση εντολή του προγράμματος μας. Για να εκτελέσει ο επεξεργαστής μια εντολή, διαβάζει από τον EIP την διεύθυνση της, πάει σε αυτήν την διεύθυνση και διαβάζει την εντολή, την εκτελεί και καταχωρεί στον EIP την επόμενη προς εκτέλεση εντολή, κοκ. Πώς όμως ο επεξεργαστής μας θα βρει ποια είναι η επόμενη προς εκτέλεση εντολή ώστε να την καταχωρήσει στον EIP; Χμ… εδώ πρέπει να διακρίνουμε δυο περιπτώσεις:
Η επόμενη εντολή προς εκτέλεση βρίσκεται αμέσως μετά την προηγούμενη.
Να έχουμε μια περίπτωση jump δηλαδή να υπάρχει (για παράδειγμα) μια συνάρτηση που καλείται προς σε ένα άλλο σημείο του προγράμματος και θα πρέπει ο επεξεργαστής μας να “πηδήσει” σε εκείνο το σημείο, ή αλλιώς σε εκείνη την διεύθυνση της μνήμης και να εκτελέσει τις εντολές εκεί.
Στην περίπτωση 1 τα πράγματα είναι απλά: Η διεύθυνση υπολογίζεται ως εξής: προσθέτουμε στον EIP το μήκοςτης τρέχουσας εντολής που εκτελέστηκε. Το αποτέλεσμα μιας τέτοιας πράξης θα είναι η διεύθυνση της αμέσως επόμενης εντολής. Για να το καταλάβετε αυτό, δείτε το εξής μικρό πρόγραμμα δύο εντολών:
100 push EDX 101 mov ESP 0
Η εντολή στην διεύθυνση 100 βάζει στο stack την τιμή του καταχωρητή EDX (αυτός είναι ένας καταχωρητής γενικής χρήσης – τον έχουμε σαν… πρόχειρο). Η εντολή στην διεύθυνση 101 δίνει στο δείκτη ESP την τιμή 0. Όταν ο επεξεργαστής μας εκτελεί την εντολή στην διεύθυνση 100 τότε θα “σκεφτεί” τα εξής:
Είναι κάποιο jump; Όχι, άρα υπολογίζω το μέγεθος της εντολής στην διεύθυνση 100 που έχω. Έστω οτι είναι 1 byte. Άρα η επόμενη εντολή προς εκτέλεση πρέπει να βρίσκεται στην διεύθυνση 100 + 1 = 101. Άρα βάζω στον EIP το 101.
Απ’ ότι καταλάβατε εδώ, κάθε εντολή – instruction (push, mov κλπ) καταλαμβάνει μνήμη και άρα έχει και κάποιο μέγεθος. Όλες οι εντολές δεν έχουν το ίδιο μέγεθος. Άλλες μπορεί να είναι 1 byte άλλες 2 άλλα 4 κοκ.
Υπάρχει βέβαια και η πιο σύνθετη περίπτωση: Η περίπτωση JUMP, δηλαδή η περίπτωση που το πρόγραμμα μας συνεχίζεται σε μια άλλη διεύθυνση πολύ πιο… “μακρινή” από την αμέσως επόμενη στη σειρά. Αυτό μπορεί να συμβεί (όπως είπαμε) όταν το πρόγραμμα καλεί μια συνάρτηση ή ένα άλλο υποπρόγραμμα. Στην πράξη γίνεται το εξής: Πριν εκτελεστεί η εντολή JUMP ο επεξεργαστής μας κρατάει την αμέσως επόμενη εντολή (αυτή που θα βρίσκεται μετά το jump) και την τοποθετεί σε ένα καταχωρητή γενικής χρήσης, ας πούμε τον EDX. Αμέσως μετά πάει στην διεύθυνση που του λέει το JUMP (Π.χ. JUMP 35456) και εκτελεί τις εντολές που βρίσκονται εκεί μία προς μία, μέχρι να συναντήσει το τέλος της συνάρτησης (που ορίζεται με μια εντολή RET, δηλαδή return), τότε απλά γράφει στο EIP το περιεχόμενο που είχε καταχωρήσει στον EDX. Κατά συνέπεια το πρόγραμμα συνεχίζει από την επόμενη εντολή που είχε σταματήσει για κάνει το jump. Η διαδικασία του JUMP υλοποιείται από το πρόγραμμα με την χρήση 2 εντολών: της CALL και της RET. H CALL μεταφέρει την λειτουργικότητα του προγράμματος σε μια άλλη (μακρινή) διεύθυνση και η RET δηλώνει το τέλος της σειράς των εντολών που βρίσκονται σε αυτήν την άλλη διεύθυνση ώστε να ξέρει πότε να σταματήσει (ή όπως λέμε να επιστρέψει) ο επεξεργαστής από την εκτέλεση των εντολών σε αυτή την περιοχή της μνήμης.
Δείκτης Βάσης – base pointer (EBP)
Κάθε φορά που εφαρμόζεται ένα jump είπαμε οτι ο επεξεργαστής πάει να εκτελέσει ένα σύνολο εντολών (instructions) σε μια άλλη θέση μνήμης (μέχρι να συναντήσει ένα RET). Αυτό το σύνολο εντολών όπως είπαμε, ονομάζεται συνάρτηση (function) ή διαδικασία (procedure). Κάθε συνάρτηση (ή διαδικασία) έχει το δικό της stack το οποίο ονομάζεται stack frame. Ένα stack frame είναι μια στοίβα στην οποία θα καταχωρηθούν μεταβλητές και διευθύνσεις που αφορούν μόνο στην τρέχουσα συνάρτηση που εκτελείται. Κάθε διεύθυνση μέσα στο συγκεκριμένο stack είναι μια σχετική διεύθυνση σε σχέση με μια βάση. Η βάση αυτή είναι ο base pointer. Όλες λοιπόν οι αναφορές στις διευθύνσεις του stack γίνονται με βάση τον τρέχοντα δείκτη βάσης (base pointer).
Στην πράξη γίνεται το εξής: Πριν καλέσουμε μια συνάρτηση βάζουμε στο EBP τον τρέχον ESP. Από εκεί και μετά κάθε φορά που θέλουμε να αναφερθούμε σε μια διεύθυνση στο stack θα το κάνουμε με βάση τον EBP που στην ουσία είναι η αρχή του stack πριν την κλήση της συνάρτησης. Για να το καταλάβετε δείτε το εξής παράδειγμα:
Στο παρακάτω stack έχουμε ebp=256 και esp=256:
Διεύθυνση
Τιμή
256
34
252
248
…
Έστω οτι καλούμε μια συνάρτηση η οποία βάζει στο stack τον αριθμό 89. Θα έχουμε:
Διεύθυνση
Τιμή
256
34
252
89
248
…
Όπου ebp=256 και esp=252.
Η χρήση του ebp μας βολεύει πολύ όταν θέλουμε να αναφερθούμε στις τιμές του stack της συγκεκριμένης συνάρτησης. Δηλαδή, η μεταβλητή που βρίσκεται στη θέση (ebp 256) είναι η πρώτη μεταβλητή που καταχώρησε στο stack η συνάρτηση μας.
Όταν τελειώσει αυτή η συνάρτηση το έργο της (με ένα RET), τότε ο EBP θα επανέλθει στον προηγούμενο EBP ο οποίος είχε φυλαχτεί σε κάποιον καταχωρητή πριν την κλήση της συνάρτησης.
Συμπεράσματα
Δώσαμε μια βασική περιγραφή για το πώς λειτουργεί εσωτερικά ένα πρόγραμμα. Οι γνώσεις που αποκομίσατε από το συγκεκριμένο άρθρο θεωρούνται στοιχειώδεις γνώσεις για ένα reverser ή για κάποιον που θέλει να καταλάβει έννοιες και να μπορέσει να διαβάσει άρθρα λίγο πιο προχωρημένα όπως αυτά που «μιλάνε» για buffer overflow.
Θα πρέπει, αν θέλετε να καταλάβετε καλά ένα Stack Buffer Overflow Attack, θα πρέπει να δώσετε βάση και να μπορείτε να εξηγήσετε τα εξής:
Τι είναι ο Instruction Pointer (EIP).
Τι είναι το Stack.
Τι είναι ο Stack Pointer (ESP).
Πώς συνδέονται τα παραπάνω μεταξύ τους.
Στα επόμενα άρθρα αυτής της οικογένειας θα δούμε λίγο πιο… core πράγματα! Προς το παρόν, σκεφτείτε το εξής:
Τι θα συμβεί αν καταφέρουμε με κάποιο τρόπο να ελέγξουμε τον Instruction Pointer (EIP);! 😎
Με πολύτιμη εμπειρία στον κόσμο της κυβερνοασφάλειας συμβάλλει ενεργά στην κοινότητά μας με αναλύσεις ευπαθειών και οδηγούς.
Με τη συνεισφορά του, προσφέρει στην κοινότητα μας ένα πλούσιο φάσμα γνώσεων και δεξιοτήτων που ενισχύουν την ανάπτυξη και την ασφάλεια του ψηφιακού μας κόσμου.