目标网址接口:aHR0cHM6Ly9kaWN0LnlvdWRhby5jb20vd2VidHJhbnNsYXRl
- 仅供学习交流使用,非商业用途,如有侵权,请联系删除!!!
- 仅供学习交流使用,非商业用途,如有侵权,请联系删除!!!
- 仅供学习交流使用,非商业用途,如有侵权,请联系删除!!!
调研接口
-
查看每次请求的参数发现,每次请求sign参数和mysticTime参数都会变
-
mysticTime参数不难看出是一个13位的时间戳
-
sign参数猜测是时间戳和一些其他参数组成的字符串进行hash之后的值
-
查看返回的响应是一堆字母,需要解密
- 为了测试自己还原的sign是不是可用,还是先解密响应数据
响应数据解密
- 一般来说数据解密都会解密为json数据,直接去
hook JSON.parse()方法
(function () {var my_parse = JSON.parse;JSON.parse = function (params) {console.log("HOOK parse", params);return my_parse(params);}
})();
-
果然发现解析的数据
-
打断点定位到这个位置发现解密函数
-
跟进参数发现是AES加密 128 cbc模式,现在只要知道key iv 就可以模拟了
-
经过跟进发现这里的key和iv是在原始的key上面又md5了之后获取了二进制数据转为了uint8数组来进行解密的
-
继续跟进发现原始的数据解密为了一个大的uint8数组
-
尝试自己用python进行base64解码一下,发现数组不一样,说明他用了自己解码base64的方式
import base64t1 = 'Z21kD9ZK1ke6ugku2ccWu-MeDWh3z252xRTQv-wZ6jddVo3tJLe7gIXz4PyxGl73nSfLAADyElSjjvrYdCvEP4pfohVVEX1DxoI0yhm36ysrEuPNKkODn7po6VcuUUdOhXRO9VoaHHPXgSaHRFizTx17FrMowUelZSlyO2Jp-9biXcOlcPxkntWQp1hPDqWu81kg8jzGxgjNOi75FsPNURfLQwSaoG83BqqTNs-LTrA1oUr9ozX7WYrui9n5voGo-P8tg3GMhKpjpC15FQRQZym6KbwDOTyTL8x87VIqwANWkuek5pPnzzlK6SxYY1I1le5EOpQnORyobm7rWr4gVp0cWI3W85cbXdMjaGSok8gQBF1rpqSF2c6CY-e5_Xihisj9hWT1VY472r7LxYbX8A2BkKHWr88pk_1Fwlk-wvn-Tx-heigVVSEFq1PRCzhB-JG4O6Zx_1YUZOSgrTHYAVrag2wsKExTRMZtxU4-7J3hXi8UYgNV-uLN0YvIRWZ0l6Vr-RAGBHu8UsmH2nHSCoanA6wHJbCv58RnYPws6OLsDAJWDnR0kp4Cr6Xm-P3zYVgXehfNyMBTewzDwbTXoSLK-HAIqZP-9T7MUxbN09aqa-CPS_eui99UqOhe780hIXNeSyHuTt5LY_PqhcLvPhkdmQch1RASrQBK4WYgEwiomPqHt_ap8DxDSOyhNsRFm8nFw1Ml1Tmr338WJPLYzUI51hqr85Tw0_9y_siScO098y26eSmBn58QZEjY5ip7IJiNIW93mLXx4Ftzg8LOgs4HRoBPuqu4PcAtXr652xE0Q30_roz2CnQ3Edp0HlDvo8KV7jbosXY_Sb4KWMwavSd-cebsVYKPq0ACaFj_iLXTV5zfQAIkjgJZzbY3N3pG_kfGGRw_0BTh7NeMeRmsuS0cMOgoE1GhQE2JaXH7q5X9oklIV1h60D8NaLUIHHZpjiWDML0cXYoNVQl8eQgxlO0PC129w3KSAGlZsaWbl-jEpap7rkNZsM9BhNcSKjOt8pBvQ3dQ2eDyMgJo28tNBA=='
a1 = base64.b64decode(t1)
print(list(a1))
- 发现是经过,r.toByteArray方法转为了uint8数组
-
那么只需要用python还原这个函数就可以了
-
h函数检测字符串长度之类 i数组是一个固定生成的值
-
python还原base64转为数组代码
因为i数组有很多空值,所以需要在python中以None替代,发现i数组为123个元素
def get_i():i = [None] * 123s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"for index, a in enumerate(s):i[ord(a)] = indexi[ord("-")] = 62i[ord("_")] = 63return i
def h(t):e = len(t)if e % 4 > 0:raise "Invalid string. Length must be a multiple of 4"try:n = t.index("=")except ValueError:n = -1if n == -1:n = er = 0 if n == e else 4 - n % 4return [n, r]def c(e, n):return int(3 * (e + n) / 4 - n)def base_64_2_bytes_array(t):# h函数r = h(t)s = r[0]a = r[1]# 用numpy创建一个全是0的uint8数组u = np.zeros(c(s, a), dtype='uint8')f = 0l = s - 4 if a > 0 else sn = 0# 获取i数组i = get_i()while n < l:e = i[ord(t[n])] << 18 | i[ord(t[n + 1])] << 12 | i[ord(t[n + 2])] << 6 | i[ord(t[n + 3])]u[f] = e >> 16 & 255f += 1u[f] = e >> 8 & 255f += 1u[f] = 255 & ef += 1n += 4if a == 2:e = i[ord(t[n])] << 2 | i[ord(t[n + 1])] >> 4u[f] = 255 & ef += 1elif a == 1:e = i[ord(t[n])] << 10 | i[ord(t[n + 1])] << 4 | i[ord(t[n + 2])] >> 2u[f] = e >> 8 & 255f += 1u[f] = 255 & ef += 1return u
-
处理key和iv
def get_md5(sb1: str):return hashlib.md5(sb1.encode()).digest() key = get_md5('ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl') iv = get_md5('ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4')
-
解密代码
aes_obj = AES.new(key=key, iv=iv, mode=AES.MODE_CBC) a1 = aes_obj.decrypt(base_64_2_bytes_array(sb1).tobytes()).decode() print(a1)
解密完之后发现还有padding,还不能进行json转换,加个unpad
aes_obj =AES.new(key=key, iv=iv, mode=AES.MODE_CBC) decrypt_str = aes_obj.decrypt(base_64_2_bytes_array(sb1).tobytes()) json_str = unpad(decrypt_str, AES.block_size, style='pkcs7').decode() json_data = json.loads(json_str) print(json_data)
sign参数逆向
- 直接从调用堆栈中第一行打断点
- 查看调用堆栈看sign参数在哪生成的
- 堆栈跟到这发现O函数生成的sign,继续跟值
t是个时间戳,sign为h函数生成
继续跟值就发现sign为字符串md5之后的十六进制字符串,多试几次之后发现只有时间戳的变化
Last
果然尝试请求之后大功告成 🐔🐔🐔🐔限单杀