李恒道 发表于 2023-4-28 00:42:23

QQ快捷登录协议分析

# 抓包

首先进入qq任意一个网页抓一下快捷登录数据
注意:本人尝试了不同网页,所以抓包的数据的appid可能不一致,请忽略

看到了

https://localhost.ptlogin2.qq.com:4303/pt_get_uins?callback=ptui_getuins_CB&r=0.7051911581809474&pt_local_tk=787563823

var var_sso_uin_list=[{"uin":4548212,"face_index":0,"gender":0,"nickname":"无敌暴龙战神李恒道","client_type":65793,"uin_flag":xxx,"account":4548212}]

得到了一个单点登录列表

提交参数有三个,**callback**应该是固定的

我们主攻**r**和**pt_local_tk**

全局搜一下

找到了

```js
    N = function N(t, e, n, o, i) {
      var r;
      k["default"].cookie.get("pt_local_token") || (k["default"].cookie.set("pt_local_token", Math.random(), "ptlogin2." + ft.ptui.domain),
      k["default"].cookie.get("pt_local_token")) ? (r = ft.ptui.isHttps ? E : x,
      t = "https://localhost.ptlogin2." + ft.ptui.domain + ":/" + t + "&r=" + Math.random() + "&pt_local_tk=" + k["default"].cookie.get("pt_local_token"),
      dt(t, r, e, window, o, i)) : c.logger.warn("无法设置cookie,无法使用快速登录")
    }
```

可以看出r是一个随机数,pt_local_tk取得是cookies中的pt_local_token

找来找去最后确定了

```
https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=716027609&daid=383&style=33&login_text=%E7%99%BB%E5%BD%95&hide_title_bar=1&hide_border=1&target=self&s_url=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump&pt_3rd_aid=102013353&pt_feedback_link=https%3A%2F%2Fsupport.qq.com%2Fproducts%2F77942%3FcustomInfo%3D.appid102013353&theme=10&verify_theme=
```

可以得到pt_local_token的返回

关于端口问题可以尝试直接搜4303

可以得到

    x = ,
    E = ,       

根据观察规律以E为主,但是秉承着安全的态度,我们可以视为一共有十个端口

# 分析点击登录

我们查看dom点击事件可以找到

pt.qlogin.imgClick

```js
    z = function z(t) {
      var e = parseInt(t.getAttribute("type"), 10)
          , n = t.getAttribute("uin");
      switch (c.logger.info("点击快速登录头像 uin=".concat(n, " type=").concat(e)),
      e) {
      case 1:
            pt.reportPath(n, 2),
            F();
            break;
      case 2:
            R(n),
            pt.reportPath(n, 1);
            break;
      case 4:
            Q(n),
            pt.reportPath(n, 1);
            break;
      case g:
            V(n, !0),
            pt.reportPath(n, 4)
      }
    }
```

这里走到了4

也就是

            Q(n),
            pt.reportPath(n, 1);

看函数应该是Q是主要函数,reportPath看名字是一个重定向函数

所以我们去分析Q吧

```js
    Q = function Q(t) {
      t && (S["default"].showLoading(),
      N("pt_get_st?clientuin=" + t, 8e3, "ptui_getst_CB", function(t) {
            c.logger.info("pt_get_st data", t),
            o.ptui_getst_CB(t)
      }, function() {
            S["default"].hideLoading(),
            o.ptui_qlogin_CB("-1234", "", "快速登录失败,请检查网络情况或QQ客户端是否打开。")
      }),
      o.ptui_getst_CB.submitUrl = B({
            "uin": t,
            "pt_local_tk": "{{hash_clientkey}}"
      }))
    }
```

showLoading显示登录

那主要逻辑就是N

看参数来说

参数1,地址'pt_get_st?clientuin=4548212'

参数2,固定参数8e3,调试猜测为超时

别问哪看出来的,qzone主动打出来日志了...

jsonp url=https://localhost.ptlogin2.qq.com:4303/pt_get_st?clientuin=4548212&r=0.8219003701233059&pt_local_tk=-1988371938 timeout=8000

参数3,一个字符串ptui_getst_CB

参数4,疑似成功函数

参数5,疑似失败函数

