最近在接触安徽某些网站时,接触到了大量 jsl_clearance 加密的cookies,以及其变种
如果你在cookies中看到了__jsl_clearance或者__jsl_clearance_s那么大概率就是了
我碰到的如下网站都采用了此种加密或加密变种:
http://www.tljq.gov.cn/
http://ggzyjyzx.tl.gov.cn/tlsggzy/
https://zwgk.hefei.gov.cn/
https://www.chaohu.gov.cn/
http://zrzyhghj.hefei.gov.cn/
https://zwgk.hefei.gov.cn/
大家可以选择其中一个进行练习
本文以 铜陵市郊区人们政府 为例, 进行讲解
分析
首先用浏览器粗略的抓个包
![](https://img.haomeiwen.com/i28164900/393f8784df2adbd1.png)
这是浏览器抓到的第一个包,可以看到此时__jsl_clearance已经存在了,显然并不合理,jsl_clearance不可能凭空生成,那么一定在这个请求之前,浏览器与服务器之间已经达成了一些交互,但是浏览器并没有抓到相关的包
所以我们换专业的抓包软件 Fiddler 同时清空浏览器缓存 重新抓包
![](https://img.haomeiwen.com/i28164900/707937db68433f10.png)
这里可以看到 正如我们所想,在响应200之前,已经经过了两次响应为521的交互
![](https://img.haomeiwen.com/i28164900/5464f70ab60a4566.png)
我们首先分析第一个521
可以看到他返回了一段js并设置了cookie, 我把把js抠出来运行试一下
cookie = ('_')+('_')+('j')+('s')+('l')+('_')+('c')+('l')+('e')+('a')+('r')+('a')+('n')+('c')+('e')+('=')+(-~[]+'')+((1+[2])/[2]+'')+([2]*(3)+'')+(-~{}+'')+((2<<1)+'')+(2+7+'')+(-~[7]+'')+((+true)+'')+(1+7+'')+(5+'')+('.')+(-~[5]+'')+(3+5+'')+('|')+('-')+(-~false+'')+('|')+('F')+('t')+('H')+('G')+('j')+('a')+('I')+('v')+('f')+('r')+('Y')+('x')+('j')+('m')+('y')+('e')+('w')+('X')+('y')+('a')+('w')+('B')+('Q')+((1+[4]>>1)+'')+('N')+((2)*[4]+'')+('M')+('%')+(1+2+'')+('D')+(';')+('m')+('a')+('x')+('-')+('a')+('g')+('e')+('=')+(3+'')+([2]*(3)+'')+(~~false+'')+(~~[]+'')+(';')+('p')+('a')+('t')+('h')+('=')+('/')
console.log(cookie)
运行结果是 __jsl_clearance=1661498185.68|-1|FtHGjaIvfrYxjmyewXyawBQ7N8M%3D;max-age=3600;path=/
设置完cookie后 他就直接重新刷新了页面(location.href=location.pathname+location.search)
接着我们分析第二个521
![](https://img.haomeiwen.com/i28164900/3ed237f97c72e56d.png)
这里可以看到,在请求头中,确实携带了我们上一阶段所获得的加密结果,验证了我们前面的工作是完全正确的
但是此次返回的依然不是我们要的数据,而是一段经过混淆加密的js代码
这里需要做一个反混淆(大家各凭手段,我用的是AST,下一次博客会拿出来做个演示,本次就不讲了, 当然你也可以使用Hook之类的手段)
混淆解开后的逻辑大概是,调用go方法,根据go的实参对象中ha这个键做对应的加密(具体细节,我后面会用Python重写,大家后面再研究) 加密结束后,根据加密结果重新设置cookie
![](https://img.haomeiwen.com/i28164900/5cb655b43eb82efc.png)
此时在次请求 就可以得到我们想要的数据
实现
既然思路明确了,那么我们用Python实现一下就好了
import requests
import execjs
# 解析第一次521
session = requests.session()
res1 = session.get(url, headers=header)
# 提取加密JS代码
jsl_clearance_s = re.findall(r'cookie=(.*?);location', res1.text)[0]
# 运行JS
jsl_clearance_s = str(execjs.eval(jsl_clearance_s))
key = jsl_clearance_s.split('=')[0]
value = jsl_clearance_s.split('=')[1].split(';')[0]
# 添加cookie
add_dict_to_cookiejar(session.cookies, {key: value})
首先使用requests.session()打开一个请求会话 (此处不能使用request.get() )
然后get请求获得Javascript,并使用正则提取出其中的加密代码
用PyExecjs模拟Node环境 运行获得加密结果
然后用split拆分成key-value
使用 add_dict_to_cookiejar方法 将加密结果添加到 cookies 中
到此为止第一阶段就完成了
res2 = session.get(url, headers=header)
# 提取go方法中的参数
data = json.loads(re.findall(r';go\((.*?)\)', res2.text)[0])
jsl_clearance_s = getCookie(data)
# 修改cookie
add_dict_to_cookiejar(session.cookies, {key: jsl_clearance_s})
接着上面setCookie完成后,再次请求当前网页
重新获取加密JS 调用加密方法 获得新的加密cookie 并重置cookie
def getCookie(data: dict):
chars = len(data['chars'])
for i in range(chars):
for j in range(chars):
clearance = data['bts'][0] + data['chars'][i] + data['chars'][j] + data['bts'][1]
encrypt = None
if data['ha'] == 'md5':
encrypt = hashlib.md5()
elif data['ha'] == 'sha1':
encrypt = hashlib.sha1()
elif data['ha'] == 'sha256':
encrypt = hashlib.sha256()
encrypt.update(clearance.encode())
result = encrypt.hexdigest()
if result == data['ct']:
return clearance
def getCookie 就是使用AST解开混淆后的逻辑 这里我已经用python复现了逻辑 整体还算比较清楚 就不介绍了
再次setCookie完成后 重新请求网页就可以拿到数据
总结
将上述代码整理一下
# -*- coding: utf-8 -*-
import requests
import re
import execjs
import hashlib
import json
from requests.utils import add_dict_to_cookiejar
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3542.0 Safari/537.36'
}
def getCookie(data: dict):
chars = len(data['chars'])
for i in range(chars):
for j in range(chars):
clearance = data['bts'][0] + data['chars'][i] + data['chars'][j] + data['bts'][1]
encrypt = None
if data['ha'] == 'md5':
encrypt = hashlib.md5()
elif data['ha'] == 'sha1':
encrypt = hashlib.sha1()
elif data['ha'] == 'sha256':
encrypt = hashlib.sha256()
encrypt.update(clearance.encode())
result = encrypt.hexdigest()
if result == data['ct']:
return clearance
def getResponse(url: str):
session = requests.session()
res1 = session.get(url, headers=header)
jsl_clearance_s = re.findall(r'cookie=(.*?);location', res1.text)[0]
# 执行js代码
jsl_clearance_s = str(execjs.eval(jsl_clearance_s))
key = jsl_clearance_s.split('=')[0]
value = jsl_clearance_s.split('=')[1].split(';')[0]
# add_dict_to_cookiejar方法添加cookie
add_dict_to_cookiejar(session.cookies, {key: value})
res2 = session.get(url, headers=header)
# 提取go方法中的参数
data = json.loads(re.findall(r';go\((.*?)\)', res2.text)[0])
jsl_clearance_s = getCookie(data)
# 修改cookie
add_dict_to_cookiejar(session.cookies, {key: jsl_clearance_s})
res1 = session.get(url, headers=header)
return res1
if __name__ == '__main__':
url = "http://www.tljq.gov.cn/jqzx/ztzl/qiyehuanjingxinxigongkai/jianshexiangmuhuanjingyingxiangpingjia/shouligongshi/"
html = getResponse(url=url).content.decode("utf-8")
print(html)
大家如果单纯想解开 jsl_clearance 加密 可以直接拿最后的代码
如果你遇到了 jsl_clearance 但是照搬代码却解不开 需要自己抓包分析一下 因为 jsl_clearance 变种特别多 一般微改一下getResponse就可以
网友评论