4月份,我向Cloud Foundry
安全团队披露了Cloud Foundry UAA(User Account and Authentication Server,用户帐户和身份验证服务器)中的两个漏洞,该团队为他们分配了CVE-2019-11268
和CVE-2019-11270
。在上一篇文章中,我讨论了CVE-2019-11268,一种SQL注入漏洞,允许在UAA身份区域内进行信息泄露。
直到上周(19年8月1日)当CF公开发表并发布补丁版本- UAA v73.7时,我才能谈论有关CVE-2019-11270的内容。CVE-2019-11270是UAA实现clients.write
作用域(scopes,即权限)的高危提权漏洞。拥有易受攻击作用域的恶意客户端可以创建具有任意作用域的新客户端,并获得对UAA服务器及其管理的应用程序的完全控制权(例如CF部署)。
如果您将UAA用作独立的Oauth2服务器或在CF部署中,强烈建议您阅读最后的“我是否受到影响?”部分。它包含识别您的环境中是否利用了漏洞的简单命令。
0x01 基础知识
UAA
Cloud Foundry UAA
(用户帐户和身份验证)是一个提供身份管理和访问控制的Oauth2
服务器。它可以在包括CF部署之外的任何环境中用作Oauth2服务器。
在我之前的文章中,涉及了UAA的部分概念,如访问令牌(access tokens),客户端(clients)和作用域(scopes)。让我们通过插图重新理解它们,因为理解它们是理解Oauth2授权流程和漏洞的关键。
oauth2
UAA服务器实现了广泛使用的Oauth2授权协议。大多数人可能都使用过基于Oauth的授权,例如在使用Facebook帐户注册eBay等网站时,并授权网站获得对该帐户的一些权限,例如阅读您的电子邮件地址或代表您发布信息。
简化一点,Oauth2授权流程通常包括以下步骤:
让我们回顾一下上图:
资源服务器和访问令牌(Resource Servers and Access tokens)
资源服务器被定义为承认UAA发布的访问令牌的任何实体,允许UAA对其资源的访问。资源服务器可以是数据库、API端点、甚至是Oauth2服务器本身。
访问令牌允许对其中编码的作用域(基本上是权限)进行访问。作用域是资源服务器可以决定附加含义的任意字符串。例如,数据库应用可以决定是否允许任何带有db.read
作用域的访问令牌的客户端从中读取数据,而其他应用程序可能不会对该作用域附加任何含义。
客户端和用户(Clients and Users)
客户表示需要访问由UAA管理的资源服务器的应用。客户端有两组权限(permissions)-作用域(scopes)和权限(authorities)。
用户通常代表一个人。用户具有组成员身份的权限,例如,一个db.read
组成员的用户就拥有db.read
赋予的权限。用户不能直接以他们的权限进行操作,只能授权客户端代替他们执行相应的操作。
UAA访问令牌授权
UAA服务器以认证的形式向客户端授予访问令牌。在两种情况下授予令牌:
1.当客户端代表用户执行相应的操作时(类似于上文提到的Facebook示例)。
这里,访问令牌授权客户端根据客户端作用域与用户组成员权限的交集(例如,具有db.read作用域的客户端和作为db.read组成员的用户)进行操作。用户还可以选择批准或拒绝客户端请求的作用域。
2.当客户端自己行动时。访问令牌授权客户端根据客户端的权限执行操作。
在这两种情况下,客户端都可以将授予的访问令牌提交给资源服务器,并根据令牌中编码的作用域进行操作。
如上所述,根据一组称为authorities的权限,一些客户端可以自行行动而无需用户的批准。这对于与用户无关的资源非常有用。在Facebook的例子中,eBay可以拥有’advertise.put’权限,允许它将广告推送到Facebook或其他受其约束的网站。
UAA管理作用域
根据“UAA作用域(UAA scopes)”所述,某些作用域允许管理UAA服务器。例如,在具有“groups.update”权限的客户端对UAA服务器进行身份验证并接收访问令牌之后,他可以将该访问令牌呈现给UAA,然后修改现有的UAA组。在UAA管理作用域的情况下,UAA也扮演资源服务器的角色。
以上是Oauth2和UAA的背景知识,现在进入漏洞的细节部分。
0x02 CVE-2019-11270 – 通过clients.write作用域提权
clients.write
是UAA管理作用域之一,是clients.admin
的一个狭义的版本。与clients.admin一样,clients.write允许创建和修改客户端,但对创建的客户端多了一些限制。’clients.write’的相关文档介绍如下:
“此作用域是创建和修改客户端所必需的。作用域以作用域持有者的客户端ID为前缀。例如,
id:testclient,authority:client.write
允许创建具有testclient.
前缀的作用域的客户端。授权仅限于uaa.resource
。“
因此,只允许创建具有以创建客户端的id为前缀的作用域的客户端。例如,id为app123
且authority为clients.write
的客户端只能注册带有前缀为app123的作用域的新客户端。(例如app123.read或app123.admin)。
这些限制的目的在于拒绝客户端使用clients.write作用域创建具有特权UAA管理作用域的客户端(例如uaa.admin)并提权。
‘Client.write’使用示例
clients.write
作用域用于管理资源服务器。为了管理数据库应用程序,UAA管理员可以创建一个id为db
的客户端,并为其提供clients.write权限。”db”客户端现在可以创建新客户端并为它们提供前缀为db的作用域。比如db.read,db.create或db.admin。“db”客户端实际上是数据库应用程序的管理客户端,可以创建对应用程序具有细粒度权限的其他客户端。
由于创建的客户端只能注册作用域而不是权限,因此它们都需要用户对其进行授权才能接收访问令牌(如上面“访问令牌授权”中所提到的)。在生产环境中,可以为“db”客户端提供scim.write和scim.read权限,这样他就能够创建具有适当组成员身份的用户(例如db.read),以便可以授权新客户端。
漏洞
检查强制执行上述限制的UAA代码,特别是ClientAdminEndpointValidator
的验证函数,似乎client.write作用域没有按照文档实现:
在上面的代码中,caller
指的是用于创建的客户端(即拥有clients.write作用域的客户端),client
指的是被创建的客户端。
可以看到,除了允许以创建客户端ID为前缀的作用域(如文档所示)之外,该函数还允许以被创建的客户端ID为前缀的作用域。此实现缺陷允许创建者创建具有任意作用域的客户端(因为其可以控制创建的客户端ID)。
例如,具有clients.write权限的恶意客户端可以创建一个id为”zones”的客户端,因此可以使用带有”zones”前缀的任何作用域,例如zones.uaa.admin,这是一个可以实现UAA服务器完全管理控制的作用域。
作为旁注,在第182行,您可以看到创建客户端也可以分配他自己的任何作用域。这是有道理的,因为创建客户端已经具有这些作用域了,因此将它们提供给新客户端并没有提权的风险。
漏洞利用
如前所述,客户端需要得到具有匹配组成员资格的用户授权才能对其作用域采取行动。例如,利用此漏洞创建具有id:’zones’和作用域:zones.write的客户端的攻击者,需要zones.write组成员的用户授权这个新的“zones”客户端。
如果该攻击者控制了这样的用户,则攻击变得很容易。如果攻击者具有scim
特权,即scim.write和scim.read,将允许他创建所需的用户,攻击也会很容易实现。
这个视频演示了此攻击,其中“evil”客户端利用此漏洞获取具有clients.admin作用域的访问令牌,从而获得对UAA服务器的完全控制权。
这是攻击的最理想情况,除了具有易受攻击的clients.write作用域之外,他还可以访问能授权使用此漏洞创建的客户端的用户。
让我们稍微限制一下攻击者,如果仅有存在漏洞的作用域,攻击者能做什么呢?在这种情况下,漏洞是否还能不能发挥作用?
自动批准的作用域
对于受限的攻击者,clients.write作用域还允许使用UAA的自动批准功能,这听起来很愚蠢。通常,当用户授权客户代表他行事时,会向他提供批准或拒绝客户端作用域请求的选项。
如上图所示,用户选择仅批准database.read作用域。
如果客户的其中一个作用域设置为自动批准,则会在用户不知情或未经用户同意的情况下自动授权。例如,在上图中,database.admin作用域自动获得批准,可以看到用户对此没有任何指示。
自动批准漏洞利用
如前所述,clients.write作用域允许将创建的客户端的作用域设置为自动批准。让我们看看攻击者如何利用此功能在模拟真实生产环境的场景中完全控制CF部署。
在之前的漏洞利用视频中,攻击者可以使用clients.write权限以客户端的形式访问clients.write作用域。对于这种情况,攻击者可以利用经典的Oauth2用户-客户端对的形式访问clients.write作用于:
‘twist’用户是clients.write作用域的成员
具有clients.write作用域的’evil’客户端,以及some.arbitrary作用域(下文将进行解释)
以下是生产环境的其他参与者:
‘some-fake’应用程序 – 一种资源服务器,它信任UAA访问令牌以管理对其资源的访问。它要求令牌包含some.arbitrary作用域
“victim”用户 – some.arbitrary和cloud_controller.admin组的成员。
“victim”用户经常批准“evil”客户端使用some.arbitrary作用域并代表他访问“some-fake”应用程序。
攻击者的目标是利用此漏洞将“cloud_controller.admin”作用域添加到“evil”客户端并将其设置为自动批准。
攻击
如果不确定攻击者是如何设法执行以下某个步骤的,那么您可以在“漏洞”一节中获得一些说明。
1.为了开始攻击,攻击者使用’twist’用户和’evil’客户端来获取具有易受攻击的clients.write作用域的访问令牌。然后,他利用此漏洞创建名为“cloud_contoller”的客户端,并为其提供cloud_contoller.admin作用域。
攻击者还为’cloud_contoller’客户端提供所有邪恶evil的作用域。
2.接下来,攻击者使用’twist’用户和’cloud_contoller’客户端来修改’evil’客户端以获得cloud_controller.admin作用域,并将其设置为自动批准。
3.在下一次’victim’授权’evil’客户端使用some.arbitrary作用域时,cloud_controller.admin作用域将在未经受害者同意的情况下自动获得批准(!):
此攻击在这一视频中成功执行。
执行攻击后,’evil’客户端对cloud_controller具有管理控制权,这意味着可以完全控制CF部署。
在视频中,我使用了uaac
,一个用于UAA服务器的CLI
。在真实的攻击场景中,“evil”客户端可能会有一个Web界面,“victim”用户将被重定向到UAA身份验证和授权页面。