Erik-Jan de Kruijf

利用自动 Cloudflare 响应检测网络服务器探查& Fuzzing in Traefik

本文展示了定制的 Elastic Security ES|QL 检测规则如何识别 Traefik 日志中的 Web 服务器探测和模糊活动,并通过 Cloudflare 自动阻止攻击 IP。

阅读时间:8分钟启用

简介

通过反向代理暴露的自托管服务不可避免地会吸引自动扫描仪来探测错误配置、管理面板和易受攻击的端点。在本文中,我将展示如何使用 Elastic Security 和 Cloudflare 将常规的特拉菲克访问日志转化为主动防御控制。

我使用开箱即用的ES|QL检测规则来识别网络服务器发现和模糊行为。当检测到可疑的探测模式时,自动工作流程会立即通过 Cloudflare API 在边缘阻止违规源 IP。这种设置的最大优点是可以毫不费力地进行扩展。通过一次构建用于模糊检测的响应管道,我可以将完全相同的拦截操作附加到任何其他 Elastic 规则,例如捕获 SQL 注入或文件包含尝试的规则。这就将一个基本的日志记录管道转变成了一个适应性极强的外围防御系统。

背景和威胁情况

我的家庭实验室设置使用 Proxmox VE 用于容器和虚拟机。我使用 Traefik 反向代理,用Authelia进行身份验证,允许在没有 VPN 的情况下进行外部访问。启用代理后,Cloudflare 负责管理 DNS。

对于不太熟悉这种特定堆栈的人来说,特拉菲克就像是网络的前门。当网络请求通过 Cloudflare 到达时,特拉菲克会将流量动态路由到正确的内部容器,同时管理 SSL 证书以保持连接加密。然而,在任何流量真正到达这些后端应用程序之前,就会被 Authelia 拦截。通过利用 Traefik 的转发验证功能,Authelia 全面实施单点登录和多因素验证。这意味着自动扫描仪和攻击者如果不通过初始安全门户,甚至无法进入我的内部服务登录屏幕。

为了保持可见性和安全性,我使用官方集成将这些 Traefik 访问日志摄入 Elastic。在例行监控过程中,我在这些日志中发现了许多来自相同源 IP 地址的 HTTP 404 响应代码。

这种模式表明,可能存在网络服务器探测或模糊流量,目标是我的网络上实际未使用的应用程序中的漏洞。这些目标路径的例子包括/wp-includes/mani.,/wp-content/plugins/all-in-one-wp-security-and-firewall/templates.php,/archive.php, 和/wp-admin/includes/header.php

设计理念:为什么不是 Fail2Ban?

家庭实验室社区的一个常见问题是,为什么不直接在特拉菲克服务器上使用Fail2BanCrowdSec等本地工具?虽然这些都是很好的工具,但通过 Elastic Security 协调响应并将块推送到 Cloudflare 有两大优势。在 Cloudflare 边缘丢弃恶意流量可节省本地带宽,并使扫描仪完全远离家庭网络。此外,通过 Elastic 协调响应,我们可以对所有安全监控进行统一管理。

检测战略和实施战略

为了有效识别恶意侦察,我们的策略依赖于分析代理层的 HTTP 响应代码频率。具体来说,我们要查找的是单个源 IP 在短时间内产生的大量 404 (未找到)错误,这是目录模糊或漏洞扫描的典型指标。

虽然 Elastic Security 针对这种情况提供了强大的开箱即用检测规则,但这些规则需要正确规范化的 ECS(Elastic Common Schema)数据才能正常运行。因此,检测和减少这些扫描需要一个协调的流程。要实现这一点,我们需要摄取特莱菲克日志,使用自定义管道修补缺失的host.name 字段,并将检测规则指向我们的数据。

阈值逻辑和调整

我们的检测策略不再是简单的字符串匹配,而是依赖于统计阈值。该规则专门监控 HTTP 403 和 404 响应代码所代表的被拒绝或不存在的资源,并按源代码 IP 汇总这一活动。

这种行为受查询中最后where 语句的制约。默认情况下,只有当一个源 IP 在 250 不同 URI 路径上产生的错误超过 500 时,才会触发警报。这种双层阈值旨在消除误报,确保不会因为单个破损资产而触发拦截,同时还能识别在目录词表中循环的自动脚本。

在较小的家庭实验室或较小的团队环境中,这些默认设置往往过于放任。由于合法的外部流量没有理由访问我的网络上不存在的管理面板,因此我调整了敏感度,以便及早捕捉更隐蔽的侦察行为。我修改了逻辑,在event_count > 100url_original_count_distinct > 50 时触发。

