Χάκερς τροποποιούν τις σελίδες 404 των ηλεκτρονικών καταστημάτων για να κλέψουν πιστωτικές κάρτες | – #1 Το Hacking σε... απλά ελληνικά –Χάκερς τροποποιούν τις σελίδες 404 των ηλεκτρονικών καταστημάτων για να κλέψουν πιστωτικές κάρτες | – #1 Το Hacking σε... απλά ελληνικά –Χάκερς τροποποιούν τις σελίδες 404 των ηλεκτρονικών καταστημάτων για να κλέψουν πιστωτικές κάρτες | – #1 Το Hacking σε... απλά ελληνικά –Χάκερς τροποποιούν τις σελίδες 404 των ηλεκτρονικών καταστημάτων για να κλέψουν πιστωτικές κάρτες | – #1 Το Hacking σε... απλά ελληνικά –Χάκερς τροποποιούν τις σελίδες 404 των ηλεκτρονικών καταστημάτων για να κλέψουν πιστωτικές κάρτες | – #1 Το Hacking σε... απλά ελληνικά –Χάκερς τροποποιούν τις σελίδες 404 των ηλεκτρονικών καταστημάτων για να κλέψουν πιστωτικές κάρτες | – #1 Το Hacking σε... απλά ελληνικά –Χάκερς τροποποιούν τις σελίδες 404 των ηλεκτρονικών καταστημάτων για να κλέψουν πιστωτικές κάρτες | – #1 Το Hacking σε... απλά ελληνικά –Χάκερς τροποποιούν τις σελίδες 404 των ηλεκτρονικών καταστημάτων για να κλέψουν πιστωτικές κάρτες | – #1 Το Hacking σε... απλά ελληνικά –
Μια νέα μορφή επίθεσης κατά των καρτών της Magecart, καταλαμβάνει τις σελίδες σφαλμάτων 404 των ιστότοπων των διαδικτυακών πωλητών, κρύβοντας κακόβουλο κώδικα για να κλέψει τα στοιχεία των πιστωτικών καρτών των πελατών.
Η τεχνική αυτή είναι μία από τις τρεις παραλλαγές που παρατηρήθηκαν από ερευνητές της Akamai Security Intelligence Group, με τις άλλες δύο να κρύβουν τον κώδικα στο χαρακτηριστικό “onerror” της ετικέτας HTML και σε ένα δυαδικό αρχείο εικόνας για να φαίνεται ως το απόσπασμα κώδικα Meta Pixel.
Η Akamai αναφέρει ότι η επίθεση επικεντρώνεται σε ιστότοπους Magento και WooCommerce, με ορισμένα θύματα να συνδέονται με γνωστούς οργανισμούς στους τομείς των τροφίμων και του λιανικού εμπορίου.
Χειραγώγηση σελίδων 404
Όλοι οι ιστότοποι διαθέτουν σελίδες σφάλματος 404, οι οποίες εμφανίζονται στους επισκέπτες όταν έχουν πρόσβαση σε μια ιστοσελίδα που δεν υπάρχει, έχει μετακινηθεί ή έχει έναν νεκρό/σπασμένο σύνδεσμο.
Οι δράστες του Magecart αξιοποιούν την προεπιλεγμένη σελίδα “404 Not Found” για να κρύψουν και να φορτώσουν τον κακόβουλο κώδικα κλοπής καρτών, κάτι που δεν έχει παρατηρηθεί ξανά σε προηγούμενες εκστρατείες.
Ο φορτωτής skimmer είτε μεταμφιέζεται ως ένα απόσπασμα κώδικα Meta Pixel είτε κρύβεται μέσα σε τυχαία inline scripts που υπάρχουν ήδη στην παραβιασμένη ιστοσελίδα πληρωμής.
Ο φορτωτής ξεκινά ένα αίτημα λήψης σε μια σχετική διαδρομή με όνομα “icons”, αλλά καθώς αυτή η διαδρομή δεν υπάρχει στον ιστότοπο, το αίτημα καταλήγει σε σφάλμα “404 Not Found”.
Οι ερευνητές της Akamai υπέθεσαν αρχικά ότι το skimmer δεν ήταν πλέον ενεργό ή ότι η ομάδα Magecart είχε κάνει κάποιο λάθος στη διαμόρφωση. Ωστόσο, κατά την προσεκτικότερη εξέταση, διαπίστωσαν ότι ο φορτωτής περιείχε μια ταυτοποίηση κανονικής έκφρασης που αναζητούσε μια συγκεκριμένη συμβολοσειρά στην επιστρεφόμενη HTML της σελίδας 404.
Κατά τον εντοπισμό της συμβολοσειράς στη σελίδα, η Akamai βρήκε μια συνυφασμένη συμβολοσειρά κωδικοποιημένη με base64, κρυμμένη σε ένα σχόλιο. Η αποκωδικοποίηση αυτής της συμβολοσειράς αποκάλυψε το JavaScript skimmer, το οποίο κρύβεται σε όλες τις σελίδες 404.
Επειδή η αίτηση γίνεται σε μια διαδρομή πρώτου μέρους, τα περισσότερα εργαλεία ασφαλείας που παρακολουθούν ύποπτα αιτήματα δικτύου στη σελίδα πληρωμής θα το παραβλέψουν.
Κλέβοντας τα δεδομένα
Ο κώδικας skimmer εμφανίζει μια ψεύτικη φόρμα την οποία οι επισκέπτες του ιστότοπου αναμένεται να συμπληρώσουν με ευαίσθητα στοιχεία, όπως τον αριθμό της πιστωτικής τους κάρτας, την ημερομηνία λήξης και τον κωδικό ασφαλείας.
Μόλις τα δεδομένα αυτά εισαχθούν στην ψεύτικη φόρμα, το θύμα λαμβάνει ένα ψεύτικο σφάλμα “session timeout”.
Στο παρασκήνιο, όλες οι πληροφορίες κωδικοποιούνται με base64 και αποστέλλονται στον επιτιθέμενο μέσω μιας διεύθυνσης URL αίτησης εικόνας που φέρει τη συμβολοσειρά ως παράμετρο ερώτησης.
Αυτή η προσέγγιση βοηθά στην αποφυγή εντοπισμού από εργαλεία παρακολούθησης της κυκλοφορίας δικτύου, καθώς η αίτηση μοιάζει με ένα καλοήθες συμβάν ανάκτησης εικόνας. Ωστόσο, η αποκωδικοποίηση της συμβολοσειράς base64 αποκαλύπτει προσωπικές πληροφορίες και πληροφορίες πιστωτικής κάρτας.
Η περίπτωση της χειραγώγησης των σελίδων 404 αναδεικνύει τις εξελισσόμενες τακτικές και την ευελιξία των φορέων του Magecart, οι οποίοι συνεχώς δυσκολεύουν τους webmaster να εντοπίσουν τον κακόβουλο κώδικά τους σε παραβιασμένους ιστότοπους και να τον αποκαταστήσουν.
Νέο CVE υψηλής βαθμολογίας από την Google στη libwebp
Η Google έχει εκχωρήσει ένα νέο αναγνωριστικό CVE (CVE-2023-5129) σε μια ευπάθεια ασφαλείας της libwebp, η οποία αξιοποιήθηκε ως zero-day σε επιθέσεις και επιδιορθώθηκε πριν από δύο εβδομάδες.
Η εταιρεία αρχικά αποκάλυψε το ελάττωμα ως αδυναμία του Chrome, που εντοπίστηκε ως CVE-2023-4863, αντί να το αποδώσει στη βιβλιοθήκη libwebp ανοικτού κώδικα που χρησιμοποιείται για την κωδικοποίηση και αποκωδικοποίηση εικόνων σε μορφή WebP.
Αυτό το σφάλμα μηδενικής ημέρας αναφέρθηκε από κοινού από την Apple Security Engineering and Architecture (SEAR) και το Citizen Lab στο Munk School του Πανεπιστημίου του Τορόντο την Τετάρτη 6 Σεπτεμβρίου και διορθώθηκε από την Google λιγότερο από μια εβδομάδα αργότερα.
Οι ερευνητές ασφαλείας του Citizen Lab έχουν καθιερωμένο ιστορικό στον εντοπισμό και την αποκάλυψη zero-day που έχουν γίνει αντικείμενο κατάχρησης σε στοχευμένες εκστρατείες κατασκοπευτικού λογισμικού, οι οποίες συχνά συνδέονται με κρατικούς φορείς απειλών που στοχεύουν κυρίως άτομα υψηλού κινδύνου, όπως δημοσιογράφους και πολιτικούς της αντιπολίτευσης.
Η απόφαση να χαρακτηριστεί ως σφάλμα του Chrome προκάλεσε σύγχυση στην κοινότητα της κυβερνοασφάλειας, προκαλώντας ερωτήματα σχετικά με την επιλογή της Google να το κατηγοριοποιήσει ως πρόβλημα του Google Chrome αντί να το προσδιορίσει ως ελάττωμα στο libwebp.
Ο ιδρυτής της εταιρείας συμβούλων ασφαλείας Ben Hawkes (ο οποίος προηγουμένως ήταν επικεφαλής της ομάδας Project Zero της Google) συνέδεσε επίσης το CVE-2023-4863 με την ευπάθεια CVE-2023-41064 που αντιμετωπίστηκε από την Apple στις 7 Σεπτεμβρίου και χρησιμοποιήθηκε καταχρηστικά ως μέρος μιας αλυσίδας εκμετάλλευσης iMessage με μηδενικό κλικ (που ονομάστηκε BLASTPASS) για τη μόλυνση πλήρως επιδιορθωμένων iPhones με το εμπορικό spyware Pegasus της NSO Group.
Νέο CVE υψηλής σοβαρότητας
Ωστόσο, τώρα έχει εκχωρήσει ένα άλλο αναγνωριστικό CVE, το CVE-2023-5129, χαρακτηρίζοντάς το ως κρίσιμο ζήτημα στη libwebp με μέγιστη βαθμολογία σοβαρότητας 10/10. Αυτή η αλλαγή έχει σημαντικές επιπτώσεις για άλλα έργα που χρησιμοποιούν τη βιβλιοθήκη ανοικτού κώδικα libwebp.
Τώρα αναγνωρίζεται επίσημα ως ελάττωμα της libwebp και αφορά μια υπερχείλιση buffer σωρού στο WebP, επηρεάζοντας τις εκδόσεις του Google Chrome που προηγούνται της 116.0.5845.187.
Αυτή η ευπάθεια βρίσκεται στον αλγόριθμο κωδικοποίησης Huffman που χρησιμοποιείται από τη libwebp για συμπίεση χωρίς απώλειες και επιτρέπει στους επιτιθέμενους να εκτελούν εγγραφές μνήμης εκτός ορίων χρησιμοποιώντας κακόβουλα διαμορφωμένες σελίδες HTML.
Αυτός ο τύπος εκμετάλλευσης μπορεί να έχει σοβαρές συνέπειες, από συντριβές έως εκτέλεση αυθαίρετου κώδικα και μη εξουσιοδοτημένη πρόσβαση σε ευαίσθητες πληροφορίες.
Η επαναταξινόμηση του CVE-2023-5129 ως ευπάθεια της libwebp έχει ιδιαίτερη σημασία λόγω του ότι αρχικά πέρασε απαρατήρητη ως πιθανή απειλή για την ασφάλεια πολλών έργων που χρησιμοποιούν τη libwebp, συμπεριλαμβανομένων των 1Password, Signal, Safari, Mozilla Firefox, Microsoft Edge, Opera και των εγγενών προγραμμάτων περιήγησης ιστού Android.
Η αναθεωρημένη κρίσιμη αξιολόγηση υπογραμμίζει τη σημασία της άμεσης αντιμετώπισης της ευπάθειας ασφαλείας (που τώρα παρακολουθείται με πολλαπλά αναγνωριστικά CVE με διαφορετικές αξιολογήσεις σοβαρότητας) σε όλες αυτές τις πλατφόρμες για να διασφαλιστεί η ασφάλεια των δεδομένων των χρηστών.
Προστατεύοντας την Επιχείρησή σας: Η Σημασία της Κυβερνοασφάλειας
Η κυβερνοασφάλεια είναι κάτι περισσότερο από μια απλή ανησυχία για την τεχνολογική ασφάλεια. Είναι η βασική αμυντική γραμμή της επιχείρησής σας, προστατεύοντας τα δεδομένα, τους πελάτες και τη φήμη σας. Σε αυτό το άρθρο, θα δούμε τη σημασία της κυβερνοασφάλειας στις επιχειρήσεις και πώς μπορείτε να την ενσωματώσετε στην καθημερινή λειτουργία σας.
Κυβερνοασφάλεια: Τι είναι και γιατί είναι σημαντική;
Η κυβερνοασφάλεια αναφέρεται στην προστασία των ψηφιακών συστημάτων, δεδομένων και δικτύων από κυβερνοαπειλές και επιθέσεις. Αυτές οι απειλές μπορούν να περιλαμβάνουν malware, phishing, επιθέσεις ransomware και πολλά άλλα. Γιατί όμως είναι τόσο σημαντική για κάθε επιχείρηση;
1. Προστασία των Δεδομένων: Οι επιχειρήσεις συχνά διαθέτουν ευαίσθητα δεδομένα πελατών, εργαζομένων και οικονομικά στοιχεία. Η διαρροή ή η κλοπή αυτών των δεδομένων μπορεί να οδηγήσει σε σοβαρές συνέπειες, συμπεριλαμβανομένης της απώλειας φήμης και των νομικών επιπτώσεων.
2. Προστασία της Φήμης: Η καλή φήμη είναι ανεκτίμητη. Ένας κακόβουλός «χάκερ» μπορεί να καταστρέψει τη φήμη μιας επιχείρησης, διαρρέοντας προσωπικά δεδομένα ή προκαλώντας αναστάτωση στις υπηρεσίες της.
3. Προστασία από Νομικές Επιπτώσεις: Η μη συμμόρφωση με τους νόμους περί προστασίας των δεδομένων και της κυβερνοασφάλειας μπορεί να οδηγήσει σε σοβαρές νομικές συνέπειες.
Πώς να Ενσωματώσετε την Κυβερνοασφάλεια:
Η κυβερνοασφάλεια δεν είναι μια μονοδιάστατη λύση. Πρέπει να ενσωματωθεί σε όλες τις πτυχές της επιχείρησης. Αναλυτικά:
1. Κατάρτιση και Ευαισθητοποίηση: Εκπαιδεύστε το προσωπικό σας για τις κυβερνοαπειλές και τις βέλτιστες πρακτικές ασφάλειας.
2. Τεχνολογικά Εργαλεία: Χρησιμοποιήστε ασφαλή λογισμικά και υλικά, όπως firewalls, antivirus, IDS/IPS, και SIEM συστήματα, για να προστατεύσετε τα συστήματά σας από επιθέσεις.
3. Ανάλυση και Εντοπισμός Κινδύνων: Εφαρμόστε μηχανισμούς ανίχνευσης και αντιμετώπισης κυβερνοαπειλών για να εντοπίσετε εγκαίρως ανωμαλίες στο δίκτυό σας.
4. Πολιτικές και Διαδικασίες: Τηρήστε πολιτικές και διαδικασίες κυβερνοασφάλειας που καθορίζουν πώς πρέπει να διαχειρίζεστε τα δεδομένα και τις πιθανές απειλές.
5. Συνεργασία με Εξωτερικούς Εμπειρογνώμονες: Εξετάστε τη συνεργασία με εξωτερικούς εμπειρογνώμονες για τον έλεγχο κυβερνοασφάλειας και τον εντοπισμό πιθανών ευπάθειών.
6. Ανάκτηση Δεδομένων και Επιχειρησιακή Συνέχεια: Αναπτύξτε σχέδια ανάκτησης δεδομένων και συνέχειας επιχειρησιακής δραστηριότητας, ώστε να αντιμετωπίσετε τις επιθέσεις.
7. Συμμόρφωση με τους Νόμους: Διασφαλίστε ότι η επιχείρησή σας συμμορφώνεται με τους νόμους περί προστασίας των δεδομένων και της κυβερνοασφάλειας.
Η κυβερνοασφάλεια δεν είναι πλέον πολυτέλεια, αλλά αναγκαίο μέτρο για κάθε επιχείρηση. Η προστασία των δεδομένων, της φήμης και της νομικής συμμόρφωσης πρέπει να βρίσκεται στην κορυφή της λίστας προτεραιοτήτων σας. Εφαρμόζοντας καλές πρακτικές κυβερνοασφάλειας, μπορείτε να προστατεύσετε την επιχείρησή σας και να διασφαλίσετε την ασφαλή της λειτουργία.
Ο Αλέξανδρος είναι ο ιδρυτής του 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);! 😎
Με πολύτιμη εμπειρία στον κόσμο της κυβερνοασφάλειας συμβάλλει ενεργά στην κοινότητά μας με αναλύσεις ευπαθειών και οδηγούς.
Με τη συνεισφορά του, προσφέρει στην κοινότητα μας ένα πλούσιο φάσμα γνώσεων και δεξιοτήτων που ενισχύουν την ανάπτυξη και την ασφάλεια του ψηφιακού μας κόσμου.