JSReverse-ASy0y0首次投稿
____. ___________________
| |/ _____/\______ \ _______ __ ___________ ______ ____
| |\_____ \ | _// __ \ \/ // __ \_ __ \/ ___// __ \
/\__| |/ \ | | \ ___/\ /\ ___/| | \/\___ \\ ___/
\________/_______ / |____|_ /\___ >\_/ \___ >__| /____ >\___ >
v1.0
by Asy0y0
项目概述
项目名称:JSReverse Tool v1.0
功能介绍:帮助使用者更好的进行JS加密参数的渗透测试
开发语言:Python
项目地址:https://github.com/tianjy12/JSReverseTool
项目架构
JSReverse
---> conf
---> Config.py
---> core
---> DecryptHandler.py
---> EncryptHandler.py
---> HttpHandler.py
---> JSFileSelector.py
---> scripts
---> JSTemplate
---> JSTemplate.js
---> BrowserEnvironment.js
---> gui
---> Main.py
---> network
---> ReceiveHttpResponse.py
---> SendHttpRequest.py
---> temp
---> temp.txt
---> imgs
---> ico.png
---> JSReverse.py
core:项目功能的核心实现模块
scripts:存放提供的浏览器环境,JS模板以及用户自定义的JS模板
gui:前端界面的展示
network:HTTP请求收发的实现模块
temp:存放临时的请求体
核心代码
JSFileSelector.py
def choose_js_template(self):
js_template_dir = 'scripts'
js_files = [f for f in os.listdir(js_template_dir) if f.endswith('.js')]
if not js_files:
messagebox.showerror("Error", "No JS templates found in the JSTemplate directory.")
return None
selected_template = None
def on_select(event):
nonlocal selected_template
selected_template = template_listbox.get(template_listbox.curselection())
template_window.destroy()
template_window = tk.Toplevel(self.root)
template_window.title("选择JS模板")
template_listbox = tk.Listbox(template_window, height=10)
for js_file in js_files:
template_listbox.insert(tk.END, js_file)
template_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
template_listbox.bind('<<ListboxSelect>>', on_select)
self.root.wait_window(template_window)
return selected_template
显示scripts目录下的JS文件列表
选择使用的JS文件,记录文件名
文件名用于后续拼接成相对路径调用对应的JS文件
DecryptHandler.py
def run_node_decrypt(self, selected_template):
try:
process = subprocess.Popen(
['node', f'scripts/{selected_template}', 'decrypt'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout, stderr = process.communicate()
if process.returncode != 0:
print(f"Error executing Node.js script: {stderr.decode('utf-8')}")
return "Error during decryption"
return stdout.decode('utf-8')
except Exception as e:
print(f"Exception while executing Node.js script: {e}")
return "Error during decryption"
调用选中的JS模板
执行命令:node scripts/selected_file.js decrypt
获取JS文件的输出并返回
def decrypt_request_body(self, selected_template, raw_request):
decrypted_body = self.run_node_decrypt(selected_template)
if "\r\n\r\n" in raw_request:
header_part, body_part = raw_request.split("\r\n\r\n", 1)
return f"{header_part}\r\n\r\n{decrypted_body}"
elif "\n\n" in raw_request:
header_part, body_part = raw_request.split("\n\n", 1)
return f"{header_part}\n\n{decrypted_body}"
else:
return raw_request
将请求头和请求体分割
用解密得到的明文替换原来的请求体
与请求头拼接后返回
EncryptHandler.py
def run_node_encrypt(self, json_body):
try:
script_path = os.path.abspath(f'scripts/{self.selected_template}')
json_data_str = json.dumps(json_body)
temp_file_path = os.path.abspath('temp/temp.txt')
with open(temp_file_path, 'w') as temp_file:
temp_file.write(json_data_str)
process = subprocess.Popen(
['node', script_path, 'encrypt'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout, stderr = process.communicate()
if process.returncode != 0:
print(f"Error executing Node.js script: {stderr.decode('utf-8')}")
return "Error during encryption"
return stdout.decode('utf-8').strip()
except Exception as e:
print(f"Exception while executing Node.js script: {e}")
return "Error during encryption"
将请求体写入temp/temp.txt文件
调用选中的JS模板
执行命令:node scripts/selected_file.js encrypt
JS文件读取temp/temp.txt的内容并执行
获取JS文件的输出并返回
def encrypt_request_body(self, raw_request):
if "\r\n\r\n" in raw_request:
header_part, body_part = raw_request.split("\r\n\r\n", 1)
elif "\n\n" in raw_request:
header_part, body_part = raw_request.split("\n\n", 1)
else:
return raw_request
try:
json_body = json.loads(body_part)
except json.JSONDecodeError:
return "Invalid JSON in request body"
encrypted_body = self.run_node_encrypt(json_body)
return f"{header_part}\n\n{encrypted_body}"
将请求头和请求体分割
用加密得到的密文替换原来的请求体
与请求头拼接后返回
JSTemplate.js
const fs = require('fs');
// 模拟浏览器环境
const { navigator, window, location, document, sessionStorage } = require('./JSTemplate/BrowserEnvironment');
global.navigator = navigator;
global.window = window;
global.location = location;
global.document = document;
global.sessionStorage = sessionStorage;
// 工具函数
// 明文模板
const template = {}
const mode = process.argv[2];
if (mode === "decrypt") {
console.log(JSON.stringify(template));
process.exit(0);
}
if (mode === "encrypt") {
const rawRequest = fs.readFileSync('temp/temp.txt', 'utf-8');
const jsonData = JSON.parse(rawRequest); // 根据要加密的参数是否为JSON格式选择
const encryptedData = window.asy0y0(jsonData); // 假设这是你的加密函数
const encodedData = encodeURIComponent(encryptedData); // 可选择是否进行URL编码
console.log('data=' + encodedData + '&crc=-1309814496'); // 输出符合原请求体格式的结果
process.exit(0);
}
其他细节
Q:为什么加密过程中,要把请求体写入temp.txt文件,再让JS从文件中读取,为什么不直接把请求体作为参数传给JS文件?
A:一是考虑到格式的问题,请求体可能比较复杂,在命令行中作为参数传递可能导致各种意想不到的问题,二是对JS参数的维护,目前的参数只有encrypt和decrypt,后续可能添加其他参数,对应新的功能模块,命令格式均为:node scripts/selected_file.js param
Q:后续有什么更新的计划吗?
A:目前比较有思路的更新计划:
增加前端界面展示的美化
新增一些功能点,针对一些细节的JS模板配置,比如是否为JSON,是否启用URL Encode等,交互性更强
新增爆破的功能,便于对加密的用户名密码等参数进行调试,但需要找一个会GoLang的人来技术支持,或者等我抽空几个GoLang编写的工具的源码再说,Python的性能太差了
遇到新的浏览器环境,当前模板配置的环境无法,满足时,会更新新的浏览器环境配置模板
- 感谢你赐予我前进的力量