HAwebsso.nl未受保护API端点泄露1.5万医生凭证数据

荷兰医疗协会SSO系统存在未授权访问漏洞,通过/api/v1/user/{id}端点可获取所有用户数据,包括邮箱、姓名和密码哈希,涉及超过1.5万名全科医生的敏感信息。漏洞类型为IDOR和关键功能缺失认证。

未受保护的API端点导致HAwebsso.nl泄露1.5万医生用户名和密码哈希

背景

我白天是全科医生,晚上是安全研究员。我的道德黑客目标之一是尽可能多地学习,以便能够审计医疗保健产品、应用程序、网站或基础设施的安全性。

今天我们将关注荷兰全科医生协会(NHG)和荷兰全科医生联盟(LHV)的安全性。这些是荷兰全科医生的专业组织。NHG为全科医生制定标准并提供教育和培训,而LHV代表全科医生的利益,致力于提高初级保健的质量和可及性。这两个组织在荷兰医疗保健系统中都扮演着重要角色,致力于确保患者从全科医生那里获得高质量的护理。目前荷兰有1.3万名全科医生。

侦察,从哪里开始?

如果NHG和LHV被发现存在漏洞,我们能否影响这1.3万名相关的医生?

NHG和LHV都有许多在线应用程序,允许医生登录和交互。例如HAweb.nl(一个医生在线社区)和richtlijnen.nhg.org(允许医生在专业指南中添加个人笔记)。

今天我只是从点击LHV.nl主网站开始,寻找不同的子域名以及登录过程的工作原理。

大多数LHV和NHG应用程序共享的是使用域hawebsso.nl的单点登录(SSO)认证方法。每当你尝试访问需要授权的应用程序时,它都会弹出,比如haweb.nl。

SSO是一种认证方法,允许用户使用一组登录凭据访问多个应用程序和服务。这消除了用户记住和管理多组登录信息的需要,可以大大改善用户体验和生产力。组织通常使用SSO来简化对多个系统和应用程序的访问,通过减少存储用户凭据的地方数量来提高安全性,并集中控制对资源的访问。此外,SSO可以与其他安全功能(如多因素认证)集成,为敏感系统和数据提供额外的保护层。

好消息是,如果我们入侵了SSO,我们就获得了一切访问权限。坏消息是,大多数使用的SSO系统都是经过严格测试的软件(可以随意调换这句话中的好消息和坏消息)。

祝你好运,打破一个经过实战检验的SSO服务。

LHV和NHG使用的SSO系统登录页面

额外收获

快速查看SSO系统可能范围的一个好技巧是检查OpenID端点,尝试访问https://hawebsso.nl/.well-known/openid-configuration

SSO系统保存了有趣的用户数据(在OpenID中称为声明)

此外,它支持许多不同的范围。例如,它有范围’HAWeb_SSO_Scope_WaarneemApp’,可以访问WaarneemApp(医生之间交换班次的工具)。

我快速检查的另一件事是,我是否得到了关于SSO背后运行系统的任何提示。我查看这个HTTP请求的响应头:

SSO运行在Microsoft IIS/10.0上

SSO运行在Microsoft IIS/10.0上。没有关于此处使用软件的提示。

到目前为止一切顺利,没有什么特别的。

登录页面的源代码呢?

登录页面引用了一个名为admin.js的Javascript文件

登录页面引用了一个名为admin.js的Javascript文件。

下一步是查看登录页面的源代码。我们是否看到了关于用于SSO的系统的任何线索,或者我们看到了其他奇怪的东西?

Admin.js

正如我们所看到的,登录页面正在加载不同的javascript文件,其中一些为登录表单添加功能。没有一个文件泄露关于实际使用系统的提示,可能是这个SSO前端是自定义构建的;它包装在一个ASP驱动的SSO后端系统周围。

然而,其中一个加载的文件引起了我的注意:admin.js。每当我们看到"admin"这个词时,我们都渴望了解更多。

