MS リモート デスクトップ ゲートウェイ、HAProxy、パスワード ブルート フォース

友達、こんにちは!

自宅からオフィスのワークスペースに接続するには、さまざまな方法があります。 その XNUMX つは、Microsoft リモート デスクトップ ゲートウェイを使用することです。 これは RDP over HTTP です。 ここでは RDGW 自体のセットアップについては触れたくありません。RDGW が良いか悪いかについては議論したくありません。RDGW をリモート アクセス ツールの XNUMX つとして扱いましょう。 RDGW サーバーを邪悪なインターネットから保護することについて話したいと思います。 RDGW サーバーをセットアップしたとき、私はすぐにセキュリティ、特にパスワードのブルート フォースに対する保護について懸念するようになりました。 これを行う方法に関する記事がインターネット上に見つからなかったことには驚きました。 まあ、自分でやる必要があります。

RDGW 自体には保護機能がありません。 はい、裸のインターフェイスを使用してホワイト ネットワークに公開でき、問題なく動作します。 しかし、これでは適切な管理者や情報セキュリティの専門家は不安になります。 さらに、不注意な従業員が自宅のコンピュータで企業アカウントのパスワードを覚えてしまい、パスワードを変更した場合にアカウントがブロックされるという状況を回避できます。

内部リソースを外部環境から保護する良い方法は、さまざまなプロキシ、公開システム、その他の WAF を使用することです。 RDGW は依然として http であることを思い出してください。RDGW は、内部サーバーとインターネットの間に特殊なソリューションを接続する必要があるだけです。

素晴らしい F5、A10、Netscaler(ADC) があることは知っています。 これらのシステムの XNUMX つの管理者として、これらのシステムにブルート フォースに対する保護を設定することも可能であると言いたいと思います。 そして、はい、これらのシステムは、あらゆる Syn フラッドからも保護します。

しかし、すべての企業がそのようなソリューションを購入する余裕があるわけではありません (そしてそのようなシステムの管理者を見つけることができます :) が、同時にセキュリティにも配慮できます。

無料バージョンの HAProxy を無料オペレーティング システムにインストールすることは完全に可能です。 安定版リポジトリの Debian 10、haproxy バージョン 1.8.19 でテストしました。 また、テスト リポジトリのバージョン 2.0.xx でもテストしました。

Debian 自体のセットアップについては、この記事の範囲外としておきます。 簡単に説明すると、白いインターフェイスではポート 443 以外のすべてを閉じ、灰色のインターフェイスでは、たとえば、ポリシーに従ってポート 22 以外のすべてを閉じます。 作業に必要なものだけを開きます(フローティング IP 用の VRRP など)。

まず、HAProxy を SSL ブリッジング モード (別名 http モード) で構成し、ログ記録をオンにして、RDP 内で何が起こっているかを確認しました。 いわば、真ん中に入ったわけです。 そのため、RDGateway のセットアップに関する「すべての」記事で指定されている /RDWeb パスがありません。 存在するのは /rpc/rpcproxy.dll と /remoteDesktopGateway/ だけです。 この場合、標準の GET/POST リクエストは使用されず、独自のタイプのリクエスト RDG_IN_DATA、RDG_OUT_DATA が使用されます。

それほど多くはありませんが、少なくとも何かはあります。

テストしてみましょう。

mstsc を起動し、サーバーにアクセスし、ログで 401 つの 200 (不正) エラーを確認し、ユーザー名とパスワードを入力すると、応答 XNUMX が表示されます。

電源を切り、再度起動すると、ログに同じ 401 エラーが 401 つ表示されます。間違ったログイン/パスワードを入力すると、再び XNUMX エラーが XNUMX つ表示されます。これが必要なのです。 これが私たちが捕まえるものです。

ログイン URL を特定できず、さらに、haproxy で 401 エラーをキャッチする方法がわからないため、すべての 4xx エラーをキャッチします (実際にはキャッチするのではなく、カウントします)。 問題解決にも最適です。

保護の本質は、単位時間当たりの (バックエンドでの) 4xx エラーの数をカウントし、それが指定された制限を超えた場合、指定された時間の間、この IP からのそれ以降のすべての接続を (フロントエンドで) 拒否することです。 。

技術的には、これはパスワード ブルート フォースに対する保護ではなく、4xx エラーに対する保護になります。 たとえば、存在しない URL (404) を頻繁にリクエストする場合も、保護は機能します。

最も簡単で効果的な方法は、バックエンドを頼りにして、何か余分なものが表示された場合に報告することです。

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

最善の選択肢ではないので、複雑にしてみましょう。 バックエンドを頼りに、フロントエンドでブロックします。

私たちは攻撃者を無礼に扱い、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 (Too Many 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
    ...

私はチェックします: mstsc を起動し、ランダムにパスワードを入力し始めます。 10 回目の試行後、XNUMX 秒以内にキックバックされ、mstsc でエラーが発生します。 ログからわかるように。

説明。 私は haproxy マスターにはほど遠いです。 理由は分かりませんが、例えば
http-リクエスト拒否deny_status 429 if { sc_http_err_rate(0) gt 4 }
機能するまでに約 10 回の間違いを犯します。

カウンターの番号の付け方で迷っています。 ハプロキシのマスターの皆さん、私を補完し、修正し、改善していただければ幸いです。

コメントでは、RD ゲートウェイを保護する他の方法を提案できます。研究するのは興味深いでしょう。

Windows リモート デスクトップ クライアント (mstsc) に関しては、TLS1.2 (少なくとも Windows 7 では) をサポートしていないことに注意してください。そのため、TLS1 を使用しない必要がありました。 は現在の暗号をサポートしていないため、古い暗号も残す必要がありました。

何も理解していない、学習中、すでにうまくいきたいと考えている人のために、構成全体を提供します。

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

なぜバックエンドに XNUMX つのサーバーがあるのでしょうか? そうすることで耐障害性を実現できるからです。 Haproxy はフローティングの白い IP で XNUMX つを作成することもできます。

コンピューティング リソース: 「XNUMX ギガバイト、XNUMX コア、ゲーミング PC」から始めることができます。 によると ウィキペディア これで十分余裕があります。

リンク:

HAProxy からの rdp-gateway のセットアップ
わざわざパスワードのブルートフォース攻撃を行っている記事を見つけた唯一の記事

出所: habr.com

コメントを追加します