Περίπου μία ευπάθεια σε…

Περίπου μία ευπάθεια σε…

Πριν από ένα χρόνο, 21 Μαρτίου 2019, στο Πρόγραμμα επιβράβευσης σφαλμάτων Mail.Ru ένα πολύ καλό ήρθε στο HackerOne αναφορά σφαλμάτων από maxarr. Κατά την εισαγωγή ενός μηδενικού byte (ASCII 0) στην παράμετρο POST ενός από τα αιτήματα API του webmail που επέστρεψαν ανακατεύθυνση HTTP, κομμάτια μη αρχικοποιημένης μνήμης ήταν ορατά στα δεδομένα ανακατεύθυνσης, στα οποία τμήματα από παραμέτρους GET και κεφαλίδες άλλων αιτημάτων στο τον ίδιο διακομιστή.

Αυτή είναι μια κρίσιμη ευπάθεια γιατί... Τα αιτήματα περιέχουν επίσης cookies περιόδου λειτουργίας. Λίγες ώρες αργότερα, έγινε μια προσωρινή επιδιόρθωση που φιλτράρει το μηδενικό byte (όπως αποδείχθηκε αργότερα, αυτό δεν ήταν αρκετό, επειδή υπήρχε ακόμα η δυνατότητα εισαγωγής CRLF / ASCII 13, 10, το οποίο σας επιτρέπει να χειρίζεστε τις κεφαλίδες και δεδομένα της απόκρισης HTTP, αυτό είναι λιγότερο κρίσιμο, αλλά εξακολουθεί να είναι δυσάρεστο). Ταυτόχρονα, το πρόβλημα μεταφέρθηκε σε αναλυτές ασφαλείας και προγραμματιστές για να βρουν και να εξαλείψουν τα αίτια του σφάλματος.

Η αλληλογραφία Mail.ru είναι μια πολύ περίπλοκη εφαρμογή· ένας μεγάλος αριθμός διαφορετικών στοιχείων front-end/back-end, τόσο ανοιχτού κώδικα (ευχαριστώ πολύ σε όλους τους προγραμματιστές ελεύθερου λογισμικού) όσο και που έχουν αναπτυχθεί εσωτερικά, μπορούν να συμμετάσχουν στη δημιουργία της απόκρισης. Καταφέραμε να εξαιρέσουμε όλα τα στοιχεία εκτός από το nginx και το openresty και να εντοπίσουμε το πρόβλημα πριν καλέσουμε ngx.req.set_uri() σε ένα σενάριο OpenResty που δεν συμπεριφέρθηκε όπως αναμενόταν (εισαγωγή ενός null byte ή τροφοδοσίας γραμμής μέσω παραμέτρων GET με rewrite στο ngx_http_rewrite_module, το οποίο, σύμφωνα με την τεκμηρίωση, χρησιμοποιείται και, όπως φαίνεται, θα πρέπει να λειτουργεί με τον ίδιο ακριβώς τρόπο, θα δεν λειτουργούν). Οι πιθανές συνέπειες εξαλείφθηκαν, το φιλτράρισμα προστέθηκε όσο το δυνατόν αυστηρότερα και το φιλτράρισμα επαληθεύτηκε για την εξάλειψη όλων των πιθανών φορέων. Όμως ο μηχανισμός που οδήγησε στη διαρροή των περιεχομένων της μνήμης παρέμεινε μυστήριο. Ένα μήνα αργότερα, η αναφορά σφάλματος έκλεισε όπως επιλύθηκε και η ανάλυση των αιτιών του σφάλματος αναβλήθηκε για καλύτερες στιγμές.

