68js加密防并发谁能并发我叫谁爹
91
猿人学练习/68js加密防并发谁能并发我叫谁爹/README.md
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# 知识点: whirlpool-js加密,ob混淆,worker多线程,headers检测
|
||||||
|
|
||||||
|
## 解题思路
|
||||||
|
|
||||||
|
看控制台返回的内容
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
查看请求参数,发现如下图字段
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
通过搜索发现找到了c,r,t,uuid,但是a是什么目前不清楚
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
进入调试控制台,查看js内容
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
发现一段可疑代码是`Worker`,和`call2(window.num, window.c, window.r, window.t, window.uuid, e.data)`
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
通过搜索`call2`对应了ajax请求
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
那么这个`e.data`应该就是要找的a,而这个e是通过`Worker`的线程返回的
|
||||||
|
|
||||||
|
进入线程调试,大量ob混淆,此地无银二百两,a的加密就在这里了
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
直接用工具解ob混淆
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
解混淆后在代码尾部找到了`onmessage`仔细阅读代码
|
||||||
|
|
||||||
|
onmessage = X => {
|
||||||
|
for (var s = parseInt(X.data.split("|")[0]); s <= parseInt(X.data.split("|")[1]); s++) {
|
||||||
|
result = self.wp.encSync(X.data.split("|")[2] + s.toString(), "hex");
|
||||||
|
|
||||||
|
if (result.slice(0, 10) === X.data.split("|")[3]) {
|
||||||
|
self.postMessage(s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
其中最最重要的一句是`if (result.slice(0, 10) === X.data.split("|")[3])`如果`result`结果前10个字符串全等`X.data.split("|")[3]`
|
||||||
|
就跳出循环,并子线程发送数据给主线程`self.postMessage(s)`,那么`result`是怎么来的,通过`self.wp.encSync(X.data.split("|")[2] + s.toString(), "hex");`得到
|
||||||
|
|
||||||
|
现在的问题就是如何得到`result`,是通过函数`self.wp.encSync`得到
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
在看解混淆后的代码,发现代码的尾部有这样的包`whirlpool-js`,这个包下面存在`.encSync`
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
在npm文档中解释是这样的,地址https://www.npmjs.com/package/whirlpool-js
|
||||||
|
|
||||||
|
whirlpool 512 bit hash in javascript for electron and the browser
|
||||||
|
Demo: https://angeal185.github.io/whirlpool-js
|
||||||
|
|
||||||
|
看解释应该是一个加密包,下面的问题就是此加密包是否魔改过?
|
||||||
|
|
||||||
|
先在控制尝试输出1的加密结果
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
再自己写一个原生的处理结果
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
一模一样,到这里主要的问题点就已经解决了。
|
||||||
|
|
||||||
|
## 注意点
|
||||||
|
|
||||||
|
在调试ob混淆的时候,我尝试本地替换成解过混淆的代码,但是程序直接卡住不动,其原因在这里
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
做了格式化检测,简单翻译如下
|
||||||
|
|
||||||
|
var K = O["xwRkz"](Z, this, function () {
|
||||||
|
return K["toString"]()["search"]("(((.+)+)+)+$")["toString"]()["constructor"](K)["search"](O["ptdii"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
相关文章介绍 https://www.cnblogs.com/kai-/p/16935788.html
|
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/1.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/10.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/11.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/12.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/13.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/2.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/3.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/4.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/5.png
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/6.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/7.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/8.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
猿人学练习/68js加密防并发谁能并发我叫谁爹/img/9.png
Normal file
After Width: | Height: | Size: 11 KiB |
@ -18,8 +18,6 @@ def challenge68(page, data):
|
|||||||
import urllib
|
import urllib
|
||||||
urllib.parse.quote(data['t'])
|
urllib.parse.quote(data['t'])
|
||||||
payload = f"page={page}&c={data['c']}&r={data['r']}&t={urllib.parse.quote(data['t'])}&uuid={data['uuid']}&a={data['a']}"
|
payload = f"page={page}&c={data['c']}&r={data['r']}&t={urllib.parse.quote(data['t'])}&uuid={data['uuid']}&a={data['a']}"
|
||||||
print(payload)
|
|
||||||
print(len(payload))
|
|
||||||
headers = {
|
headers = {
|
||||||
'content-length': f'{len(payload)}',
|
'content-length': f'{len(payload)}',
|
||||||
'pragma': 'no-cache',
|
'pragma': 'no-cache',
|
||||||
@ -37,7 +35,8 @@ def challenge68(page, data):
|
|||||||
'sec-fetch-dest': 'empty',
|
'sec-fetch-dest': 'empty',
|
||||||
'referer': 'https://www.python-spider.com/challenge/68',
|
'referer': 'https://www.python-spider.com/challenge/68',
|
||||||
'accept-encoding': 'gzip, deflate, br',
|
'accept-encoding': 'gzip, deflate, br',
|
||||||
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8'
|
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
||||||
|
'cookie': 'Hm_lvt_337e99a01a907a08d00bed4a1a52e35d=1679292698,1679332474,1679672673,1679888049; no-alert=true; sessionid=xxxxxxxxxxxxxxxxxxxxxxxxxx; Hm_lpvt_337e99a01a907a08d00bed4a1a52e35d=1680829731'
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
payload = ''
|
payload = ''
|
||||||
@ -57,7 +56,8 @@ def challenge68(page, data):
|
|||||||
'sec-fetch-dest': 'empty',
|
'sec-fetch-dest': 'empty',
|
||||||
'referer': 'https://www.python-spider.com/challenge/68',
|
'referer': 'https://www.python-spider.com/challenge/68',
|
||||||
'accept-encoding': 'gzip, deflate, br',
|
'accept-encoding': 'gzip, deflate, br',
|
||||||
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8'
|
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
||||||
|
'cookie': 'Hm_lvt_337e99a01a907a08d00bed4a1a52e35d=1679292698,1679332474,1679672673,1679888049; no-alert=true; sessionid=xxxxxxxxxxxxxxxxxxxxxxxxxx; Hm_lpvt_337e99a01a907a08d00bed4a1a52e35d=1680829731'
|
||||||
}
|
}
|
||||||
session = requests.session()
|
session = requests.session()
|
||||||
session.headers = headers
|
session.headers = headers
|
||||||
@ -74,16 +74,13 @@ def run():
|
|||||||
res_dict['a'] = a
|
res_dict['a'] = a
|
||||||
print(res_dict)
|
print(res_dict)
|
||||||
res_dict = challenge68(page, res_dict)
|
res_dict = challenge68(page, res_dict)
|
||||||
print(res_dict)
|
data_list = res_dict.get('data')
|
||||||
exit()
|
data_list_num = []
|
||||||
|
for data in data_list:
|
||||||
# data_list_num = []
|
data_list_num.append(int(data.get('value')))
|
||||||
# for data in data_list:
|
data_num += int(data.get('value'))
|
||||||
# data_list_num.append(int(data.get('value')))
|
print(data_list_num, page)
|
||||||
# data_num += int(data.get('value'))
|
print(data_num)
|
||||||
# print(data_list_num, page)
|
|
||||||
# print(data_num)
|
|
||||||
# print(data_num)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -11,11 +11,11 @@ function hex_1_str(data){
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const data = {"uuid": "e4c958f2d45611eda02c52540078cc4c", "c": "787aaa89c8", "r": "UCHQwxAwjX", "t": "eCOZi8Zg31uZsXxm3WKyeKSNRhrHh5RGCd+XifzvIwM="}
|
// const data = {"uuid": "caa26ad8d4e011edb2255254006d01b8", "c": "c05d8d4bdd", "r": "zvBrJDiBzH", "t": "eSaajsdg8G6TkkFa9VeiaKWIRR/Gh5RGCd+YjPXtJg4="}
|
||||||
//
|
//
|
||||||
// a = hex_1_str(data);
|
// a = hex_1_str(data);
|
||||||
// console.log(a);
|
// console.log(a);
|
||||||
|
//
|
||||||
|
|
||||||
module.exports =
|
module.exports =
|
||||||
{
|
{
|
||||||
|
3
猿人学练习/68js加密防并发谁能并发我叫谁爹/测试whirlpool-js.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const wp = require('whirlpool-js');
|
||||||
|
r = wp.encSync('1', "hex");
|
||||||
|
console.log(r);
|