专栏首页云爬虫技术研究笔记2019年末逆向复习系列之Boss直聘Cookie加密字段__zp_stoken__逆向分析

2019年末逆向复习系列之Boss直聘Cookie加密字段__zp_stoken__逆向分析

嗨!這个最有深度的『研究笔记』由程序员界最会排版の追星族运营?

2019年

12月16日

推荐几个高质量公众号!

小编:Lateautumn4lin(逆向小小小学生)

郑重声明:本项目的所有代码和相关文章, 仅用于经验技术交流分享,禁止将相关技术应用到不正当途径,因为滥用技术产生的风险与本人无关。

这篇文章是公众号《云爬虫技术研究笔记》的《2019年末逆向复习系列》的第七篇:《Boss直聘Cookie加密字段__zp_stoken__逆向分析》

本次案例的代码都已上传到Review_Reverse上面,后面会持续更新,大家可以Fork一波。

具体加密JS可以在Review_Reverse.boss_zp.encrypt.js中看到,替换具体的参数即可。

背景分析

Boss直聘大概可以算是目前最火的招聘软件了!几个月前的火遍全网的“找工作,马上,和老板谈!”真的是洗脑了一遍又一遍啊!

鉴于Boss直聘的职位更新速度快,职位发布多的两大特点,很多做行业分析和各地岗位差距报告的人都会利用Boss直聘的数据来做分析,几个月前,Boss直聘对他们的接口在Cookie方面做了__zp_stoken__字段的加密,这次案例就用它来做逆向分析。

逆向分析

__zp_stoken__字段生成流程分析

我们需要分析的是__zp_stoken__字段,我们看看它是在哪里生成的

我们要获取Cookie生成的过程,先把网站的数据清空,在Chrome中的Application中利用Clear site data清理好该网站下的数据,然后我们重新刷新网站(我们需要在具体的职位信息页面刷新,因为首页不需要Cookie就能直接访问),看看Network列表中的Cookie生成过程

我们首先会访问具体的职位信息页面,得到一个HttpCode302的响应,代表这次的访问重定向到一个新的URL了,这个URL可以在响应中的Location中看到,拿到的是security-check.html这个URL,我们看看这个URL是什么内容

这个URL具体有几个Param

  • name
  • ts
  • callbackUrl
  • srcReferer
  • seed

根据多次的访问测试,发现变化的字段主要是seednamets,也就是这个URL是动态的,我们直接下断点是打不到具体的地方的,在Chrome里我们也拿不到这个链接的具体响应内容,我们利用Fiddler来获取链接内容

保存响应内容到html中,具体看看里面的内容,文件中搜索__zp_stoken__

var Cookie = {
    get: function(name) {
        var arr,
            reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
        if ((arr = document.cookie.match(reg))) {
            return unescape(arr[2]);
        } else {
            return null;
        }
    },
    set: function(name, value, time, domain, path) {
        var str = name + "=" + encodeURIComponent(value);
        if (time) {
            var date = new Date(time).toGMTString();
            str += ";expires=" + date;
        }
        str = domain ? str + ";domain=" + domain : str;
        str = path ? str + ";path=" + path : str;
        document.cookie = str;
    }
};

var url = window.location.href;
var seed = decodeURIComponent(getQueryString("seed")) || "";
var ts = getQueryString("ts");
var fileName = getQueryString("name");
var callbackUrl = decodeURIComponent(getQueryString("callbackUrl"));
var srcReferer = decodeURIComponent(getQueryString("srcReferer")||'');

