爬虫 jsl_clearance 解密

2022-08-25  本文已影响0人  会爬虫的小蟒蛇

最近在接触安徽某些网站时,接触到了大量 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/

大家可以选择其中一个进行练习
本文以 铜陵市郊区人们政府 为例, 进行讲解

分析

首先用浏览器粗略的抓个包

浏览器抓包.png

这是浏览器抓到的第一个包,可以看到此时__jsl_clearance已经存在了,显然并不合理,jsl_clearance不可能凭空生成,那么一定在这个请求之前,浏览器与服务器之间已经达成了一些交互,但是浏览器并没有抓到相关的包
所以我们换专业的抓包软件 Fiddler 同时清空浏览器缓存 重新抓包

Fiddler抓包.png

这里可以看到 正如我们所想,在响应200之前,已经经过了两次响应为521的交互

第一个521.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

第二个521.png

这里可以看到,在请求头中,确实携带了我们上一阶段所获得的加密结果,验证了我们前面的工作是完全正确的
但是此次返回的依然不是我们要的数据,而是一段经过混淆加密的js代码
这里需要做一个反混淆(大家各凭手段,我用的是AST,下一次博客会拿出来做个演示,本次就不讲了, 当然你也可以使用Hook之类的手段)
混淆解开后的逻辑大概是,调用go方法,根据go的实参对象中ha这个键做对应的加密(具体细节,我后面会用Python重写,大家后面再研究) 加密结束后,根据加密结果重新设置cookie

200响应.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就可以

上一篇下一篇

猜你喜欢

热点阅读