参数6,通过B函数传入t为4548212(我的qq),生成一串url到o.ptui_getst_CB.submitUrl

https://ssl.ptlogin2.qq.com/jump?clientuin=4548212&keyindex=9&pt_aid=549000912&daid=5&u1=https%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_local_tk={{hash_clientkey}}&pt_3rd_aid=0&ptopt=1&style=40&has_onekey=1

再作为参数

这里可能是利用副作用生成一串跳转函数

猜测一下之后继续往里看

```js
    N = function N(t, e, n, o, i) {
      var r;
      k["default"].cookie.get("pt_local_token") || (k["default"].cookie.set("pt_local_token", Math.random(), "ptlogin2." + ft.ptui.domain),
      k["default"].cookie.get("pt_local_token")) ? (r = ft.ptui.isHttps ? E : x,
      t = "https://localhost.ptlogin2." + ft.ptui.domain + ":/" + t + "&r=" + Math.random() + "&pt_local_tk=" + k["default"].cookie.get("pt_local_token"),
      dt(t, r, e, window, o, i)) : c.logger.warn("无法设置cookie,无法使用快速登录")
    }
```

这里并没有参数六,所以可能单纯就是利用副作用设置url,然后抛弃了这个参数

第一句功能就是先检测是否有pt_local_token的cookies,没有就随便设一个

```js
k["default"].cookie.get("pt_local_token") || (k["default"].cookie.set("pt_local_token", Math.random(), "ptlogin2." + ft.ptui.domain)

```

然后尝试调用k["default"].cookie.get("pt_local_token"))读取

最后可以确定基本走到了

```js
(r = ft.ptui.isHttps ? E : x,
      t = "https://localhost.ptlogin2." + ft.ptui.domain + ":/" + t + "&r=" + Math.random() + "&pt_local_tk=" + k["default"].cookie.get("pt_local_token"),
      dt(t, r, e, window, o, i))
```

r = ft.ptui.isHttps ? E : x是选择端口,判断是否是https,如果是就是



如果不是就是



这里我们知道了E和x的使用,不过出于兼容开发我个人依然倾向于全用

然后拼接出来一个t

```js
t = "https://localhost.ptlogin2." + ft.ptui.domain + ":/" + t + "&r=" + Math.random() + "&pt_local_tk=" + k["default"].cookie.get("pt_local_token")
```

然后调用dt(t, r, e, window, o, i))

继续往里看dt

```js
    dt = function dt(t, e, n, o, i, r) {
      -1 < t.indexOf("/pt_get_st?") ? ct(t, e, n, i, r) : lt(t, e, n, o, i, r)
    }
```

判断是否是pt_get_st,调用ct或lt,这次我们调用ct

注意,这里忽略了参数o,也就是 window的函数

```js
    ct = function ct(t, e, n, o, i) {
      return rt.apply(this, arguments)
    }
```

继续往里看,到这里往里就是一系列传参了,我个人来说比较懒得调了

于是直接抓包+刚才的几个函数下断

于是断到了

```js
      N("pt_get_st?clientuin=" + t, 8e3, "ptui_getst_CB",xxxxx)
```

中的

```js
function(t) {
            c.logger.info("pt_get_st data", t),
            o.ptui_getst_CB(t)
}
```

传入的t是{uin: 4548212, keyindex: 9}

这个参数是来自于

https://localhost.ptlogin2.qq.com:4303/pt_get_st?clientuin=4548212&r=0.8813633351013919&pt_local_tk=-1988371938&callback=__jp1

这个网址设置了一些cookies,凭感觉重要

Set-Cookie:

clientkey=0001644A9ADA0068911F2DDABS89881BB01D262197CC69F90F250E5A3921264AF159455562A4B03BDD8FB76C371EBEF54945DA9E5EE4A3E32EFC298172F773E7BF75B15F788DB1BFADSW28E9F0EE7F407AD5A4BF48C5044C98AFE920FB4ASX9D777D60007A34D97C6E5F35A362F; path=/; domain=ptlogin2.qq.com; Secure; SameSite=None

可以看出就是端口遍历+N函数传入的地址参数拼接一下

然后调用o.ptui_getst_CB(t)

