MS Remote Desktop Gateway, HAProxy un paroles uzlaušana

Sveiki draugi!

Pastāv daudzi veidi, kā pieslēgties no mājām uz darba vietu birojā. Viens no tiem ir Microsoft Remote Desktop Gateway izmantošana. Tas ir RDP pār HTTP. Es nevēlos šeit runāt par paša RDGW konfigurēšanu, nevēlos diskutēt par to, kāpēc tas ir labs vai slikts, pieņemsim to kā vienu no attālinātā pieejas rīkiem. Es vēlos runāt par jūsu RDGW servera aizsardzību pret ļauno internetu. Kad es uzstādīju RDGW serveri, es nekavējoties uztraucos par aizsardzību, īpaši par aizsardzību pret paroles brutālo spēku. Mani pārsteidza, ka interneta plašumos es neatradu rakstus par to, kā to var izdarīt. Nu, nāksies rīkoties pašam.

Pašam RDGW nav nekādu aizsardzības līdzekļu. Jā, to var izņemt ar pliku saskarni baltajā tīklā, un tas darbosies lieliski. Bet pareizam administratoram vai kiberdrošības speciālistam no tā būs neomulīgi. Turklāt tas novērstu konta bloķēšanas situāciju, kad neuzmanīgs darbinieks ir atcerējies korporatīvā konta paroli mājas datorā, un pēc tam mainījis savu paroli.

Labs veids, kā aizsargāt iekšējos resursus no ārējās vides, ir dažādi proxy, publikācijas sistēmas un citas WAF. Atcerēsimies, ka RDGW ir tomēr HTTP, tad tiešām nāk prātā iebūvēt speciālizētu risinājumu starp iekšējiem serveriem un internetu.

Es zinu, ka ir forši F5, A10, Netscaler(ADC). Kā administratoram vienam no šīm sistēmām, varu teikt, ka aizsardzību pret brutālā spēka uzbrukumiem šajās sistēmās arī var iestatīt. Un jā, šīs sistēmas blakus pasargās jūs no jebkāda syn plūdu.

Bet ne katra kompānija var atļauties iegādāties līdzīgu risinājumu (un atrast šīs sistēmas administratoru :), bet par drošību šajā gadījumā būs jārūpējas!

Pavisam iespējams ir uzstādīt bezmaksas HAProxy versiju uz bezmaksas operētājsistēmas. Es testēju uz Debian 10, stabilajā repozitorijā versija haproxy 1.8.19. Tāpat pārbaudīju uz 2.0.xx versijām no testēšanas repozitorija.

Debiana pašas konfigurācijas atstāsim ārpus raksta. Īsumā: baltajā saskarnē aizvērt visu, izņemot 443. portu, pelēkajā saskarnē — pēc jūsu politikas, piemēram, arī aizvērt visu, izņemot 22. portu. Atvērt tikai to, kas nepieciešams darbam (VRRP piemēram, plūstošajam IP).

Vispirms konfigurēju haproxy SSL tilta režīmā (tas ir, http režīmā) un ieslēdzu žurnālfailu, lai redzētu, kas notiek iekš RDP. Teiksim, ieiešu pa vidu. Tātad, ceļš, kas norādīts visās RDGateway iestatīšanas rakstos, \/RDWeb trūkst. Viss, kas tur ir, ir \/rpc\/rpcproxy.dll un \/remoteDesktopGateway\/. Turklāt netiek izmantoti standarta GET\/POST pieprasījumi; tiek izmantots savs pieprasījuma veids RDG_IN_DATA, RDG_OUT_DATA.

Ne daudz, bet vismaz kaut kas.

Sāksim testēt.

Palaidzu mstsc, eju uz serveri, žurnālfailos redzu četras kļūdas 401 (nav autorizēts), pēc tam ievadu lietotājvārdu\/paroles un redzu atbildi 200.

Atspēju, palaidzu vēlreiz, žurnālfailos redzu tās pašas četras kļūdas 401. Ievadu nepareizu lietotājvārdu\/paroles un pēc tam atkal redzu četras kļūdas 401. Tas ir tieši tas, ko meklējam. To arī sekosim.

Tā kā definēt login url neizdevās un es nezinu, kā haproxy uztvert tieši kļūdu 401, es sekosim (patiesībā ne sekosim, bet skaitīsim) visas kļūdas 4xx. Tas arī derēs uzdevuma risināšanai.

Aizsardzības būtība būs tāda, ka mēs skaitīsim 4xx kļūdu skaitu (uz backend) noteiktā laika vienībā, un, ja tas pārsniegs norādīto slieksni, mēs noraidīsim (uz frontend) visus turpmākos savienojumus no šī IP uz norādīto laiku.

Tehniski, tas nebūs aizsardzība pret paroles uzminēšanu, bet tas būs aizsardzība pret 4xx kļūdām. Piemēram, ja bieži pieprasīs neeksistējošu URL (404), tad aizsardzība arī darbosies.

