某信用中心之加速乐实战分析

某信用中心之加速乐实战分析

  • 某信用中心之加速乐实战分析
    • 声明
    • 逆向目标
    • 逆向分析
      • 第一层cookie获取
      • 第二层cookie获取
      • 调试分析JS文件
    • 模拟执行
      • 致谢

某信用中心之加速乐实战分析

声明

本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!

逆向目标

某信用中心之加速乐实战分析_第1张图片

逆向分析

通过打开F12抓包查看是否存在加密参数

发现我们需要的数据在xhr请求中

某信用中心之加速乐实战分析_第2张图片

再查看标头和负载,初步看好像没有加密参数,所以我们直接发送request请求尝试能不能获取到数据。

某信用中心之加速乐实战分析_第3张图片
在这里插入图片描述

发送请求后发现返回一个js文件

在这里插入图片描述

如果有了解过的同学就知道,这是加速乐cookie反爬虫,是知道创宇推出的一款网站CDN加速、网站安全防护平台。

加速乐的特点是访问网站一般有三次请求:

  1. 第一次请求网站,网站返回的响应状态码为 521,响应返回的为经过 AAEncode 混淆的 JS 代码;
  2. 第二次请求网站,网站同样返回的响应状态码为 521,响应返回的为经过 OB 混淆的 JS 代码;
  3. 第三次请求网站,网站返回的响应状态码 200,即可正常访问到网页内容。

我们可以在网页中清除cookie后再尝试抓包查看是否和我们上述所说

某信用中心之加速乐实战分析_第4张图片

接下来就是重点分析这三个cookie文件

第一层cookie获取

直接查看 response 是显示无响应内容的,所以我们通过之前发送请求包中返回的响应包代码进行分析

某信用中心之加速乐实战分析_第5张图片

分析响应包,可以看到第一个xyxx-list.do返回的响应内容经过 AAEncode 加密,大致内容如下,可以看到一堆颜表情符号,还挺有意思的:


document.cookie 里的颜表情串实际上是第一次 __jsl_clearance_s 的值,可以直接通过正则提取到加密内容后,使用execjs.eval()方法即可得到解密后的值:

import re
import execjs

js_clearance = re.findall('cookie=(.*?);location',response.text)[0]
jsl_clearance_s  = execjs.eval(js_clearance).split(';')[0]
print(jsl_clearance_s)

// __jsl_clearance_s=1690686292.777|-1|uzTU5s0inLnvhCVdFmuyRXtr69k%3D

在这里插入图片描述

第二层cookie获取

第二层cookie获取可以直接查看第一个xyxx-list.do的响应包,或者通过第一层cookie获取后的__jsl_clearance_s __jsluid_s两个cookie参数发包请求,也能获得对应响应代码,如图所示

某信用中心之加速乐实战分析_第6张图片

某信用中心之加速乐实战分析_第7张图片

将文件复制出来分析后发现是一个经过 OB 混淆的 JS 文件,我们需要对其进行调试分析,所以我们首先需要寻找找这个js代码的加密位置,先清除本地浏览器的cookie。

某信用中心之加速乐实战分析_第8张图片

然后在源代码中勾选住脚本,这样网页执行的每一个js文件都会被我们断住了,当然也可以使用hook注入等方式寻找加密位置

某信用中心之加速乐实战分析_第9张图片

刷新网页,然后不断进行F8往下,我们首先会看到我们之前分析过的第一个cookie文件,继续F8往下走

某信用中心之加速乐实战分析_第10张图片

成功找到我们所需要的js文件

某信用中心之加速乐实战分析_第11张图片

调试分析JS文件

由于网站是cookie加密,所以每次刷新JS文件的一些参数都是在动态变换的,所以我们可以使用本地替换的方式固定一套下来再进行调试。然后在该 JS 文件中通过 CTRL + F 搜索 document,只有一个,在第 596 行打断点调试,选中_0x1739('0x93', '3R@K') + 'ie'后进入控制台输入会发现这里就是 cookie 经过混淆后的样式:
某信用中心之加速乐实战分析_第12张图片

在这里插入图片描述

将等号后面的内容全部选中,进入控制台输入可以发现,这里生成了 Cookie 中 __jsl_clearance_s 参数的值:

在这里插入图片描述

至此,我们知道了 Cookie 生成的位置,接下来就需要了解其加密逻辑和加密方法,然后通过 python 对其进行复现了,document 部分完整的代码如下:

document[_0x1739('0x93', '3R@K') + 'ie'] = _0x3fa957[_0x1739('0x9b', '9PBK') + 'W'](_0x3fa957[_0x1739('0x43', '7C)&') + 'W'](_0x3fa957[_0x1739('0xbc', 'ML*i') + 'X'](_0x3fa957[_0x1739('0x37', 'tfb]') + 'X'](_0x5a3a5f['tn'] + '=', _0x4bca4c[0x0]), _0x1739('0x114', '@XV)') + _0x1739('0x10f', ')!ai') + '='), _0x5a3a5f['vt']), _0x1739('0x20', '711Q') + _0x1739('0xda', 'R2lr') + '\x20/');