admin.js文件内部的部分源代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$scope.GetAdmin = function () {
    return $http({
        method: 'GET',
        url: '/api/v1/user/admin',
    }).then(function (response) {
        $scope.adminUser = response.data;
        if ($scope.adminUser.roles != null && $scope.adminUser.roles.length > 0) {
            var roles = $scope.adminUser.roles.split(",");
            $scope.permissions = {
                admin_level_1: roles.indexOf("Admin_level_1") > -1,
                admin_level_2: roles.indexOf("Admin_level_2") > -1,
                allow_edit: roles.indexOf("Admin_allow_edit") > -1,
                allow_merge: roles.indexOf("Admin_allow_merge") > -1,
                allow_activate: roles.indexOf("Admin_allow_activate") > -1,
                allow_deactivate: roles.indexOf("Admin_allow_deactivate") > -1,
                allow_make_admin: roles.indexOf("Admin_level_1") > -1,
                allow_deactivate_admin: roles.indexOf("Admin_level_1") > -1,
                show_field_id: roles.indexOf("Admin_show_field_id") > -1,
                show_field_firstname: roles.indexOf("Admin_show_field_firstname") > -1,
                show_field_insertion: roles.indexOf("Admin_show_field_insertion") > -1,
                show_field_lastname: roles.indexOf("Admin_show_field_lastname") > -1,
                show_field_lhv_id: roles.indexOf("Admin_show_field_lhv_id") > -1,
                show_field_nhg_id: roles.indexOf("Admin_show_field_nhg_id") > -1,
                show_field_emailaddress: roles.indexOf("Admin_show_field_emailaddress") > -1,
                show_field_cat_override: roles.indexOf("Admin_show_field_cat_override") > -1,
                congres_admin: roles.indexOf("Admin_congres") > -1
            };
        }
    }).catch(function (response) {
        $scope.addMessage(response.data, response.status, response.status == 200 ? "success" : "error");
    });
}

$scope.GetAdmin();

所以有一个管理员可以访问的端点,返回用户的不同角色。在这种情况下是/admin用户。在主要登录屏幕上共享此代码很奇怪。

作为拥有SSO登录的全科医生之一,我可以登录并访问该端点。

端点返回当前登录用户的所有数据,包括密码哈希

糟糕。该端点返回当前登录用户的所有数据。包括电子邮件、全名、密码哈希和一些会员详细信息。

如果我们访问相同的端点并将/admin替换为ID会怎样?正如我们所看到的,我有ID 2027。让我们看看如果我们尝试访问ID 15000会发生什么:https://hawebsso.nl/api/v1/user/15000

用户ID 15000存在,所有账户详细信息都与我们共享,包括密码

用户ID 15000存在,所有账户详细信息都与我们共享,包括密码。

我们现在已经展示了这个端点的影响,它泄露了所有在SSO服务hawebsso.nl注册的用户详细信息。

在技术术语中,我们称这种错误为IDOR;不安全的直接对象引用。

端点/api/v1/user/1是一个通用端点,可以很容易地被黑客发现。可以使用单词列表在这样的资产上暴力破解端点,一个很好的例子是Assetnote.io他们共享的单词列表。单词列表https://wordlists-cdn.assetnote.io/data/automated/httparchive_apiroutes_2020_11_20.txt包含这个特定的端点,其中包含一个会返回命中的ID。

会给出命中的单词列表条目的例子

会给出命中的单词列表条目的例子。

黑客可以采取的另一种方法是扫描所有使用的javascript文件以查找端点。例如,LinkFinder可以为你做到这一点。

无需认证

我们现在已经展示了一个特定的端点泄露了用户详细信息,但是它需要认证吗?一个人可以在没有登录的情况下访问这个端点吗?

在浏览器的隐身模式下打开相同的端点

在浏览器的隐身模式下打开相同的端点。没有设置cookie,我没有登录。所有用户详细信息都被返回。

答案是是的。这个端点不需要任何登录。在技术术语中,我们现在有另一个错误,关键功能缺失认证。在浏览器中打开端点而不登录会返回所有用户详细信息。

端点无需登录即可工作的概念证明(已审查机密数据)

端点无需登录即可工作的概念证明(已审查机密数据)。

密码哈希,如何破解?

现在我们有了密码的哈希值。使用密码哈希减少了数据泄露的影响,因为必须首先破解哈希才能检索密码。过去,像MD5这样的密码哈希很容易通过使用彩虹表之类的东西被破解;所有可能哈希的列表,预先计算以破解哈希。

如今,通过使用更安全的哈希算法和包含盐值来解决这个问题。

