MS Remote Desktop Gateway, HAProxy ja paroolipüüdmine

Tere, sõbrad!

On palju viise, kuidas kodust töökohta kontorisse ühenduda. Üks neist on Microsoft Remote Desktop Gateway'i kasutamine. See on RDP üle HTTP. Ma ei soovi siin RDGW seadistamisega tegeleda ega arutada, miks see on hea või halb, vaid käsitlen seda kui ühte kaugjuurdepääsu tööriista. Soovin rääkida teie RDGW serveri kaitsmisest paha interneti eest. Kui ma RDGW serverid seadistasin, siis mõtlesin kohe kaitsmise peale, eriti paroolipüüdmisest. Mind üllatas, et ma ei leidnud internetist artikleid, mis selgitaks, kuidas seda teha. Tundub, et tuleb ise korda ajada.

RDGW'l endal ei ole mingeid kaitsemehhanisme. Jah, seda võib lihtsalt avada valgesse võrku, ja see töötab suurepäraselt. Kuid korralik administraator või küberturbe spetsialist tunneb sellest muret. Lisaks aitab see vältida olukordi, kus konto on blokeeritud, kui hooletu töötaja on salvestanud oma ettevõtte konto parooli kodusesse arvutisse, ja seejärel muutnud oma parooli.

Hea viis kaitsta sisemisi ressursse väliskeskkonna eest on erinevad proksid, publikatsiooni süsteemid ja muud WAF-ied. Meenutame, et RDGW on ikka http, seega on loogiline paigutada spetsialiseeritud lahendus sisemiste serverite ja Interneti vahele.

Ma tean, et on ägedaid F5, A10, Netscaler(ADC). Ühe sellise süsteemi administraatorina ütlen, et ka nende süsteemide seadistamine rünnakute ärahoidmiseks on täiesti võimalik. Ja jah, need süsteemid kaitsevad teid ka igasuguse syn-aktiivsuse eest.

Kuid mitte iga ettevõte ei saa endale lubada sellise lahenduse ostmist (ja sellise süsteemi administraatori leidmist :), aga keegi saab siiski hoolitseda julgeoleku eest!

On täiesti võimalik installida tasuta versioon HAProxy tasuta operatsioonisüsteemile. Olen testinud Debian 10 peal, stabiilses repodes on versioon haproxy 1.8.19. Olen kontrollinud ka versioone 2.0.xx testimise repos.

Debiani seadistust artiklis ei kajastata. Lühidalt: valges liides sulgege kõik peale 443 pordi, hallis liides — vastavalt teie poliitikale, näiteks sulgege kõik peale 22 pordi. Avage ainult see, mis on tööks vajalik (näiteks VRRP, ujuva IP jaoks).

Esiteks seadistasin haproxy SSL bridging režiimis (sama, mis http režiim) ja lõin logimise, et näha, mis RDP-s toimub. Niisiis, niikaua kui rahakoti vahelt sisse ronisin. Noh, teed, mis on näidatud "kõikides" RDGateway seadistamise artiklites, ei ole. Kõik, mis seal on, on \/rpc\/rpcproxy.dll ja \/remoteDesktopGateway\/. Samal ajal ei kasutata standardseid GET\/POST päringuid, vaid kasutatakse oma päringutüüpi RDG_IN_DATA, RDG_OUT_DATA.

Natuke, aga midagi siiski.

Alustame katsetamist.

Käitan mstsc ja lähen serverisse, logides näen nelja 401 (autentimise puudumine) viga, seejärel sisestan kasutajanime\/parooli ja näen vastust 200.

Lülitan välja, käivitame uuesti, logides näen samu nelja 401 viga. Sisestan vale kasutajanime\/parooli ja näen jälle nelja 401 viga. Just seda me püüame.

Kuna login URL-i määramine ei õnnestunud ja ma ei tea, kuidas haproxys täpselt 401 viga kinni püüda, siis loen kõiki 4xx vigu. See sobib samuti ülesande lahendamiseks.

Kaitse olemus seisneb selles, et loeme 4xx vigade arvu (backend'is) ajaühikus ning kui see ületab määratud piiri, siis keeldume (frontend'is) kõikide edasiste ühenduste tegemisest selle IP-ga määratud ajaks.

