日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

【JS 逆向百例】复杂的登录过程,最新微博登录逆向

發(fā)布時間:2023/12/10 javascript 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【JS 逆向百例】复杂的登录过程,最新微博登录逆向 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

    • 聲明
    • 逆向目標(biāo)
    • 登錄流程
      • 1.預(yù)登陸
      • 2.獲取加密后的密碼
      • 3.獲取 token
      • 4.獲取加密后的賬號
      • 5.發(fā)送驗證碼
      • 6.校驗驗證碼
      • 7.訪問 redirect url
      • 8.訪問 crossdomain2 url
      • 9.通過 passport url 登錄
    • 加密密碼逆向
    • 完整代碼
      • 關(guān)鍵 JS 加密代碼架構(gòu)
      • Python 登錄關(guān)鍵代碼


聲明

本文章中所有內(nèi)容僅供學(xué)習(xí)交流,抓包內(nèi)容、敏感網(wǎng)址、數(shù)據(jù)接口均已做脫敏處理,嚴(yán)禁用于商業(yè)用途和非法用途,否則由此產(chǎn)生的一切后果均與作者無關(guān),若有侵權(quán),請聯(lián)系我立即刪除!

逆向目標(biāo)

本次的逆向目標(biāo)是WB的登錄,雖然登錄的加密參數(shù)沒有太多,但是登錄的流程稍微復(fù)雜一點,經(jīng)歷了很多次中轉(zhuǎn),細(xì)分下來大約要經(jīng)過九次處理才能成功登錄。

在登錄過程中遇到的加密參數(shù)只有一個,即密碼加密,加密后的密碼在獲取 token 的時候會用到,獲取 token 是一個 POST 請求,其 Form Data 里的 sp 值就是加密后的密碼,類似于:e23c5d62dbf9f8364005f331e487873c70d7ab0e8dd2057c3e66d1ae5d2837ef1dcf86......

登錄流程

首先來理清一下登錄流程,每一步特殊的參數(shù)進(jìn)都行了說明,沒有提及的參數(shù)表示是定值,直接復(fù)制即可。

