
简单数据加密
更新: 2025/2/24 字数: 0 字 时长: 0 分钟
DES加密
难度:简单
页面信息的详情URL中存在 projectId
、projectInfo
加密参数:
打开开发者工具,进行抓包,响应中发现 projectId
参数,但是一个未加密的数值:
我们全局收索 projectId
关键词,在可疑的位置打上断点:
提醒
当关键词出现的地方很多时,我们可以使用”关键词+冒号“、”关键词+等号“、”关键词+空格+等号“的形式进行搜索,也就是说通过 JS 代码给的自定义变量赋值的形式来缩小查找关键词的范围。
我们点击标题,触发事件,断点断住,控制台打印相关信息,发现 e.projectId
的数值就是该标题上面响应中的 projectId
参数,而且这里的 projectId
、projectInfo
恰好对应URL中的两个加密参数:
英语稍微好一点的,我们还可以看到函数的名称 encryptJumpPage
即”加密跳转页“,侧面猜测该函数就是加密函数,我们选中该函数,点击地址进行跳转:
我们在跳转过来后的位置打上断点再次调试,通过控制台输出信息可以看到,是这里的 c
函数加密了 projectId
参数:
同样的,我们选中 c
函数点击地址进行跳转:
跳转过来信息就很多了,可以看到 c
函数是一个 DES
加密函数,加密模式为 CBC
模式,而密钥 o.keyHex
和偏移量 o.ivHex
都可以在上面找到:
我们输出密钥 o.keyHex
和偏移量 o.ivHex
发现都不是一个字符串,而是一个类似数组的对象,原因就是它们都使用了 s.a.enc.Utf8.parse()
方法,将 UTF-8 编码的字符串转换为表示的字节数组。这时我们就可以使用相同路径下的另一个 s.a.enc.Utf8.stringify()
方法将字节数组转换回 UTF-8 编码的字符串。转换后可以看到密钥 o.keyHex
和偏移量 o.ivHex
的都为 54367819
值:
我们通过代码进行验证,可以看数值一样,说明 URL 网址使用的是标准的 DES 加密:
import binascii
# 导入DES加密算法
from Crypto.Cipher import DES
# 从Crypto.Cipher模块中导入pad填充
from Crypto.Util.Padding import pad
# 加密函数
def DES_Encrypt(data, key, iv):
# 设置CBC模式
des = DES.new(key.encode(), DES.MODE_CBC, iv.encode())
# 设置填充方式为pkcs7填充
pad_pkcs7 = pad(data.encode(), DES.block_size, style='pkcs7')
# 加密补位后的明文
encrypt_data = des.encrypt(pad_pkcs7)
# 返回bytes对象(密文)
return encrypt_data
# 密匙"54367819",偏移量"54367819"
key = "54367819"
iv = "54367819"
# 加密projectId参数
projectId = "630"
encrypt_data = DES_Encrypt(projectId, key, iv)
hex_en_data = binascii.b2a_hex(encrypt_data).decode()
print(hex_en_data) # 输出:b345c271921d3e41
# 加密projectInfo参数
projectInfo = "ZBGG"
encrypt_data = DES_Encrypt(projectInfo, key, iv)
hex_en_data = binascii.b2a_hex(encrypt_data).decode()
print(hex_en_data) # 输出:ff15d186c4d5fa7a
AES加密
难度:简单
首先我们需要判断数据是静态数据还是动态数据,查看静态页面的源代码,发现源代码中并不包含我们需要数据,也就是说网站的使用的是动态数据。
打开开发者工具,刷新页面进行抓包,定位接受动态数据的 XHR 请求,可以看到 POST 提交的参数和 Response 响应的内容都不具有可读性,可以断定数据进行了加密,但加密方式暂不确定。
这里我们先查看 JS 一栏,发现有一个名称很熟悉的 aes.js
文件,查看其内容就是 JS 编写的 AES 对称加密算法:
现在我们要确定网站是否使用了AES加密以及加密的模式,在 utils.js
文件中,我们看到了 AES.encrypt
说明网站使用了AES加密,当中 CryptoJS.mode.ECB
确定了加密模式为ECB模式, CryptoJS.pad.Pkcs7
确定了填充方式是Pkcs7填充。由于AES是对称加密,其加密和解密使用是同一密匙,自然而然就领会 aesKey
就是存储密匙的变量:
选中 utils.js
文件右键选择 Open in Sources panel
选项,在浏览器的 Sources
选项卡中打开该文件:
我们在上面所定位加密的位置处打上断点,刷新页面,断点被断住,可以看到右侧边栏加密参数为:白银市宇力检测有限公司
,加密密匙为:YWJjZGVmZ2hpamts
Python库解密
**到这里,我们就已经拿到了加密密匙,结合前面讲的数据加密算法中的 AES 解密函数,大概率破解了该 JS 加密。为什么说大概率呢?因为我们现在还不清楚,网站使用的 AES 加密是否是“标准 AES”“,若网站的技术人员修改了 AES 加密算法中的一些参数,变成“魔改 AES”,我们还得去一步步跟踪流程。**接下来,我们使用 Python 的 Crypto
库中自带的“标准 AES”来验证看是否能成功解密:可以看到下面的输出中,密文是成功解密的,说明网站使用的是“标准AES“进行加密的。
import base64
from Crypto.Cipher import AES
# 加密后的参数
str1 = "Gs/nl960sHJcPrPr83z9MRMC7LBr/GY/K8gmbW68iFdjLCYTehkRYafNPbLvsQ8v"
# 加密后的结果
str2 = "+LZgDXrUvn52pmaRCuHYFlNTvfhGg9p7waDQjjW54Kf334rhYVaS7eN/5USlS6d9NKDpcBGl0GzPqlLY6qb70TB90VLhfFhW6zT3fWTp/dZTQbO/ZNK3ui57bLi7K4uyMmE3xzM1bF+gO7de4rIzH93dGG3/DsIXgaEwK5qn4r6gTW4oyz6LXKKUSOubFXeCnqSVRGnQorAs/9HLm3R6o9Uasfjv5LA08vJ5fRuvsY3F3vXIxXpPyY7e10hnYCMGAo1fvm1I86q0U2BBxRkQDcgRjlEcBXmG9xbocqX8m3HCPZCVPs82sAE2yUCUDpOZ4KVCUtzkpSQr0I/Bt2tJwyG/cgf5aVKOBUJdCX3jMS/t4TRvE9SZJTUMxdjwZKTd0EfyQjdQAGCo6K+Jxil8wjYhhzsDsWu3Aga8LC1+j2WpkzjBDrJ4jMsgCEdHuNXr8KpOmuZvQD/JZKZmqceZd4HpEXigmlog86hfNG9unUSvdCnkittVLYZz9OaWV1Tq1Loa0O4T/jrVQhcmpJM/dA8qkPRS8m1RjWXgpeGDQ1aDT48082kJ3QIm3RHqGfV4e0e0wpdWDCK2TmbcOM2PT2WXOvWOPXoeI2KRpEVwJaOJE2T0dZe7Y7BYHsootmampwZxnObjiqWJiqU7rA6ejLDFkFCtKrodymMKm7gf7Ee2+NqoQTEtBa8y348NzPhK9sgz6rGS6Q5d8BaX8rcWDH0LTMvi28tMgEr7OpyURucomYTeLjIqDmGsLiLwezbWxaB9QvAvHvg6Wavd2Z4IBL0WVl3YJzrHjxmy4VLCJHOzheKeLebOYTpqf5plfIx2ZstWlVi3OPFnNgnmGkTw3trYQeOIIUzGU+TkYKD8tzWQjGAmnM77bNieLHZus+TiGs5+MvGKWJnerL0SpK5mye7jX1wqJPIu0aPklZZ0B+LZ7dazpQAlbYTIH1EczHsELHwGY4m65XwMcztn27y7x9ZryvsLcmIC4bVENmeREWalgedTFZa+zEQ/yoCPCUrVyFCdlaeAz7JidLFSZulycdZp8o+O568We+83a4B+lMrDe4jLnuK0xXdPyyNgdlmvNYJH1Gbds8Iq8HKRiSZ7XA=="
# 解密函数
def AES_Decrypt(data, key):
cipher = AES.new(key.encode('UTF-8'), AES.MODE_ECB)
text = base64.b64decode(data.encode('utf8'))
result = cipher.decrypt(text)
detext = result.decode('UTF-8')
return detext[0:len(detext)-ord(detext[-1])]
print('解密后的参数:'+AES_Decrypt(str1, 'YWJjZGVmZ2hpamts'))
print('解密后的结果:'+AES_Decrypt(str2, 'YWJjZGVmZ2hpamts'))
'''
输出:
解密后的参数:{"en":"白银市宇力检测有限公司"}
解密后的结果:{
"type" : "SUCCESS",
"key" : "200",
"message" : "数据查询成功",
"data" : [ {
"POSTALCODE" : "730913",
"APTITUDENUM" : "甘建检字第6204083号",
"ADDRESS" : "甘肃省白银市平川区向阳路北侧",
"ENTERPRISENAME" : "白银市宇力检测有限公司",
"ENTERPRISECREATETIME" : "2006-04-27",
"LEGALPERSON" : "王鸿淑",
"AREANAME" : "白银市",
"GRANTCERTIFICATEDEPART" : "甘肃省建设工程安全质量监督管理局",
"LICENCENUM" : "916204037840388071",
"CATEGORYNEW" : "[{\"APTITUDECATEGORYNAME\":\"见证取样检测\",\"APTITUDESPECIALITYNAME\":\"建筑工程检测\",\"APTITUDEGRADE\":\"乙级\"},{\"APTITUDECATEGORYNAME\":\"专项检测\",\"APTITUDESPECIALITYNAME\":\"地基基础和主体结构检测\",\"APTITUDEGRADE\":\"乙级\"}]"
}]}
'''
JS库解密
除了使用 Python 的库来解密,我们还可以使用 JS 的库进行解密。首先我们在 Pycharm 的 Terminal 终端中执行下面命令安装 JS 的 crypto-js
加密算法库:
npm install crypto-js
执行完成后,会在命令的执行路径下生成一个名称为 node_modules
文件夹,里面包含各种用 JS 实现的标准加密算法:
现在我们新建一个 JS 文件,在里面引入我们下载的标准加密算法,并将上面我们所定位解密的位置处的 JS 代码复制到这里面,执行解密操作:
// 引入JS加密算法库
CryptoJS = require('crypto-js')
// 密钥
aesKey = "YWJjZGVmZ2hpamts"
// aes解密(网页上复制下来)
function Decrypt(word){
var key = CryptoJS.enc.Utf8.parse(aesKey);
var decrypt = CryptoJS.AES.decrypt(word, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7});
return CryptoJS.enc.Utf8.stringify(decrypt).toString();
}
// 加密后的参数
str1 = "Gs/nl960sHJcPrPr83z9MRMC7LBr/GY/K8gmbW68iFdjLCYTehkRYafNPbLvsQ8v"
// 加密后的结果
str2 = "+LZgDXrUvn52pmaRCuHYFlNTvfhGg9p7waDQjjW54Kf334rhYVaS7eN/5USlS6d9NKDpcBGl0GzPqlLY6qb70TB90VLhfFhW6zT3fWTp/dZTQbO/ZNK3ui57bLi7K4uyMmE3xzM1bF+gO7de4rIzH93dGG3/DsIXgaEwK5qn4r6gTW4oyz6LXKKUSOubFXeCnqSVRGnQorAs/9HLm3R6o9Uasfjv5LA08vJ5fRuvsY3F3vXIxXpPyY7e10hnYCMGAo1fvm1I86q0U2BBxRkQDcgRjlEcBXmG9xbocqX8m3HCPZCVPs82sAE2yUCUDpOZ4KVCUtzkpSQr0I/Bt2tJwyG/cgf5aVKOBUJdCX3jMS/t4TRvE9SZJTUMxdjwZKTd0EfyQjdQAGCo6K+Jxil8wjYhhzsDsWu3Aga8LC1+j2WpkzjBDrJ4jMsgCEdHuNXr8KpOmuZvQD/JZKZmqceZd4HpEXigmlog86hfNG9unUSvdCnkittVLYZz9OaWV1Tq1Loa0O4T/jrVQhcmpJM/dA8qkPRS8m1RjWXgpeGDQ1aDT48082kJ3QIm3RHqGfV4e0e0wpdWDCK2TmbcOM2PT2WXOvWOPXoeI2KRpEVwJaOJE2T0dZe7Y7BYHsootmampwZxnObjiqWJiqU7rA6ejLDFkFCtKrodymMKm7gf7Ee2+NqoQTEtBa8y348NzPhK9sgz6rGS6Q5d8BaX8rcWDH0LTMvi28tMgEr7OpyURucomYTeLjIqDmGsLiLwezbWxaB9QvAvHvg6Wavd2Z4IBL0WVl3YJzrHjxmy4VLCJHOzheKeLebOYTpqf5plfIx2ZstWlVi3OPFnNgnmGkTw3trYQeOIIUzGU+TkYKD8tzWQjGAmnM77bNieLHZus+TiGs5+MvGKWJnerL0SpK5mye7jX1wqJPIu0aPklZZ0B+LZ7dazpQAlbYTIH1EczHsELHwGY4m65XwMcztn27y7x9ZryvsLcmIC4bVENmeREWalgedTFZa+zEQ/yoCPCUrVyFCdlaeAz7JidLFSZulycdZp8o+O568We+83a4B+lMrDe4jLnuK0xXdPyyNgdlmvNYJH1Gbds8Iq8HKRiSZ7XA=="
// 解密后的参数
console.log(Decrypt(str1));
// 解密后的结果
console.log(Decrypt(str2));
RSA加密
难度:简单
现在我们做一道 RSA 加密题目,首先访问页面获取到的信息如下:
- 获取 100 页的数字计算加和;
- 顶部标签页提示本题有 RSA 加密;
- 在 XHR 请求的响应中发现服务器返回的 RSA 加密的内容。
逻辑分析:RSA 是非对称加密,也就是说有两把密钥,一把叫”公钥“用来加密,一把叫”私钥“用来解密,且公钥和私钥是同一对象生成的。在响应中没有返回公钥,也就是说公钥放在了服务器,加密在服务器中完成,但由于解密在浏览器中完成,且响应并没有返回私钥,那么私钥只能在客户端生成,又由于公钥和私钥不是同一进程中的对象生成的,也就确定每次使用的公钥和私钥都是定值。
点击 Initiator 选项卡,点击 call 后面的定位,对该请求溯源:
进入后我们对内容进行格式化,记住 RSA 的密钥样式,无论是公钥还是私钥,开头都是 -----BEGIN
,我们就以这个为关键词进行搜索,发现两处地方,都打上断点进行翻页,断点卡在 2056 行,根据英文内容提示,这就是我们要找的 RSA 私钥:
在控制台输入该 RSA 私钥,内容如下:
最后,直接拿着私钥解密服务器发送过来的加密数据,就能获取到原始数据了。
RC4加密
难度:中等
访问网址获取任务,在 Network 里面的 Fetch/XHR 选项中定位到了该网页数据的来源请求,发现该请求的参数和响应都不可读取,根据题目提示估计传递的就是加密参数:
那我们就通过 Initiator 选项卡来追溯请求发送过程,点击 call 后面的地址进行跳转:
跳转后,发现 post 传递的是 data
参数值是 N(code)
而其中 code
的值来源于上面,我们在该两处打上断点:
首先调试 s()
方法里面的代码 J['lzaCv'](J['qromH'](j, -0xb31 + 0x53 * -0x42 + 0x4b1 * 0x7), y['toString']())
返回的是 随机的64位的大小写字母 + 'f' + 页面
,接下来进入 s()
方法,发现是一个 RC4 的 encrypt
加密算法,其中加密的key是 12345678912345678912345678912345
值,加密的内容就是上面返回的内容:
接下来就是 N()
方法,就是一个返回指定位置字符的 Unicode 编码的方法:
现在我们已经将请求的参数处理完成了,最后就是处理返回的二进制数据了。进入 success 部分,在解密处打算断点,发现里面有一个 c
方法:
进入 c
方法,发现是一个 RC4 的 decrypt
解密算法,注意这里解密的 key 和上面加密的 key 是不一样的,里面有个数字发生了变化,其 key 值为 12345678812345678912345678912345
:
建议
有人会问,RC4 加密算法不是对称加密吗,为什么加密和解密的 key 值不一样?个人猜测,是因为服务器那边使用 RC4 加密算法也有两套不同的 key 用于加密和解密。