Vienkāršākais un strādājošais veids — tas ir backend skaitīt un bloķēt, ja parādās kas lieks:

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

    #izveidot tabulu, virkni, 1000 elementiem, derīguma termiņš 15 sek., saglabāt kļūdu skaitu pēdējās 10 sek.
    stick-table type string len 128 size 1k expire 15s store http_err_rate(10s)
    #atcerēties IP
    http-request track-sc0 src
    #aizliegt ar http kļūdu 429, ja pēdējās 10 sek. ir vairāk nekā 4 kļūdas
    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

Ne vislabākais variants, sarežģīsim. Skaitīsim uz backend, bet bloķēsim uz frontend.

Ar uzbrucēju izturēsimies rauji, noraidīsim viņam tcp savienojumu.

frontend fe_rdp_tsc
    bind *:443 ssl crt /etc/haproxy/cert/ertelecom_ru_2020_06_11.pem
    mode http
    ...
    #izveidot IP adresu tabulu, 1000 elementi, termiņš 15 sek, saglabāt no globālā skaitītāja
    stick-table type ip size 1k expire 15s store gpc0
    #iegūt avotu
    tcp-request connection track-sc0 src
    #noraidīt tcp savienojumu, ja globālais skaitītājs >0
    tcp-request connection reject if { sc0_get_gpc0 gt 0 }
	
    ...
    default_backend be_rdp_tsc


backend be_rdp_tsc
    ...
    mode http
    ...
	
    #izveidot IP adresu tabulu, 1000 elementi, termiņš 15 sek, saglabāt kļūdu skaitu 10 sek
    stick-table type ip size 1k expire 15s store http_err_rate(10s)
    #pārāk daudz kļūdu, ja kļūdu skaits 10 sek laikā pārsniedz 8
    acl errors_too_fast sc1_http_err_rate gt 8
    #atzīmēt uzbrukumu globālajā skaitītājā (palielināt skaitītāju)
    acl mark_as_abuser sc0_inc_gpc0(fe_rdp_tsc) gt 0
    #nulles globālo skaitītāju
    acl clear_as_abuser sc0_clr_gpc0(fe_rdp_tsc) ge 0
    #iegūt avotu
    tcp-request content track-sc1 src
    #noraidīt, atzīmēt, ka tas ir uzbrukums
    tcp-request content reject if errors_too_fast mark_as_abuser
    #atļaut, izdzēst uzbrukuma karodziņu
    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

tāpat kā iepriekš, bet laipni, atgriezīsim http kļūdu 429 (Pārāk daudz pieprasījumu)

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

Pārbaudu: palaidu mstsc un sāku nekārtīgi ievadīt parole. Pēc trešās mēģinājuma 10 sekunžu laikā man izmet ārā, un mstsc parāda kļūdu. To var redzēt arī žurnālos.

Skaidrojumi. Es neesmu haproxy meistars. Es nesaprotu, kāpēc, piemēram,
http-request deny deny_status 429 if { sc_http_err_rate(0) gt 4 }
ļauj izdarīt apmēram 10 kļūdas, pirms tas aktivizējas.

Es apmulsu skaitītāju numerācijā. Haproxy meistari, būšu priecīgs, ja papildināsiet mani, labosiet, darīsiet labāk.

Komentāros varat uzskaitīt citus RD Gateway aizsardzības veidus, būs interesanti izpētīt.

Attiecībā uz Windows attālinātā darba stacijas klientu (mstsc) jāatzīmē, ka tas neatbalsta TLS1.2 (vismaz Windows 7), tāpēc nācās atstāt TLS1; neatbalsta aktuālos cipher, tādēļ arī jāatstāj vecie.

Lai palīdzētu tiem, kas neko nesaprot, tikai mācas un jau vēlas izdarīt labi, es sniegšu visu konfigurāciju.

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

        # Noklusējuma SSL materiālu atrašanās vietas
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        # Skatīt: 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

Kāpēc divi serveri backend? Tāpēc, ka tā var izveidot augstāku pieejamību. Ar Haproxy varat izveidot divus ar peldošo balto IP.

Datu resursi: varat sākt ar "divi gigabaiti, divas kodola, spēļu dators". Saskaņā ar Vikipēdiju tas būs pietiekami ar uzviju.

Saites:

RDP-gateway iestatījumi, izmantojot HAProxy
Vienīgā atrastā raksta, kurā tika nopietni pievērsta uzmanība paroles pārbaudei

Avots: habr.com

Iegādājieties uzticamu tīmekļa hostingu ar DDoS aizsardzību, VPS VDS serveriem 🔥 Iegādājieties uzticamu tīmekļa hostingu ar DDoS aizsardzību, VPS VDS serveriem | ProHoster