Tehniliselt ei ole see kaitse paroolide häkkimise vastu, vaid kaitse 4xx vigade vastu. Näiteks kui sagedasti küsitakse mitte eksisteerivat URL-i (404), siis toimib kaitse samuti.

Lihtsaim ja toimiv viis on backend'is loendada ja blokeerida, kui midagi üleliigset tekib:

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
    ...

    #loo create a string table, 1000 entries, expires in 15 seconds, records the number of errors in the last 10 seconds
    stick-table type string len 128 size 1k expire 15s store http_err_rate(10s)
    #remember ip
    http-request track-sc0 src
    #deny with http error 429 if more than 4 errors in the last 10 seconds
    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

See, this is not the best option; let's complicate it. We will count on the backend and block on the frontend.

We will deal with the attacker harshly; we will drop the TCP connection.

frontend fe_rdp_tsc
    bind *:443 ssl crt /etc/haproxy/cert/ertelecom_ru_2020_06_11.pem
    mode http
    ...
    # looja ip aadresside tabel, 1000 elementi, kehtib 15 sek, salvestada globaalne loendur
    stick-table type ip size 1k expire 15s store gpc0
    # võtma allikas
    tcp-request connection track-sc0 src
    # lükata tagasi tcp ühendus, kui globaalne loendur >0
    tcp-request connection reject if { sc0_get_gpc0 gt 0 }
	
    ...
    default_backend be_rdp_tsc


backend be_rdp_tsc
    ...
    mode http
    ...
	
    # looja ip aadresside tabel, 1000 elementi, kehtib 15 sek, salvestada vigade arv 10 sek
    stick-table type ip size 1k expire 15s store http_err_rate(10s)
    # liiga palju vigu, kui vigade arv 10 sekundi jooksul ületab 8
    acl errors_too_fast sc1_http_err_rate gt 8
    # märgi rünnak globaalne loendurisse (suurenda loendur)
    acl mark_as_abuser sc0_inc_gpc0(fe_rdp_tsc) gt 0
    # nullida globaalne loendur
    acl clear_as_abuser sc0_clr_gpc0(fe_rdp_tsc) ge 0
    # võtma allikas
    tcp-request content track-sc1 src
    # lükata tagasi, märgi kui rünnak
    tcp-request content reject if errors_too_fast mark_as_abuser
    # luba, tühista rünnaku lipp
    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

ka sama, aga viisakalt, tagastame http 429 (Liiga Palju Päringuid) vea.

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
    ...

Kontrollin: käivitan mstsc ja hakkan juhuslikult parooli sisestama. Pärast kolmandat katset 10 sekundi jooksul visatakse mind välja ja mstsc annab veateate. See on nähtav ka logides.

Selgitused. Ma ei ole haproxy ekspert. Ma ei saa aru, miks näiteks
http-request deny deny_status 429 if { sc_http_err_rate(0) gt 4 }
lubab teha umbes 10 viga, enne kui see aktiveerub.

Ma segan kokku loendurite numbrid. Haproxy meistrid, oleksin tänulik, kui täiendaksite mind, parandaksite, teeksite paremini.

Kommentaarides saate jagada muid RD Gateway kaitse meetodeid, oleks huvitav uurida.

Seoses Windowsi kaugjuhtimise töölaudade kliendiga (mstsc) tasub märkida, et see ei toeta TLS1.2 (vähemalt Windows 7-s), seega tuli jätta TLS1; ei toeta kaasaegseid cipher’e, seega tuli ka jätta vanad.

Needjatele, kes ei saanud aru ja alles õpivad, aga tahavad juba hästi teha, toon välja kogu konfiguratsiooni.

haproxy.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

        # Vaikimisi SSL materjalide asukohad
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        # Vaata: 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

Miks on kaks serverit backendis? Sest nii saab teha tõrkekindluse. HAProxy saab samuti teha kaks ujuva valge IP-ga.

Arvutusressursid: saab alustada "kaks gigabaiti, kaks tuuma, mänguri ПК". Vastavalt vikipeedia seda on piisavalt isegi varuga.

Lingid:

RDP-gateway seadistamine HAProxy'lt
Ainus artikkel, mille ma leidsin, kus muretsetakse parooli proovimise üle

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster