已遷移平臺(tái):segmentfault洽沟,搜索 erma0
換平臺(tái)了,簡書發(fā)什么都鎖定裆操,廣告一堆,趁早倒閉吧踪区。
JavaScript逆向練習(xí)1
0x01 目標(biāo)網(wǎng)址
0x02 定位JS
1. 隨便輸入賬號(hào)密碼驗(yàn)證碼,點(diǎn)擊登錄静尼,查看提交的參數(shù)
可以看到传泊,發(fā)出了兩個(gè)請(qǐng)求,第一個(gè)是獲取key眷细,第二個(gè)是登錄,在登錄包里有加密過 的password參數(shù)薪鹦。
2. Ctrl+Shift+F調(diào)出搜索面板惯豆,搜索jxy_parameter
,有三條結(jié)果楷兽,依此打開查看华临,發(fā)現(xiàn)第三個(gè)才是需要的芯杀。直接在這里下一個(gè)斷點(diǎn)雅潭。
3. 重新輸入賬號(hào)密碼驗(yàn)證碼,點(diǎn)擊登錄扶供,JS被斷了下來。F11跟進(jìn)太援,或者鼠標(biāo)懸停在斷點(diǎn)處函數(shù)名上,點(diǎn)擊彈出的內(nèi)容提岔,也能跳轉(zhuǎn)進(jìn)去。
這里可以看到e
就是之前的第一個(gè)請(qǐng)求包的返回內(nèi)容碱蒙,而n
就是待加密的明文密碼夯巷。加密函數(shù)的調(diào)用核心就是在這里赛惩。
4. 同上趁餐,F(xiàn)11跟進(jìn),進(jìn)入一個(gè)JSEncrypt.min.js
澎怒,傳入?yún)?shù)為第一步返回的hash + 明文密碼
這里一看到JSEncrypt,再看一下上下文星瘾,可以確認(rèn)是AES加密(可以百度一下JSEncrypt),那就直接把整個(gè)JSEncrypt.min.js
拿走惧辈,再改寫一個(gè)調(diào)用的函數(shù)就行了。
0x03 改寫JS
1. 仿照?qǐng)D3的位置盒齿,寫一個(gè)調(diào)用函數(shù)困食。
function getrsa(pKey, password) { // 也可以把key寫死,這個(gè)公鑰是不會(huì)變的
var encrypt = new JSEncrypt();
encrypt.setPublicKey(pKey);
var encrypted = encrypt.encrypt(password);
return encrypted
}
此時(shí)在多數(shù)情況下就能正常運(yùn)行了硕盹。
2. 練習(xí)在Python中調(diào)用時(shí)發(fā)現(xiàn)叨咖,這樣會(huì)報(bào)錯(cuò)JSEncrypt is not defined
瘩例,一下整懵了甸各,嘗試直接賦值一個(gè)空對(duì)象,結(jié)果不行趣倾,仔細(xì)看了一下代碼,發(fā)現(xiàn)第一部分是在判斷客戶端儒恋。
! function(t, e) {
"function" == typeof define && define.amd ? define(["exports"], e) : e("object" == typeof exports && "string" != typeof exports.nodeName ? module.exports : t)
}(this, function(t) {**函數(shù)主體**});
瀏覽器中調(diào)試發(fā)現(xiàn)"function" == typeof define && define.amd
為true
,那就直接把函數(shù)給改一下,把函數(shù)主體暴露出來瘟仿。
var JSEncryptExports = {};
(function(t) {
**函數(shù)主體**
})(JSEncryptExports);
var JSEncrypt = JSEncryptExports.JSEncrypt;
此時(shí)JSEncrypt
就是一個(gè)構(gòu)造函數(shù)了,接著把上面5中的代碼貼在下面劳较,就可以在Python中運(yùn)行了。
0x04 Python代碼
一開始嘗試了js2py观蜗,報(bào)錯(cuò),可能是js代碼比較多墓捻,所以又直接改用execjs了。
PS. 其實(shí)可以嘗試直接調(diào)用Python的AES加密庫砖第,如果這個(gè)JS沒改過,結(jié)果應(yīng)該是能用的(也就是另一個(gè)思路:JS功能可以通過所使用的語言直接實(shí)現(xiàn))放吩。
# -*- encoding: utf-8 -*-
'''
@File : 0x01-juxiangyou.com.py
@Time : 2019/11/06 10:42:43
@Author : 獨(dú)孤孤獨(dú)嘟咕嚕犢子
@Version : 1.0
@Link : http://www.reibang.com/u/6a4c6ef97be7
@Desc : 聚享游www.juxiangyou.com 登錄例子
'''
# start
import execjs
import requests
import time
import json
HEADERS = {
'User-Agent':
'Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; Mi Note 2 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.1.1'
}
s = requests.Session()
s.headers.update(HEADERS)
imageURL = 'http://www.juxiangyou.com/verify?v={}000'.format(int(time.time()))
keyURL = 'http://www.juxiangyou.com/login/getkey'
loginURL = 'http://www.juxiangyou.com/login/auth'
# 下載驗(yàn)證碼
image = s.get(imageURL).content
with open('image.png', 'wb') as f:
f.write(image)
# 獲取公鑰
publicKey = s.post(keyURL).json()
jskey = publicKey['key']
jshash = publicKey['hash']
# 登錄
username = 'ermao6@qq.com'
password = '******'
varifyCode = input('請(qǐng)輸入驗(yàn)證碼(當(dāng)前目錄下image.png):')
# varifyCode = '1111'
timestamp = int(time.time() * 1000)
with open('js/0x01-juxiangyou.com.js') as f: # 坑0x01 相對(duì)路徑前面不帶/羽杰,帶/不報(bào)錯(cuò)但讀不出數(shù)據(jù)
jscode = f.read()
ctx = execjs.compile(jscode) # execjs載入js代碼
xsign = ctx.call('get', timestamp) # 坑0x02 這里傳入的時(shí)間戳為整數(shù)型(老版本驗(yàn)證的參數(shù)到推,現(xiàn)在不計(jì)算也行)
# xsign = ctx.eval('get({})'.format(timestamp)) # 通過eval調(diào)用js代碼里的函數(shù)
enPass = ctx.call('getrsa', jskey, jshash + password) # 通過call調(diào)用js代碼里的函數(shù)
data = {
'jxy_parameter': # 坑0x03 提交json格式參數(shù)需要轉(zhuǎn)成json字符串,否則請(qǐng)求失敗
json.dumps({
"c": "index",
"fun": "login",
"account": username,
"password": enPass,
"verificat_code": varifyCode,
"is_auto": True
}),
'timestamp':
timestamp
}
result = s.post(loginURL, data=data).json()
print(result) # {'code': 10000} 登錄成功