上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
123下一页
返回列表 发新帖

QQ快捷登录协议分析

[复制链接]
  • TA的每日心情
    慵懒
    2024-10-28 07:07
  • 签到天数: 193 天

    [LV.7]常住居民III

    712

    主题

    5960

    回帖

    6759

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6759

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2023-4-28 00:42:23 | 显示全部楼层 | 阅读模式

    抓包

    首先进入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应该是固定的

    我们主攻rpt_local_tk

    全局搜一下

    找到了

        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 + ":[port]/" + t + "&r=" + Math.random() + "&pt_local_tk=" + k["default"].cookie.get("pt_local_token"),
            dt(t, r, e, window[n], 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 = [4300, 4302, 4304, 4306, 4308],
    E = [4301, 4303, 4305, 4307, 4309], 

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

    分析点击登录

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

    pt.qlogin.imgClick

        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吧

        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

    再作为参数

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

    猜测一下之后继续往里看

        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 + ":[port]/" + t + "&r=" + Math.random() + "&pt_local_tk=" + k["default"].cookie.get("pt_local_token"),
            dt(t, r, e, window[n], o, i)) : c.logger.warn("无法设置cookie,无法使用快速登录")
        }

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

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

     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 + ":[port]/" + t + "&r=" + Math.random() + "&pt_local_tk=" + k["default"].cookie.get("pt_local_token"),
            dt(t, r, e, window[n], o, i))

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

    [4301, 4303, 4305, 4307, 4309]

    如果不是就是

    [4300, 4302, 4304, 4306, 4308]

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

    然后拼接出来一个t

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

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

    继续往里看dt

        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[n]的函数

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

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

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

    于是断到了

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

    中的

    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)

        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))
        }

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

        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做计算的

    直接拆函数

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

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

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

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

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

    结语

    撒花~

    已有1人评分好评 油猫币 理由
    syy + 1 + 1 很给力!

    查看全部评分 总评分:好评 +1  油猫币 +1 

    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
  • TA的每日心情
    慵懒
    2024-10-28 07:07
  • 签到天数: 193 天

    [LV.7]常住居民III

    712

    主题

    5960

    回帖

    6759

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6759

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2023-4-28 00:45:01 | 显示全部楼层
    @王一之 我好像真的能打开潘多拉魔盒!让我们将上帝的物归给上帝,凯撒的物归于凯撒
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    8 小时前
  • 签到天数: 213 天

    [LV.7]常住居民III

    305

    主题

    4189

    回帖

    4056

    积分

    管理员

    积分
    4056

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2023-4-28 01:26:52 | 显示全部楼层
    厉害了 localhost
    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    14 小时前
  • 签到天数: 765 天

    [LV.10]以坛为家III

    46

    主题

    197

    回帖

    849

    积分

    荣誉开发者

    积分
    849

    荣誉开发者油中2周年生态建设者

    发表于 2023-4-28 09:53:21 | 显示全部楼层
    远在远方的风比远方更远,我把这远方的远归还草原
    回复

    使用道具 举报

  • TA的每日心情
    开心
    8 小时前
  • 签到天数: 213 天

    [LV.7]常住居民III

    305

    主题

    4189

    回帖

    4056

    积分

    管理员

    积分
    4056

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2023-4-28 10:21:09 | 显示全部楼层
    没有这个需要,看不懂,呜呜呜
    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2024-10-28 07:07
  • 签到天数: 193 天

    [LV.7]常住居民III

    712

    主题

    5960

    回帖

    6759

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6759

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2023-4-28 10:36:03 | 显示全部楼层
    王一之 发表于 2023-4-28 10:21
    没有这个需要,看不懂,呜呜呜

    核心其实就一个问题...
    1.任何可以跨域的代码都可以直接拿到网页版cookie做登录
    并且很可能这个行为不报毒
    2.qq几乎没有任何措施防范这个...
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    881

    回帖

    1379

    积分

    荣誉开发者

    积分
    1379

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2023-4-28 21:10:30 | 显示全部楼层
    南山必胜客都敢招惹
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2024-10-28 07:07
  • 签到天数: 193 天

    [LV.7]常住居民III

    712

    主题

    5960

    回帖

    6759

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6759

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2023-4-28 21:26:55 | 显示全部楼层
    cxxjackie 发表于 2023-4-28 21:10
    南山必胜客都敢招惹

    最近突然来了两个灵感
    一个是想做实时的邮件验证码提醒
    第二个就是QQ空间的自动点赞
    所以就决定尝试逆向一下
    结果发现他没加密并且一点防护都没有
    感觉完全放弃维护了一样
    也是一脸懵逼...
    还有一个问题就是
    我用ScriptCat设置匿名模式返回cookie
    需要自己管理cookie
    但是没有找到什么特别好的cookie的合并和读取的库
    不知道这个C大有没有研究
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    881

    回帖

    1379

    积分

    荣誉开发者

    积分
    1379

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

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

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

    使用道具 举报

  • TA的每日心情
    开心
    8 小时前
  • 签到天数: 213 天

    [LV.7]常住居民III

    305

    主题

    4189

    回帖

    4056

    积分

    管理员

    积分
    4056

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

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

    我不是推荐了几个么?
    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。
    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表