近期,两位安全研究人员,Klemen Bratec及 Ioannis Kakavas,公布了他们发现的一个在Microsoft Office 365平台上的SAML服务漏洞,该漏洞可被利用进行跨域认证绕过,最终可对 365平台上的所有联邦 域造成影响。
攻击者可以利用这个漏洞突破访问权限限制,越权获取到受害用户的Office 365账户信息,并可借此访问他们的邮箱以及存储在 OneDrive(微软的云存储服务)上的文件等等。目前该漏洞已经被微软临时修复。
SAML即为安全声明标记语言,英文全称是Security Assertion Markup Language。它是一个基于XML的标准,用于在不同的安全域(security domain)之间交换认证和授权数据。其重要的作用在于跨域的单点登录。SAML实现的目标在于用户经过认证后,能对多个应用服务中的资源进行访问,无需重新进行身份验证(比如再次输入账户和密码等),而SAML便是这个过程中的“中间人”。
单点登录是一种用于方便用户访问网络的技术。如上所述,用户只需在登录时进行一次注册,即可获得访问系统和应用软件的授权,以后便可以在各类应用中切换,不必多次输入用户名和口令来确定身份。在此条件下,管理员无需修改或干涉用户登录就能方便地实施希望得到的安全控制。
例如,我们很多时候登录一些网站时,发现除了注册新账户外,还可以通过其他应用账户(如QQ、微博等)来进行登录,其中便会使用到WEB单点登录技术。因为从用户重复性的角度出发的话,实际上有些网站的用户是重复的,那么对于这部分用户来说,如何在访问网站A之后,无需验证地去访问网站B,web单点登录技术便是一个不错的解决方案。
我们从前文简单了解了这一部分主要会详细关注在SAML 2.0的原理上。目前,SAML标准中最为重要的组成部分如下,
1、声明(Assertions)
首先,声明是一个XML结构,其中包含了打包在声明中的用户信息。其中两个最为常用的声明类型是:
(1)认证声明(Authentication Assertions),包含用户已经对其身份进行认定的信息;
(2)属性声明(Attribute Assertions),包含关于用户的特定信息(如邮件地址,名称等等)。
2、协议(Protocols)
SAML协议描述了某些SAML要素(例如声明)是如何被封装在请求及系统是如何响应请求的,并给出了当进行登录或注销时,SAML实体(身份提供方和服务提供方)必须遵循的处理规则。也可以这么说,SAML协议定义了系统实体之间传递和处理SAML声明的协议集合,其中上述提到的验证请求协议将在之后介绍。
3、绑定(Bindings)
SAML绑定描述了一个SAML消息如何被映射到非SAML相关的消息格式和通信协议中。例如,我们在进行身份验证过程中,服务提供方(即用户去访问的应用资源)需与身份提供方进行通讯验证,那么如何从传输的消息中,提取双方需要的信息,这个就涉及到了绑定。 当需要从一个HTTP GET请求中取出URL中的查询字符串时, HTTP重定向绑定(HTTP Redirect Binding )定义了如何对该URL进行格式化,使之符合 SAML消息标准格式 。而在通讯过程中,SAML请求是经过SAMLRequest查询参数进行传递的,并经过压缩后,再进行基于base64的编码和URL解码。
4、身份提供方(Identity Provider)
身份提供方经过SAML 授权,并持有着关于用户的信息, 身份提供方 可以为使用者发布声明,使其能够于 身份提供方 的应用上进行权限内的操作。
5、服务提供方(Service Provider)
服务提供方是SAML消息的接收者,其接受来自身份提供方的用户信息,并开放符合该用户访问权限的资源。
接下来可以看一个基于Web浏览器单点登录框架的简单例子,我们可以通过这个例子来更加深入理解SAML。首先,在进行单点登录的过程中,服务提供方使用 HTTP重定向绑定和身份提供方使用 HTTP POST绑定。其中整个过程涉及到的部分如下,
1、用户使用的浏览器
2、身份提供方
3、服务提供方
我们从下图中也可以看到关于三者之间的交互,
一、在我们这个例子中,这个单点登录过程始于一个用户尝试访问一个受保护的资源(或者简单来说,可以理解为请求登录)。服务提供方拥有允许或者拒绝联合登录的功能配置,以及实时地将用户重定向到一个发现服务接口,以便来选择他们的身份提供方。通过自动匹配选择,可让服务提供方知道和信任所其选择的身份提供方,接着服务提供方会创建一个SAML身份验证请求,具体如下:
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="_bec424fa5103428909a30ff1e31168327f79474984" Version="2.0" IssueInstant="2016-04-14T11:39:34Z" ForceAuthn="false" IsPassive="false" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="https://myserviceprovider.atsomeorg.com/Shibboleth.sso/SAML2/POST"> <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> https://myserviceprovider.atsomeorg.com/shibboleth </saml:Issuer> <samlp:NameIDPolicy xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" AllowCreate="true" /> </samlp:AuthnRequest>
在请求的信息中,有两个重要部分需要了解下,
1、编码中的Issuer(发行人)代表了服务提供方的实体ID,其表现形式为一个 URI(统一资源标识符),像一串身份标识字符串一样的。Issuer(发行人)包含了服务提供方请求用户身份验证的信息。
2、IssueIstant,其包含的信息体现了当服务提供方发出请求后,生成的内部识别ID ,用以匹配在接受到该条请求后发出的SAML响应。
二、然后用户的浏览器被重定向到身份提供方绑定的URL,SAML Authentication Request(SAML 验证请求)是通过 HTTP GET中的一串查询参数(之后请求的信息会被进行压缩,再经过 base64以及URL编码再进行传递)
三、在接收来自用户浏览器的SAML请求后,身份提供方检查发送请求验证信息的服务提供方身份,并在成功认证服务提供方身份后,验证请求的内容,提示用户进行登录认证(输入账户密码)。如果用户认证成功,身份提供方将生成SAML回应,具体如下:
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_8e8dc5f69a98cc4c1ff3427e5ce34606fd672f91e6" Version="2.0" IssueInstant="2016-04-14T11:40:48Z" Destination="https://myserviceprovider.atsomeorg.com/Shibboleth.sso/SAML2/POST" InResponseTo="_bec424fa5103428909a30ff1e31168327f79474984"> <saml:Issuer>http://idp.example.com/idp/shibboleth</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="pfx65c8c6cd-b03b-8634-fd54-636fa66e7722" Version="2.0" IssueInstant="2016-04-14T11:40:48Z"> <saml:Issuer>http://idp.example.com/idp/shibboleth</saml:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <ds:Reference URI="#pfx65c8c6cd-b03b-8634-fd54-636fa66e7722"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ds:DigestValue>gxnHkIizISbLkkB1vSWapmWuQzk=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>Qn69P4a3PQTISfqk/0t2JdJqG1nlswFQt8bNWPZ+K41EIYkCcTyuwlKnCzlTvU1YgNXIvHcFEyKjYAge+s3gwqecATI+yRB9OtD34YxBC4kyGcbq/ETQxIQ515xehfRxLrQjUpRzgHQXMLSjGdgjeelfKsHeSczA9Hp44kasQSs=</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>MIICajCCAdOgAwIBAgIBADANBgkqhkiG9w0BAQ0FADBSMQswCQYDVQQGEwJ1czETMBEGA1UECAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMT25lbG9naW4gSW5jMRcwFQYDVQQDDA5zcC5leGFtcGxlLmNvbTAeFw0xNDA3MTcxNDEyNTZaFw0xNTA3MTcxNDEyNTZaMFIxCzAJBgNVBAYTAnVzMRMwEQYDVQQIDApDYWxpZm9ybmlhMRUwEwYDVQQKDAxPbmVsb2dpbiBJbmMxFzAVBgNVBAMMDnNwLmV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZx+ON4IUoIWxgukTb1tOiX3bMYzYQiwWPUNMp+Fq82xoNogso2bykZG0yiJm5o8zv/sd6pGouayMgkx/2FSOdc36T0jGbCHuRSbtia0PEzNIRtmViMrt3AeoWBidRXmZsxCNLwgIV6dn2WpuE5Az0bHgpZnQxTKFek0BMKU/d8wIDAQABo1AwTjAdBgNVHQ4EFgQUGHxYqZYyX7cTxKVODVgZwSTdCnwwHwYDVR0jBBgwFoAUGHxYqZYyX7cTxKVODVgZwSTdCnwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOBgQByFOl+hMFICbd3DJfnp2Rgd/dqttsZG/tyhILWvErbio/DEe98mXpowhTkC04ENprOyXi7ZbUqiicF89uAGyt1oqgTUCD1VsLahqIcmrzgumNyTwLGWo17WDAa1/usDhetWAMhgzF/Cnf5ek0nK00m0YZGyc4LzgD0CROMASTWNg== </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <saml:Subject> <saml:NameID SPNameQualifier="https://myserviceprovider.atsomeorg.com/shibboleth" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"> _ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7 </saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData NotOnOrAfter="2016-04-14T11:50:48Z" Recipient="https://myserviceprovider.atsomeorg.com/Shibboleth.sso/SAML2/POST" InResponseTo="_bec424fa5103428909a30ff1e31168327f79474984"/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2016-04-14T11:40:48Z" NotOnOrAfter="2016-04-14T11:50:48Z"> <saml:AudienceRestriction> <saml:Audience>https://myserviceprovider.atsomeorg.com/shibboleth</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2016-04-14T11:40:48Z" SessionNotOnOrAfter="2016-04-14T11:50:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93"> <saml:AuthnContext> <saml:AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:Password </saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> <saml:AttributeStatement> <saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">test@example.com</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">users</saml:AttributeValue> <saml:AttributeValue xsi:type="xs:string">examplerole1</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> </saml:Assertion> </samlp:Response>
四、接下来,引导用户浏览器回应一个HTTP POST请求到服务提供方,在本次案例中假设为 https://myserviceprovider.atsomeorg.com/Shibboleth.sso/SAML2/POST 。其中,有部分内容也是需要了解的,具体如下。
1、InResponseTo,包含了一个ID值,该ID会与先前服务提供方发送请求的时候产生的内部标识ID进行匹配(避免重放攻击);
2、IssueIstant, NotBefore 以及NotOnOrAfter 定义了 SAML响应(以及声明)的有效时间,也是为了避免重放攻击;
3、声明还包含了一个 Isssuer字段,其中具有一个 url,因此服务提供方可以确认身份提供方的身份(是否符合此前请求指定的身份提供方地址);
4、AudienceRestriction部分,则定义了可对该声明进行读取的服务提供方,而其他服务提供方并无权限进行读取。
5、Subject,用于识别验证用户身份;
6、AttributeStatement部分,包含用户进行验证的信息,其中也包括各种属性以及它们的值;
在这份声明中(也包括全部的 SAML响应)是基于XML签名( XML Signature )来保护其完整性,检查其在传输过程中并未遭受篡改。
五、在接收到SAML响应后,服务提供方可以验证其内容和结构,并验证签名,随后通过了用户认证,分配用户一个Cookie,启动与用户间的Web会话。
那么到这里,或许你会有些疑惑,
1、服务提供方如何知道并信任身份提供方?
2、身份提供方如何知道并信任服务提供方?
3、身份提供方如何对声明进行签名?
4、服务提供方在接受到一份声明后如何验证其完整性?
实际上,在验证之前,身份提供方和服务提供方会进行相互之间的信任处理。为了实现在请求和响应的交互过程中,身份及信息的验证,两者之间需要交换元数据。我们可以理解为,此处的元数据包含了一个公钥,对应着身份提供方对声明进行签名加密所使用的私钥,每一个实体(可以是用户、服务提供方或是身份提供方)所绑定的URL以及支持或响应的算法等等。那么基于这样的出发点,有两种方法可让他们获取彼此的元数据:
1、双方以一种安全的方式交换元数据,确立信任关系;
2、或者通过加入一个联邦(Federation),将这种信任关系委托給第三方机构。然后联邦运营者会设定任务,收集来自所有参与的实体(身份提供方和服务提供方)的元数据,并发布这些数据。每个身份提供方和服务供应方都会提交其元数据来获取有关参与该联邦的其他实体的信息。
Office 365平台服务提供方使用的是一个WS-Trust以及 SAML 2.0 web 浏览器单点登录框架的混合体。Office 365平台支持通过WS-Trust以及SAML 2.0 web 浏览器进行单点登录两种方式进行访问,但两者之间并不孤立。
实际上,WS-Trust为我们提供了一种安全令牌服务,比如令牌的颁发(Issuance)、续订(Renewal)和终止(Cancel)等。但SAML的服务提供方会将SAML 2.0标准的传输信息,使用令牌( token)转换服务,在内部将 SAML信息转化为WS-Trust信息。而因为上述的令牌转换服务,所以此次在 SAML服务提供方发现的漏洞,也会影响到WS-Trust单点登录。
然而,为了简单起见,在理解本文Office 365 的服务提供方时,均可认为是使用SAML进行单点登录。
不过有一点需要强调的是, 对于经过SAML的账户验证,Office 365并不支持实时资源配置,所以对于使用账户进行单点登录的用户,需要已经在Azure AD上有租户才行。这个需要经过Directory同步或者经过用户在IDM 系统的帮助下进行配置,不过这已经超出了本文的范围,这里先略过不谈。
从一个身份提供方到 Office 365服务提供方,需要在请求消息中发布的属性,以便进行信息匹配,包括以下两个:
1、UPN(User principal name)用户主体名称,包含IDP(即身份提供方)Email名称等信息;
2、ImmutableId,用户的唯一识别符,存放于SAML声明的Subject中。
接下来,我们可以看下Office 365平台的登录情况,
流程始于用户开始访问 Office 365 portal ,接着被重定向到 https://login.microsoftonline.com/login.srf ,而响应形式如下,
在键入用户名称以及按下“TAB”或点击密码输入区域,该页面将构建一个XHR (XMLHttpRequest)发送到 https://login.microsoftonline.com/common/userrealm ,而为了验证用户的域(可以简单理解为用户归属的企业)是否能与Office 365平台上的租户(可以理解为某企业所租赁的服务)相匹配。
GET /common/userrealm/?user=ikakavas@testdomain.gr&api-version=2.1&stsRequest=rQIIAbNSzigpKSi20tcvyC8qSczRy09Ly0xO1UvOz9XLL0rPTAGxioS4BMruuVuZ2Fh77Wj-e6KxLMF2FaMaTp36OYl5KZl56XqJxQUVFxgZu5hYDA2MjTcxsfo6-zp5nmCacFbuFpOgf1G6Z0p4sVtqSmpRYklmft4jJt7Q4tQi_7ycypD87NS8Scx8OfnpmXnxxUVp8Wk5-eVAAaDxBYnJJfElmcnZqSW7mFVSU00tTCxTUnRNkpOTdU2Sksx0kwxSzXRTzZMtTC1ME00Mk1MOsGwIucAi8IOFcREr0C-3A6ZLrn182Gt-tWV-vVlpwi5OW-L8Yl-SWJSeWmKrapSWkpqWWJpTAhYGAA2&checkForMicrosoftAccount=false HTTP/1.1 Host: login.microsoftonline.com User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0 Accept: application/json Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br DNT: 1 X-Requested-With: XMLHttpRequest Referer: https://login.microsoftonline.com/login.srf?wa=wsignin1.0&rpsnv=4&ct=1460721662&rver=6.7.6640.0℘=MCMBI&wreply=https%3a%2f%2fportal.office.com%2flanding.aspx%3ftarget%3d%252fdefault.aspx&lc=1033&id=501392&msafed=0&client-request-id=3a47de76-3c34-4a3b-b883-fdc88176603d
如果域已被知道及配置成联邦身份,用户的浏览器将被引导构建一个 HTTP POST请求到 HTTP-POST绑定的身份提供方的 URL,具体的信息如下,
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_f6daef39-fb54-407e-abb4-c75d261b75ae" IssueInstant="2016-04-11T21:13:44Z" Version="2.0" AssertionConsumerServiceIndex="0" > <saml:Issuer>urn:federation:MicrosoftOnline</saml:Issuer> <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" /> </samlp:AuthnRequest>
用户实时在身份提供方中进行身份验证,如下,
随后浏览器会被引导到创建一个HTTP POST返回到 Office 365 HTTP-POST绑定的 URL,这里为 https://login.microsoftonline.com/login.srf 。通过包含着声明的SAML响应。一个简单的响应例子如下,
<saml2p:Response Destination="https://login.microsoftonline.com/login.srf" ID="_cefc5f992f2e455d7b3e52522fc479db" InResponseTo="_f6daef39-fb54-407e-abb4-c75d261b75ae" IssueInstant="2016-04-11T21:14:35.365Z" Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"> https://idp.admin.grnet.gr/idp/shibboleth </saml2:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> <ds:Reference URI="#_cefc5f992f2e455d7b3e52522fc479db"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> <ec:InclusiveNamespaces PrefixList="xsd" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transform> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <ds:DigestValue>dc1f3jn97lZ6FWdxGxsEWxXNsTM=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue> Removed for brevity </ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate> Removed for brevity </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <saml2p:Status> <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /> </saml2p:Status> <saml2:Assertion ID="_b971f4e7f575bcc9cbc9034246c62c98" IssueInstant="2016-04-11T21:14:35.365Z" Version="2.0" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <saml2:Issuer>https://idp.admin.grnet.gr/idp/shibboleth</saml2:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> <ds:Reference URI="#_b971f4e7f575bcc9cbc9034246c62c98"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> <ec:InclusiveNamespaces PrefixList="xsd" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transform> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <ds:DigestValue>WBgE+nW+3g9P5XpiZwGE06MT//g=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue> Removed for brevity </ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate> Removed for brevity </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <saml2:Subject> <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"> This is where my ImmutableId is </saml2:NameID> <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml2:SubjectConfirmationData Address="2a02:214d:811b:7200:dc15:b7bc:a304:3738" InResponseTo="_f6daef39-fb54-407e-abb4-c75d261b75ae" NotOnOrAfter="2016-04-11T21:19:35.384Z" Recipient="https://login.microsoftonline.com/login.srf"/> </saml2:SubjectConfirmation> </saml2:Subject> <saml2:Conditions NotBefore="2016-04-11T21:14:35.365Z" NotOnOrAfter="2016-04-11T21:19:35.365Z"> <saml2:AudienceRestriction> <saml2:Audience>urn:federation:MicrosoftOnline</saml2:Audience> </saml2:AudienceRestriction> </saml2:Conditions> <saml2:AuthnStatement AuthnInstant="2016-04-11T21:14:35.027Z" SessionIndex="_91380d0480ac9af6bcb19f3b26f0ea81"> <saml2:SubjectLocality Address="2a02:214d:811b:7200:dc15:b7bc:a304:3738" /> <saml2:AuthnContext> <saml2:AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes: </saml2:AuthnContextClassRef> </saml2:AuthnContext> </saml2:AuthnStatement> <saml2:AttributeStatement> <saml2:Attribute FriendlyName="IDPEmail" Name="IDPEmail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string"> ikakavas@mymail.example.com </saml2:AttributeValue> </saml2:Attribute> </saml2:AttributeStatement> </saml2:Assertion> </saml2p:Response>
在声明中的Subject 属性里面,包含的唯一标识符ImmutableId,具体如下,
<saml2:Subject> <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"> //以下为ImmutableId所在 </saml2:NameID> <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml2:SubjectConfirmationData Address="2a02:214d:811b:7200:dc15:b7bc:a304:3738" InResponseTo="_f6daef39-fb54-407e-abb4-c75d261b75ae" NotOnOrAfter="2016-04-11T21:19:35.384Z" Recipient="https://login.microsoftonline.com/login.srf"/> </saml2:SubjectConfirmation> </saml2:Subject>
在属性声明中,包含着与用户在Azure AD已有账号的UPN(用户主体名称)相匹配的 IDPEmail信息,具体如下,
<saml2:AttributeStatement> <saml2:Attribute FriendlyName="IDPEmail" Name="IDPEmail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string"> ikakavas@mymail.example.com </saml2:AttributeValue> </saml2:Attribute> </saml2:AttributeStatement>
在这里,同样能将SAML响应以及SAML声明看成是经过数字签名的。
首先我们从上方的声明中可以注意到,Office 365 SAML 服务提供方忽略了声明中的Subject,虽然ImmutableId 值包含了用户在Azure AD 唯一标识符。
而名称标识符,可以通过SAML 2 .0 < nameid >元素来体现,往往用以识别一个SAML声明中的 subject的。名称识别符可以是任意的字符,而其通常是一个邮件地址或电脑用户名称。
从攻击者的角度出发,事实上NameID的准确性并无进行校验,而使得事情更加容易的是,ImmutableID通常是来自于 AD objectGUID。
在身份校验的过程中,IDPEmail属性值会去匹配Azure AD中用户的UPN,而这依靠在声明中的信息便可达到。但是声明中亦包含了Issuer(发行人)的信息(虽然有经过签名验证),所以根据前文的了解,正常来说,一个不相关的身份提供方是无法为其他域(或是租户)的用户创建声明么?
答案是否定的。
事实证明(在本文的漏洞利用过程中),服务提供方使用使用声明中的 Issuer (发行人)只是为了找到匹配的认证,识别SAML响应或者是声明的签名而已,但却没有真正对IDPEmail属性值进行任何检查。这基本上意味着可以通过声明,以身份提供方A的声明来认证身份提供方B的用户。以此便可实现越权访问B域的资源。
在验证该漏洞时,我们需要有一个 Office 365租户作为连接Office 365和 SAML 2.0身份提供方的平台。我们还需要拥有一个基本的 Active Directory实例以及 SimpleSAMLphp (SAML 2.0 服务提供者和标识提供者功能的 PHP 实现,兼容 Shibboleth 1.3 和 2.0)作为我们的身份提供方。
首先,设置另外一个组织机构,其在我们这次试验中扮演着受害用户的角色。其中包含不同的EntityID并且是为新的Office 365试用租户,同时我们还需另外一个SimpleSAMLphp实例。
我们的测试所需环境如下,
1、首先,Office 365通过预设someorg-attacker.com作为身份提供方,具体为 http://idp.someorg-attacker.com/ ;
2、接着, Office 365再通过预设 someorg-victim.com作为身份提供方,具体为 http://idp.someorg-victim.com/ 。
接下来,我们增加账户到 someorg-attacker的用户目录下,看下当我们尝试登录时会发生些什么。在AD(Active Directory)上增加一个新的alternative UPN suffix,接着通过内置的工具来新增用户,
以下为someorg-victim用户目录下的实体用户,
以下为someorg-attacker用户目录下的包含两个组织机构的实体用户,
我们可以看到其中新增了关于受害方中的实体用户。
接下来,该验证我们的发现了。首先从前文中,我们也可以知道一开始用户访问的页面为 https://login.microsoftonline.com/ ,验证步骤具体如下,
1、我们通过使用XXX@someorg-attacker.com账户(以上用户目录中的两个账户任意一个)作为登录的用户名,然后浏览器会被重定向到someorg-attacker的身份提供方进行身份认证;
2、当我们在身份提供方的实时身份验证登录过程中,我们通过使用此前在someorg-attacker目录下创建的带有受害方域名称的账户(例如john.smith@someorg-victim.com),进行登录验证,接着顺利完成了在身份提供方的验证过程;
3、接下来,我们会看到问题点所在,如上,在经过身份提供方的验证后,微软的登录页面会提示一个错误的信息,但除此之外并没有其他特别的提示和处置。而最终,我们也“顺利”以 john.smith@someorg-victim.com的身份登录进来了,并拥有了访问someorg-victim资源的权限。
而对于这样的情况,我们不知道该是高兴(因为验证了我们的发现)还是担忧(因为其影响的范围)。
受影响的用户包括,
1、 telefonika
2、 Caltex Australia
3、 Georgia State University
4、 Japan Airlines
5、 Santa Clara County
6、 City of Chicago,IL
7、 British Airways
我们也可以通过以下的查询方式,确认某个域是否设置为加入联邦中,具体如下,
https://login.microsoftonline.com/common/userrealm/?user=something@domain&api-version=2.1&checkForMicrosoftAccount=false
上述为检测一个域是否加入联邦的HTTP GET请求,而将会返回一个 json的响应信息,
{ "NameSpaceType":"Federated", "federation_protocol":"WSTrust", "Login":"something@ba.com", "AuthURL":"https://sts.baplc.com/adfs/ls/?username=something%40ba.com&wa=wsignin1.0&wtrealm=urn%3afederation%3aMicrosoftOnline&wctx=", "DomainName":"ba.com", "FederationBrandName":"BA.COM", "cloudinstancename":"login.microsoftonline.com" }
从响应的参数来看,其中,
1、对于NameSpaceType参数来说,如果其值为Federated,那么说明该域被设置为联合单点登录,因此存在漏洞。
2、对于federation_protocol参数来说,如果该值为WSTrust或者是SAML2.0,这说明单点登录被设置为以上两种之一的协议,那么也是说明存在漏洞的。
*参考来源: bratec.si ,FB小编troy编译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)