当前位置:论坛首页 > BUG提交 > Linux面板

【BUG】宝塔 WAF 的 CDN 客户端地址获取设计缺陷

发表在 BUG提交2026-9-10 19:46 [复制链接] 0 132

本帖最后由 小德 于 2026-9-10 19:57 编辑

无任何可信代理校验 → 直连源站任意伪造
只要站点 cdn=true,任何人只要能访问到源站 IP(源站暴露、IP 扫描、DNS 历史记录),即可完全控制 ngx.ctx.ip:

  1. GET / HTTP/1.1
  2. Host: victim.com
  3. CF-Connecting-IP: 1.2.3.4
复制代码

影响面(全部基于 ngx.ctx.ip):

IP 白名单绕过:waf.lua:140-143 命中后 return true,在 UA/URL/CC/POST/GET 全部检测之前直接放行。
CC 防护完全失效:cc.lua:83/115/168/233/307/309 以 ngx.ctx.ip 为计数键,每换一个头就是全新计数器。
地域/城市/IDC 封禁失效:drop_abroad、drop_china、reg_city、idc 全部读 ngx.ctx.iplong / ngx.ctx.country。
封禁第三方 IP(放大攻击):IpInfo.lan_ip() → ipinfo.bt_ip_filter(ip, 86400)(ipinfo.lua:160-195)会把伪造的 IP 写进 /dev/shm/.bt_ip_filter,即系统防火墙拉黑列表。攻击者只需故意触发一条规则,即可让任意第三方 IP 被服务器防火墙封禁最长 24 小时。
日志与统计污染:database.totla_log_insert、insert_ip_count、UV/UIP 快照、攻击溯源全部失真;Public.send_spider()(ipinfo.lua:597)还会把伪造 IP 当作蜘蛛候选上报。
remote-host 逻辑让伪造在"CDN 链路"下依然成立
ipinfo.lua:218-223:

  1.                                                 if request_header['remote-host'] and request_header['remote-host']~=nil then
  2.                                                         if request_header['remote-host']==client_ip then
  3.                                                                 client_ip=tmpe[1]
  4.                                                                 client_ip=ngx.re.gsub(client_ip," ","","jo")
  5.                                                         end
  6.                                                 end
复制代码

remote-host 不是任何 CDN 的标准头,完全由客户端控制并会被 CDN 透传。默认分支取 XFF 最后一个值(真实 IP),但攻击者只要同时把 remote-host 填成自己的真实 IP,就会被强制改判为 XFF 的第一个值:

  1. X-Forwarded-For: 8.8.8.8          ← 攻击者伪造
  2. remote-host: 203.0.113.9          ← 攻击者自己的真实 IP
复制代码


Cloudflare 追加后 → X-Forwarded-For: 8.8.8.8, 203.0.113.9 → 取最后一个 = 203.0.113.9 → remote-host == client_ip 成立 → 改取 tmpe[1] = 8.8.8.8

即:即使站点正确接入 Cloudflare、流量没有绕过 CDN,IP 依然可伪造。 这段代码等价于给了攻击者一个"取首/取尾"的开关。

cdn_baidu 模式取 XFF 首值 → 必然可伪造


ipinfo.lua:211-213。开启"百度 CDN"后直接取 tmpe[1],即客户端最先写入的值,任何场景下都可伪造。

is_localhost 覆盖不全,is_internal_ip 根本没被调用

public.luaL526-L544

  1. function public.is_localhost(ip)
  2.     if not ip then return false end
  3.     if ip == "unknown" then return false end
  4.     if public.find_str(ip, ":") then return false end     -- IPv6 直接放行
  5.     local ip_nmber = public.ip2long(ip)
  6.     if ip_nmber == 0 then return false end
  7.     if ip_nmber >= 2130706433 and ip_nmber <= 2130706687 then   -- 仅 127.0.0.1 ~ 127.0.0.255
  8.         return true
  9.     end
  10.     return false
  11. end
复制代码

回环段是 127.0.0.0/8,这里只覆盖 127.0.0.1–127.0.0.255 → 127.1.1.1、127.0.1.1 均可伪造成功。
含 : 直接 return false → ::1、0:0:0:0:0:0:0:1 等 IPv6 回环地址全部绕过检查。
私网段 10/8、172.16/12、192.168/16 完全未过滤:项目里已有 public.is_internal_ip()(public.lua:550-577),但在 get_client_ip_bylog 中从未调用(全仓库仅 database.lua:294 用了一次)。很多站点把内网 IP 或服务器 IP 加进白名单 → 直接全站 WAF 失效。

同名头只取第一条

ipinfo.lua:207-208:type(header_tmp)=="table" 时取 header_tmp[1]。攻击者先发的那条头会被优先采用,CDN 后续追加/单独设置的头被忽略。正确做法应取最后一条,或按可信跳数从右往左回溯。

cdn=true 但 cdn_header 缺失 → 整个 WAF fail-open

ipinfo.lua:204 的 ipairs(Site_config[server_name]['cdn_header']) 在 cdn_header 为 nil 时抛错。而 waf.lua:224-233 用 pcall 包住了整个 btwaf_run:

waf.luaL224-L233

  1. local ok,error = pcall(function()
  2.         return btwaf_run()
  3. end)

  4. if not ok then
  5.    if not ngx.shared.spider:get("btwaf_access") then
  6.         Public.logs(error)
  7.         ngx.shared.spider:set("btwaf_access",1,180)
  8.     end
  9. end
复制代码


IpInfo.get_client_ip_bylog() 在第 63 行,异常后 CC、URL、GET、POST、Cookie、UA、扫描器……全部跳过,请求正常放行,且错误信息 3 分钟才记一次日志。这比伪造 IP 更严重。

Public.get_client_ip() 未定义 → 自定义规则整条链路 fail-open

modules/customize.lua:938:

customize.luaL938-L940

  1.                             local ip = Public.get_client_ip()
  2.                             local cache_key ="customize_cc__"..v..ip
  3.                             local safe_count = ngx.shared.drop_sum:incr(cache_key, 1)
复制代码


全仓库只有这 5 处 get_client_ip 匹配,没有任何定义(public.lua 里不存在 public.get_client_ip,也没有 __index 元表兜底)。命中"自定义 CC 防御"规则时必然 attempt to call a nil value,同样被 waf.lua 的 pcall 吞掉 → 后续所有检测(args/post/URL 规则)被跳过。顺带一提,此处本应直接用 ngx.ctx.ip。



使用道具 举报 只看该作者 回复
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

紧急运维服务

响应时间:3分钟

问题处理方式:宝塔专家1对1服务

工作时间:工作日:9:00 - 18:30

宝塔专业团队为您解决服务器疑难问题

点击联系技术分析

工作时间:09:00至18:30

快速回复 返回顶部 返回列表