通过将我的密码更改为我拥有的相同密码,我可以确认生成了一个新的唯一哈希。这给了我们一个线索,彩虹表可能在这里不起作用(例如,如果它们为每个用户包含一个唯一的盐)。

为了测试,我使用了以下哈希来破解(不用担心,这是我自己的哈希,带有虚拟密码):

1
em1EijmR7gmSA0NC2fbbl488pWDpX6YEfPtU4BNRsu01VX9VZFRuvSBAPaaIwVe5KC0enebMfwJC1AGZVNFbRsZ+7Pa7hj718HfKfIolp/5rDgsp/52UOqawXrNGHgwCHYsd+S0gG4K+ba3zjsjg5cVXCpIrqvlJbO45DkPqZ+B/REWhOmkBdRdie76z9oWk1qp7LFa9l/4Z3TtCgucS+m0Sl66mYcWwafRZkAas5a5z15v9iweiZK4WyEbkmUFQDgAqXMAsljftoJxSP0QN/BbXUtAm0wENIGvt7PPTg7dGxdUoySbUFpmnzm/eTeCcgbEpsJhb3bwAulMVl0F3

在黑客攻击一段时间后,你可以通过查看大多数哈希类型来识别它们,就像皮肤病一样。

1
2
3
098f6bcd4621d373cade4e832627b4f6 - MD5
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 - SHA-256
$2y$12$xyq65gSoKygKl5kxKYDbjeTocAh8BcbuprbohD.kkX0PZr73pH5LC - Bcrypt

然而,在这里我现在不知道使用了哪种哈希算法。在联系到我的一位道德黑客同事后,我被告知这看起来像一个base64编码的字符串,解码后正好是255字节长。

echo  | base64 –decode | wc -c的输出

echo | base64 –decode | wc -c的输出。

从我们的侦察中知道ASP运行在服务器上,我们可能从Microsoft提供的文档中得到更多线索:https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity

后来我发现了这篇(5年前的)关于不同哈希算法的博客https://andrewlock.net/exploring-the-asp-net-core-identity-passwordhasher/,并发现了以下有趣的部分:

ASP.NET Core Identity Version 3: PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations

这给了我一个提示,ASP开箱即用地使用了适当的哈希算法,一个我目前无法轻易破解的算法。关于PBKDF2和未来的一些有趣讨论可以在这里阅读。

目前我放弃了破解这些哈希。

然而,我很想从这篇博客的读者那里了解更多,你能够破解我的哈希吗?如果是,请告诉我你会怎么做。第一个破解它的人将获得我稀有的闪亮闪光贴纸和一些其他独特的赠品!如你所知,这个世界全是关于贴纸的。

结论

我们发现了一个数据泄露,泄露了荷兰全科医生使用的所有电子邮件和密码哈希。这个端点未受保护,不需要任何授权。由于它是一个通用路径,可以很容易地被黑客猜到。此外,对此端点的引用隐藏在登录页面包含的admin.js文件中,像LinkFinder这样的工具会通知任何扫描黑客这个特定的端点。

讨论

LHV在他们的网站上发布了一个负责任的披露政策,允许我进行这项研究:https://www.lhv.nl/cvd-coordinated-vulnerability-disclosure/ 这是一个如何支持道德黑客的好例子。

此外,他们试图通过制定如何处理数据泄露的指南来提高初级保健的整体安全性。最近他们在全科医生阅读的一本杂志中发表了关于此的文章:https://www.syntheshis.nu/wp-content/uploads/2022/12/Synth-2022-03-Totaal.pdf(荷兰语,第22页)。相关成员能够查看此指南:https://www.lhv.nl/product/praktijkwijzer-informatiebeveiliging/

然而,如果每个人都能访问这个文档,那将是很棒的,我们分享得越多,我们就越能对抗风险。在初级保健中,我与学生、数据经理和许多不是LHV成员的人一起工作;如果我能轻松分享这些文档,那将有所帮助(我宁愿不分享过时的PDF)。

另一件重要的事情是在每个在线资产上添加负责任的披露政策。例如,hawebsso.nl不包含任何引用。同样,NHG.org网站(使用SSO)也没有分享任何在线负责任的披露政策。一个好的做法是尽快发布此政策,并让在NHG工作的每个人都适应这种良好实践;参见https://www.ncsc.nl/onderwerpen/cvd-beleid/cvd-beleid-opstellen以了解作为组织如何继续。