这里等号后面的内容比较冗杂,其实我们想要获取的是 jsl_clearance_s 参数的值,通过逐步分析调试可以看到其值由(_0x5a3a5f['tn'] + '=', _0x4bca4c[0x0])生成:

在这里插入图片描述

继续分析可知_0x5a3a5f['tn']对应的部分是__jsl_clearance_s,而其值是_0x4bca4c[0x0],因此我们需要进一步跟踪 _0x4bca4c 生成的位置。

在这里插入图片描述

通过搜索,在第 587行可以找到其定义生成的位置,打断点调试可以看到,_0x4bca4c[0x0]其实就是取了 _0x4bca4c 数组中的第一个位置的值:

某信用中心之加速乐实战分析_第13张图片

我们来进一步分析 _0x4bca4c 后面代码各自的含义,完整代码如下

_0x3fa957[_0x1739('0x11', '3)Nv') + 'V'](_0x29f4ef, _0x5a3a5f['ct'], _0x5a3a5f[_0x1739('0x68', '&GmG')]);

通过控制台可知_0x3fa957[_0x1739('0x11', '3)Nv') + 'V']取的是后面参数中第一个参数当做函数体,第二和第三个值当做参数传入。
在这里插入图片描述

_0x5a3a5f['ct'])取的是 go 函数传入的字典中 ct 参数的值:

在这里插入图片描述
某信用中心之加速乐实战分析_第14张图片

分析可知将_0x5a3a5f[_0x1739('0x68', '&GmG')]数组中的值按照某种规则进行拼接就是 __jsl_clearance_s 参数的值,并且_0x1739('0x68', '&GmG')对应字典中 bts 的值:
某信用中心之加速乐实战分析_第15张图片

所以需要进一步跟踪 _0x29f4ef,可以发现其是个函数体,第 582 行 return 后的返回值就是 __jsl_clearance_s参数的值:

某信用中心之加速乐实战分析_第16张图片

在第 581 行打断点调试,能知道 hash 后 _0x2cc335 为 __jsl_clearance_s 参数的值:

某信用中心之加速乐实战分析_第17张图片

hash( _0x2cc335) 的值为 _0x2cc335 经过加密后的结果,在本例中,加密结果特征分析很明显能看出是SHA256的加密长度,其实通过查看之前获取的go字典也能看到他写出了用的什么加密方式。

但加密的方法即 hash 方法不全是 SHA256,多刷新几次发现会变化,实际上这个 hash 方法与原来调用 go 函数传入的字典中 ha 的值相对应,ha 即加密算法的类型,一共有 md5、sha1、sha256 三种,所以我们在本地处理的时候,要同时有这三种加密算法,通过 ha 的值来匹配不同算法。

某信用中心之加速乐实战分析_第18张图片

进一步观察这里还有个 for 循环,分析发现每次循环 hash(_0x2cc335) 的值是动态变化的,原因是 _0x2cc335 的值是在动态变化的,_0x2cc335 中只有中间两个字母在变化,不仔细看都看不出来:

某信用中心之加速乐实战分析_第19张图片

跟进 _0x2cc335 生成的位置,分析可知 _0x2cc335 参数的值是由 _0xf7137b 数组的第一个值加上两个字母再加上该数组第二个值组成的结果:

某信用中心之加速乐实战分析_第20张图片

_0x2cc335的源代码混淆参数很多不好直接分析,建议解混淆后再进行分析

var _0x2cc335 = _0xf7137b[0x0] + _0x5a3a5f[_0x1739('0x89', 'BSbR') + 's'][_0x1739('0xb8', 'jBDG') + 'tr'](_0x107bb7, 0x1) + _0x5a3a5f[_0x1739('0x105', 'kvMu') + 's'][_0x1739('0x6e', 'm%$p') + 'tr'](_0x4ec95b, 0x1) + _0xf7137b[0x1];

解混淆后代码如下

var _0x2cc335 = _0xf7137b[0x0] + _0x5a3a5f['chars']["substr"](_0x107bb7, 0x1) + _0x5a3a5f['chars']["substr"](_0x4ec95b, 0x1) + _0xf7137b[0x1];

中间两个字母是将底下这段写了两次生成的,即 _0x5a3a5f['chars']['substr'][1], 取字典中 chars 参数的一个字母,取了两次,这里通过 for 循环在不断取这两个值,直到其值加密后与 _0x1c0bb7(即 ct)的值相等,则作为返回值传递给 __jsl_clearance_s 参数:

_0x1c0bb7为ct的值:

某信用中心之加速乐实战分析_第21张图片

最前面_0x3fa957[_0x1739('0xf0', 'oMaE') + 'E']是个方法,我们进一步跟进过去,看这个方式里面实现了什么样的逻辑:

其内容如下,可以看到这个方法返回的值是两个相等的参数:
在这里插入图片描述

模拟执行

综上所述,_0x29f4ef 函数中的逻辑就是判断 _0x2cc335 的值经过 hash 方法加密后的值,是否与 ct 的值相等,若相等则将返回值传递给 __jsl_clearance_s 参数,循环完后还未有成功匹配的值则会执行提示失败,传入参数中 ha 的值是在变化的,即加密算法也是在变化的,有三种加密方式 SHA1SHA256MD5,我们可以扣下三种 hash 方法,也可以直接使用 crypto-js 库来实现:

var CryptoJS = require('crypto-js');


function hash(type, value){
    if(type == 'md5'){
        return CryptoJS.MD5(value).toString();
    }
    if(type == 'sha1'){
        return CryptoJS.SHA1(value).toString();
    }
    if(type == 'sha256'){
        return CryptoJS.SHA256(value).toString();
    }
}

function cookies(_0x5a3a5f){
    var _0x26fd06 = new Date();
    function _0x29f4ef(_0x1c0bb7, _0xf7137b) {
        var _0x5dfb01 = _0x5a3a5f['chars']['length'];
        for (var _0x107bb7 = 0x0; _0x107bb7 < _0x5dfb01; _0x107bb7++) {
            for (var _0x4ec95b = 0x0; _0x4ec95b < _0x5dfb01; _0x4ec95b++) {
                var _0x2cc335 = _0xf7137b[0x0] + _0x5a3a5f['chars']["substr"](_0x107bb7, 0x1) + _0x5a3a5f['chars']["substr"](_0x4ec95b, 0x1) + _0xf7137b[0x1];
                if ((hash(_0x5a3a5f['ha'],_0x2cc335) == _0x1c0bb7)) {
                    return [_0x2cc335, new Date() - _0x26fd06];
                }
            }
        }
    }
    var _0x4bca4c = _0x29f4ef (_0x5a3a5f['ct'], _0x5a3a5f['bts']);

  return {'__jsl_clearance_s' : _0x4bca4c[0]};
}

console.log(cookies({
    "bts": ["1690639070.278|0|ihl", "l%2FaY6Y3B%2FKq8I4GT55NZvc%3D"],
    "chars": "iMyDvZzWmPBnCGdujVpCAJ",
    "ct": "fb9fe0ec006b42f92ffbd372dc71b4612c989e2bf4d095afb8abbfce8ed3d35f",
    "ha": "sha256",
    "is": false,
    "tn": "__jsl_clearance_s",
    "vt": "3600",
    "wt": "1500"
}))

获取结果如下

在这里插入图片描述

python代码只演示部分关键代码,完整代码可私信联系我

def get_first_cookie():
    global cookies
    resp_first = requests.post(url, headers=headers,  data=data)
    # 获取 cookie 值 __jsluid_s
    cookies.update(resp_first.cookies)
    # 获取第一层响应内容, AAEncode 加密
    content_first = re.findall('cookie=(.*?);location', resp_first.text)[0]
    jsl_clearance_s = execjs.eval(content_first).split(';')[0]
    # 获取 cookie 值 __jsl_clearance_s
    cookies['__jsl_clearance_s'] = jsl_clearance_s.split("=")[1]


def get_second_cookie():
    global cookies
    # 通过携带 jsluid_s 和 jsl_clearance_s 值的 cookie 获取第二层响应内容
    resp_second = requests.get(url=url, headers=headers, cookies=cookies)
    # 获取 go 字典参数
    go_params = re.findall(';go\((.*?)\)', resp_second.text)[0]
    params = json.loads(go_params)
    return params


def get_third_cookie():
    with open('jsl.js', 'r', encoding='utf-8') as f:
        jsl_js = f.read()
    params = get_second_cookie()
    # 传入字典
    third_cookie = execjs.compile(jsl_js).call('cookies', params)
    cookies.update(third_cookie)


def main():
    get_first_cookie()
    get_third_cookie()
    resp_third = requests.post(url, headers=headers,cookies=cookies , data=data)
    resp_third.encoding = 'utf-8'
    print(resp_third.text)


if __name__ == '__main__':
    main()

获取结果如下

某信用中心之加速乐实战分析_第22张图片

致谢

部分思路代码通过以下文章学习:【JS 逆向百例】某网站加速乐 Cookie 混淆逆向详解

你可能感兴趣的:(python,node.js,爬虫,网络爬虫,js逆向,javascript,pycharm)