<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    原文地址:http://drops.wooyun.org/tips/13556

                    0x00 概述


                    很多時候,我們需要模擬QQ自動登錄的場景,比如爬取QQ頁面的時候,我們需要登錄,當然,還有其它的需求就不方便說了。

                    比較簡單的帳號登錄,基本上都是發送一個請求包, 最多再偽造一下UserAgent,加一個驗證碼,就能搞定。

                    然而當我看到鵝廠的的登錄接口時,內心是崩潰的,加密的過程讓我有點驚慌失措。

                    我們訪問一下QQ的登錄頁面:

                    http://ui.ptlogin2.qq.com/cgi-bin/login?hide_title_bar=0&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=636014201&target=self&s_url=http%3A//www.qq.com/qq2012/loginSuccess.htm

                    通常會看到如下頁面

                    p1

                    簡單的分析一下這個登錄頁面,這里QQ支持3種登陸方式:

                    登錄頁面展示的邏輯如下:

                    p2

                    從自動化的角度來考慮,第一種方式直接排除,需要手機互動;第三種方式,需要有客戶端支持,在win下面也是不錯的方案;第二種方式最普遍,也是比較實用,本文重點講解這種登陸方式的自動化。

                    0x01 用戶名密碼登錄流程分析


                    要想實現模擬登錄,我們得先搞清楚登錄的流程。

                    所以,我們先來簡單看一下用戶名密碼登錄的流程。

                    PS: 個人習慣把QQ的這個登錄頁面叫做登錄組件。

                    0x02 整體流程


                    p3

                    流程說明

                    1.組件加載

                    組件加載會做一些準備工作,這里不做詳解,只講一個重要的點:

                    加載成功后會生成一個長度64的字符串簽名:login_sig,后續每一步都需要返回這個簽名做校驗。簽名的字符串通常如下:

                    #!bash
                    V0VRhNIHGyezVzO7YgH82MmYj78KF6csGHq3330UXWDa79ZSUPy6J84RwcBzbFaQ
                    

                    2.登錄檢測

                    簡單看了下,主要做了2件事情:一個是用戶名校驗,一個是登錄環境校驗。

                    校驗不通過的策略可能不同,彈圖片驗證碼是比較通用的策略;

                    校驗通過會返回一個JSON串,其中3個返回值比較重要,這里說明下:

                    1. 一個長度為4的校驗碼verifycode,驗證碼。校驗碼verifycode是以嘆號!開頭,后面是3位大寫字母,形式如下:

                      #!bash
                      !QWE
                      
                    2. 一個長度為32的16進制格式的鹽salt。 鹽salt,看了下,其實就是uin(qq號碼)的16進制,形式如下:

                      #!bash
                      \x00\x00\x00\x00\x6b\x68\x90\xfb
                      
                    3. 一個長度為112的session pt_verifysession_v1,校驗session。session pt_verifysession_v1,形式如下:

                      #!bash
                      69a55c643beecaf5580394c80e9a0f8e800d8c0f3cab6a95ba77e39703e80b83ba2bde15d54558120e782a26f815a3ff97fdfb46ae92db6d
                      

                    3.登錄

                    上述流程正常后,就進入了登錄。這里主要是對用戶的密碼進行特定加密,然后和前面兩步獲取的必要參數一同提交登錄,進行帳號和密碼校驗。

                    登錄成功會返回一個回調URL和植入認證cookie superkey。

                    這里補充說明下:

                    QQ的密碼的處理流程比較復雜,關鍵是,除了一些標準密碼處理方法(MD5,SALT ,RSA),還有TX自帶的TEA算法;

                    當然,在登錄的JavaScript代碼里面都有具體實現,感興趣的同學可以研究下;

                    整個流程還是蠻有意思的,后續有機會可以給大家分享一下如何自己實現TX的密碼加密流程:)

                    0x03 自動登錄實現


                    自動登錄實現的幾種方案

                    通過上面的流程,我們可以看到,自動登錄實現的難點在于加密的密碼如何獲取,這里提供幾種登錄方案:

                    具體實現

                    所以我們選第三種方案,不用深入具體的密碼加密流程和算法,同時實現成本也比較低。

                    下面我們用python進行一個簡單的登錄實現:

                    我們直接使用V8引擎,調用JavaScript中的Encryption方法進行密碼加密是非常簡單的:

                    #!python
                    def tx_pwd_encode_by_js(self, pwd, salt, verifycode):
                        """
                        調用V8引擎,直接執行TX的登陸JS中的加密方法,不用自己實現其中算法。
                        """
                        # pwd, salt, verifycode, undefined
                        with PyV8.JSContext() as ctxt:
                            with open("qq.login.encrypt.js") as jsfile:
                                ctxt.eval(jsfile.read())
                                encrypt_pwd = ctxt.eval("window.$pt.Encryption.getEncryption('%s', '%s', '%s', undefined)"
                                                 %(pwd, salt, verifycode) )
                                return encrypt_pwd
                    

                    其他的就是體力活了,按照登陸的流程一步一步來,參考如下:

                    首先,我們第一步先加載組件,獲取簽名,參考代碼:

                    #!python
                    def get_signature(self):
                        """
                        step 1, load web login iframe and get a login signature
                        """
                        params = {
                            'no_verifyimg': 1,
                            "appid": self.appid,
                            "s_url": self.urlSuccess,
                        }
                        params = urllib.urlencode(params)
                        url = "%s?%s" %(self.urlRaw, params)
                        r = self.session.get(url)
                        if 200 != r.status_code:
                            error_msg = "[Get signature error] %s %s" %(r.status_code, url)
                            return [False, error_msg]
                        else:
                            self.login_sig = self.session.cookies['pt_login_sig']
                            return [True, ""]
                    

                    獲取了login_sig后,我們進行第二步,進行登錄檢測:

                    #!python
                    def check_login(self):
                        '''
                        step 2: get verifycode and pt_verifysession_v1.
                        TX will check username and the login's environment is safe
                          '''
                        params = {
                            "uin": self.uin,
                            "appid": self.appid,
                            "pt_tea": 1,
                            "pt_vcode": 1,
                            "js_ver": 10151,
                            "js_type": 1,
                            "login_sig": self.login_sig,
                            "u1": self.urlSuccess,
                        }
                        params = urllib.urlencode(params)
                        url = "%s?%s" %(self.urlCheck, params)
                        r = self.session.get(url)
                        if 200 != r.status_code:
                            error_msg = "[Get verifycode error] %s %s" %(r.status_code, url)
                            return [False, error_msg]
                        else:
                            v = re.findall('\'(.*?)\'', r.text)
                            self.check_code = v[0]
                            if self.check_code != '0':
                                error_msg = "[Verifycode not 0] %s %s" %(self.check_code, url)
                                return [False, error_msg]
                            self.verifycode = v[1]
                            self.salt = v[2]
                            self.pt_verifysession_v1 = v[3]
                            return [True, ""]
                    

                    檢測成功后,我們就可以進行直接登陸,登陸流程代碼參考如下:

                    #!python
                    def login(self):
                        '''
                        step 3: login and get cookie.
                        TX will check encrypt(password)
                            '''
                        encrypt_pwd  =  self.tx_pwd_encode_by_js(self.pwd, self.salt, self.verifycode)
                    
                        if not self.pt_verifysession_v1:
                            self.pt_verifysession_v1 = self.session.cookies['ptvfsession']
                        params = {
                            'u': self.uin,
                            'verifycode': self.verifycode,
                            'pt_vcode_v1': 0,
                            'pt_verifysession_v1': self.pt_verifysession_v1,
                            'p': encrypt_pwd,
                            'pt_randsalt': 0,
                            'u1': self.urlSuccess,
                            'ptredirect': 0,
                            'h': 1,
                            't': 1,
                            'g': 1,
                            'from_ui': 1,
                            'ptlang': 2052,
                            'action': self.action,
                            'js_ver': 10143,
                            'js_type': 1,
                            'aid': self.appid,
                            'daid': 5,
                            'login_sig': self.login_sig,
                        }
                        params = urllib.urlencode(params)
                        url = "%s?%s" %(self.urlLogin, params)
                        r = self.session.get(url)
                        if 200 != r.status_code:
                            error_msg = "[Login error] %s %s" %(r.status_code, url)
                            return [False, error_msg]
                        else:
                            v = re.findall('\'(.*?)\'', r.text)
                            if v[0] != '0':
                                error_msg = "[Login Faild] %s %s" %(url, v[4])
                                return [False, error_msg]
                            self.nick = v[5]
                            return [True, ""]
                    

                    show me the code代碼傳送門:
                    https://github.com/LeoHuang2015/qqloginjs

                    0x04 總結


                    通過這種方式,只需要使用JS引擎,調用JS的加密方法即可生成加密的密碼,不需要深入研究TX密碼加密的流程和算法,比較簡單方便。

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频