执行摘要
auth.username/password 均为空字符串且 enabled=true,登录用 == 明文比较空串,发送空用户名/密码即获管理员权限;结合 0.0.0.0:5000 暴露,构成远程未授权完全接管。
空凭证登录后可拉取全部短信日志;sms_reminder.log 明文记录 213 处手机号+真实姓名+部门,仓库无 .gitignore。
经 C-01 登录后 POST /run 可远程触发批量短信,造成资费损失与骚扰。
项目概述
/api/sms/send,日志 JSON 存储| 端点 | 子系统 | 绑定 | 认证 | 用途 |
|---|---|---|---|---|
| POST /login | ms-reminder | 0.0.0.0:5000 | 无 | 登录(C-01 空凭证) |
| GET / /logs /config | ms-reminder | 0.0.0.0:5000 | login_required(可绕过) | 页面查看 |
| GET /api/logs /api/stats | ms-reminder | 0.0.0.0:5000 | login_required(可绕过) | 日志/统计 JSON |
| POST /run /reminder/* | ms-reminder | 0.0.0.0:5000 | login_required + CSRF(可绕过) | 触发短信/调度 |
| POST /config/update | ms-reminder | 0.0.0.0:5000 | login_required + CSRF(可绕过) | 修改配置 |
| POST /api/sms/send | sms-tool | 127.0.0.1:8080 | 无 | 发送短信(H-01) |
ms-reminder 使用
5000 端口、sms-tool 使用 8080 端口,均为攻击扫描工具的常用扫描目标(Flask 开发默认端口 + Java Web 默认端口)。建议修改为非常用高位端口(如 5xxx 随机高位),大幅降低自动化扫描工具发现服务的概率。漏洞详情
- 配置(Sink 侧凭据) config/app_config.json:15-19
auth.enabled=true但username/password均为空字符串。 - 配置加载 config.py:47,77
AUTH_CONFIG = {"enabled": true, "username": "", "password": ""} - Source(外部输入) app.py:60-61
攻击者提交空或省略字段 →request.form.get('username','')得到''。 - Filter(不充分) login.html:30,34
required仅为客户端浏览器校验,curl/Burp 直接构造 POST 即可绕过;服务端无非空校验、无失败次数限制。 - Service + Sink(比较与登录) app.py:62-64
'' == '' and '' == ''→True,设置session['logged_in']=True并重定向。
# 攻击者发送空用户名/空密码即可登录,获得管理员 session curl -i -X POST -d 'username=&password=' -c cookies.txt http://<目标>:5000/login # 预期:HTTP 302 重定向到 /,cookies.txt 含 session
app.py:306 host='0.0.0.0' 对外暴露)- Source:外部攻击者经 C-01 获登录态后访问
/api/logs、/logs、/。 - Filter(被绕过) app.py:286-290
@login_required已被 C-01 绕过,jsonify(sms_logs)直接返回全部日志。 - Service(读取日志) app.py:79-93
SELECT * FROM sms_logs返回phone/content/indiv_name/task_dept_name等全部字段。 - Sink(敏感数据返回 + 日志文件泄露)
日志文件sms_reminder.log(2578 行)明文记录 213 处 11 位手机号 + 真实姓名 + 部门 + 任务内容;全仓库无.gitignore。
# logs/sms_reminder.log 实测样本(手机号已脱敏)
243: ... Virtual SMS sent to <手机号>: [*世奇]你好![丹江口市**局(丹江口市**局)]...
244: ... SMS sent successfully for task RW4203... to <手机号>
246: ... Virtual SMS sent to <手机号>: [*坤鹏]你好![郧西县**局]...
- Source:外部攻击者经 C-01 登录后 POST
/run(携带登录后获取的 CSRF token)。 - Filter(被绕过) app.py:245-247
@login_required(C-01 绕过)+@require_csrf(token 登录时已生成,登录后可读取)。 - Service + Sink app.py:254-265 → reminder.py:76-137
调用reminder.process_reminder(),扫描达梦 DB 待办任务并循环send_sms()发送短信。
app.py:57-67 login() 无失败计数、无锁定、无延时。当前因 C-01 已无需爆破,但 修复 C-01 后此问题将暴露为暴力破解入口。
app.py:210-243:/config/update 在登录(C-01 可绕过)+ CSRF 后,将用户提交的 start_id 直接写入 cursor.txt 与 app_config.json,无业务合法性校验。reminder.py:37-43 以 start_id 为阈值,task_id <= start_id 则跳过。
- sms.py:45
logger.info(f"Virtual SMS sent to {phone}: ...")— 明文手机号+内容 - sms.py:97
logger.info(f"SMS sent successfully to {phone}: ...")— 明文手机号 - reminder.py:70 等多处记录手机号;实测
sms_reminder.log2578 行含 213 处手机号+姓名+部门 - 全仓库无
.gitignore(根目录、ms-reminder/、sms-tool/ 均无)
sms-tool 的 SmsService.maskMobile() 对日志手机号脱敏,是正确实践,ms-reminder 应参照。app.py:11-12:未配置 SESSION_COOKIE_SECURE、SESSION_COOKIE_SAMESITE(HttpOnly Flask 默认开启,但 Secure/SameSite 缺失)。
0.0.0.0 且为 HTTP,Secure 无法生效;SameSite 缺失降低 CSRF 防护深度| 编号 | 项 | 证据 | 说明 |
|---|---|---|---|
| M-01 | 明文密码存储与比较 | app_config.json:18 + app.py:62 == | 内网单机可接受;建议 bcrypt 存储 + hmac.compare_digest |
| L-01 | 硬编码真实手机号 | sendMsg.py:58 mobile="158..." | 测试代码硬编码,建议改环境变量 |
| L-03 | page 参数未校验导致 500 | app.py:164 int(...) | ?page=abc 触发 500;加 try-except 与范围校验 |
| L-04 | 登录表单缺少 CSRF 保护 | app.py:57-67 | 登录 CSRF,影响有限;建议 Flask-WTF |
| I-01 | SECRET_KEY 每次重启随机 | app.py:12 os.urandom(24) | 安全可接受;建议持久化到环境变量 |
| I-02 | .DS_Store 提交(通用) | 根目录/sms-tool/ 各 1 个 | macOS 元数据泄露目录结构,加入 .gitignore |
| I-04 | start_scheduler.py 引用不存在函数 | :37,44,54 start_backtrack_scheduler | 功能 bug(非安全),脚本运行会失败 |
| 编号 | 项 | 证据 | 说明 |
|---|---|---|---|
| M-02 | MAS 凭据默认值 | application.yml ${SMS_MAS_USER:YBTsjj} | 环境变量注入机制合规,仅默认值含真实凭据需清理 |
| H-01 | 无认证短信发送接口 | SmsController.java:21 /api/sms/send | 仅本地可达;端口暴露则风险回升;建议认证+频率限制 |
| H-02 | 短信内容伪造 | SmsService.java:85-87 buildContent | 仅本地可达;建议长度限制+敏感词过滤 |
| I-03 | system-scope 本地 jar 供应链不透明 | pom.xml masmgc.sdk.sms 1.0.3-SNAPSHOT | 本地 jar 无 CVE 跟踪,向移动云官方核实并锁正式版 |
| I-05 | CORS 配置略宽 | WebConfig.java:11-16 | origins 合规,allowedHeaders("*") 偏宽,建议收窄 |
攻击链分析
GET /logs → 页面浏览
供应链 CVE 分析
| 编号 | CVE | 依赖(版本) | 严重度 | 受影响 | 实际可利用 | 建议 |
|---|---|---|---|---|---|---|
| S-01 | CVE-2024-22243/22259/22262 | Spring 6.1.1 | High 8.1 | 是 | 否 未用 UriComponentsBuilder | 升级 |
| S-02 | CVE-2025-41249 | Spring 6.1.1 | High | 是 | 否 未引入 Spring Security | 升级 |
| S-03 | CVE-2025-41242 | Spring 6.1.1 | High | 是 | 否 需 Jetty,实为 Tomcat | 升级 |
| S-04 | CVE-2025-22235 | Spring Boot 3.2.0 | High 7.3 | 是 | 否 未用 Security+actuator | 升级 |
| S-05 | CVE-2026-22733 | Spring Boot actuator | High | 是 | 否 无 actuator 依赖 | N/A |
| S-06 | CVE-2026-22737/22735 | Spring 6.1.1 | Med/Low | 是 | 否 未用脚本模板/SSE | 升级 |
| S-07 | CVE-2026-22732/40976 | Spring Security/Boot 4.0 | Critical 9.1 | 否 | 不受影响 | - |
| S-08 | CVE-2026-54515 | jackson 2.16.0 | Med 5.3 | 是 | 否 DTO 未用 @JsonIgnoreProperties | 升级至 2.18.9+ |
| S-09 | jackson SSRF | jackson 2.16.0 | Med | 是 | 否 无 InetSocketAddress 字段 | 升级至 2.18.8+ |
| S-10 | CVE-2023-35116/2025-52999 | jackson 2.16.0 | - | 否 | 不受影响 2.16.0 为修复版 | - |
| S-11 | - | Lombok | - | 否 | 无 CVE 编译时注解处理器 | - |
| S-12 | - | masmgc.sdk.sms 1.0.3-SNAPSHOT | - | 未知 | 本地 jar,公开库无记录 | 向移动云核实 |
| 编号 | CVE | 依赖(版本) | 严重度 | 受影响 | 实际可利用 | 建议 |
|---|---|---|---|---|---|---|
| S-13 | CVE-2026-27205 | Flask 2.3.3 | Low 4.3 | 是 | 部分 需缓存代理,内网直连风险低 | 设 Cache-Control 或升级 |
| S-14 | CVE-2026-25645 | requests 2.31.0 | Med 4.4 | 是 | 否 未用 extract_zipped_paths | 升级 2.33.0+ |
| S-15 | CVE-2024-35195 | requests 2.31.0 | Mod 5.0 | 是 | 否 未用 Session+verify=False | 升级 2.32.2+ |
| S-16 | CVE-2024-47081 | requests 2.31.0 | Mod 5.3 | 是 | 否 无 netrc | 升级 2.32.4+ |
| S-17 | CVE-2026-31072 | apscheduler 3.10.4 | Critical 9.8 | 否 | 不受影响 双重证据:序列化器 4.0 引入 + 代码从未 import | 移除无用依赖 |
| S-18 | CVE-2023-30861/32681 | Flask/requests | - | 否 | 不受影响 已为修复版本 | - |
| S-19 | - | dmPython 2.5.32 | - | 未知 | 公开库无记录 | 向达梦核实 |
requirements.txt 仅锁 4 个顶层依赖,Werkzeug / urllib3 / certifi 等间接依赖完全未锁定,且项目无 lockfile。| 编号 | CVE | 间接依赖 | 严重度 | 利用条件 | 建议 |
|---|---|---|---|---|---|
| S-20 | CVE-2024-49767 / 2023-46136 | Werkzeug(未锁定) | High 7.5 | 部分 若 Werkzeug<3.0.6 则 multipart DoS 可利用 | 锁定 ≥3.0.6 + lockfile |
| S-21 | CVE-2024-34069 | Werkzeug | High 7.5 | 否 需 debug 模式,本项目 debug=False | 建议 ≥3.0.3 |
| S-22 | CVE-2024-49766/2025-66221 | Werkzeug | Med | 否 仅 Windows+Python<3.11 | - |
| S-23 | CVE-2026-44431/21441/2024-37891 | urllib3(未锁定) | Med-High | 否 需 ProxyManager/流式/跨域重定向 | 锁定版本 |
- Spring Boot 3.2.0 已 EOL(S-04~S-07 同类)— 最紧迫,升级至 3.5.x/4.0.x
- Werkzeug 版本未锁定(S-20)— 唯一可能真实可利用的 DoS,确认并锁定 ≥3.0.6
- jackson 2.16 EOL(S-08/S-09)— 升级至 2.18.x LTS
- apscheduler 无用依赖(S-17)— 从 requirements.txt 移除
- 间接依赖无 lockfile — 引入
uv lock/ pip-tools 锁定全量依赖树
无漏洞维度
db.py 所有查询使用 ? 参数化占位符;reminder.py:149 LIKE ? 参数化;sms.py:16-19 INSERT 参数化。
Flask render_template 默认自动转义;4 个模板均无 |safe 用法;日志内容经 Jinja2 转义渲染。
Jackson 反序列化类型固定(SmsSendRequest、SmsLog),无 enableDefaultTyping/多态;Python 侧无 pickle.loads 用户输入。
/config/update 写入路径固定(cursor.txt/app_config.json),不接受用户控制路径;read_system_logs 读固定路径。
短信 API URL 与 MAS URL 均来自配置文件,/config/update 不修改 sms_api.url,用户无法控制请求目标 URL。
修复建议
- C-01 设置强用户名/密码(非空、高熵);
app.py:62增加非空校验;密码改 bcrypt 存储 +hmac.compare_digest;增加失败计数与锁定(L-02) - C-02 修复 C-01 后未授权访问自然收敛;立即清理
sms_reminder.log已泄露 PII;按 M-04 改造脱敏;/api/logs按最小权限返回
- H-01/H-02
/api/sms/send增加认证+频率限制+每日配额;reportName加长度限制+敏感词过滤;确认server.address=127.0.0.1 - 🔴 端口变更 ms-reminder 的
5000→ 改为非常用高位端口(如5xxx随机值);sms-tool 的8080→ 改为server.port=1xxxx,降低被自动化扫描发现的概率 - H-03 修复 C-01 后收敛;
/run增加操作审计日志与二次确认 - M-02 移除
application.yml真实凭据默认值 - M-03
/config/update对start_id增加格式/业务校验 - M-04 日志手机号脱敏;新增
.gitignore
- M-06 配置
SESSION_COOKIE_SECURE/SAMESITE=Lax(启用 HTTPS 后) - L-01 移除硬编码手机号,改环境变量
- L-03
page转换加 try-except+范围校验 - L-04
login()POST 加@require_csrf或 Flask-WTF - 供应链 Spring Boot →3.5.x/4.0.x;requests→2.33.0+;jackson→2.18.9+ LTS;锁定 Werkzeug≥3.0.6;移除 apscheduler;引入 lockfile
- I-01
SECRET_KEY持久化到环境变量 - I-02
.gitignore加入.DS_Store - I-03 MAS SDK 替换正式版本,向移动云核实
- I-04 修复
start_scheduler.py引用不存在函数的 bug - I-05 CORS
allowedHeaders收窄为实际所需头 - 引入 SAST(Semgrep/SpotBugs)+ 依赖扫描(pip-audit/mvn dependency-check)纳入 CI
覆盖矩阵自检
未覆盖范围与说明
- 运行时环境:未实际部署运行,未做动态渗透;所有结论基于静态代码分析 + 配置/日志文件取证。C-01 可利用性已通过代码逻辑严格论证,但未执行实际 HTTP 请求复现。
- 达梦数据库侧:未审查达梦 DB 的配置、权限、视图层安全(仅审查应用层 SQL,均为参数化)。
- MAS SDK 内部实现:
masmgc.sdk.sms-1.0.3-SNAPSHOT.jar为二进制 jar,未反编译审查其内部实现,仅评估接口调用层。 - 部署环境:未评估生产部署的网络拓扑、反向代理、WAF 等。ms-reminder 实际风险取决于 5000 端口暴露范围;sms-tool 取决于 8080 是否严格保持 localhost。
- dmPython / masmgc.sdk.sms:公开漏洞库无记录,需向厂商官方核实。
- CVE-2026-31072(apscheduler):NVD 与 GitHub Advisory 描述存在矛盾,本项目初步判断不受影响,建议人工二次核实。
维度框架:D1-D10 十维安全模型 + 三轨模型(Sink-driven / Control-driven / Config-driven)
供应链数据源:NVD、Spring 官方安全公告、GitHub Advisory、Debian Security Tracker、FasterXML Jackson Releases
原则:所有漏洞均附代码路径证据链;供应链 CVE 均核实实际利用条件,版本受影响但利用条件不满足的已标注。