MS Remote Desktop Gateway, HAProxy και κωδικός πρόσβασης brute force

Φίλοι, γεια σας!

Υπάρχουν πολλοί τρόποι για να συνδεθείτε από το σπίτι στον χώρο εργασίας του γραφείου σας. Ένα από αυτά είναι η χρήση της πύλης Microsoft Remote Desktop Gateway. Αυτό είναι RDP μέσω HTTP. Δεν θέλω να θίξω τη ρύθμιση του ίδιου του RDGW εδώ, δεν θέλω να συζητήσω γιατί είναι καλό ή κακό, ας το αντιμετωπίσουμε ως ένα από τα εργαλεία απομακρυσμένης πρόσβασης. Θέλω να μιλήσω για την προστασία του διακομιστή RDGW από το κακό Διαδίκτυο. Όταν εγκατέστησα τον διακομιστή RDGW, ανησυχούσα αμέσως για την ασφάλεια, ειδικά την προστασία από την ωμή βία με κωδικό πρόσβασης. Ήμουν έκπληκτος που δεν βρήκα κανένα άρθρο στο Διαδίκτυο σχετικά με το πώς να το κάνω αυτό. Λοιπόν, θα πρέπει να το κάνετε μόνοι σας.

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

Ένας καλός τρόπος για την προστασία των εσωτερικών πόρων από το εξωτερικό περιβάλλον είναι μέσω διαφόρων proxies, συστημάτων δημοσίευσης και άλλων WAF. Ας θυμηθούμε ότι το RDGW εξακολουθεί να είναι http, τότε απλώς ζητά να συνδέσουμε μια εξειδικευμένη λύση μεταξύ των εσωτερικών διακομιστών και του Διαδικτύου.

Ξέρω ότι υπάρχουν cool F5, A10, Netscaler(ADC). Ως διαχειριστής ενός από αυτά τα συστήματα, θα πω ότι είναι επίσης δυνατό να δημιουργηθεί προστασία έναντι της ωμής βίας σε αυτά τα συστήματα. Και ναι, αυτά τα συστήματα θα σας προστατεύσουν επίσης από κάθε πλημμύρα syn.

Αλλά δεν έχει κάθε εταιρεία να αγοράσει μια τέτοια λύση (και να βρει έναν διαχειριστή για ένα τέτοιο σύστημα :), αλλά ταυτόχρονα μπορεί να φροντίσει για την ασφάλεια!

Είναι απολύτως δυνατή η εγκατάσταση μιας δωρεάν έκδοσης του HAProxy σε ένα δωρεάν λειτουργικό σύστημα. Δοκίμασα στο Debian 10, haproxy έκδοση 1.8.19 στο σταθερό αποθετήριο. Το δοκίμασα επίσης στην έκδοση 2.0.xx από το αποθετήριο δοκιμών.

Θα αφήσουμε τη ρύθμιση του ίδιου του debian εκτός του πεδίου εφαρμογής αυτού του άρθρου. Εν συντομία: στη λευκή διεπαφή, κλείστε τα πάντα εκτός από τη θύρα 443, στη γκρι διεπαφή - σύμφωνα με την πολιτική σας, για παράδειγμα, κλείστε επίσης τα πάντα εκτός από τη θύρα 22. Ανοίξτε μόνο ότι είναι απαραίτητο για εργασία (VRRP για παράδειγμα, για floating ip).

Πρώτα απ 'όλα, ρύθμισα το haproxy σε λειτουργία γεφύρωσης SSL (γνωστός και ως λειτουργία http) και ενεργοποίησα την καταγραφή για να δω τι συμβαίνει μέσα στο RDP. Έτσι για να πω, μπήκα στη μέση. Έτσι, η διαδρομή /RDWeb που καθορίζεται σε "όλα" άρθρα σχετικά με τη ρύθμιση του RDGateway λείπει. Το μόνο που υπάρχει είναι το /rpc/rpcproxy.dll και το /remoteDesktopGateway/. Σε αυτήν την περίπτωση, δεν χρησιμοποιούνται τυπικά αιτήματα GET/POST· χρησιμοποιείται ο δικός τους τύπος αιτήματος RDG_IN_DATA, RDG_OUT_DATA.

Όχι πολλά, αλλά τουλάχιστον κάτι.

Ας δοκιμάσουμε.

Εκκινώ το mstsc, πηγαίνω στον διακομιστή, βλέπω τέσσερα σφάλματα 401 (μη εξουσιοδοτημένα) στα αρχεία καταγραφής, μετά εισάγω το όνομα χρήστη/κωδικό μου και βλέπω την απάντηση 200.

