认证授权协议笔记

Published: 三 16 十一月 2022

In Misc.

在漏洞挖掘时鉴权是个重点,经常遇到各种三方认证方式,一直似懂非懂因此决定之后再遇到就把它们都记下来...

SAML

基本概念

SAML(Security Assertion Markup Language)是一种基于XML的认证与授权协议,听着就比较古老但因此特别普遍所以必会!相比于其他协议它可以说是灰常复杂啦,相关手册数百页,不过只需要关注常见用法遇到不懂得再查手册就行!接下来将根据如下图介绍它的一些基本概念:

image-20221116213728444

首先是Profile,它表示一套方案,SAML可用于单点登录(Single Sign-On)/联合身份(Federated identity)或其他安全场景,这里也只需要关注前两者,一种典型的工作流程(Profile)如下:

image.png

SP即服务提供者(Service Provider)是我们要请求的资源(如通常挖掘的目标),而idP即身份提供者(identity Provider)是进行认证和授权服务,看过程很好懂可对?

请注意这只是一种场景的过程,说到其他流程就得提一个术语Binding,它在这里指将SAML和具体的协议映射起来,SAML并没有新的传输协议,只是指定了怎么使用现有协议,有多种binding这里介绍常见的几个:

1.HTTP Redirect Binding:使用HTTP协议传输,通过Location头重定向各个请求,由于使用GET能传输的数据量有限制

2.HTTP POST Binding:使用HTTP协议传输,通过隐藏表单返回数据,再有JS脚本触发请求,嗯,POST方式,这两种的过程都和上图一致,由UserAgent和SP/idP交互,后两者不会直接通信

3.HTTP Artifact Binding:依然是HTTP协议,但UA只会收到SP返回的Artifact再转发给idP,idP识别后直接和SP通信

4.HTTP SOAP Binding:基于SOAP over HTTP协议来传递数据,过程和1/2差不多

还有绑定其他方式,有需要可以见binding文档,接下来的术语是Assertion,就是SAML里的A,直译为断言,在这里表示SAML权威在一个认证行为后产生的关于主体的一些数据,如属性信息,认证状态,授权状态等。

接下来是metadata元信息,它表示各种配置数据,如SP要配置idP的地址与公钥才能使用这个idP进行鉴权。最后是Protocol规定了具体的请求与响应格式等规范,见后文。

⚠️:再遇到不理解的术语可查查Glossary参考

协议分析

SAML定义了多种协议,这里暂只关注Authentication Request Protocol,它就是用来认证和授权的,这里只需要看懂两个包即可:

AuthnRequest

它是SP生成的交给idP的包,用于告知idP俺要干嘛,需要哪些东西等,接下来从samltool上找几个例子分析,先看个妹签名的:

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="ONELOGIN_809707f0030a5d00620c9d9df97f627afe9dcc24" Version="2.0" ProviderName="SP test" IssueInstant="2014-07-16T23:52:45Z" Destination="http://idp.example.com/SSOService.php" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="http://sp.example.com/demo1/index.php?acs">
  <saml:Issuer>http://sp.example.com/demo1/metadata.php</saml:Issuer>
  <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" AllowCreate="true"/>
  <samlp:RequestedAuthnContext Comparison="exact">
    <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
  </samlp:RequestedAuthnContext>
</samlp:AuthnRequest>

解释下这里面一些可能看不懂的字段含义:

1.samlp:AuthnRequest: 根嘛看属性,ID是实体都要有的,IssueInstant是生成时间,Destination是交给哪个idP处理,AssertionConsumerServiceURL指向生成的请求交给谁

2.saml:Issuer: 请求生成者的实体标志符

3.samlp:NameIDPolicy: 要返回的名称/格式

4.saml:AuthnContextClassRef: 标识一个认证上下文类,告知idP使用哪种方式进行认证,PasswordProtectedTransport当然是说用账号密码咯!

没签名的看完了,但通常请求也是有签名的,它的签名使用了xmldsig,重点关注这里,还是上例子:

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfx41d8ef22-e612-8c50-9960-1b16f15741b3" Version="2.0" ProviderName="SP test" IssueInstant="2014-07-16T23:52:45Z" Destination="http://idp.example.com/SSOService.php" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="http://sp.example.com/demo1/index.php?acs">
  <saml:Issuer>http://sp.example.com/demo1/metadata.php</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="#pfx41d8ef22-e612-8c50-9960-1b16f15741b3">
        <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>yJN6cXUwQxTmMEsPesBP2NkqYFI=</ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>g5eM...</ds:SignatureValue>
    <ds:KeyInfo>
      <ds:X509Data>
        <ds:X509Certificate>MIICajCC...</ds:X509Certificate>
      </ds:X509Data>
    </ds:KeyInfo>
  </ds:Signature>
  <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" AllowCreate="true"/>
  <samlp:RequestedAuthnContext Comparison="exact">
    <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
  </samlp:RequestedAuthnContext>
</samlp:AuthnRequest>

可以看到相比于未签名的版本,它是在原有的根结点下新增了个节点ds:Signature,这其实是xmldsig的enveloped签名方式,这部分得先从ds:Reference节点开始看:

1.ds:Reference:一个该节点指明一个要签名的节点,这里只有一个节点samlp:AuthnRequest需要签名因此只有一个Reference节点,它的URI指向要签名的节点,不写也是指根节点。

