我如何发现一个IDOR:它暴露了政府医疗平台上的癌症患者身份

admin 2026-04-02 03:45:01 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文记录了在政府医疗平台的Odoo系统肿瘤模块中发现IDOR漏洞的过程。通过未授权访问nameget方法,攻击者可获取全部癌症患者姓名、医疗记录及内部消息,根本原因是代码使用.sudo()绕过权限控制。文章提出渗透测试中需重点检查displayname等隐蔽攻击面,并强调医疗数据泄露的严重性。 综合评分: 87 文章分类: 渗透测试,漏洞分析,WEB安全,数据安全,应用安全


cover_image

我如何发现一个 IDOR:它暴露了政府医疗平台上的癌症患者身份

haidragon haidragon

安全狗的自我修养

2026年4月1日 17:10 湖南

官网:http://securitytech.cc

#

引言

在一次经过授权的漏洞赏金(bug bounty)测试中,我与合作伙伴 itsnotthathard 一起,在一个患者门户中发现了一个 不安全直接对象引用(IDOR)漏洞

该应用是一个基于 Odoo 17.0 的定制肿瘤中心模块,用于管理癌症患者的预约、医疗记录以及治疗流程。

一个自注册用户(与任何患者记录都没有关系)通过滥用一个开发者忘记限制权限的 JSON-RPC 方法,成功枚举出了系统中所有癌症患者的全名

最终影响非常严重:

  • 约 2800+ 医疗记录
  • 约 3000+ 预约记录
  • 约 48900+ 内部医疗消息

这些数据全部泄露给任何可以注册账号的人。


目标系统

该门户允许患者通过基础信息和社会安全号码进行注册。

系统只校验身份证号的格式校验位(checksum),但没有与后端数据库核验。

因此,任何人都可以生成一个“看似合法”的号码并注册成功。

登录后界面看似安全:

  • 只能看到自己的数据
  • 无法看到其他患者信息
  • 无法访问其他记录

表面上完全正常。

但漏洞从来不会在“表面”。


侦察:理解 Odoo 的 RPC 层

如果你做过 Odoo 安全测试,会知道它的 Web 前端只是一个薄客户端,所有操作都通过 JSON-RPC API

/web/dataset/call_kw

所有按钮、页面加载、数据请求最终都会调用:

  • 模型(model)
  • 方法(method)
  • 参数(args)

Odoo 常见数据访问方法

| 方法 | 作用 | | — | — | | read | 按 ID 读取完整记录 | | search_read | 搜索 + 读取 | | web_read | 前端优化读取 | | export_data | 批量导出 | | name_get | 返回 (id, display_name) |


前四个是“重型方法”,通常会被 ACL(访问控制)严格限制。

但 name_get 呢?

它只是返回一个名字,看起来完全无害。

但在医疗系统里——非常危险。


发现过程

我首先测试最直接的方式:

Model: vcc.medical.finding
Method: read
IDs: [3809]

返回:

❌ AccessError(访问被拒绝)

很好,权限正常。

同样测试:

  • search_read

  • web_read

  • export_data

都被阻止。


关键一步:测试 name_get

我尝试:

{
  "model": "vcc.medical.finding",
  "method": "name_get",
  "args": [[3809, 3808, 3807, 3800, 3700]]
}

结果:

✅ 返回成功 ✅ 返回真实患者姓名 ❗ 没有任何权限限制


结果

系统返回的 display_name 类似:

“Medizinische Befunde: [患者姓名]”

直接把患者身份嵌入返回值中。


进一步测试:影响范围

我继续测试其他模型:

📌 vcc.appointment

约 3000+ 预约记录

📌 res.users

所有注册患者用户

📌 mail.message(最大问题)

约 48900+ 条内部消息

这些消息包含:

  • 治疗流程
  • 医疗更新
  • 内部沟通
  • 医护交接信息

全部都嵌入患者姓名。


根本原因:.sudo() 反模式

在错误堆栈中发现关键代码:

record.display_name =_("Tumor Board: %s") %record.sudo().case_id.patient_id.name

问题点:

.sudo() 在 Odoo 中代表:

以超级管理员权限执行,绕过所有 ACL

开发者这样写的初衷是:

  • 为了让 display_name 在 UI 中正确显示
  • 访问关联字段 case → patient → name

但实际发生了什么?

  • name_get

    会触发 display_name

  • display_name

    使用 .sudo()

  • .sudo()

    绕过权限控制

  • 所有人都能获取患者姓名


核心问题总结

这不是简单的访问控制失败,而是:

“安全方法调用了不安全的超级权限路径”


关键经验总结(渗透测试角度)

1. 不要只测 read

Odoo 中必须单独测试:

  • read
  • name_get
  • name_search
  • fields_get

2. display_name 是攻击面

如果 display_name 包含敏感信息:

  • 姓名
  • 邮箱
  • ID

并且使用 .sudo() 👉 就可能导致 IDOR


3. 医疗系统影响极大

同样漏洞:

  • 普通系统:低危
  • 医疗系统:GDPR 高危违规 + 隐私泄露

4. 不一致就是证据

如果:

  • A 模型禁止 name_get
  • B 模型允许

👉 说明是设计错误,而不是正常行为


5. 初始拒绝不代表漏洞无效

很多漏洞需要:

  • 重新表达
  • 简化影响
  • 再提交

最终结论

这个漏洞技术上非常简单:

  • 一个 RPC 方法
  • 一个缺失权限检查
  • 一个 .sudo() 调用

但影响极其严重:

数千名癌症患者的身份信息被暴露


最后的思考

最危险的漏洞往往不是复杂逻辑,而是:

“大家都以为它是安全的地方”

  • 公众号:安全狗的自我修养
  • vx:2207344074
  • http://gitee.com/haidragon
  • http://github.com/haidragon
  • bilibili:haidragonx

#


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:安全狗的自我修养 haidragon haidragon《我如何发现一个 IDOR:它暴露了政府医疗平台上的癌症患者身份》

评论:0   参与:  0