if (seed && ts && fileName) {
    seriesLoadScripts("security-js/" + fileName + ".js", function() {
        var expiredate = new Date().getTime() + 32 * 60 * 60 * 1000 * 2;
        var code = "";
        var nativeParams = {};
        var ABC = window.ABC || frame.contentWindow.ABC;
        try {
            code = new ABC().z(seed, parseInt(ts)+(480+new Date().getTimezoneOffset())*60*1000);
        } catch (e) {}
        if (code && callbackUrl) {
            Cookie.set("__zp_stoken__", code, expiredate, COOKIE_DOMAIN, "/");
            // 据说iOS 客户端存在有时写cookie失败的情况,因此调用客户端提供的方法,交由客户端额外写一次cookie
            if (typeof window.wst != "undefined" && typeof wst.postMessage == "function") {
                nativeParams = {
                    name: "setWKCookie",
                    params: {
                        url: COOKIE_DOMAIN,
                        name: "__zp_stoken__",
                        value: encodeURIComponent(code),
                        expiredate: expiredate,
                        path: "/"
                    }
                };
                window.wst.postMessage(JSON.stringify(nativeParams));
            }

            if(srcReferer && isSeo(srcReferer) && srcReferer != 'https://m.baidu.com/'){
                window.location.replace(srcReferer);
            } else {
                window.location.replace(callbackUrl);
            }
        } else {
            window.history.back();
        }
    });
} else {
    if(srcReferer && isSeo(srcReferer) && srcReferer != 'https://m.baidu.com/'){
        window.location.replace(srcReferer);
    }else if (callbackUrl) {
        window.location.replace(callbackUrl);
    } else {
        window.history.back();
    }
}

可以看出__zp_stoken__是这么生成的

var seed = decodeURIComponent(getQueryString("seed")) || "";
var ts = getQueryString("ts");
code = new ABC().z(seed, parseInt(ts)+(480+new Date().getTimezoneOffset())*60*1000);

简化一下

480+new Date().getTimezoneOffset() = 0
code = ABC.z(seed,ts)

如上所示,通过传入的seedts参数调用实例ABCc方法来生成,给当前的document对象加上带__zp_stoken__Cookie之后重新加载页面,这样整个从无Cookie访问到生成Cookie重载页面访问的流程就分析到这里。

__zp_stoken__生成逆向分析

1. 切中关键语句,下断点

刚才说了security-check.html这个问题是动态的,我们不能去给这个文件下断点,重新看看security-check.html的页面源码

var fileName = getQueryString("name");
seriesLoadScripts("security-js/" + fileName + ".js", function())

加载了包含加密方法的Js文件,fileNamesecurity-check.htmlparams中的name字段,我们在SourcesPage中找到该Js文件,整个文件一共是5381

上面我们分析了加密使用ABCz方法,在文件中搜索ABC字符,找到了z方法

先对最后的return语句打断点

重新刷新页面,可以获取的整个方法中各个参数的值,接下来开始分析整个加密方法的流程

2. 删繁就简,核心流程分析

分析z加密方法

