Πολεμικά Παίγνια: OTW Natas #14

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

Πηγή: InformationSecurityBuzz.com

Ακριβώς όπως κάναμε και στα προηγούμενα επίπεδα, χρησιμοποιούμε τα στοιχεία πρόσβασης που αποκτήσαμε από το επίπεδο 13. Όταν συνδεθούμε στο 14ο επίπεδο βλέπουμε μία νέα φόρμα. Είναι ένα πεδίο για το όνομα χρήστη (Username), ένα για το κωδικό πρόσβασης (Password), και ένα κουμπί πρόσβασης (Login). Επίσης, όπως και στα προηγούμενα, οι δημιουργοί του ήταν αρκετά καλοί ώστε να μας δείξουν το πηγαίο κώδικα (View sourcecode) που εκτελεί ο εξυπηρετητής σε αυτή τη σελίδα.

Πηγή: OverTheWire.org

Διαβάζοντας το πηγαίο κώδικα της σελίδας βλέπουμε ότι η φόρμα είναι πολύ απλή και το μόνο που κάνει είναι να αποστέλει ότι εισάγει ο χρήστης σε αυτά τα δύο πεδία στη σελίδα index.php μέσω της μεθόδου αποστολής POST. Βλέπετε το σχετικό απόσπασμα εδώ.

 <form action="index.php" method="POST">
 Username: <input name="username"><br>
 Password: <input name="password"><br>
 <input type="submit" value="Login" />
 </form>

