MS Remote Desktop Gateway, HAProxy i brute force lozinke

Prijatelji, zdravo!

Postoji mnogo načina da se povežete od kuće do vašeg radnog prostora u kancelariji. Jedan od njih je korištenje Microsoft Remote Desktop Gatewaya. Ovo je RDP preko HTTP-a. Ne želim se ovdje doticati postavljanja samog RDGW-a, ne želim raspravljati zašto je to dobro ili loše, hajde da ga tretiramo kao jedan od alata za daljinski pristup. Želim razgovarati o zaštiti vašeg RDGW servera od zlog Interneta. Kada sam podesio RDGW server, odmah sam se zabrinuo za sigurnost, posebno zaštitu od grube sile lozinke. Iznenadio sam se što na internetu nisam našao nijedan članak o tome kako to učiniti. Pa, moraćete to sami da uradite.

Sam RDGW nema nikakvu zaštitu. Da, može se izložiti s golim sučeljem bijeloj mreži i radit će odlično. Ali ovo će učiniti pravog administratora ili stručnjaka za sigurnost informacija nelagodnim. Osim toga, omogućit će vam da izbjegnete situaciju blokade računa, kada je nepažljivi zaposlenik zapamtio lozinku za korporativni račun na svom kućnom računaru, a zatim promijenio lozinku.

Dobar način zaštite internih resursa od vanjskog okruženja je kroz različite proxy servere, sisteme za objavljivanje i druge WAF-ove. Podsjetimo da je RDGW još uvijek http, onda samo traži da se spoji specijalizovano rješenje između internih servera i Interneta.

Znam da postoje cool F5, A10, Netscaler(ADC). Kao administrator jednog od ovih sistema, reći ću da je i na ovim sistemima moguće podesiti zaštitu od grube sile. I da, ovi sistemi će vas također zaštititi od bilo kakvog syn flooda.

Ali ne može svaka kompanija priuštiti kupovinu ovakvog rješenja (i pronaći administratora za takav sistem :), ali u isto vrijeme može se pobrinuti za sigurnost!

Potpuno je moguće instalirati besplatnu verziju HAProxy na besplatni operativni sistem. Testirao sam na Debianu 10, haproxy verziji 1.8.19 u stabilnom spremištu. Također sam ga testirao na verziji 2.0.xx iz testnog spremišta.

Ostavit ćemo samo postavljanje debiana izvan okvira ovog članka. Ukratko: na bijelom sučelju zatvorite sve osim porta 443, na sivom sučelju - prema vašoj politici, na primjer, također zatvorite sve osim porta 22. Otvorite samo ono što je potrebno za rad (VRRP na primjer, za plutajući ip).

Prije svega, konfigurirao sam haproxy u SSL modu premošćavanja (aka http mod) i uključio logovanje da vidim šta se dešava unutar RDP-a. Tako da kažem, ušao sam u sredinu. Dakle, /RDWeb putanja navedena u "svim" člancima o postavljanju RDGateway-a nedostaje. Sve što postoji su /rpc/rpcproxy.dll i /remoteDesktopGateway/. U ovom slučaju se ne koriste standardni GET/POST zahtjevi, koristi se njihov vlastiti tip zahtjeva RDG_IN_DATA, RDG_OUT_DATA.

Ne mnogo, ali barem nešto.

Hajde da testiramo.

Pokrećem mstsc, idem na server, vidim četiri 401 (neovlaštene) greške u evidenciji, zatim unesem svoje korisničko ime/lozinku i vidim odgovor 200.

Isključim ga, pokrenem ponovo i u logovima vidim iste četiri greške 401. Unesem pogrešan login/lozinku i opet vidim četiri greške 401. To je ono što mi treba. To je ono što ćemo uhvatiti.

Pošto nije bilo moguće utvrditi url za prijavu, a osim toga, ne znam kako da uhvatim grešku 401 u haproxy-u, uhvatit ću (ne zapravo uhvatiti, već brojati) sve 4xx greške. Pogodan i za rješavanje problema.

Suština zaštite će biti u tome da ćemo računati broj 4xx grešaka (na backendu) po jedinici vremena i ako pređe navedeno ograničenje, onda odbaciti (na frontendu) sve daljnje veze sa ovog ip-a za određeno vrijeme .

Tehnički, ovo neće biti zaštita od grube sile lozinke, to će biti zaštita od 4xx grešaka. Na primjer, ako često tražite nepostojeći url (404), zaštita će također raditi.

Najjednostavniji i najefikasniji način je računati na backend i prijaviti se ako se nešto dodatno pojavi:

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

Nije najbolja opcija, zakomplicirajmo. Računaćemo na backend i blokirati na frontendu.

Grubo ćemo se ponašati prema napadaču i prekinuti njegovu TCP vezu.

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

ista stvar, ali ljubazno, vratit ćemo grešku http 429 (Previše zahtjeva)

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

Provjeravam: Pokrećem mstsc i počinjem nasumično unositi lozinke. Nakon trećeg pokušaja, u roku od 10 sekundi me vraća, a mstsc daje grešku. Kao što se može vidjeti u dnevnicima.

Objašnjenja. Daleko sam od haproxy majstora. Ne razumijem zašto, na primjer
http-request deny deny_status 429 if { sc_http_err_rate(0) gt 4 }
omogućava vam da napravite oko 10 grešaka prije nego što proradi.

Zbunjen sam oko numeracije brojača. Majstori haproksija, biće mi drago ako me upotpunite, ispravite, učinite boljim.

U komentarima možete predložiti druge načine zaštite RD Gatewaya, bit će zanimljivo proučiti.

Što se tiče Windows Remote Desktop klijenta (mstsc), vrijedi napomenuti da on ne podržava TLS1.2 (barem u Windows 7), pa sam morao napustiti TLS1; ne podržava trenutnu šifru, tako da sam morao ostaviti i stare.

Za one koji ništa ne razumiju, tek uče, a već žele da rade dobro, dat ću vam cijelu konfiguraciju.

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

        # 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

Zašto dva servera na backendu? Jer na ovaj način možete napraviti toleranciju grešaka. Haproxy takođe može napraviti dva sa plutajućim bijelim IP-om.

Računarski resursi: možete početi sa „dva koncerta, dva jezgra, računar za igre“. Prema wikipedia ovo će biti dovoljno.

Reference:

Postavljanje rdp-gateway-a sa HAProxy
Jedini članak koji sam pronašao gdje su se potrudili da grubo forsiraju lozinku

izvor: www.habr.com

Dodajte komentar