ABC[_0x56ae('0x3e')]['z'] = function(_0x172aa3, _0x38e762) {
  //_0x56ae('0x3e') 是 prototype,ABC[_0x56ae('0x3e')]['z']也就是给ABC方法的prototype属性中的键z指定方法,_0x172aa3是seed,ts是时间戳
    var _0x3a1f8c = {};
    _0x3a1f8c[_0x56ae('0x3f')] = function(_0x5362ae, _0x320fdd) {
        return _0x5362ae == _0x320fdd;
    }
    ;
    _0x3a1f8c[_0x56ae('0x40')] = _0x56ae('0x41');
    _0x3a1f8c[_0x56ae('0x42')] = _0x56ae('0x43');
    _0x3a1f8c[_0x56ae('0x44')] = function(_0x2e473d, _0x3ad5ac, _0x1c497c) {
        return _0x2e473d(_0x3ad5ac, _0x1c497c);
    }
    ;
    _0x3a1f8c[_0x56ae('0x45')] = function(_0x1f3c2a, _0x218684) {
        return _0x1f3c2a + _0x218684;
    }
    ;
    try {
        if (document && _0x3a1f8c[_0x56ae('0x3f')](_0x3a1f8c[_0x56ae('0x40')], typeof document[_0x56ae('0x46')])) {
            _0x5606fe = _0x172aa3;
            _0x2f4975 = _0x38e762;
        } else {
            _0x5606fe = _0x3a1f8c[_0x56ae('0x42')];
        }
    } catch (_0x1f6304) {
        _0x5606fe = _0x3a1f8c[_0x56ae('0x42')];
    }
    //上面几项是给dict赋值,没有什么难度,可以不做修改,重点是最后的return语句中的方法
    return _0x3a1f8c[_0x56ae('0x44')](_0x49423a, this, _0x3a1f8c[_0x56ae('0x45')](_0x172aa3[_0x56ae('0x47')], 0xb));

return语句是这样,我们在console中获取每个参数的值,看看能不能做精简

  • _0x3a1f8c[_0x56ae('0x44')]
function(_0x2e473d, _0x3ad5ac, _0x1c497c) {
        return _0x2e473d(_0x3ad5ac, _0x1c497c);
}

_0x3a1f8c[_0x56ae('0x44')]是这样一个方法,参数一是方法,参数二、三作为参数一方法的参数

  • this
function ABC() {
    this['i0'] = 0x0;
    this['d'] = [this];
}

this就是ABC实例,可以在同一个文件中搜索ABC可以得到

  • _0x3a1f8c[_0x56ae('0x45')](_0x172aa3[_0x56ae('0x47')], 0xb

这个参数直接放在console里面运行,得到固定值是55,

从上面分析来看,return语句可以直接简化成

_0x49423a(ABC,55)

3. 还是那句话,缺啥补啥

我们现在拿到了关键语句,接下来就是调试_0x49423a方法,往js文件里面添加缺少的变量和函数方法,出于简单的考虑,直接使用node来调用js文件

直接拿node运行js文件得出来的结果和在Chromeconsole里运行js内容得到的结果不一样,看来还需要调试在哪个地方引用的windowsthis之类的值两个运行环境有差别

__zp_stoken__参数生成注意要求

  1. Js加密函数所在文件不同,不过文件内容逻辑基本相同,只用分析一个文件即可
  2. __zp_stoken__参数生成之后,不能直接在Cookie中使用,需要做URLencode才能使用

复习要点

  1. 这个案例也是很好的动态Cookie生成的案例,和之前的努比亚论坛的Cookie生成案例类似,利用window.location.href/replace/reload()这些机制来重载页面,具体如下图所示
  2. 在调试的时候注意关键词的值,比如thisdocumentwindows这些,往往有时候虽然方法走通了,但是值不对,很有可能就是上面这些值在赋值时发生了错误。

END

鉄子,“在看”来一个

文章分享自微信公众号:
云爬虫技术研究笔记

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 2019年末逆向复习系列之努比亚Cookie生成逆向分析

    这篇文章是《2019年末逆向复习系列》的第二篇:《努比亚Cookie生成逆向分析》

    云爬虫技术研究笔记
  • 2019年末逆向复习系列之知乎登录formdata加密逆向破解

    这篇文章是公众号《云爬虫技术研究笔记》的《2019年末逆向复习系列》的第五篇:《知乎登录formdata加密逆向破解》

    云爬虫技术研究笔记
  • 2019年末逆向复习系列之淘宝M站Sign参数逆向分析

    本次案例的代码都已上传到Review_Reverse上面,后面会持续更新,大家可以Fork一波。

    云爬虫技术研究笔记
  • 2019年末逆向复习系列之拼夕夕Web端anti_content参数逆向分析

    这篇文章是公众号《云爬虫技术研究笔记》的《2019年末逆向复习系列》的第八篇:《拼夕夕Web端anti_content参数逆向分析》

    云爬虫技术研究笔记
  • 2019年末逆向复习系列之今日头条WEB端_signature、as、cp参数逆向分析

    这篇文章是公众号《云爬虫技术研究笔记》的《2019年末逆向复习系列》的第四篇:《今日头条WEB端_signature、as、cp参数逆向分析》

    云爬虫技术研究笔记
  • Boos直聘cookie字段__zp_stoken__参数(亲妈都认不出来的混淆)逆向分析

    这里可以不用清掉cookie。直接全局搜__zp_stoken__参数既可,直接到加密的位置。

    懒py夏洛
  • 商业数据分析从入门到入职(9)Python网络数据获取

    本文主要讲Python最常见的应用之一——网络数据获取,即爬虫: 先介绍了网页和网络的基础知识,为从网页中获取数据打好基础;接下来以两个案例介绍从网络中获取数...

    cutercorley
  • 2019年末逆向复习系列之从猫眼字体反爬分析谈谈字体反爬的前世今生

    这篇文章是公众号《云爬虫技术研究笔记》的《2019年末逆向复习系列》的第六篇:《从猫眼字体反爬分析谈谈字体反爬的前世今生》

    云爬虫技术研究笔记
  • 2019年末逆向复习系列之从猫眼字体反爬分析谈谈字体反爬的前世今生

    这篇文章是公众号《云爬虫技术研究笔记》的《2019年末逆向复习系列》的第六篇:《从猫眼字体反爬分析谈谈字体反爬的前世今生》

    netkiller old
  • 大专读者被裁,但他却拒绝了42k的Offer?| 一名爬虫工程师自述

    这篇文章来自我的一个读者朋友,虽然是大专学历,但精通爬虫技术。一般大厂相对比较卡学历,经过之前我的内推,阿里进行了 4 轮面试(当然内推只是第一步,能经历 4 ...

    程序猿石头
  • [系统安全] 二.如何学好逆向分析及吕布传游戏逆向案例

    娜璋AI安全之家于2020年8月18日开通,将专注于Python和安全技术,主要分享Web渗透、系统安全、CVE复现、威胁情报分析、人工智能、大数据分析、恶意代...

    Eastmount
  • daydao入选「2020中国ToB新增长势力TOP榜」|腾讯SaaS加速器·学员动态

    来源 | 腾讯SaaS加速器首期项目-理才网 ---- ——腾讯SaaS加速器 二期30席项目招募—— 报名方式 腾讯SaaS加速器,作为腾讯产业加速器的一个重...

    腾讯SaaS加速器
  • [系统安全] 二.如何学好逆向分析及吕布传游戏逆向案例

    您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列。因此,我重新开设了这个专栏...

    Eastmount
  • [系统安全] 二十七.WannaCry勒索病毒分析 (3)蠕虫传播机制分析及IDA和OD逆向

    前文分享了MSF利用MS17-010漏洞进行反弹Shell,再上传勒索病毒,复现了WannaCry勒索病毒。这篇文章作者将继续分析WannaCry勒索病毒,主要...

    Eastmount
  • [系统安全] 二十五.WannaCry勒索病毒分析 (1)Python复现永恒之蓝漏洞实现勒索加密

    作者前文介绍了OllyDbg动态调试工具,包括INT3断点、反调试、硬件断点和内存断点。接下来的系列将分享新知识,最近WannaRen勒索软件爆发(下图是安天的...

    Eastmount
  • [系统安全] 二十三.逆向分析之OllyDbg动态调试复习及TraceMe案例分析

    作者前文介绍了微软证书漏洞CVE-2020-0601,并讲解ECC算法、Windows验证机制,复现可执行文件签名证书的例子。这篇文章将详细讲解逆向分析Olly...

    Eastmount
  • [系统安全] 二十一.PE数字签名之(中)Signcode、PEView、010Editor、Asn1View工具用法

    作者前文介绍了什么是数字签名,并采用Signtool工具对EXE文件进行签名,后续深入分析数字签名的格式及PE病毒内容。这篇文章将详细解析数字签名,采用Sign...

    Eastmount
  • [系统安全] 二十八.CS逆向分析 (1)你的游戏子弹用完了吗?Cheat Engine工具入门

    前文分享了WannaCry勒索病毒,主要通过IDA和OD逆向分析蠕虫传播部分,详细讲解蠕虫是如何感染传播的。这篇文章将回到逆向知识,利用Cheat Engine...

    Eastmount
  • [系统安全] 十二.熊猫烧香病毒IDA和OD逆向分析(上)病毒初始化

    如果你想成为一名逆向分析或恶意代码检测工程师,或者对系统安全非常感兴趣,就必须要认真分析一些恶意样本。熊猫烧香病毒就是一款非常具有代表性的病毒,当年造成了非常大...

    Eastmount

扫码关注云+社区

领取腾讯云代金券