Εάν δούμε το πηγαίο κώδικα της σελίδας που επεξεργάζεται αυτά τα στοιχεία τότε θα δούμε ότι σε αυτό το επίπεδο μαθαίνουμε για κενά ασφαλείας σε βάσεις δεδομένων (databases). Οι βάσεις δεδομένων (databases ή DB για συντομία) είναι λογισμικά που είναι ειδικά σχεδιασμένα για αποθήκευση και συσχέτιση μεγάλου όγκου δεδομένων. Έτσι, οι περισσότερες ιστοσελίδες αποθηκεύουν με αυτό το τρόπο τα δεδομένα τους. Παρακάτω βλέπετε τις τρεις πρώτες γραμμές του πηγαίου κώδικα της σελίδας. Η πρώτη γραμμή ελέγχει ότι υπάρχει κάτι στο πεδίο ονόματος χρήστη (username). Η δεύτερη γραμμή χρησιμοποιεί τη συνάρτηση mysql_connect() με τρεις παραμέτρους. Η πρώτη παράμετρος είναι το όνομα συστήματος της βάσης δεδομένων, το δεύτερο το όνομα χρήστη για να συνδεθεί εκεί, και το τρίτο ο κωδικός πρόσβασης. Η τρίτη γραμμή είναι η κλήση στη συνάρτηση mysql_select_db() δίδοντας τη παράμετρο «natas14» και τη σύνδεση που μόλις δημιουργήσαμε με τη προηγουμένη συνάρτηση. Αυτό δηλαδή λέει στη βάση δεδομένων ότι θέλουμε να επιλέξουμε, από όλες τις βάσεις δεδομένων που έχει, τη βάση δεδομένων με όνομα «natas14».

 if(array_key_exists("username", $_REQUEST)) {
   $link = mysql_connect('localhost', 'natas14', '<censored>');
   mysql_select_db('natas14', $link);

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

Πηγή: Προσωπικό αρχείο

Το επόμενο είναι το πιο ενδιαφέρον κομμάτι για τη περίπτωση μας, η μέθοδος με την οποία επικοινωνεί κανείς με μία βάση δεδομένων όπως η MySQL που χρησιμοποιείται εδώ. Η επικοινωνία πραγματοποιείται με τη γλώσσα ερωτημάτων SQL (Structured Query Language, Γλώσσα Δομημένων Ερωτημάτων). Όπως δηλώνει και το όνομα της, η SQL είναι μία γλώσσα με την οποία μπορούμε να γράψουμε ερωτήματα προς τη βάση δεδομένων και να λάβουμε τις αντίστοιχες απαντήσεις. Για παράδειγμα, εάν έχουμε ένα πίνακα με εκατομμύρια εγγραφές που μοιάζει με το παρακάτω.

Πηγή: Προσωπικό αρχείο

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

SELECT * FROM mydb WHERE username = "user_7";

Τώρα που εξηγήσαμε το τι είναι οι βάσεις δεδομένων και η γλώσσα SQL, ας προχωρήσουμε με το κώδικα της σελίδας. Όπως βλέπετε και παρακάτω, στη συνέχεια στο κώδικα της σελίδας δημιουργεί μία μεταβλητή με όνομα $query και εκεί αποθηκεύει ένα ερώτημα σε γλώσσα SQL όπου ζητάει όλα τα αποτελέσματα από το πίνακα «users» για οτιδήποτε έχει το όνομα χρήστη και κωδικό πρόσβασης που εισάγαμε στη φόρμα.

$query = "SELECT * from users where username=\"".$_REQUEST["username"]."\" and password=\"".$_REQUEST["password"]."\"";

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

   if(array_key_exists("debug", $_GET)) {
     echo "Executing query: $query<br>";
   }

Έπειτα, μέσω της συνάρτησης mysql_query() εκτελεί το περιεχόμενο της μεταβλητής $query στον εξυπηρετητή και το αποτέλεσμα δίδεται στη συνάρτηση mysql_num_rows() η οποία μετράει τον αριθμό των εγγραφών. Εάν μία ή παραπάνω εγγραφές βρέθηκαν, τότε μας δίνει πρόσβαση. Εάν όχι, τότε μας λέει ότι δεν έχουμε πρόσβαση. Τέλος, κλείνει τη σύνδεση με τη βάση δεδομένων με τη συνάρτηση mysql_close().

   if(mysql_num_rows(mysql_query($query, $link)) > 0) {
       echo "Successful login! The password for natas15 is <censored><br>";
   } else {
       echo "Access denied!<br>";
   }
   mysql_close($link);
 } else {
 ?>

Το πρώτο σημαντικό που αξίζει να παρατηρήσουμε είναι ότι ο κώδικας δεν ελέγχει τίποτα στο λογαριασμό παρά μόνο εάν βρέθηκε κάποια εγγραφή στη βάση που να έχει το ίδιο όνομα χρήστη και κωδικό πρόσβασης με αυτό που δώσαμε στη φόρμα. Το δεύτερο είναι ότι με τη παράμετρο debug μπορούμε να δούμε το ερώτημα SQL που θα εκτελεστεί προτού σταλεί για εκτέλεση στη βάση δεδομένων. Παρακάτω βλέπετε μία δοκιμή με όνομα χρήστη και κωδικό πρόσβασης «test», προσθέτοντας τη παράμετρο debug στο URL ώστε να δούμε το ερώτημα SQL που θα εκτελέσει.

Πηγή: OverTheWire.org

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

username=\"".$_REQUEST["username"]."\"

Το πρόβλημα είναι ότι στη γλώσσα SQL τα εισαγωγικά χρησιμοποιούνται για να δείξουν ότι υπάρχει μία τιμή. Δηλαδή, λέει ότι η μεταβλητή username να έχει τιμή ίση με ότι υπάρχει μέσα στα εισαγωγικά. Αλλά εφόσον δε γίνεται κανένας έλεγχος για το τι περίεχει το όνομα χρήστη που δίνουμε, εάν βάλουμε εισαγωγικά ως όνομα χρήστη, τότε θα «σπάσουμε» αυτή τη λογική.

Πηγή: OverTheWire.org

Όπως βλέπουμε η συνάρτηση mysql_num_rows() επέστρεψε ένα σφάλμα ότι δεν είχε σωστά δεδομένα στην είσοδο της. Αυτό σημαίνει ότι αυτή η αλλαγή μας, άλλαξε το ερώτημα SQL που εκτελέστικε. Οπότε γνωρίζουμε ότι μπορούμε να εκτελέσουμε κώδικα σε γλώσσα SQL λόγω αυτού του κενού ασφαλείας, τι ακριβώς μπορούμε να κάνουμε όμως; Αρχικά, γνωρίζουμε ότι μπορούμε να «βγούμε» από το όνομα χρήστη και να αλλάξουμε το ερώτημα με το χαρακτήρα από τα εισαγωγικά. Αυτό που θέλουμε είναι να καταφέρουμε να κάνουμε το ερώτημα να επιστρέψει μία ή παραπάνω εγγραφές από τη βάση δεδομένων. Ο πιο εύκολος τρόπος θα ήταν με κάτι όπως αυτό που βλέπετε παρακάτω. Με κόκκινο χρώμα έχουμε επισημάνει αυτό που θα εισάγουμε εμείς στα δύο πεδία (username και password).

Πηγή: Προσωπικό αρχείο

Στη γλώσσα SQL υπάρχει η λογική πράξη OR (είτε) όπως βλέπετε παραπάνω. Αυτό λέει στη βάση δεδομένων MySQL να επιστρέψει είτε οτιδήποτε έχει όνομα χρήστη test, είτε (OR) οτιδήποτε εάν το ένα είναι ίσο με ένα, δηλαδή τα πάντα. Και μετά ξανά το ίδιο και για τη παράμετρο password. Άρα το παραπάνω ερώτημα πρακτικά μπορεί να μεταφραστεί ως, επέστρεψε μου από τη βάση δεδομένων όλα τα περιεχόμενα του πίνακα users εάν το ένα είναι ίσο με το ένα. Ας το δοκιμάσουμε όμως και στη πράξη.

Πηγή: OverTheWire.org

Και όπως βλέπετε και μόνοι σας λειτούργησε και καταφέραμε να πάρουμε το κωδικό πρόσβασης για το επόμενο επίπεδο του πολεμικού παιγνίου Natas. Αυτός ο τύπος επίθεσης ονομάζεται SQL Injection (Έγχυση SQL) γιατί αυτό ουσιαστικά κάνουμε. Εισάγουμε κακόβουλα ερωτήματα SQL λόγω έλλειψης ελέγχων. Σήμερα αυτός ο τύπος επιθέσεων είναι στους 10 πιο δημοφιλείς και πολλές υψηλής αξίας επιθέσεις ξεκίνησαν από ένα τέτοιο κενό ασφαλείας. Ένα πολύ πρόφατο πραγματικό παράδειγμα ήταν η πρόσβαση στο εκλογικό σύστημα της πολιτείας του Ιλινόι των ΗΠΑ τις αρχές του Ιουλίου του 2017 όπως μπορείτε να διαβάσετε και εδώ. Το σύστημα είχε ένα τέτοιο κενό ασφαλείας και οι επιτιθέμενοι, μέσω αυτού του κενού, πήραν στοιχεία 80 χιλιάδων εγγραφών από τη βάση δεδομένων (όπως ονόματα, διευθύνσεις, ημ. γέννησης, φύλλο, κ.α.) και εν συνεχεία μέσω άλλων ερωτημάτων SQL εγκατέστησαν κακόβουλο λογισμικό στον εξυπηρετητή και πήραν πλήρη πρόσβαση. Τα κενά ασφαλείας SQL Injection, ή SQLi για συντομία, μπορούν να αποτραπούν με καλό έλεγχο των δεδομένων που εισάγει ο χρήστης προτού χρησιμοποιήσουν αυτά τα δεδομένα στη κατασκευή ερωτημάτων SQL. Πολύ ενδιαφέρον επίπεδο και ακόμα πιο ενδιαφέρον κενό ασφαλείας.

Πηγή: HackIsPower.blogspot.com

Γράψτε τα σχόλια σας εδώ...

Εισάγετε τα παρακάτω στοιχεία ή επιλέξτε ένα εικονίδιο για να συνδεθείτε:

Λογότυπο WordPress.com

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό WordPress.com. Αποσύνδεση / Αλλαγή )

Φωτογραφία Twitter

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Twitter. Αποσύνδεση / Αλλαγή )

Φωτογραφία Facebook

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Facebook. Αποσύνδεση / Αλλαγή )

Φωτογραφία Google+

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Google+. Αποσύνδεση / Αλλαγή )

Σύνδεση με %s