防止此类数据泄露的一个好保护是双因素认证(2FA),HAwebsso.nl支持这一点,但默认情况下未激活。我的建议是激活它,以便在密码泄露时使攻击者更难访问你的账户。同样重要的是不要重复使用密码,如本报告所示,当泄露(和破解)时,它可能在其他服务上被滥用;凭据填充。

我们如何避免这样的错误?

这个错误存在了大约3年,所以有足够的时间发现它。

有不同的方法来处理这个问题。一种是在管理层面;获得认证并采用行业标准。

行业标准

如今我们有不同的国际行业标准(即ISO 27001)或国家标准(即NEN 7510)来描述如何管理信息安全。将一些良好的信息安全实践嵌入到组织中的好方法。实施它,让审计员确认一切都已正确实施,营销可以分享你是安全的好消息。

“先生,我们是ISO 27001认证的,我们超级安全” — 每个销售部门。

证书是好的,但不能保护你免受黑客攻击

证书是好的,但不能保护你免受黑客攻击。

正如我们今天将看到的,没有认证会阻止你被黑客攻击。然而,这并不意味着我们不应该这样做。每一种结构化的提高安全性的方法都值得实施。

渗透测试顾问与道德黑客

另一种方法是执行定期的渗透测试;雇佣一家公司并要求他们入侵你。这个错误非常直接,很可能在渗透测试中被发现。

然而,这些渗透测试通常发生在特定的时间段内,这不是一个连续的过程。因此,在渗透测试之间发布的资产中的任何新错误可能会被忽视。

一个解决方案可能是创建一个道德黑客社区,使用漏洞赏金平台(如HackerOne或BugCrowd),并开始投资于在你的资产中发现错误的道德黑客。我们有一些关于如何在荷兰创建社区的好例子:Hack the Hague。

威胁建模

我是INCLUDESNODIRT.com方法的忠实粉丝;聚集一群人(即开发人员、道德黑客、全科医生、产品所有者和隐私官),填写问卷并 brainstorming 20分钟。每当你引入新资产、向应用程序添加功能或组织发生变化时(即合并和收购)。在这个例子中,人们会问自己"添加到hawebsso.nl的新管理功能是否适当地保护免受未经授权的访问?如果是,解释如何。"

数字医疗的威胁建模

数字医疗的威胁建模。

我还没有看到这种方法在生产中被使用,但我很想听听已经实施它的其他人的故事。我们可以从中学到什么,它真的有效吗?

透明就是信任

从这个特定错误报告的开始到结束,LHV隐私官员对我的电子邮件非常响应。他经常向我发送更新,这有助于我确信所有利益相关者都理解错误的影响,并且正在迅速修复。他做得很好,是其他人如何处理此类报告的榜样,谢谢!

在任何组织中,透明就是信任。如果是关于数据泄露,我们有很好的流程图,帮助我们如何继续并透明地通知最终用户(比如能够发布像这样的博客)。

这份报告展示了群众的力量,透明和适当的披露政策使世界上所有的道德黑客能够帮助你变得更安全。你可以将这种群众模型应用到组织中所有其他层面,并更快地实现你的目标。

最后,我们都希望明天有一个更好、更安全的初级保健,并从过去犯的错误中学习。

时间线

04-12-2022 — 发现错误,通过电子邮件向LHV隐私官员报告 05-12-2022 — 隐私官员回复确认错误 06-12-2022 — 隐私官员更新 08-12-2022 — 隐私官员更新:错误存在3年(自2019年底以来),过去2年的日志中没有滥用迹象 11-12-2022 — 写了这篇博客 12-12-2022 — 通过电子邮件将博客草稿发送给隐私官员 12-12-2022 — LHV和NHG通过电子邮件通知所有成员数据泄露;要求成员重置密码 13-12-2022 — LHV建议一些小的更改 14-12-2022 — 发布博客 15-12-2022 — 读者告知我Admin.js文件在2017年存在;https://web.archive.org/web/20170905141113/https://hawebsso.nl/Js/admin/admin.js 这是否意味着错误存在了+5年?向LHV询问了关于此的一些见解,得到回复他们将与开发人员仔细检查。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计