Το σβήνω, το ξαναρχίζω και στα αρχεία καταγραφής βλέπω τα ίδια τέσσερα σφάλματα 401. Εισάγω λάθος login/password και ξαναβλέπω τέσσερα σφάλματα 401. Αυτό χρειάζομαι. Αυτό θα πιάσουμε.

Δεδομένου ότι δεν ήταν δυνατός ο προσδιορισμός του url σύνδεσης και, επιπλέον, δεν ξέρω πώς να συλλάβω το σφάλμα 401 στα χαπροξικά, θα πιάσω (στην πραγματικότητα δεν θα πιάσω, αλλά θα μετρήσω) όλα τα σφάλματα 4xx. Κατάλληλο και για την επίλυση του προβλήματος.

Η ουσία της προστασίας θα είναι ότι θα μετρήσουμε τον αριθμό των σφαλμάτων 4xx (στο backend) ανά μονάδα χρόνου και εάν υπερβεί το καθορισμένο όριο, τότε θα απορρίψουμε (στο frontend) όλες τις περαιτέρω συνδέσεις από αυτήν την ip για τον καθορισμένο χρόνο .

Τεχνικά, αυτό δεν θα είναι προστασία έναντι ωμής βίας με κωδικό πρόσβασης, θα είναι προστασία έναντι σφαλμάτων 4xx. Για παράδειγμα, εάν ζητάτε συχνά μια ανύπαρκτη διεύθυνση url (404), τότε η προστασία θα λειτουργήσει επίσης.

Ο απλούστερος και πιο αποτελεσματικός τρόπος είναι να υπολογίζετε στο backend και να αναφέρετε εάν εμφανιστεί κάτι επιπλέον:

frontend fe_rdp_tsc
    bind *:443 ssl crt /etc/haproxy/cert/desktop.example.com.pem
    mode http
    ...
    default_backend be_rdp_tsc


backend be_rdp_tsc
    ...
    mode http
    ...

    #создать таблицу, строковую, 1000 элементов, протухает через 15 сек, записать кол-во ошибок за последние 10 сек
    stick-table type string len 128 size 1k expire 15s store http_err_rate(10s)
    #запомнить ip
    http-request track-sc0 src
    #запретить с http ошибкой 429, если за последние 10 сек больше 4 ошибок
    http-request deny deny_status 429 if { sc_http_err_rate(0) gt 4 }
	
	...
    server rdgw01 192.168.1.33:443 maxconn 1000 weight 10 ssl check cookie rdgw01
    server rdgw02 192.168.2.33:443 maxconn 1000 weight 10 ssl check cookie rdgw02

Δεν είναι η καλύτερη επιλογή, ας το περιπλέκουμε. Θα υπολογίζουμε στο backend και θα μπλοκάρουμε στο frontend.

Θα συμπεριφερθούμε με αγένεια στον εισβολέα και θα εγκαταλείψουμε τη σύνδεσή του TCP.

frontend fe_rdp_tsc
    bind *:443 ssl crt /etc/haproxy/cert/ertelecom_ru_2020_06_11.pem
    mode http
    ...
    #создать таблицу ip адресов, 1000 элементов, протухнет через 15 сек, сохрянять из глобального счётчика
    stick-table type ip size 1k expire 15s store gpc0
    #взять источник
    tcp-request connection track-sc0 src
    #отклонить tcp соединение, если глобальный счётчик >0
    tcp-request connection reject if { sc0_get_gpc0 gt 0 }
	
    ...
    default_backend be_rdp_tsc


backend be_rdp_tsc
    ...
    mode http
    ...
	
    #создать таблицу ip адресов, 1000 элементов, протухнет через 15 сек, сохранять кол-во ошибок за 10 сек
    stick-table type ip size 1k expire 15s store http_err_rate(10s)
    #много ошибок, если кол-во ошибок за 10 сек превысило 8
    acl errors_too_fast sc1_http_err_rate gt 8
    #пометить атаку в глобальном счётчике (увеличить счётчик)
    acl mark_as_abuser sc0_inc_gpc0(fe_rdp_tsc) gt 0
    #обнулить глобальный счётчик
    acl clear_as_abuser sc0_clr_gpc0(fe_rdp_tsc) ge 0
    #взять источник
    tcp-request content track-sc1 src
    #отклонить, пометить, что атака
    tcp-request content reject if errors_too_fast mark_as_abuser
    #разрешить, сбросить флажок атаки
    tcp-request content accept if !errors_too_fast clear_as_abuser
	
    ...
    server rdgw01 192.168.1.33:443 maxconn 1000 weight 10 ssl check cookie rdgw01
    server rdgw02 192.168.2.33:443 maxconn 1000 weight 10 ssl check cookie rdgw02

το ίδιο πράγμα, αλλά ευγενικά, θα επιστρέψουμε το σφάλμα http 429 (Πάρα πολλά αιτήματα)

