javascript
【JS 逆向百例】如何跟栈调试?某 e 网通 AES 加密分析
關(guān)注微信公眾號:K哥爬蟲,QQ交流群:808574309,持續(xù)分享爬蟲進階、JS/安卓逆向等技術(shù)干貨!
聲明
本文章中所有內(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):某 e 網(wǎng)通登錄接口
- 主頁:aHR0cHM6Ly93ZWIuZXd0MzYwLmNvbS9yZWdpc3Rlci8jL2xvZ2lu
- 接口:aHR0cHM6Ly9nYXRld2F5LmV3dDM2MC5jb20vYXBpL2F1dGhjZW50ZXIvdjIvb2F1dGgvbG9naW4vYWNjb3VudA==
- 逆向參數(shù):
- Request Headers:sign: 3976F10977FC65F9CB967AEF79E508BD
- Request Payload:password: "A7428361DEF118911783F446A129FFCE"
逆向過程
抓包分析
來到某 e 網(wǎng)通的登錄頁面,隨便輸入一個賬號密碼登陸,抓包定位到登錄接口為 aHR0cHM6Ly9nYXRld2F5LmV3dDM2MC5jb20vYXBpL2F1dGhjZW50ZXIvdjIvb2F1dGgvbG9naW4vYWNjb3VudA==,請求頭里,有一個 sign,Payload 里,密碼 password 被加密處理了。
參數(shù)逆向
sign
首先來看一下請求頭的 sign,嘗試直接搜索一下,發(fā)現(xiàn)并不是經(jīng)過某些請求返回的數(shù)據(jù),觀察一下其他請求,可以發(fā)現(xiàn)同樣有 sign,而且每次請求的值都不一樣:
由此可以初步判斷這個值應(yīng)該是通過 JS 生成的,全局搜索關(guān)鍵字 sign:,可以分別在 request.js、request.ts 兩個文件里面看到疑似 sign 賦值的地方,埋下斷點調(diào)試,成功斷下,原理也很簡單,時間戳加上一串固定的字符,經(jīng)過 MD5 加密后再轉(zhuǎn)大寫即可。
使用 Python 實現(xiàn):
import time import hashlibtimestamp = str(int(time.time() * 1000)) sign = hashlib.md5((timestamp + 'bdc739ff2dcf').encode(encoding='utf-8')).hexdigest().upper() print(sign)password
password 是明文密碼經(jīng)過加密后得到的值,如果嘗試直接去搜索的話,會發(fā)現(xiàn)出來的值非常非常多,要想找到準(zhǔn)確的值難度巨大:
可以看到這條請求是 XHR 請求,本次我們使用 XHR 斷點的方法來定位具體的加密位置,通過本次案例,我們來學(xué)習(xí)一下具體是如何跟進調(diào)用棧、如何通過上下文來定位具體的加密位置。
切換到 Network 選項卡,找到登陸請求,鼠標(biāo)移動到 Initiator 選項卡下的 JS 上,可以看到其調(diào)用棧,如果站點的加密方式比較簡單,沒有太多混淆的話,調(diào)用棧里面就可以看到 login、send、post、encrypt 等等之類的關(guān)鍵詞,這種情況下就可以直接點進去,比較容易找到加密的地方,但是大多數(shù)站點對于函數(shù)名、變量名都做了混淆,和本案例一樣,調(diào)用棧里面顯示的都是一些單個或者多個無規(guī)則的字母的函數(shù),無法直接定位,此時就需要我們從最后一個函數(shù)往前慢慢找。
點擊進入最后一個函數(shù),即 Y 函數(shù),它位于調(diào)用棧的最頂層,表示經(jīng)過此函數(shù)后,瀏覽器就會發(fā)送登錄的請求,密碼的加密過程已經(jīng)處理完畢。在此函數(shù)埋下斷點,可以在右側(cè)的 Call Stack 看到調(diào)用棧,從下到上,表示的是點擊登陸后,先后調(diào)用的函數(shù)的執(zhí)行過程:
想要找到具體的加密位置,我們就要依次往前找,挨個函數(shù)進行分析,例如往前定位到倒數(shù)第二個調(diào)用棧,即 o 函數(shù),可以看到傳進來的 params 參數(shù)里面就包含了已加密的密碼信息,這說明加密操作肯定在此函數(shù)之前:
根據(jù)這種思路,一步一步往下跟進調(diào)用棧,可以看到在 utils.ts 里面執(zhí)行了一個匿名函數(shù),其中調(diào)用了一個 passwordEncrypt 函數(shù),通過函數(shù)名就可以看出基本上就是密碼加密的函數(shù)了:
在此處埋下斷點進行調(diào)試,傳進來的是明文密碼,passwordEncrypt 實際上是調(diào)用的 encode.ts 中的 O 函數(shù):
跟進 O 函數(shù),引用了 crypto-js 加密模塊,很明顯的 AES 加密,本地改寫一下就行了。
本次的案列加密比較簡單,但是加密函數(shù)隱藏得比較好,需要耐心跟進調(diào)用棧,通過直接搜索的話,結(jié)果太多,是不太容易定位加密函數(shù)的,本次案例中跟進到一個函數(shù)后,可以很清楚的看到加密的地方,那么有的站點可能混淆得更加厲害,是看不出來有加密函數(shù)的,這種情況下就需要我們注意參數(shù)的變化情況,如果在這個調(diào)用棧看到的是加密后的參數(shù),在上一個調(diào)用棧里面看到的是明文的參數(shù),那么加密的操作必定在這兩個調(diào)用棧之間,埋下斷點,仔細分析即可。
完整代碼
GitHub 關(guān)注 K 哥爬蟲,持續(xù)分享爬蟲相關(guān)代碼!歡迎 star !https://github.com/kgepachong/
**以下只演示部分關(guān)鍵代碼,不能直接運行!**完整代碼倉庫地址:https://github.com/kgepachong/crawler/
JavaScript 加密代碼
CryptoJS = require("crypto-js")const key = CryptoJS.enc.Utf8.parse("20171109124536982017110912453698"); const iv = CryptoJS.enc.Utf8.parse('2017110912453698'); //十六位十六進制數(shù)作為密鑰偏移量function getEncryptedPassword(word) {let srcs = CryptoJS.enc.Utf8.parse(word);let encrypted = CryptoJS.AES.encrypt(srcs, key, {iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7});return encrypted.ciphertext.toString().toUpperCase(); }// 測試樣例 // console.log(getEncryptedPassword("123457"))Python 登錄代碼
#!/usr/bin/env python3 # -*- coding: utf-8 -*-import time import hashlibimport execjs import requestslogin_url = '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler' session = requests.session()def get_sign():timestamp = str(int(time.time()*1000))sign = hashlib.md5((timestamp + 'bdc739ff2dcf').encode(encoding='utf-8')).hexdigest().upper()return signdef get_encrypted_parameter(password):with open('ewt360_encrypt.js', 'r', encoding='utf-8') as f:ewt360_js = f.read()encrypted_password = execjs.compile(ewt360_js).call('getEncryptedPassword', password)return encrypted_passworddef login(sign, username, encrypted_password):headers = {'sign': sign,'timestamp': str(int(time.time()*1000)),'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'}data = {'autoLogin': True,'password': encrypted_password,'platform': 1,'userName': username}response = session.post(url=login_url, headers=headers, json=data)print(response.json())def main():username = input('請輸入登錄賬號: ')password = input('請輸入登錄密碼: ')sign = get_sign()encrypted_password = get_encrypted_parameter(password)login(sign, username, encrypted_password)if __name__ == '__main__':main()總結(jié)
以上是生活随笔為你收集整理的【JS 逆向百例】如何跟栈调试?某 e 网通 AES 加密分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 本期生肖排第八,三月阳春好风光打一生肖指
- 下一篇: 【JS 逆向百例】网洛者反爬练习平台第三