Ξεπερνώντας το DEP
~~~~~~~~~~~~~~~~~~
Η micro$oft σε μια προσπάθεια να εμποδίσει το buffer overflow εφάρμοσε μια «νέα» τεχνική (της 10ετίας του 70) για να προστατέψει τους χρήστες από την εκτέλεση μη εξουσιοδωτημένου κώδικα.
Δεν θα αναλύσω με λεπτομέριες την μεθοδολογία του DEP (για περισσότερες λεπτομέριες δείτε [1],[2]) εδώ παρά μόνο θα αναφέρω το εξής:
Αυτό που έκανε η Micro$oft ήτανε να απαγορέυσει να εκτελείται κώδικας στο stack segment ή καλύτερα στο data segment, όπως επίσης και να ελέγχει αν έχει γίνει buffer overflow του EIP χρησιμοποιόντας ένα «cookie» ή αλλιώς μια υπογραφή στο stack που την ελέγχει κατά την προσπέλαση του.
Με αυτόν τον τρόπο θεώρησε οτι θα μπορούσε να αποτρέψει κάποιον που κάνει ένα buffer overflow να «πάρει» κάποιο box.
Για να δείτε αν την έχετε ενεργοποιημένη αυτην την δυνατότητα στα XP πατήστε δεξί click στο MyComputer μετά properties. Μετά πατήστε το TAΒ advanced και εκεί που λέει performance πατήστε το button [Settings]. Μόλις ανοίξει το Performance Options πατήστε το TAB “Data Execution Prevention”... Xειρότερο μέρος δεν είχανε να το κρύψουνε?? Τεσπα... Τι να πω!!
Το παράδειγμα που θα σας δείξω πραγματοποιεί ένα ελεγχόμενο buffer overflow και μέσα από αυτό τρέχει ένα πρόγραμμα του λειτουργικού συστήματος.... ας πούμε το... windows explorer.
Το «καλό» της υπόθεσης είναι οτι η τεχνική λειτουργεί είτε έχουμε ενεργοποιημένο το DEP!! είτε όχι.
Πρέπει να πούμε βέβαια οτι το DEP έχει δύο είδη. Hardware DEP και Software DEP. Το hardware DEP δεν υποστηρίζετε από τον επεξεργαστή Pentium 4, παρά μόνο από της τελευταίας γενιάς των AMD, Intel. H Δοκιμή έγινε σε Win XP Pro με SP2 σε Pentium 4, οπότε το bypassing έγινε σε software DEP scheme ;-)
Βέβαια όσοι μπορούν και έχουν πρόσβαση σε επεξεργαστές που υποστησίζουν Hardware DEP θα ήταν πολύ χρήσιμο να μας πούνε τις «εντυπώσεις» του...
Ένα ευπαθές (vulnerable) πρόγραμμα
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ας κατασκευάσουμε ένα ευπαθές πρόγραμμα σε buffer overflow. Χρησιμοποίησα τη Micro$oft C++ (Visual Studio 2005).
Σημείωση: Για να μπορέσει να λειτουργήσει η δοκιμή μας (για την δοκιμή) σετάρουμε τις εξής flags του compiler:
Basic Runtime Checks: Default
Buffer Security Check: No (GS-)
Για command line lovers:
/Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MDd /Yu"stdafx.h" /Fp"Debug\BufferOverflow_Attack.pch" /Fo"Debug\\" /Fd"Debug\vc80.pdb" /W3 /nologo /c /Wp64 /ZI /TP /errorReport:prompt
Επίσης να ξεκαθαρίσω πως οτιδήποτε πω και αναφέρετε σε μεγέθοι αφορά στον στον 32μπιτο Pentium 4 και όλους τους όμοιους του ;-) π.χ. AMD κλπ.
Ας έρθω επιτέλους στο πρόγραμμα:
/*
A vulnerable Program.
(c) by Thiseas 2007
*/
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char s[06];
strcpy(s,argv[1]);
printf("The string is %s\n",s);
return 0;
}
** Μη μου πει κανείς οτι δεν χρησιμοποιούμε πια την strcpy!! Δεν είναι αυτός ο στόχος εδώ. Το πρόγραμμα είναι καθαρά εκπαιδευτικό για να διευκολύνει την διαδικασία!
Απ’ ότι βλέπουμε η μεταβλητή s καταχωρεί ότι δώθηκε σαν πρώτο command line argument. Έχει μήκος 8 bytes. Έτσι αν δώσουμε:
C:> vuln hello!
The string is hello!
Τι θα γίνει όμως αν δώσουμε κάτι μεγαλύτερο από 8 bytes?
Ας δούμε...
C:> vuln aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
The string is aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Unhandled exception at 0x61616161 in vuln.exe: 0xC0000005: Access violation reading location 0x61616161.
Χμ... έσκασε.
Ξέρετε τι είναι το 0x61616161?
Είναι η τιμή του καταχωρητή (register) EIP (Extended Instruction Pointer) ο οποίος δείχνει την επόμενη πρός εκτέλεση εντολή. Αυτός χωράει 4 bytes. Δηλαδή είναι 61 61 61 61. Το 61 είναι ένας 16δικός αριθμός που αναπαριστά τον χαρακτήρα a.
Μα βέβαια τον a!! Θυμάστε..! δώσαμε aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa. Οπότε καταφέραμε να γραψουμε επάνω στο EIP!!
Σε ποιά θέση όμως της σειράς aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa έγινε το overflow?
Κάποιος θα έλεγε στην 7η, δηλαδή στην αμέσως επόμενη από αυτήν που ορίζει το μήκος της μεταβλητής μας (s).
Nice try... δεν είναι όμως έτσι.
Υπάρχουνε 2 τρόποι να βρούμε την ακριβή διεύθυνση:
Ο θεωρητικός και ο πρακτικός.
Έστω οτι δεν γνωρίζουμε θεωρία και ας πάμε με την γνωστή μέθοδο “blind attack”.
Αυτό που πρέπει να ξέρουμε είναι οτι (στο stack) oι μεταβλητές μας αποθηκεύονται σε θέσεις των 4ων Bytes. Για να βρούμε που ακριβώς σκάει το πρόγραμμα θα κανουμε ένα κόλπο. Θα δώσουμε:
C:> vuln xxxxyyyyzzzzaaaabbbbcccc
The string is xxxxyyyyzzzzaaaabbbbcccc
Unhandled exception at 0x61616161 in vuln.exe: 0xC0000005: Access violation reading location 0x61616161.
Πάλι 61!! Δηλαδή το aaaa στις θέσεις 13-16 (4 θέσεις!). Τι είναι εκεί? Μα η διεύθυνση που δείχνει ο καταχωτητής της επόμενης προς εκτέλεση εντολής (ο EIP).
Άρα!!!!!
Άν σε αυτές τις θέσεις βάλω μια «δική» μου διεύθυνση τότε το πρόγραμμα θα συνεχίσει την εκτέλεση του από εκεί που θα του πω εγώ!
Και λίγη θεωρία
~~~~~~~~~~~~~~~
Γιατι ο IP «κοιτά» στην θεση 13?
Στο stack που καταχωρούνται οι τιμές που δίνουμε είναι ως εξής:
xxxx <- s[4]
yyyy <- s[2]
zzzz <- EBP
aaaa <- EIP !!!!!!! Εδώ γίνεται το overflow.
bbbb
cccc
Μπορεί την μεταβλητή s να την έχουμε δηλώσει σαν μέγεθος 6 αλλά στην πραγματικότητα τα bytes που θα «κρατηθούν» στην μνήμη θα είναι πολλαπλάσια του 4, δηλαδή στην περίπτωση μας 8. Tα πρώτα 8 byteς, λοιπόν, φυλάχθηκαν για να κρατήσουν τα δεδομένα της μεταβλητής s.
Τα επόμενα 4 κρατούνται για τον καταχωρητή Base Pointer [7]. Τέλος, τα επόμενα 4 bytes κρατούνται από τον καταχωρητή EIP. Δηλαδή αυτόν που μας ενδιαφέρει!
Επίθεση!
~~~~~~~~
Για την επίθεση θα χρησιμοποιήσουμε την εξής τεχνική:
Θα κάνουμε redirection τον EIP σε μια διεύθυνση που δείχνει σε μια api function (την WinExec) μέσα στην system dll kernel32.dll. Αυτήν την dll την «βλέπουνε» όλα τα executables. Με αυτόν τον τρόπο δεν θα μπορέσει το DEP να καταλάβει αν το redirection έγινε από άλλο πρόγραμμα με «κακό» σκοπό ή από το ίδιο το πρόγραμμα «θύμα» μέσω μιας κανονικής κλήσης που αποτελούσε μέρος της κανονικής ροής του προγράμματος.
Αυτό που μας λείπει τώρα είναι η διεύθυνση της WinExec.
Για να την βρούμε θα χρησιμοποιήσουμε ένα μικρό αλλά πολύ χρήσιμο προγραμματάκι. Το depends.exe (μπορούμε να το κατεβάσουμε από το site της micro$oft).
Ξεκινάμε το πρόγραμμα. Πατάμε Open και επιλέγουμε το vuln.exe.
Η οθόνη του προγράμματος χωρίζετε σε 5 μέρη:
12
13
44
55
Επιλέχτε Kernel32.DLL στο μέρος 1.
Μετά, επιλέχτε (στο μέρος 3) την WinExec function. Κρατήστε την διεύθυνση της WinExec. Ας την ονομάσουμε [FA] – (function address)
Τωρα, κρατήστε ένα ακόμα πράγμα:
Το entry point address της Kernel32.DLL που είναι η στήλη “Preffered Base” στο κομμάτι 5. Ας την ονομάσουμε [KBA] - (Kernel Base Address).
Η διεύθυνση που μας ενδιφέρει βρίσκεται από τον τύπο:
[KBA]+[FA].
Στο box μου αυτή η διεύθυνση είναι η 0x7c86136d.
Αυτό που μένει τώρα είναι να κάνουμε την επίθεση.
Εδώ (κλασικά) θα χρησιμοποιήσουμε Perl. Ο λόγος είναι οτι δεν μπορούμε με ποιο έυκολο τρόπο να περάσουμε στην command line του vuln.exe την 16δική διεύθυνση 0x7c86136d παρά μόνο αν το καλέσουμε μέσα από ένα άλλο πρόγραμμα (αυτό της Perl).
Φτιάχνουμε, λοιπόν, το εξής γελοίο πρόγραμμα σε perl:
# c:\perl\bin\perl attack.perl
#
# Buffer overflow using Command line attach.
# (c) by Thiseas 2007
#
$prg = "vuln xxxxyyyyzzzz\x6d\x13\x86\x7c explorer.exe";
system($prg);
Δώστε βάση στην διεύθυνση που περνάμε ... είναι με την ανάποδη σειρά από αυτήν που βρήκαμε... Αυτό δεν θα το εξηγήσω, βρήτε και κάτι μόνοι σας, εκτός από αυτούς που ήδη το γνωρίζουν, στους οποίους ζητώ συγγνώμη για τον... «εξυπνακισμό» μου!!
Το παραπάνω προγραμματάκι με overflow καλεί τον windows explorer.. ;)
Θα δούμε οτι «παίζει» ανεξάρτητα από το αν έχουμε activate το DEP ή οχι.
Παίζοντας με το παραπάνω παράδειγμα μπορούμε να βγάλουμε και άλλα χρήσιμα συμπεράσματα όπως επίσης και κάποια... παράδοξα. Δεν θα τα πω όλα εδώ όμως... άλλοστε αυτό το αρθράκι σκοπεύει στην περαιτέρω μελέτη από εσάς μιας και ο στόχος είναι η γνώση που αποκτιέται από την προσωπική αφιέρωση και κόπο, γιατί μόνο τότε αξίζει πραγματικά.
Happy Programming
Bye By Thiseas
Αναφορές
[1]. http://support.microsoft.com/kb/875352
[2]. http://msdn2.microsoft.com/en-us/library/aa366553.aspx
[3]. http://www.uninformed.org/?v=2&a=4
[4]. http://www.nextgenss.com/papers/defeating-w2k3-stack-protection.pdf
[5]. http://en.wikipedia.org/wiki/X86_assembly_language
[6.]. http://en.wikipedia.org/wiki/Processor_register
[7]. http://www.cs.miami.edu/~burt/journal/NT/basepointer.html
[8.]. http://www.maxpatrol.com/defeating-xpsp2-heap-protection.pdf
Nothing to declare...