课程设计: Oauth2.0 服务器取证
这里主要是针对QQ账户的oauth2.0进行一个认证取证的过程。
已认证网站我这里使用了Leetcode, 实际上使用什么都是可以的。采集一些基本的信息,并但是由于认证过程Token是无法面向用户的,所以我又搭建了一个可以获取token的机器来模拟Token的过程。
基本概念:
Oauth, Open Authorization , 一种开放授权协议,允许第三方应用程序使用资源的所有者通过凭据获取资源访问权限。官方是RFC4769。腾讯家Oauth认证这个业务叫做QQ互联,主要是允许第三方采集一些不多不少刚刚好的数据,让第三方应用看着挺有牌面实际没什么用,最主要是我们不用频繁的注册账户了,为我们方便了那么一点点,也算是有些用。
取证部分
访问令牌
这个服务器是公家的,渗透我是真的不咋地,就简单的看看包,流量变化,拿到一些基本属性就差不多了。
首先是我们去到登陆的页面,可以看到是支持我们用QQ登陆的,说明注册了QQ家Oauth2的业务:(有一排支持的第三方账号)

对于应用而言,需要进行两步:
-
获取Authorization Code;
-
通过Authorization Code获取Access Token
在这个例子中我们并无法抓到服务器上面的包,推测服务器至少应该请求到腾讯https://graph.qq.com/oauth2.0/authorize这个接口。那我们先老老实实的解读参数吧:
{
"GET": {
"scheme": "https",
"host": "graph.qq.com",
"filename": "/oauth2.0/show",
"query": {
"which": "Login", // 定义动作
"response_type": "code", // 定义返回类型
"redirect_uri": "https://leetcode-cn.com/accounts/qq/login/callback", // 回返uri
"scope": "get_user_info", // 调用的功能
"client_id": "101468852", // 注册的id
"display": "None",
"state": "wPqM80YK_pc" // 防止第三方CSFR攻击
},
}
}
这些参数包括有一些重要的也有不重要的,我已经做了注释。重要的包括ID, state,redirect_uri 等等。乍一看还是有我们更改的空间,实际上按照Tencent那边的要求我们无法更改redirect_uri与client_id 与 display. 不过有了client_id 我们可以尝试一下爆破key.
关于state是如何防止CSFR的,我简单的更改一下state. 这种规则确实是生产环境该有的保险丝。
对于这种认证方式,我们用户所能看到的极限就是code如上图, code在被使用过之后就会被remove(尝试用旧的code登录)
不过这里我们尝试做这样的一种实验,我们在登录界面把state改掉, 这样我们完成了第一步获得了code但是改掉了state我们不能成功登录,但ode在获取token的时候就会失效,那么此时code还能使用么?因为Oauth没有state相关的部分,而腾讯的开发者文档并不涉及这样的内容:我们可以做出这样的假设:
当他是在C 判断state是否失效的时候, 此时code生效,那我们接下来修改code和state可以登录此网站
在E判断的时候,已经获取Token, code失效,无法登录
结果是可以,实验过程如下
首先我们改掉这里的state, 并保留一份副本
这个时候我们拿到了code, 但由于state的不同无法匹配,接下来我们直接更改此请求的state
就会成功登陆了。得益于Leetcode复杂的一堆如Cookie参数我们实现远程登录有一点点的麻烦,就也算是个小bug。
最后是获取Token, 一般采取这种授权码模式的认证过程Token对我们用户来说是不可兼得,所以只能去官网申请,并用本地搭建的环境模拟获取Token这一过程
构造请求:
{
"GET": {
"scheme": "https",
"host": "graph.qq.com",
"filename": "/oauth2.0/token",
"query": {
"grant_type": "authorization_code",
"client_id": "XXXX",
"client_secret": "XXXXX",
"code": "D91BA2F5254C3C4CDF3BD6293ED6DA8D",
"redirect_uri": "XXXX"
},
"remote": {
"地址": "183.194.238.158:443"
}
}
}
这种请求是一次性的,无论成功与否code都会被销毁,要重新模拟一次, 如下:
callback( {“error”:100020,“error_description”:“code is reused error”} );
我们真正拿到的Token一共有三个:
{
access_token: "XXXXXX", // 我们与source服务器交互的Token
expires_in:7776000, // 有效时间,差不多是两天多
refresh_token: "XXXXXX", // 续期access_token的ti=oken , 同样与authorization服务器交互
}
实验:同一用户在同一网站上登陆两次的Token变化:
既然Token保质期比较长, 对于同一个用户来说Token虽然只能拿到寥寥的信息,不过关联到了OpenID键还是比较有用的。毕竟其他平台也应该有直接以OpenID键存取了相应的用户数据(官网的推荐做法),对于Token的变化,我们可以做这样的假设:
- Token两次申请后 后一次申请完Token后前一次的Token直接失效
- Token两次申请后前一次后后一次的Token都保持活性
实验过程:略微有些重复就不放了(这个Code不同而且过期的太快了,忘记截图了)
结果:
两次申请到的Token是相同的,不存在后一次申请前一次失效的情况
资源服务器请求数据
最后是申请数据的过程:这里的appid, OpenID都是基于Token获得的,也就是说这个体系的数据获取部分的安全性完全集中在Token上
使用Token获取用户的OpenID --> 使用Token与OpenID与appid 获取用户的基本信息
获取OpenID
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 采集数据
关于这里向data_Source索要data的过程, Token, appID, OpenID必须要保持高度一致才能获取数据,也就是说Token把那个不能获取所有人的数据,只能获取当前登录对象的数据,并且验证appID是否匹配
尝试更改OpenID :
{“ret”:-71,“msg”:“openid and token not match”}
尝试更改AppID:
{“ret”:-22,“msg”:“openid is invalid”}