速看:CryptoJS.base64 的不同之处,别再死扣源码了「附正确实现」

当我们在逆向分析 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 进制编码的不就可以了吗

  1. 在 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)
    
  2. 或者直接返回 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"));

参考

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值