MS 远程桌面网关、HAProxy 和密码暴力破解

朋友们,你们好!

有多种方法可以从家中连接到办公室工作区。 其中之一是使用 Microsoft 远程桌面网关。 这是基于 HTTP 的 RDP。 我不想在这里讨论 RDGW 本身的设置,我不想讨论它的好坏,让我们将它视为远程访问工具之一。 我想谈谈如何保护您的 RDGW 服务器免受邪恶互联网的侵害。 当我设置 RDGW 服务器时,我立即开始担心安全性,尤其是防止密码暴力破解。 令我惊讶的是,我在互联网上没有找到任何有关如何执行此操作的文章。 好吧,你必须自己做。

RDGW本身没有任何保护。 是的,它可以通过裸接口暴露到白色网络,并且效果很好。 但这会让合适的管理员或信息安全专家感到不安。 此外,它还可以让您避免帐户被封锁的情况,即粗心的员工在他的家庭计算机上记住了公司帐户的密码,然后更改了密码。

保护内部资源免受外部环境影响的一个好方法是通过各种代理、发布系统和其他 WAF。 让我们记住,RDGW 仍然是 http,那么它只是请求在内部服务器和互联网之间插入专门的解决方案。

我知道有很酷的F5、A10、Netscaler(ADC)。 作为这些系统之一的管理员,我会说还可以在这些系统上设置针对暴力破解的保护。 是的,这些系统还将保护您免受任何同步洪水的影响。

但并不是每个公司都有能力购买这样的解决方案(并为这样的系统找到管理员:),但同时他们可以照顾安全!

完全可以在免费操作系统上安装免费版本的 HAProxy。 我在稳定存储库中的 Debian 10、haproxy 版本 1.8.19 上进行了测试。 我还在测试存储库中的 2.0.xx 版本上对其进行了测试。

我们将把 Debian 本身的设置排除在本文的讨论范围之外。 简而言之:在白色界面上,关闭除端口 443 之外的所有内容,在灰色界面上 - 根据您的策略,例如,也关闭除端口 22 之外的所有内容。 仅打开工作所需的内容(例如 VRRP,用于浮动 ip)。

首先,我在 SSL 桥接模式(也称为 http 模式)下配置 haproxy,并打开日志记录以查看 RDP 内部发生的情况。 可以这么说,我是夹在中间的。 因此,有关设置 RDGateway 的“所有”文章中指定的 /RDWeb 路径丢失。 那里只有 /rpc/rpcproxy.dll 和 /remoteDesktopGateway/。 在这种情况下,不使用标准的 GET/POST 请求;使用它们自己的请求类型 RDG_IN_DATA、RDG_OUT_DATA。

不多,但至少有一些东西。

我们来测试一下。

我启动 mstsc,转到服务器,在日志中看到四个 401(未经授权)错误,然后输入我的用户名/密码并看到响应 200。

我将其关闭,再次启动,在日志中我看到相同的四个 401 错误。我输入错误的登录名/密码,然后再次看到四个 401 错误。这就是我需要的。 这就是我们要抓住的。

由于无法确定登录网址,而且我不知道如何在 haproxy 中捕获 401 错误,因此我将捕获(实际上不是捕获,而是计数)所有 4xx 错误。 也适合解决问题。

保护的本质是,我们将计算每单位时间(在后端)的 4xx 错误数量,如果超过指定的限制,则在指定时间内拒绝(在前端)来自该 ip 的所有进一步连接。

从技术上讲,这不会防止密码暴力破解,而是防止 4xx 错误。 例如,如果您经常请求不存在的网址(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(请求过多)

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 秒内它把我踢了回来,并且 mstsc 给出了错误。 从日志中可以看出。

解释。 我距离 haproxy 大师还很远。 我不明白为什么,例如
http请求拒绝deny_status 429 if { sc_http_err_rate(0) gt 4 }
允许你犯大约 10 个错误才起作用。

我对计数器的编号感到困惑。 haproxy的大师们,如果你们补充我、纠正我、让我变得更好,我将非常高兴。

在评论中您可以建议其他保护 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

为什么后端有两台服务器? 因为这就是容错的方法。 Haproxy也可以做两个浮动的白色ip。

计算资源:您可以从“两个千兆、两个核心的游戏 PC”开始。 根据 维基百科 这足够了。

参考文献:

从 HAProxy 设置 rdp 网关
我发现的唯一一篇他们费尽心思暴力破解密码的文章

来源: habr.com

添加评论