· ~4 λεπτά ανάγνωσης
Στήνοντας μια PKI με mutual TLS, και τι κάνει ένας MitM χωρίς αυτή
Μια certificate authority δύο επιπέδων, ένας Apache με κλειδιά ελλειπτικών καμπυλών που δέχεται μόνο clients με πιστοποιητικό, και μια προσομοίωση man-in-the-middle σε απροστάτευτο LAN που δείχνει γιατί υπάρχουν αυτά τα μέτρα.
Στόχος
Να στήσω την υποδομή πιστοποιητικών που θα χρειαζόταν ένας μικρός οργανισμός, να κλειδώσω μια web υπηρεσία πίσω από mutual TLS, και μετά να δω το ίδιο είδος δικτύου από την πλευρά του επιτιθέμενου, για να φανεί τι πάει στραβά όταν το layer 2 και το TLS δεν προστατεύονται. Το αμυντικό κομμάτι είναι ο πυρήνας του lab· η επίθεση υπάρχει για να το δικαιολογήσει.
Οι εντολές και τα screenshots είναι στο repository στο GitHub.
Μια certificate authority δύο επιπέδων
| Επίπεδο | Ρόλος | Πού βρίσκεται |
|---|---|---|
| Root CA (RSA 4096, κλειδί κρυπτογραφημένο με AES-256) | Υπογράφει μόνο την intermediate | Offline |
| Intermediate CA (RSA 4096) | Υπογράφει servers και clients καθημερινά | Online, αντικαταστάσιμη |
| Server (ECDSA P-256) | Ο web server Apache | Web server |
| Client (RSA 4096, εξαγωγή ως .p12) | Ο browser ενός χρήστη | Μηχάνημα του χρήστη |
Το νόημα του δεύτερου επιπέδου είναι ο περιορισμός της ζημιάς. Αν παραβιαστεί το κλειδί της intermediate, η root την ανακαλεί και εκδίδει νέα· τίποτα που εμπιστεύεται τη root δεν χρειάζεται να αλλάξει. Αν η ίδια η root ήταν online και κλεβόταν, θα έπρεπε να ξαναχτιστεί όλη η ιεραρχία.
Ο server χρησιμοποιεί κλειδί ελλειπτικής καμπύλης (P-256): το ίδιο επίπεδο ασφάλειας με ένα πολύ μεγαλύτερο κλειδί RSA, με μικρότερα handshakes και λιγότερη CPU ανά σύνδεση.
Mutual TLS στον Apache
Το απλό TLS αποδεικνύει τον server στον client. Το mutual TLS κάνει και τον client να αποδείξει ποιος είναι, με πιστοποιητικό από μια CA που εμπιστεύεται ο server:
SSLCertificateFile server.crt
SSLCertificateKeyFile server.key
SSLCertificateChainFile chain.crt
SSLCACertificateFile chain.crt
SSLVerifyClient require
SSLVerifyDepth 2
Το SSLVerifyClient require αρνείται το TLS handshake σε όποιον δεν έχει έγκυρο πιστοποιητικό client· δεν υπάρχει σελίδα σύνδεσης να δεχτεί επίθεση, γιατί η σύνδεση δεν φτάνει ποτέ ως εκεί. Το SSLVerifyDepth 2 επιτρέπει ακριβώς την αλυσίδα client, intermediate, root. Η ρύθμιση ελέγχθηκε μετά με το sslscan.
Η άλλη πλευρά: ένας man-in-the-middle σε απροστάτευτο LAN
Σε ξεχωριστή προσομοίωση, σε απομονωμένο δίκτυο εργαστηρίου, έπαιξα τον επιτιθέμενο απέναντι σε ένα μηχάνημα-θύμα στο ίδιο LAN. Το ARP poisoning έβαλε τον επιτιθέμενο ανάμεσα στο θύμα και το gateway, και μια κλωνοποιημένη σελίδα σύνδεσης σε απλή διεύθυνση HTTP μάζεψε τα credentials που πληκτρολόγησε το θύμα. Τίποτα δεν ήταν εξελιγμένο, και αυτό είναι το δίδαγμα: σε ένα επίπεδο LAN χωρίς προστασία στο layer 2, ένας χρήστης που δεν κοιτά τη γραμμή διευθύνσεων απέχει ένα βήμα από το να δώσει τον κωδικό του.
Η ίδια επίθεση δεν κάνει τίποτα στην υπηρεσία με mTLS παραπάνω: ο επιτιθέμενος δεν μπορεί να παρουσιάσει το πιστοποιητικό του server, ούτε να ολοκληρώσει το handshake χωρίς πιστοποιητικό client.
Μέτρα
- Dynamic ARP Inspection (μαζί με DHCP snooping) στα switches, ώστε οι πλαστές απαντήσεις ARP να πετιούνται στη θύρα.
- Port security ή 802.1X, ώστε ένα άγνωστο μηχάνημα να μην παίρνει καν θύρα που δουλεύει.
- HSTS στα πραγματικά sites, ώστε οι browsers να αρνούνται να τους μιλήσουν με απλό HTTP και να αποτυγχάνει το SSL stripping.
- Αυθεντικοποίηση ανθεκτική στο phishing (κλειδιά FIDO2 ή passkeys) και, για εσωτερικές υπηρεσίες, mTLS: credentials που δεν πληκτρολογούνται σε ψεύτικη σελίδα δεν μπορούν να μαζευτούν από αυτήν.
- Ενημέρωση των χρηστών, τελευταία και όχι πρώτη: η εκπαίδευση βοηθά, αλλά τα μέτρα που δεν εξαρτώνται από το αν κάποιος θα προσέξει ένα λουκέτο που λείπει είναι πιο δυνατά.
Τι έμαθα
Ξαναδιαβάζοντας το δικό μου write-up, θα διόρθωνα και θα πρόσθετα κάποια πράγματα.
- Το HSTS δεν σταματά μια κλωνοποιημένη σελίδα σε άλλη διεύθυνση. Είχα γράψει αρχικά ότι το HSTS θα εξουδετέρωνε την κλωνοποιημένη σελίδα σύνδεσης. Προστατεύει το πραγματικό domain από υποβάθμιση σε HTTP· δεν κάνει τίποτα για μια σελίδα που μοιάζει, σε διαφορετική διεύθυνση. Απέναντι στο phishing credentials, αυτά που δουλεύουν είναι η αυθεντικοποίηση ανθεκτική στο phishing και τα μέτρα δικτύου, όχι το HSTS.
- Κάνε ρητά τα extensions των πιστοποιητικών. Οι browsers αγνοούν το common name και απαιτούν subjectAltName για το hostname του server, και ένα πιστοποιητικό CA πρέπει να το δηλώνει με
basicConstraints = CA:TRUE(μεpathlen:0στην intermediate). Η υπογραφή μεopenssl x509 -reqχωρίς αρχείο extensions τα αφήνει στην τύχη· θα υπέγραφα από αρχείο ρυθμίσεων με τα extensions γραμμένα. - Προστάτευσε το κλειδί client που εξάγεται. Ένα αρχείο .p12 κρατά το ιδιωτικό κλειδί του client· θέλει δυνατό κωδικό εξαγωγής και πρέπει να αντιμετωπίζεται όπως ο κωδικός που αντικαθιστά.
- Σχεδίασε την ανάκληση. Όπως σε κάθε PKI, πρέπει να υπάρχει CRL ή OCSP responder, ώστε το πιστοποιητικό client ενός χαμένου laptop να ανακαλείται πριν λήξει.
Προσωπικό lab σε απομονωμένο εικονικό δίκτυο· η επίθεση έτρεξε μόνο απέναντι στα δικά μου μηχανήματα του lab.
Θέλεις τα configs ή τον κώδικα από αυτό το lab, ή έχεις κάποια ερώτηση; Στείλε μου email στο papas@viotnet.com