MS Remote Desktop Gateway, HAProxy è password brute force

Amici, salutu !

Ci hè parechje manere di cunnette da casa à u vostru spaziu di travagliu di l'uffiziu. Unu di elli hè di utilizà Microsoft Remote Desktop Gateway. Questu hè RDP sopra HTTP. Ùn vogliu micca toccu nantu à a creazione di RDGW stessu quì, ùn vogliu micca discutiri perchè hè bonu o cattivu, trattemu cum'è unu di l'arnesi d'accessu remoto. Vogliu parlà di prutezzione di u vostru servitore RDGW da l'Internet male. Quandu aghju stallatu u servitore RDGW, aghju subitu preoccupatu di a sicurità, in particulare a prutezzione contra a forza bruta di password. Eru surprised chì ùn aghju micca truvatu alcunu articulu in Internet nantu à cumu fà questu. Ebbè, vi tuccherà à fà tù stessu.

RDGW stessu ùn hà micca prutezzione. Iè, pò esse esposta cù una interfaccia nuda à una reta bianca è hà da travaglià bè. Ma questu ferà l'amministratore ghjustu o specialista in a sicurità di l'infurmazioni inquiete. Inoltre, vi permetterà di evità a situazione di bloccu di u contu, quandu un impiigatu trascuratu si ricurdò di a password per un contu corporativu in u so urdinatore di casa, è dopu hà cambiatu a so password.

Un bonu modu per prutege e risorse internu da l'ambiente esternu hè attraversu diversi proxy, sistemi di pubblicazione è altri WAF. Ricurdemu chì RDGW hè sempre http, allora solu dumanda à plug una suluzione specializata trà i servitori internu è Internet.

Sò chì ci sò cool F5, A10, Netscaler (ADC). Cum'è amministratore di unu di sti sistemi, diceraghju chì hè ancu pussibule di stallà a prutezzione contra a forza bruta in questi sistemi. È iè, sti sistemi vi prutege dinù da ogni syn flood.

Ma micca ogni cumpagnia pò permette di cumprà una tale suluzione (è truvà un amministratore per un tali sistema :), ma à u stessu tempu ponu piglià a cura di a sicurità!

Hè interamente pussibule installà una versione libera di HAProxy in un sistema operatore gratuitu. Aghju pruvatu in Debian 10, versione haproxy 1.8.19 in u repository stabile. Aghju pruvatu ancu in a versione 2.0.xx da u repository di teste.

Lasceremu a stallazione di Debian stessu fora di u scopu di stu articulu. In breve: nantu à l'interfaccia bianca, chjude tuttu fora di u portu 443, nantu à l'interfaccia grisa - secondu a vostra pulitica, per esempiu, chjude ancu tuttu fora di u portu 22. Apertura solu ciò chì hè necessariu per u travagliu (VRRP per esempiu, per floating ip).

Prima di tuttu, aghju cunfiguratu haproxy in u modu di ponte SSL (aka mode http) è aghju attivatu u logu per vede ciò chì passava in RDP. Cusì per parlà, sò ghjuntu à mezu. Dunque, a strada / RDWeb specificata in "tutti" l'articuli nantu à a stallazione di RDGateway manca. Tuttu ciò chì ci hè hè /rpc/rpcproxy.dll è /remoteDesktopGateway/. In questu casu, e dumande standard GET / POST ùn sò micca utilizzate; u so propiu tipu di dumanda RDG_IN_DATA, RDG_OUT_DATA hè utilizatu.

Micca assai, ma almenu qualcosa.

Testemu.

Lanciau mstsc, andate à u servitore, vede quattru errori 401 (non autorizati) in i logs, dopu entre u mo nome d'utilizatore / password è vede a risposta 200.

L'aghju spentu, cumminciate di novu, è in i logs vecu i stessi quattru errori 401. Intrudu u login / password sbagliatu è vede novu quattru errori 401. Hè ciò chì aghju bisognu. Questu hè ciò chì avemu da piglià.

Siccomu ùn era micca pussibule di determinà l'url di login, è in più, ùn sò micca sapè cumu catturà l'errore 401 in haproxy, aghju catturà (micca veramente catturà, ma cuntà) tutti l'errori 4xx. Hè ancu adattatu per risolve u prublema.

L'essenza di a prutezzione serà chì cuntaremu u nùmeru di errori 4xx (nantu à u backend) per unità di tempu è s'ellu supera u limitu specificatu, allora ricusate (nantu à u frontend) tutte e più cunnessione da questa ip per u tempu specificatu. .

Tecnicamente, questu ùn serà micca prutezzione contra a forza bruta di password, serà prutezzione contra l'errore 4xx. Per esempiu, se spessu dumandate un url inesistente (404), allora a prutezzione hà da travaglià ancu.

U modu più simplice è efficau hè di cuntà u backend è di riportà se qualcosa extra appare:

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

Ùn hè micca a megliu opzione, complichemu. Cuntaremu nantu à u backend è bluccà nantu à u frontend.

Tratteremu l'attaccu rudely è abbandunemu a so cunnessione 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

listessa cosa, ma educatamente, vulteremu l'errore http 429 (Troppi Requests)

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

Cuntrolla: lanciau mstsc è cumincianu à inserisce password aleatoriamente. Dopu à u terzu tentativu, in 10 seconde mi chjappà, è mstsc dà un errore. Comu pò esse vistu in i logs.

Spiegazioni. Sò luntanu da un maestru haproxy. Ùn capiscu micca perchè, per esempiu
http-request deny deny_status 429 if { sc_http_err_rate (0) gt 4 }
permette di fà circa 10 sbagli prima di travaglià.

Sò cunfusu nantu à a numerazione di i contatori. Maestri di l'haproxy, seraghju cuntentu se mi cumplementarii, mi correggete, mi fate megliu.

In i cumenti pudete suggerisce altre manere di prutezzione di RD Gateway, serà interessante di studià.

In quantu à u Cliente di Windows Remote Desktop (mstsc), vale a pena nutà chì ùn sustene micca TLS1.2 (almenu in Windows 7), cusì aghju avutu à lascià TLS1; ùn sustene micca u cifru attuale, cusì aghju avutu ancu à lascià i vechji.

Per quelli chì ùn capiscenu nunda, sò solu à amparà, è digià vulete fà bè, vi daraghju tutta a cunfigurazione.

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

Perchè dui servitori nantu à u backend? Perchè questu hè cumu pudete fà a tolleranza di difetti. Haproxy pò ancu fà dui cù un ip biancu flottante.

Risorse di computing: pudete inizià cù "dui concerti, dui core, PC di ghjocu". Secondu Wikipedia questu serà abbastanza per risparmià.

Referenze:

Configurazione di rdp-gateway da HAProxy
L'unicu articulu chì aghju trovu induve si preoccupavanu di forza brute a password

Source: www.habr.com

Add a comment