对于应用程序自然产生较多错误的生产环境,可以考虑增加这些值或附加 ES|QLwhere not 子句,以排除已知的断开链接。最后,我使用where source.ip not in (...) 过滤器来确保授权的安全工具或个人漏洞扫描仪不会被自动工作流程意外禁止。

输入特捷飞客访问日志

为了将特拉菲克访问日志摄取到集群中,我使用了 特拉菲克的 默认 集成 。弹性代理从特捷飞克服务器收集日志。该集成将摄取的日志写入logs-traefik.access-default 数据流。

构建自定义摄取管道

host.name 字段对我使用的检测规则至关重要,但默认的特拉菲克集成并不填充该字段。因此,需要自定义摄取管道来添加此字段。由于特莱菲克集成利用的是特莱菲克服务器上的文件流,因此我可以从现有的agent.name 字段中复制值来填充host.name

我特别使用了logs-traefik.access@custom 管道,而不是修改主管道。弹性集成的设计目的是在处理流程结束时自动接收并运行这些@custom 管道。更重要的是,每次升级集成时,默认管道都会被完全覆盖。将我的逻辑存储在自定义管道中,可以确保我的字段映射在下一次更新后仍然有效。创建此管道所需的 API 调用可在 Dev Tools 控制台中执行:

PUT _ingest/pipeline/logs-traefik.access@custom
{
  "description": "copy the agent.name field to the host.name field",
  "processors": [
    {
      "set": {
        "field": "host.name",
        "value": "{{{agent.name}}}",
        "override": false,
        "ignore_empty_value": true,
        "ignore_failure": true
      }
    }
  ]
}

通过 Cloudflare 工作流程自动响应

为了从检测转向主动防御,我们实施了一个工作流程,在我们的弹性警报和 Cloudflare 边缘之间架起了一座桥梁。这种逻辑设计非常高效:工作流首先检索现有的阻止列表,而不是为每个警报创建新的防火墙规则,因为这样做很快就会超出 Cloudflare 的规则限制。然后,它会将新的违规源 IP 动态附加到该列表中,然后再将更新推送回 Cloudflare API。一旦确保了边缘的安全,工作流程就会通过在 Elastic 中确认警报来完成,从而有效地结束事件循环。

前提条件和令牌范围

此过程需要一个 API 密钥和 Cloudflare 配置的 Zone ID。API 令牌必须拥有"Zone WAF 编辑" 权限,才能创建规则。在 Cloudflare 仪表板中生成此令牌时,请使用"Create Custom Token" 选项,并将权限严格设置为Zone -> Zone WAF -> Edit

配置工作流程后,必须将其指定为"Web 服务器发现或模糊活动" 检测规则的操作。

有了这些先决条件,让我们一步步来了解如何建立工作流程。

工作流程配置和触发器

首先,我们定义基本元数据。此工作流程会阻止在 Web 服务器发现或模糊活动警报中发现的 IP 地址。工作流程已启用,API 请求的超时时间为 30 秒。在这种情况下,它以警报为基础,因此在触发安全警报时会自动运行。

# =========================================================================
# Workflow: Block IP at Cloudflare test
# Category: security/response
# =========================================================================
version: '1'
name: Block IP at Cloudflare
enabled: true

triggers:
  - type: alert

常量和验证

该部分包含用于身份验证的变量。切记用实际的 API 标记和 Zone ID 代替占位符字符串。

consts:
  cloudflare_api: "<cloudflare API>"
  cloudflare_zone: "<cloudflare ZONE>"

步骤 1:检索当前拦截列表

该序列会检查防火墙规则是否已经存在。工作流程会发出 HTTP GET 请求,以检索现有的 IP block 规则。

steps:
  - name: cloudflare_current_block
    type: http
    with:
      url: "https://api.cloudflare.com/client/v4/zones/{{consts.cloudflare_zone}}/rulesets/phases/http_request_firewall_custom/entrypoint"
      headers:
        Authorization: Bearer {{consts.cloudflare_api}}
      method: GET
    on-failure:
      continue: true

步骤 2:更新或创建防火墙规则