大致流程如下:

  • 預(yù)登陸

  • 獲取加密密碼

  • 獲取 token

  • 獲取加密后的賬號

  • 發(fā)送驗證碼

  • 校驗驗證碼

  • 訪問 redirect url

  • 訪問 crossdomain2 url

  • 通過 passport url 登錄

  • 1.預(yù)登陸

    預(yù)登陸為 GET 請求,Query String Parameters 中主要包含兩個比較重要的參數(shù):su:用戶名經(jīng)過 base64 編碼得到,_: 13 位時間戳,返回的數(shù)據(jù)包含一個 JSON,可用正則提取出來,JSON 里面包含 retcode,servertime,pcid,nonce,pubkey,rsakv, exectime 七個參數(shù)值,其中大多數(shù)值都是后面的請求當(dāng)中要用到的,部分值是加密密碼要用到的,返回數(shù)據(jù)數(shù)示例:

    xxxxSSOController.preloginCallBack({"retcode": 0,"servertime": 1627461942,"pcid": "gz-1cd535198c0efe850b96944c7945e8fd514b","nonce": "GWBOCL","pubkey": "EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245......","rsakv": 1330428213,"exectime": 16 })

    2.獲取加密后的密碼

    密碼的加密使用的是 RSA 加密,可以通過 Python 或者 JS 來獲取加密后的密碼,JS 加密的逆向在后面拿出來單獨分析。

    3.獲取 token

    這個 token 值在后面的獲取加密手機號、發(fā)送驗證碼、校驗驗證碼等步驟中都會用到,獲取 token 值為 POST 請求,Query String Parameters 的值是固定的:client: ssologin.js(v1.4.19),Form Data 的值相對來說比較多,但是除了加密的密碼以外,其他參數(shù)其實都是可以在第1步預(yù)登陸返回的數(shù)據(jù)里找到,主要的參數(shù)如下:

    • su:用戶名經(jīng)過 base64 加密得到
    • servertime:通過第1步預(yù)登陸返回的 JSON 里面獲取
    • nonce:通過第1步預(yù)登陸返回的 JSON 里面獲取
    • rsakv:通過第1步預(yù)登陸返回的 JSON 里面獲取
    • sp:加密后的密碼
    • prelt:隨機值

    返回數(shù)據(jù)為 HTML 源碼,可以從里面提取 token 值,類似于:2NGFhARzFAFAIp_QwX70Npj8gw4lgj7RbCnByb3RlY3Rpb24.,如果返回的 token 不是這種,則說明賬號或者密碼錯誤。

    4.獲取加密后的賬號

    前面我們遇到的 su 是用戶名經(jīng)過 base64 加密得到,這里它對用戶名進(jìn)行了進(jìn)一步的加密處理,加密后的用戶名在發(fā)送驗證碼和校驗驗證碼的時候會用到,GET 請求,Query String Parameters 的參數(shù)也比較簡單,token 就是第3步獲取的 token 值,callback_url 是網(wǎng)站的主頁,返回數(shù)據(jù)是 HTML 源碼,可以使用 xpath 語法://input[@name='encrypt_mobile']/@value 來提取加密后的賬號,其值類似于:f2de0b5e333a,這里需要注意的是,即便是同一個賬號,每次加密的結(jié)果也是不一樣的。

    5.發(fā)送驗證碼

    發(fā)送驗證碼是一個 POST 請求,其參數(shù)也比較簡單,Query String Parameters 里的 token 是第3步獲取的 token,Form Data 里的 encrypt_mobile 是第4步獲取的加密后的賬號,返回的數(shù)據(jù)是驗證碼發(fā)送的狀態(tài),例如:{'retcode': 20000000, 'msg': 'succ', 'data': []}。

    6.校驗驗證碼

    校驗驗證碼是一個 POST 請求,其參數(shù)也非常簡單,Query String Parameters 里的 token 是第3步獲取的 token,Form Data 里的 encrypt_mobile 是第4步獲取的加密后的賬號,code 是第5步收到的驗證碼,返回數(shù)據(jù)是一個 JSON,retcode 和 msg 代表校驗的狀態(tài),redirect url 是校驗步驟完成后接著要訪問的頁面,在下一步中要用到,返回的數(shù)據(jù)示例:

    {"retcode": 20000000,"msg": "succ","data": {"redirect_url": "https://login.xxxx.com.cn/sso/login.php?entry=xxxxx&returntype=META&crossdomain=1&cdult=3&alt=ALT-NTcxNjMyMTA2OA==-1630292617-yf-78B1DDE6833847576B0DC4B77A6C77C4-1&savestate=30&url=https://xxxxx.com"} }

    7.訪問 redirect url

    這一步的請求接口其實就是第6步返回的 redirect url,GET 請求,類似于:https://login.xxxx.com.cn/sso/login.php?entry=xxxxx&returntype=META......

    返回的數(shù)據(jù)是 HTML 源碼,我們要從中提取 crossdomain2 的 URL,提取的結(jié)果類似于:https://login.xxxx.com.cn/crossdomain2.php?action=login&entry=xxxxx......,同樣的,這個 URL 也是接下來需要訪問的頁面。

    8.訪問 crossdomain2 url

    這一步的請求接口就是第7步提取的 crossdomain2 url,GET 請求,類似于:https://login.xxxx.com.cn/crossdomain2.php?action=login&entry=xxxxx......

    返回的數(shù)據(jù)同樣是 HTML 源碼,我們要從中提取真正的登錄的 URL,提取的結(jié)果類似于:https://passport.xxxxx.com/wbsso/login?ssosavestate=1661828618&url=https......,最后一步只需要訪問這個真正的登錄 URL 就能實現(xiàn)登錄操作了。

    9.通過 passport url 登錄

    這是最后一步,也是真正的登錄操作,GET 請求,請求接口就是第8步提取的 passport url,類似于:https://passport.xxxxx.com/wbsso/login?ssosavestate=1661828618&url=https......

    返回的數(shù)據(jù)包含了登錄結(jié)果、用戶 ID 和用戶名,類似于:

    ({"result":true,"userinfo":{"uniqueid":"5712321368","displayname":"tomb"}});

    自此,WB的完整登錄流程已完成,可以直接拿登錄成功后的 cookies 進(jìn)行其他操作了。

    加密密碼逆向

    在登錄流程中,第2步是獲取加密后的密碼,在登錄的第3步獲取 token 里,請求的 Query String Parameters 包含了一個加密參數(shù) sp,這個就是加密后的密碼,接下來我們對密碼的加密進(jìn)行逆向分析。

    直接全局搜索 sp 關(guān)鍵字,發(fā)現(xiàn)有很多值,這里我們又用到了前面講過的技巧,嘗試搜索 sp=、sp: 或者 var sp 等來縮小范圍,在本案例中,我們嘗試搜索 sp=,可以看到在 index.js 里面只有一個值,埋下斷點進(jìn)行調(diào)試,可以看到 sp 其實就是 b 的值:

    PS:搜索時要注意,不能在登錄成功后的頁面進(jìn)行搜索,此時資源已刷新,重新加載了,加密的 JS 文件已經(jīng)沒有了,需要在登錄界面輸入錯誤的賬號密碼來抓包、搜索、斷點。

    繼續(xù)往上追蹤這個 b 的值,關(guān)鍵代碼有個 if-else 語句,分別埋下斷點,經(jīng)過調(diào)試可以看到 b 的值在 if 下面生成:

    分析一下兩行關(guān)鍵代碼:

    f.setPublic(me.rsaPubkey, "10001"); b = f.encrypt([me.servertime, me.nonce].join("\t") + "\n" + b)

    me.rsaPubkey、me.servertime、me.nonce 都是第1步預(yù)登陸返回的數(shù)據(jù)。

    把鼠標(biāo)移到 f.setPublic 和 f.encrypt,可以看到分別是 br 和 bt 函數(shù):

    分別跟進(jìn)這兩個函數(shù),可以看到都在一個匿名函數(shù)下面:

    直接將整個匿名函數(shù)復(fù)制下來,去掉最外面的匿名函數(shù),進(jìn)行本地調(diào)試,調(diào)試過程中會提示 navigator 未定義,查看復(fù)制的源碼,里面用到了 navigator.appName 和 navigator.appVersion,直接定義即可,或者置空都行。

    navigator = {appName: "Netscape",appVersion: "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" }

    繼續(xù)調(diào)試會發(fā)現(xiàn)在 var c = this.doPublic(b); 提示對象不支持此屬性或方法,搜索 doPublic 發(fā)現(xiàn)有一句 bq.prototype.doPublic = bs;,這里直接將其改為 doPublic = bs; 即可。

    分析整個 RSA 加密邏輯,其實也可以通過 Python 來實現(xiàn),代碼示例(pubkey 需要補全):

    import rsa import binasciipre_parameter = {"retcode": 0,"servertime": 1627461942,"pcid": "gz-1cd535198c0efe850b96944c7945e8fd514b","nonce": "GWBOCL","pubkey": "EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245......","rsakv": 1330428213,"exectime": 16 }password = '12345678'public_key = rsa.PublicKey(int(pre_parameter['pubkey'], 16), int('10001', 16)) text = '%s\t%s\n%s' % (pre_parameter['servertime'], pre_parameter['nonce'], password) encrypted_str = rsa.encrypt(text.encode(), public_key) encrypted_password = binascii.b2a_hex(encrypted_str).decode()print(encrypted_password)

    完整代碼

    GitHub 關(guān)注 K 哥爬蟲,持續(xù)分享爬蟲相關(guān)代碼!歡迎 star !https://github.com/kgepachong/

    **以下只演示部分關(guān)鍵代碼,不能直接運行!**完整代碼倉庫地址:https://github.com/kgepachong/crawler

    關(guān)鍵 JS 加密代碼架構(gòu)

    navigator = {appName: "Netscape",appVersion: "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" }function bt(a) {}function bs(a) {}function br(a, b) {}// 此處省略 N 個函數(shù)bl.prototype.nextBytes = bk; doPublic = bs; bq.prototype.setPublic = br; bq.prototype.encrypt = bt; this.RSAKey = bqfunction getEncryptedPassword(me, b) {br(me.pubkey, "10001");b = bt([me.servertime, me.nonce].join("\t") + "\n" + b);return b }// 測試樣例 // var me = { // "retcode": 0, // "servertime": 1627283238, // "pcid": "gz-a9243276722ed6d4671f21310e2665c92ba4", // "nonce": "N0Y3SZ", // "pubkey": "EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245A87AC253062882729293E5506350508E7F9AA3BB77F4333231490F915F6D63C55FE2F08A49B353F444AD3993CACC02DB784ABBB8E42A9B1BBFFFB38BE18D78E87A0E41B9B8F73A928EE0CCEE1F6739884B9777E4FE9E88A1BBE495927AC4A799B3181D6442443", // "rsakv": "1330428213", // "exectime": 13 // } // var b = '12312312312' // 密碼 // console.log(getEncryptedPassword(me, b))

    Python 登錄關(guān)鍵代碼

    #!/usr/bin/env python3 # -*- coding: utf-8 -*-import re import json import time import base64 import binasciiimport rsa import execjs import requests from lxml import etree# 判斷某些請求是否成功的標(biāo)志 response_success_str = 'succ'pre_login_url = '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler' get_token_url = '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler' protection_url = '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler' send_code_url = '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler' confirm_url = '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler'headers = {'Host': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler','Referer': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler','sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } session = requests.session()def get_pre_parameter(username: str) -> dict:su = base64.b64encode(username.encode())time_now = str(int(time.time() * 1000))params = {'entry': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler','callback': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler','su': su,'rsakt': 'mod','checkpin': 1,'client': 'ssologin.js(v1.4.19)','_': time_now,}response = session.get(url=pre_login_url, params=params, headers=headers).textparameter_dict = json.loads(re.findall(r'\((.*)\)', response)[0])# print('1.【pre parameter】: %s' % parameter_dict)return parameter_dictdef get_encrypted_password(pre_parameter: dict, password: str) -> str:# 通過 JS 獲取加密后的密碼# with open('encrypt.js', 'r', encoding='utf-8') as f:# js = f.read()# encrypted_password = execjs.compile(js).call('getEncryptedPassword', pre_parameter, password)# # print('2.【encrypted password】: %s' % encrypted_password)# return encrypted_password# 通過 Python 的 rsa 模塊和 binascii 模塊獲取加密后的密碼public_key = rsa.PublicKey(int(pre_parameter['pubkey'], 16), int('10001', 16))text = '%s\t%s\n%s' % (pre_parameter['servertime'], pre_parameter['nonce'], password)encrypted_str = rsa.encrypt(text.encode(), public_key)encrypted_password = binascii.b2a_hex(encrypted_str).decode()# print('2.【encrypted password】: %s' % encrypted_password)return encrypted_passworddef get_token(encrypted_password: str, pre_parameter: dict, username: str) -> str:su = base64.b64encode(username.encode())data = {'entry': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler','gateway': 1,'from': '','savestate': 7,'qrcode_flag': False,'useticket': 1,'pagerefer': '','vsnf': 1,'su': su,'service': 'miniblog','servertime': pre_parameter['servertime'],'nonce': pre_parameter['nonce'],'pwencode': 'rsa2','rsakv': pre_parameter['rsakv'],'sp': encrypted_password,'sr': '1920*1080','encoding': 'UTF-8','prelt': 38,'url': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler','returntype': 'META'}response = session.post(url=get_token_url, headers=headers, data=data)# response.encoding = 'gbk'ajax_login_url = re.findall(r'replace\("(.*)"\)', response.text)[0]token = ajax_login_url.split('token%3D')[-1]if 'weibo' not in token:# print('3.【token】: %s' % token)return tokenelse:raise Exception('登錄失敗! 用戶名或者密碼錯誤!')def get_encrypted_mobile(token: str) -> str:params = {'token': token,'callback_url': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler'}response = session.get(url=protection_url, params=params, headers=headers)tree = etree.HTML(response.text)encrypted_mobile = tree.xpath("//input[@name='encrypt_mobile']/@value")[0]# print('4.【encrypted mobile】: %s' % encrypted_mobile)return encrypted_mobiledef send_code(token: str, encrypt_mobile: str) -> str:params = {'token': token}data = {'encrypt_mobile': encrypt_mobile}response = session.post(url=send_code_url, params=params, data=data, headers=headers).json()if response['msg'] == response_success_str:code = input('請輸入驗證碼: ')# print('5.【code】: %s' % code)return codeelse:# print('5.【failed to send verification code】: %s' % response)raise Exception('驗證碼發(fā)送失敗: %s' % response)def confirm_code(encrypted_mobile: str, code: str, token: str) -> str:params = {'token': token}data = {'encrypt_mobile': encrypted_mobile,'code': code}response = session.post(url=confirm_url, params=params, data=data, headers=headers).json()if response['msg'] == response_success_str:redirect_url = response['data']['redirect_url']# print('6.【redirect url】: %s' % redirect_url)return redirect_urlelse:# print('6.【驗證碼校驗失敗】: %s' % response)raise Exception('驗證碼校驗失敗: %s' % response)def get_cross_domain2_url(redirect_url: str) -> str:response = session.get(url=redirect_url, headers=headers).textcross_domain2_url = re.findall(r'replace\("(.*)"\)', response)[0]# print('7.【cross domain2 url】: %s' % cross_domain2_url)return cross_domain2_urldef get_passport_url(cross_domain2_url: str) -> str:response = session.get(url=cross_domain2_url, headers=headers).textpassport_url_str = re.findall(r'setCrossDomainUrlList\((.*)\)', response)[0]passport_url = json.loads(passport_url_str)['arrURL'][0]# print('8.【passport url】: %s' % passport_url)return passport_urldef login(passport_url: str) -> None:response = session.get(url=passport_url, headers=headers).textlogin_result = json.loads(response.replace('(', '').replace(');', ''))if login_result['result']:user_unique_id = login_result['userinfo']['uniqueid']user_display_name = login_result['userinfo']['displayname']print('登錄成功!用戶 ID:%s,用戶名:%s' % (user_unique_id, user_display_name))else:raise Exception('登錄失敗:%s' % login_result)def main():username = input('請輸入登錄賬號: ')password = input('請輸入登錄密碼: ')# 1.預(yù)登陸,獲取一個字典參數(shù),包含后面要用的 servertime、nonce、pubkey、rsakvpre_parameter = get_pre_parameter(username)# 2.通過 JS 或者 Python 獲取加密后的密碼encrypted_password = get_encrypted_password(pre_parameter, password)# 3.獲取 tokentoken = get_token(encrypted_password, pre_parameter, username)# 4.通過 protection url 獲取加密后的手機號encrypted_mobile = get_encrypted_mobile(token)# 5.發(fā)送手機驗證碼code = send_code(token, encrypted_mobile)# 6.校驗驗證碼,校驗成功則返回一個重定向的 URLredirect_url = confirm_code(encrypted_mobile, code, token)# 7.訪問重定向的 URL,提取 crossdomain2 URLcross_domain2_url = get_cross_domain2_url(redirect_url)# 8.訪問 crossdomain2 URL,提取 passport URLpassport_url = get_passport_url(cross_domain2_url)# 9.訪問 passport URL 進(jìn)行登錄操作login(passport_url)if __name__ == '__main__':main()

    總結(jié)

    以上是生活随笔為你收集整理的【JS 逆向百例】复杂的登录过程,最新微博登录逆向的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。