frontend fe_rdp_tsc
    ...
    stick-table type ip size 1k expire 15s store gpc0
    http-request track-sc0 src
    http-request deny deny_status 429 if { sc0_get_gpc0 gt 0 }
    ...
    default_backend be_rdp_tsc

backend be_rdp_tsc
    ...
    stick-table type ip size 1k expire 15s store http_err_rate(10s)
    acl errors_too_fast sc1_http_err_rate gt 8
    acl mark_as_abuser sc0_inc_gpc0(fe_rdp_tsc) gt 0
    acl clear_as_abuser sc0_clr_gpc0(fe_rdp_tsc) ge 0
    http-request track-sc1 src
    http-request allow if !errors_too_fast clear_as_abuser
    http-request deny deny_status 429 if errors_too_fast mark_as_abuser
    ...

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

Εξηγήσεις. Απέχω πολύ από τον αφρόξο. Δεν καταλαβαίνω γιατί, για παράδειγμα
http-request deny deny_status 429 if { sc_http_err_rate(0) gt 4 }
σας επιτρέπει να κάνετε περίπου 10 λάθη πριν λειτουργήσει.

Έχω μπερδευτεί με την αρίθμηση των μετρητών. Δάσκαλοι της αφροξίας, θα χαρώ να με συμπληρώσετε, να με διορθώσετε, να με κάνετε καλύτερο.

Στα σχόλια μπορείτε να προτείνετε άλλους τρόπους προστασίας του RD Gateway, θα είναι ενδιαφέρον να μελετήσετε.

Όσον αφορά το Windows Remote Desktop Client (mstsc), αξίζει να σημειωθεί ότι δεν υποστηρίζει TLS1.2 (τουλάχιστον στα Windows 7), οπότε έπρεπε να φύγω από το TLS1. δεν υποστηρίζει την τρέχουσα κρυπτογράφηση, οπότε έπρεπε επίσης να αφήσω τα παλιά.

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

απροξία.conf

global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        # See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
        #ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE
-RSA-AES256-GCM-SHA384
        ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
        #ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
        ssl-default-bind-options no-sslv3
        ssl-server-verify none


defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5000
        timeout client  15m
        timeout server  15m
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http


frontend fe_rdp_tsc
    bind *:443 ssl crt /etc/haproxy/cert/dektop.example.com.pem
    mode http
    capture request header Host len 32
    log global
    option httplog
    timeout client 300s
    maxconn 1000

    stick-table type ip size 1k expire 15s store gpc0
    tcp-request connection track-sc0 src
    tcp-request connection reject if { sc0_get_gpc0 gt 0 }

    acl rdweb_domain hdr(host) -i beg dektop.example.com
    http-request deny deny_status 400 if !rdweb_domain
    default_backend be_rdp_tsc


backend be_rdp_tsc
    balance source
    mode http
    log global

    stick-table type ip size 1k expire 15s store http_err_rate(10s)
    acl errors_too_fast sc1_http_err_rate gt 8
    acl mark_as_abuser sc0_inc_gpc0(fe_rdp_tsc) gt 0
    acl clear_as_abuser sc0_clr_gpc0(fe_rdp_tsc) ge 0
    tcp-request content track-sc1 src
    tcp-request content reject if errors_too_fast mark_as_abuser
    tcp-request content accept if !errors_too_fast clear_as_abuser

    option forwardfor
    http-request add-header X-CLIENT-IP %[src]

    option httpchk GET /
    cookie RDPWEB insert nocache
    default-server inter 3s    rise 2  fall 3
    server rdgw01 192.168.1.33:443 maxconn 1000 weight 10 ssl check cookie rdgw01
    server rdgw02 192.168.2.33:443 maxconn 1000 weight 10 ssl check cookie rdgw02


frontend fe_stats
    mode http
    bind *:8080
    acl ip_allow_admin src 192.168.66.66
    stats enable
    stats uri /stats
    stats refresh 30s
    #stats admin if LOCALHOST
    stats admin if ip_allow_admin

Γιατί δύο διακομιστές στο backend; Γιατί έτσι μπορείς να κάνεις ανοχή σφαλμάτων. Το Haproxy μπορεί επίσης να κάνει δύο με μια αιωρούμενη λευκή ip.

Υπολογιστικοί πόροι: μπορείτε να ξεκινήσετε με «δύο συναυλίες, δύο πυρήνες, υπολογιστή παιχνιδιών». Σύμφωνα με Βικιπαίδεια αυτό θα είναι αρκετό για να περισώσει.

Βιβλιογραφικές αναφορές:

Ρύθμιση rdp-gateway από το HAProxy
Το μόνο άρθρο που βρήκα όπου μπήκαν στον κόπο να επιβάλουν τον κωδικό πρόσβασης

Πηγή: www.habr.com

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