如果存在,规则会附加 IP 地址,否则会创建规则。工作流程可识别"网站服务器扫描块" 说明是否存在。如果是,它就会通过 PUT 请求将新 IP 地址添加到当前被屏蔽的 IP 地址列表中。如果没有,就会退回到创建新规则。

 - name: cloudflare_block
    type: if
    condition: 'steps.cloudflare_current_block.output.data.result.rules[0].description == "webserver scanning block"'
    steps:
      - name: ip-block-cloudflare_add
        type: http
        with:
          url: "https://api.cloudflare.com/client/v4/zones/{{consts.cloudflare_zone}}/rulesets/phases/http_request_firewall_custom/entrypoint"
          method: PUT
          headers:
            Authorization: Bearer {{consts.cloudflare_api}}
          timeout: 30s
          body: '{ "rules": [ { "description": "webserver scanning block", "expression": "{{steps.cloudflare_current_block.output.data.result.rules[0].expression}} or (ip.src eq {{event.alerts[0].source.ip}})", "action": "block" } ]}'
    else:
      - name: ip-block-cloudflare_new
        type: http
        with:
          url: "https://api.cloudflare.com/client/v4/zones/{{consts.cloudflare_zone}}/rulesets/phases/http_request_firewall_custom/entrypoint"
          method: PUT
          headers:
            Authorization: Bearer {{consts.cloudflare_api}}
          timeout: 30s
          body: '{ "rules":[ { "description": "webserver scanning block", "expression": "(ip.src eq {{event.alerts[0].source.ip}})", "action": "block" } ]}'
    on-failure:
      continue: true

步骤 3:确认警报

然后警报被确认。此步骤使用kibana.SetAlertsStatus 操作自动关闭 Elastic Security 中的警报。

  - name: update_alert_status
    type: kibana.SetAlertsStatus
    with:
      status: "acknowledged"
      signal_ids: ["{{event.alerts[0]._id}}"]

第 4 步:将工作流程附加到规则中

工作流程创建完成后,最后一步就是将其实际附加到检测规则中,使其自动启动。在"Web Server Discovery or Fuzzing Activity" 规则的弹性安全规则设置中,我导航到规则操作选项卡并添加了一个新操作。从连接器下拉菜单中,我只需选择刚刚创建的 Cloudflare 工作流。

关于 WAF 限制的说明

由于此工作流程使用or 语句 (or (ip.src eq <IP>)) 连接 IP 地址,因此请注意 Cloudflare 对自定义 WAF 表达式有字符限制(标准层通常为 4096 字符)。在目标高度集中的环境中,这个字符串最终会达到极限。对于家庭实验室和小型团队来说,偶尔手动清除 WAF 规则可以起到健康重置的作用。

测试和验证

为了验证流水线端到端是否正常工作,我们可以使用标准模糊工具生成一些噪音。您可以使用ffufgobuster 等模糊工具模拟针对自己家庭实验室的扫描攻击。

对面向公众的特拉菲克域中不存在的目录进行快速扫描:

ffuf -u https://your-domain.com/FUZZ -w /path/to/wordlist.txt

模拟运行后,我们就可以观察自动防御链的运行情况。 404 错误几乎立即出现在logs-traefik.access-default 数据流中。在轮询间隔内,ES|QL 规则会识别模式,并在 "弹性安全警报 "页面中生成新警报。从这里开始,工作流程接管:它会将警报状态转移到"acknowledged" ,并将 IP block 推送到我们的 Cloudflare WAF 规则,从而在扫描仪继续侦察之前有效地在边缘将其消灭。

您可以查看Security -> WAF -> Custom rules 下的 Cloudflare 控制面板,确认阻止是否成功。(注意:请务必在之后从 Cloudflare 规则中删除您的 IP,以免将自己锁定在外!)。

扩大防御

这种设置的好处在于,我们的 Cloudflare 工作流程不仅限于模糊检测。建立自动化后,我们可以将其附加到任何标记可疑代理流量的 Elastic 规则中。例如,我们可以将完全相同的响应操作与针对特定应用程序漏洞的开箱即用规则绑定,如 Web 服务器本地文件包含活动 Web 服务器潜在远程文件包含活动 ,以便立即阻止攻击者。它还能与网络服务器错误日志潜在峰值异常网络用户代理完美搭配,捕捉配置错误的刮擦器和更广泛的网络噪声。我们只需修建一次管道,整个周边就会变得更加智能。

结论

将 Traefik 和 Cloudflare 接入 Elastic Security 是将基本访问日志转化为主动防御的好方法。家庭实验室环境不断受到自动扫描仪的轰炸,寻找低垂的果实。这种自动化工作流程不仅能在边缘阻止攻击者,还能通过自动确认事件来减少警报疲劳。这是一个安全协调和响应如何在节省时间的同时显著改善安全态势的实例。

分享这篇文章