2.ds:Transforms: 是转换方式,即这个节点在签名前需要先进行某种转换,这里有两个转换,第一个xmldsig#enveloped-signature表示当前文档是enveloped方式只取原文档的信息,xml-exc-c14n#表示用该算法进行规范化,XML规范化用于消除无意义(字面上不同但含义上一致,如外部空格数不一致,属性顺序不一致等)差异,因此在做比较(包括签名等)时需要先规范化。

3.ds:DigestMethod: 即对该节点用的摘要算法

4.ds:DigestValue: 最终生成的摘要值

所有Reference处理完后,会生成整个文档的签名信息,即ds:Signature节点:

1.ds:SignedInfo: 它里面除了Reference的信息,还有签名这部分使用的规范化算法xml-exc-c14n,签名算法rsa-sha1

2.ds:KeyInfo: 为签名用的证书(公钥)

3.ds:SignatureValue: 为对SignedInfo部分最终生成的签名

这里就要注意了,尽管这里面携带了证书/公钥但只是为了方便对方确定主体,接收方还需要对该证书进行验证或者使用自己保存的证书对该签名进行验证!

Response

认证请求的响应内容就会多很多,依然先看未签名与加密的,如下例:

<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="2014-07-17T01:01:48Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685">
  <saml:Issuer>http://idp.example.com/metadata.php</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="_d71a3a8e9fcc45c9e9d248ef7049393fc8f04e5f75" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
    <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
    <saml:Subject>
      <saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php" 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="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z">
      <saml:AudienceRestriction>
        <saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01: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>

根里面的属性同上,IssuserStatus表示签发者和响应状态秒懂,主要还是看Assertion里的元素:

1.saml:Subject: 指示主体

2.saml:Conditions: 该响应的使用限制,如NotBeforeNotBefore为有效时间,AudienceRestriction指定只能由谁使用

3.AuthnStatement: 描述idP在什么时间通过什么方式进行认证,AuthnContext里面有熟悉的AuthnContextClassRef用来告知SP这个响应是用什么方式认证的

4.AttributeStatement: 包含主体的属性信息

响应里的断言可以被签名或加密,签名过程和请求那是一样的,而加密是把Assertion改成了EncryptedAssertion放密文,详见文档。

⚠️:遇到其他不懂的字段可见断言与协议参考

漏洞挖掘

1.即然用的XML首先排除XXE啦

2.即然不是SP与idP直接交互,那就研究有没有必要加密(泄漏敏感信息了吗),有没有必要签名,验签的过程有问题吗?

参考

[0] Security Assertion Markup Language (SAML) V2.0 Technical Overview

LDAP

LDAP即轻量级目录访问协议(Light Directory Access Portocol),这里轻量是历史原因别管,目录是一种非关系型的数据库,用于存放树形结构的数据,可以和文件系统里的目录对应,其实像文件系统,组织人员等信息都很适合用树形来存储,这就是它的应用场景!访问指它主要用于读操作(读超快写很慢),协议就是说它不是某个具体的软件,它定义了访问目录数据的方法,数据模型的表示方式等内容。

本文只关注它在人员组织(用于认证与授权)上的用途,这在企业级应用上也炒鸡常见,就是把身份信息都放这上面实现统一密码认证啦。

基本概念

数据在LDAP中表现为树状结构,每个对象为entry,它们组成目录信息树(DIT),顶部为root,每个entry可以有0个或多个子entry,一个父entry与0个或多个兄弟entry,如下图左半部所示:

LDAP 对象模型

每个entry由一个或多个objectClass组成,所谓objectClass就是一组属性的集合(包含0个属性),有三种objectClass --Structural/Abstract/Auxiliary类,每个entry有且只有一个Structural来指定它的类型,其他随意,有一些公共的对象类可以直接使用,如要新增人员信息的entry则使用person类,使用后就会根据schema填写必需的属性和可选的属性。

看完DIT组成结构后,在看其导航方式,即如何定位一个/组entry,当然是使用它定义的名称系统(Java反序列化内容开始打你了):

关键字 英文全称 含义
dc Domain Component 域名组成部分,即完整的域名分成几部分后的形式,如域名为example.com变成dc=example,dc=com
ou Organization Unit 组织单位,组织单位可以包含其他各种对象(包括其他组织单元)
cn Common Name 公共名称
dn Distinguished Name 辨别名称,即唯一标识符,全路径名,用它唯一标识一个entry
rdn Relative dn 相对辨别名,类似文件系统的相对路径,在指定父entry下使用rdn可确定子entry

嗯,如下图:

DN 和 RDN - 树层次结构

最后一个概念就是操作,LDAP定义了多种操作类型,常用到的就是Search/Update/Bind,如下表:

模型

LDAP Server搭建

不像SAML那种SP不直接与idP交互,LDAP是CS架构,在测试时配好服务是有必要的,LDAP的实现有很多,例如windows的活动目录(AD),不过那太重了这里还是关注用OpenLDAP,它可以安装在windows/linux上,过程中可设置密码(默认secret),之后可匿名读,要写的话需要用(User=cn=manager,dc=maxcrc,dc=com与密码登录),若想使用命令行工具操作它,需要使用LDIF(LDAP Data Interchange Files)文件,不过这里直接使用图形化软件即可,可以用LdapAdminister/JXplorer/phpLdapadmin等...

漏洞挖掘

1.首先肯定是ldap注入啦

2.todo....

参考

[0] LDAP for Rocket Scientists