```js
    function p(t) {
      var e;
      p.called = !0,
      t && (r["default"].hideLoading(),
      p.submitUrl && (e = p.submitUrl.replace("{{hash_clientkey}}", a["default"].str.hash33(a["default"].cookie.get("clientkey"))),
      t.keyindex && (e = e.replace(/keyindex=\d+/, "keyindex=" + t.keyindex),
      a["default"].report.monitor(2423538, 1)),
      u["default"].reportPCMgr(t.uin, 2),
      a["default"].http.loadScript(e)),
      a["default"].report.monitor(508159, 1))
    }
```

还记着我们最开始的的副作用函数吗

```js
    o.ptui_getst_CB.submitUrl = B({
      "uin": t,
      "pt_local_tk": "{{hash_clientkey}}"
    }))

```

这里就是做了一个简单的替换,然后加载对应地址

之前是

https://ssl.ptlogin2.qq.com/jump?clientuin=4548212&keyindex=9&pt_aid=549000912&daid=5&u1=https%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_local_tk={{hash_clientkey}}&pt_3rd_aid=0&ptopt=1&style=40&has_onekey=1

生成的地址是

https://ssl.ptlogin2.qq.com/jump?clientuin=4548212&keyindex=9&pt_aid=549000912&daid=5&u1=https%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_local_tk=687472173&pt_3rd_aid=0&ptopt=1&style=40&has_onekey=1

可以看出替换了个hash_clientkey

是使用a["default"].str.hash33对我们上一个地址获取的clientkey做计算的

直接拆函数

```js
function(t) {
                for (var e = 0, n = 0, o = t.length; n < o; ++n)
                  e += (e << 5) + t.charCodeAt(n);
                return 2147483647 & e
}
```

我们计算出刚才替换的地址后直接访问会得到

```js
ptui_qlogin_CB('0', 'https://ptlogin2.qzone.qq.com/check_sig?pttype=2&uin=4548212&service=xxxxx', '')
```

直接访问该地址就实现了快捷登录

那么至此,qq快捷登录就算分析完毕了

# 结语

撒花~

李恒道 发表于 2023-4-28 00:45:01

@王一之 我好像真的能打开潘多拉魔盒!让我们将上帝的物归给上帝,凯撒的物归于凯撒

王一之 发表于 2023-4-28 01:26:52

厉害了 localhost

tfsn20 发表于 2023-4-28 09:53:21

远在远方的风比远方更远,我把这远方的远归还草原

王一之 发表于 2023-4-28 10:21:09

没有这个需要,看不懂,呜呜呜

李恒道 发表于 2023-4-28 10:36:03

王一之 发表于 2023-4-28 10:21
没有这个需要,看不懂,呜呜呜

核心其实就一个问题...
1.任何可以跨域的代码都可以直接拿到网页版cookie做登录
并且很可能这个行为不报毒
2.qq几乎没有任何措施防范这个...

cxxjackie 发表于 2023-4-28 21:10:30

南山必胜客都敢招惹{:4_111:}

李恒道 发表于 2023-4-28 21:26:55

cxxjackie 发表于 2023-4-28 21:10
南山必胜客都敢招惹
最近突然来了两个灵感
一个是想做实时的邮件验证码提醒
第二个就是QQ空间的自动点赞
所以就决定尝试逆向一下
结果发现他没加密并且一点防护都没有
感觉完全放弃维护了一样
也是一脸懵逼...
还有一个问题就是
我用ScriptCat设置匿名模式返回cookie
需要自己管理cookie
但是没有找到什么特别好的cookie的合并和读取的库
不知道这个C大有没有研究

cxxjackie 发表于 2023-4-29 20:32:39

李恒道 发表于 2023-4-28 21:26
最近突然来了两个灵感
一个是想做实时的邮件验证码提醒
第二个就是QQ空间的自动点赞


没有,我都是自己写的,这个好像不太值得做成库,难度不大。

王一之 发表于 2023-4-29 22:13:38

李恒道 发表于 2023-4-28 21:26
最近突然来了两个灵感
一个是想做实时的邮件验证码提醒
第二个就是QQ空间的自动点赞


我不是推荐了几个么?
页: [1] 2 3
查看完整版本: QQ快捷登录协议分析