Το OpenResty είναι ένα πολύ δημοφιλές πρόσθετο που σας επιτρέπει να γράφετε σενάρια Lua μέσα στο nginx και χρησιμοποιείται σε πολλά έργα Mail.ru, επομένως το πρόβλημα δεν θεωρήθηκε λυμένο. Και μετά από κάποιο χρονικό διάστημα, τελικά επέστρεψαν σε αυτό για να κατανοήσουν τους πραγματικούς λόγους, τις πιθανές συνέπειες και να κάνουν συστάσεις για τους προγραμματιστές. Συμμετείχε στην ανασκαφή του πηγαίου κώδικα Ντένις Ντενίσοφ и Νικολάι Ερμίσκιν. Αποδείχθηκε ότι:

  • Στο nginx, όταν χρησιμοποιείται επανεγγραφή με δεδομένα χρήστη, υπάρχει η δυνατότητα διέλευσης καταλόγου (και πιθανώς SSRF) σε ορισμένες διαμορφώσεις, αλλά αυτό είναι γνωστό γεγονός και θα πρέπει να ανιχνεύεται από αναλυτές στατικής διαμόρφωσης Nginx Amplify и Γκιξ από το Yandex (ναι, το χρησιμοποιούμε κι αυτό, ευχαριστώ). Όταν χρησιμοποιείτε το OpenResty, αυτή η δυνατότητα είναι εύκολο να χαθεί, αλλά αυτό δεν επηρέασε τη διαμόρφωσή μας.

    Παράδειγμα διαμόρφωσης:

    location ~ /rewrite {
        rewrite ^.*$ $arg_x;
    }
    
    location / {
        root html;
        index index.html index.htm;
    }

    αποτέλεσμα

    curl localhost:8337/rewrite?x=/../../../../../../../etc/passwd
    root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
    ...

  • Το Nginx έχει ένα σφάλμα που προκαλεί διαρροή μνήμης εάν η γραμμή επανεγγραφής περιέχει ένα μηδενικό byte. Όταν εκδίδεται μια ανακατεύθυνση, το nginx εκχωρεί μια νέα προσωρινή μνήμη που αντιστοιχεί στο πλήρες μήκος της γραμμής, αλλά αντιγράφει τη γραμμή εκεί μέσω μιας συνάρτησης γραμμής στην οποία το μηδενικό byte είναι ένας τερματιστής γραμμής, επομένως η γραμμή αντιγράφεται μόνο μέχρι το μηδέν byte· το υπόλοιπο buffer περιέχει μη αρχικοποιημένα δεδομένα. Μια λεπτομερής ανάλυση μπορεί να βρεθεί εδώ.

    παράδειγμα διαμόρφωσης (^@ μηδέν byte)

    
    location ~ /memleak {
        rewrite ^.*$ "^@asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdasdf";
    }
    
    location / {
        root html;
        index index.html index.htm;
    }

    αποτέλεσμα
    curl localhost:8337/secret -vv
    ...
    curl localhost:8337/memleak -vv
    ...
    Location: http://localhost:8337/secret
    ...

  • Το Nginx προστατεύει τις παραμέτρους GET από την εισαγωγή χαρακτήρων υπηρεσίας και καθιστά δυνατή τη χρήση μόνο των παραμέτρων GET στην επανεγγραφή. Επομένως, δεν είναι δυνατή η εκμετάλλευση της ένεσης μέσω παραμέτρων ελεγχόμενων από τον χρήστη στο nginx. Οι παράμετροι POST δεν προστατεύονται. Το OpenResty σάς επιτρέπει να εργάζεστε τόσο με τις παραμέτρους GET όσο και με τις παραμέτρους POST, επομένως όταν χρησιμοποιείτε παραμέτρους POST μέσω του OpenResty, καθίσταται δυνατή η εισαγωγή ειδικών χαρακτήρων.

    Παράδειγμα διαμόρφωσης:

    location ~ /memleak {
        rewrite_by_lua_block {
            ngx.req.read_body();
            local args, err = ngx.req.get_post_args();
            ngx.req.set_uri( args["url"], true );
        }
    }
    
    location / {
        root html;
        index index.html index.htm;
    }
    

    αποτέλεσμα:

    curl localhost:8337 -d "url=secret" -vv
    ...
    curl localhost:8337 -d "url=%00asdfasdfasdfasdfasdfasdfasdfasdf" -vv
    ...
    Location: http://localhost:8337/{...может содержать secret...}
    ...

Περαιτέρω αντίδραση

Το πρόβλημα αναφέρθηκε στους προγραμματιστές του nginx και του OpenResty, οι προγραμματιστές δεν θεωρούν το πρόβλημα ως σφάλμα ασφαλείας στο nginx, επειδή στο ίδιο το nginx δεν υπάρχει τρόπος να εκμεταλλευτεί κανείς το σφάλμα μέσω της ένεσης ειδικών χαρακτήρων, διορθώστε αποκάλυψη μνήμης δημοσιεύτηκε στις 16 Δεκεμβρίου. Στους 4 μήνες από την αναφορά, δεν έγιναν αλλαγές στο OpenResty, αν και έγινε κατανοητό ότι χρειαζόταν μια ασφαλής έκδοση της συνάρτησης ngx.req.set_uri(). Στις 18 Μαρτίου 2020 δημοσιεύσαμε πληροφορίες, στις 21 Μαρτίου κυκλοφόρησε το OpenResty έκδοση 1.15.8.3, το οποίο προσθέτει επικύρωση URI.

Portswigger написал καλό άρθρο και έλαβε σχόλια από το OpenResty και το Nginx (αν και το σχόλιο ότι εκτίθεται μόνο ένα μικρό κομμάτι μνήμης είναι εσφαλμένο και παραπλανητικό, αυτό καθορίζεται από το μήκος της γραμμής που ακολουθεί το null byte και, ελλείψει σαφών περιορισμών στο μήκος, μπορεί να ελεγχθεί από τον εισβολέα).

Ποιο ήταν λοιπόν το λάθος και τι μπορεί να γίνει για να το αποτρέψει;

Υπήρχε κάποιο σφάλμα στο nginx; Ναι, ήταν, γιατί μια διαρροή μνήμης είναι σφάλμα σε κάθε περίπτωση.

Υπήρχε κάποιο σφάλμα στο OpenResty; Ναι, τουλάχιστον το θέμα της ασφάλειας της λειτουργικότητας που προσφέρει το OpenResty δεν έχει διερευνηθεί και τεκμηριωθεί.

Υπήρχε σφάλμα διαμόρφωσης/χρήσης με το OpenResty; Ναι, επειδή ελλείψει ρητής δήλωσης, έγινε μια μη επαληθευμένη υπόθεση σχετικά με την ασφάλεια της λειτουργικότητας που χρησιμοποιείται.

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

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

Ερράτα

Από εμπειρία προηγούμενο άρθρο, για χάρη της διατήρησης της καθαρότητας της γλώσσας:

bug bounty - Διαγωνισμός κυνηγιού ζωύφιου
αναφορά σφαλμάτων - ειδοποίηση σφάλματος
διευθύνω πάλιν - ανακατεύθυνση
ανοιχτή πηγή - ανοιχτή πηγή
λάθος - εργαστείτε σε λάθη

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο