- 问题现象
- 分析
- 解决
- 参考
当我们在逆向分析 JS 代码时,常见的一个库就是 CryptoJS
,它实现了众多算法,可以很方便的对数据进行编码,加密。但是它的 Base64 却与正常的 Base64 有一些不同,本文以一个实际案例,以做说明。
调试 js 过程中,发现了如下代码:
se.MD5(JSON.stringify(e.data)).toString(se.enc.Base64) : ""
经过调试分析,确认采用了 CryptoJS,代码很好理解,转换伪代码就是 Base64(MD5(data))
,使用 Python 可以很方便实现这个步骤:
data = '{"username":"admin","password":"123456"}'
def md5(data):
m = hashlib.md5()
m.update(data.encode('utf-8'))
return m.hexdigest()
result = base64.b64encode(md5(data).encode())
print(result)
但是最终的结果却不同:
# CryptoJS 方案: ajLsAwT3NLtxEp+rUwIY8A==
# Python 方案: ODNhMTJmZGYwYTI1NTIxOGIwNDc4YWZjM2U2YmY3M2M=
分析
由于最终结果仅通过 md5 以及 base64 编码得来,猜测可能是 CryptoJS 内容对这两种算法进行了魔改,我们便可以将目标锁定在这两种算法上。
因此,首先,我们确认一下 CryptoJS MD5 的结果是否与 Python 一致:
// CryptoJS MD5
se.MD5(JSON.stringify(e.data)).toString(); // 6a32ec0304f734bb71129fab530218f0
// Python MD5
print(md5(data)) // 6a32ec0304f734bb71129fab530218f0
结果一致,那么大概率问题是发生了 CryptoJS 的 Base64 上边,经过一顿查询资料,最后发现是 加密结果传递类型导致的问题。
在 CryptoJS 中,采用 WordArray 类型来传递数据。在 控制台打 se.MD5(JSON.stringify(e.data))
,你就会得到一个 WordArray 对象:
当你调用 WordArray 的 toString()
方法时,你会得到该二进制对象的 16 进制编码的字符串。
toString: function (encoder) {
return (encoder || Hex).stringify(this);
}
而当你执行 toString(CryptoJS.enc.Base64)
会将该 16 进制编码的字符串 编码为 Base64,而我们在 Python 中或者在一些网页在线工具进行 Base64 编码时,会默认把这段字符串视为 UTF8 编码格式,这也是问题所在!
# 可以看到这里我们的 MD5 的结果 encode 为 utf8(无参数默认为 utf8 编码)
# 而 CryptoJS 中会把 MD5 的结果视为 16 进制编码字符串
result = base64.b64encode(md5(data).encode())
解决
要解决这个问题,也非常简单,我们把 MD5 的结果结果视为 16 进制编码的不就可以了吗
-
在 Python3 中我们可以使用
bytes.fromhex()
方法def md5(data): m = hashlib.md5() m.update(data.encode('utf-8')) return m.hexdigest() result = base64.b64encode(bytes.fromhex(md5(data))) print(result)
-
或者直接返回 md5 编码后的 bytes 数据
def md5(data): m = hashlib.md5() m.update(data.encode('utf-8')) return m.digest() result = base64.b64encode(md5(data)) print(result)
而如果你是一名前端程序员,那么如何让 CryptoJS 中的 Base64 返回 UTF8 格式编码后的结果呢?毕竟这样更符合直觉嘛!下面给出部分示例:
// md5 -> utf8 -> base64
CryptoJS.enc.Utf8.parse(CryptoJS.MD5("123456")).toString(CryptoJS.enc.Base64);
// str -> utf8 -> base64
CryptoJS.enc.Utf8.parse("123456").toString(CryptoJS.enc.Base64);
CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse("123456"));
参考
-
CryptoJS.enc.Base64.stringify() 和正常的Base64加密之间的区别
https://blog.csdn.net/qq_41385602/article/details/122982911
-
Difference between CryptoJS.enc.Base64.stringify() and normal Base64 encryption
https://www.yuanmacha.com/1325533793.html
-
python3 字符串 hex 相互转换
https://blog.csdn.net/whatday/article/details/107769032
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)