其他分享
首页 > 其他分享> > test

test

作者:互联网

声明

原创文章,请勿转载!
1、本文内容仅限于安全研究,不公开具体源码。维护网络安全,人人有责。
2、如果想更系统地了解第三代验证码、更全面体会安全产品的设计,可以结合我的另几篇文章
(1)《第三代验证码研究》https://www.cnblogs.com/boycelee/p/11363611.html(推荐)

(2)《顶象验证码破解与研究》https://www.cnblogs.com/boycelee/p/14269941.html(推荐)

(3)《极验验证码破解与研究》https://www.cnblogs.com/boycelee/p/14021048.html(推荐)

(4)《极验无感验证破解》https://www.cnblogs.com/boycelee/p/13951819.html

(5)《同盾小程序指纹破解》https://www.cnblogs.com/boycelee/p/13899956.html

3、本文主要通过破解协议的方式绕过顶象安全验证,思路与网上自动化的方式有很大的不同


一、个人心路历程二、完整流程三、实例研究1、研究目标2、案例历史研究3、官网案例分析四、请求分析1、c1请求:请求顶象服务器,获取c参数。(1)请求参数示例 :(2)请求参数信息:(3)加密算法(4)返回参数(5)指纹本地存储2、a请求:获取图片与token2(1)请求参数示例:(2)返回参数:3、v1请求:获取token3(1)请求示例:(2)返回示例:4、check五、部分服务化源码greenseer.js部分服务化代码Java服务化代码六、服务化关键1、图片还原2、随机加密算法解析(重点设计部分)(1)语法树思路(2)举例子七、成果八、顶象无感验证流程(1)顶象无感验证流程图(2)顶象风控流程图九、总结十、最后



一、个人心路历程

(1)顶象的验证码真的非常棒。从2018年12月开始到2019年5月持续与顶象验证码对抗半年。

(2)js混淆与加密算法一天更换两次、滑块验证码干扰槽等应该都是在于我对抗中升级的。

(3)一年后回头看顶象的验证码产品又多了语序点选、刮刮卡验证、空间语义验证、乱序拼图验证、旋转验证、面积验证等验证码类型,在创新方面做得非常好,应该是国内数一数二的。

(4)与顶象的对抗,使我对安全产品有了更深刻、全面的认识。

(5)以下是我与顶象的对抗过程。

极验完整流程
极验完整流程

二、完整流程

三、实例研究

1、研究目标

当用户滑动验证码通过后,验证码服务就会生成token,用户携带token上传至顶象服务进行验证。我们的目标就是生成没有被标记为异常的token。

极验完整流程
极验完整流程

2、案例历史研究

2018年12月研究的是国航的手机注册场景。不过由于国航该场景的验证码已经不再是滑块,所以后续可能需要使用官网案例来具体分析。

极验完整流程
极验完整流程

3、官网案例分析

极验完整流程
极验完整流程

从请求中我们可以看出,一共是三个请求(c1、a、v1)。我们需要弄清楚这三个请求分别的含义。(从设计角度个人觉得顶象相对于极验要简洁一些。个人觉得顶象的设计非常棒,在做公司的安全产品时,我也会参考一些顶象的设计)

四、请求分析

1、c1请求:请求顶象服务器,获取c参数。

目的:此处应该是计算设备指纹,通过设备指纹能够标识唯一设备信息

(1)请求参数示例 :

428#X8m8K4SIcMDkTOm/r2P3j5vTyaRhmW3m9aksXQ8m2r13DgOarX1TmbmTMX13/vXXC9RmXS8m2XHfDg/uV8RP/4uaMuk8/WnUNX+6Xnah2rDfmZ3YXXwR0gpt2lJu07Nozs5jXY433RaCfCO6Y8VX/6aVU2mT6cuhX14q+2v8jcQ/awvNF8X1YuuJmzf3XXbXmCvq8M8uiwXSm3vhmyyuXXOiXmo8Ya21XXGjS8ft1qT2+Al3+Ab0wXWXmyf8aCO4WrrXj6flFh9p4PnSFPokuP5vXmuFn9fM8Am+JXvlT2TiW8QL88SXjtZykz8LUtZ9kAQpkd4pn2oXmpP9upuLVr2XvVTUjyTPTXWPCy+oTofzwi2oRX41sYk1sXWARiw1w32AOrfAe1fPTXVXivd2CFHaGgNezipHxx6cciF1xORN2iUklOpQzldUBvAxwBHXSoHBAGyUXXJ99ei8lxEoj2X8sJTvz/novxbofltai6k3wmXXjtyTItyoi8QsjUMIGI0siT3XYWKG9FkI54DQdTnXm00umH0KBTIXmACOT1rFmC8XmA2rTPuVmm/Xmg1R9usmM5/6XX+vqnlSylnDXX+jGnElyi3fXXphvMw444YeNUpw0TyXuFi3HFitgAiquUM3HXtquUM3HXwt1rXSuNMs1MJfuNrniBCkEnrfYmCsYuL5Y5Cf+nCkUFCkYdCSUFrSJXonuMoXZkrpk8nf3Ue/P9F0pmjG6Q9/DgBJzVZqcg6po/NleM6PXXVE8F9oSzdt++YgMiFBYxWbOUaHPXXS+2C5jY5/ZcmEaAvR+cxxjRQ+k8CoD1xHFcxSj6ovU270Dwyik9oBPTVXYNS86LTmha3t68oQPrXs3/ZLJMPTI2QLAtomXX07drAmu4omycphXrnXYbUG9GpOSg6yts0JX2XfTXVqvE26Y/COD9OqWA5IPaQTDVxc41r6mXXn8Xo6JyIPJPyuXYQim8OYJX3tu6ci/TX3muOg/Lm8//nuY9nljN/sX3vTXX4qX1nIa//1Yc9x

(2)请求参数信息:

只展示部分数据

"supportAddBehavior": "ab","adblock": "adb","availResolution": "ar","canvasFP": "can","cpuClass": "cc","colorDepth": "cd","cookieEnabled": "ce","canPlayType": "cpt","collectTime": "ct","doNotTrack": "dnt","deviceMemory": "dm","languages": "lugs","mimeTypes": "mts","mediaDevices": "mds","platform": "np","supportOpenDatabase": "od","devicePixelRatio": "pr","resolution": "res","plugins": "rp","supportSessionStorage": "ss","timezoneOffset": "to","touch": "ts","userAgent": "ua","webgl": "web","webgl2": "gi"

通过加密以上操作系统与浏览器以及网络数据等信息生成c1请求参数param。

(3)加密算法

极验完整流程
极验完整流程

index.js?_t=xxxx中,进行每日更新。那么该如何确保每日都能获取到准确的加密算法呢?通过解析原语法树,生成我们想要的语法树。(这个后续讲)

(4)返回参数

{"data":"f8839e00435f2e05f9ed60b3d3c5498554cb367655ec6e7318adefda150437040a74963c","msg":"lid invalid","status":-4} // 会根据指纹情况对指纹进行风险等级判断

(5)指纹本地存储

顶象会将指纹进行多地存储,例如cookie、Session Storage、Local Storage等

2、a请求:获取图片与token2

极验完整流程
极验完整流程

(1)请求参数示例:

de=0&wp=1&aid=dx-1547996895410-3601284-1&jsv=1.3.11.98&c=5c3c65a6uSNGXiEhdEwxwwICxBq5Qdjdky4kxjo1&ak=5f6727ec854786a86cd4c3c171d13499&s=50&h=150&w=300&_r=0.9866721061865382

(2)返回参数:

{"sid":"86ae78ed0fba04f8384f3c9376271b0d","y":30,"success":true,"p1":"/dx/ib3oV3MeuO/zib3/b5cce61f91c6447bbc2f10e7836a7827.webp","p2":"/dx/ib3oV3MeuO/zib3/e34db2ab70064b2c998d14159f0b8ff8.webp","p3":"/dx/ib3oV3MeuO/zib3/50969dc0b2f14d118fcf166dc0871021.webp","msg":null,"t":null,"result":1,"type":0,"logo":null}

注意:如果该请求错误,可能会返回另一种图片验证码(点击类型)

3、v1请求:获取token3

(1)请求示例:

y: 30 x: 33 aid: dx-1547997910506-78792589-1 sid: 75dc20f81b2bd0ff871b9f12e54ef2c8 jsv: 1.3.11.98 c: 5c448ee09pUgUAwgiaRMmhhDea79K4O1B7oQhRh1 ak: 5f6727ec854786a86cd4c3c171d13499 ac: 492#X8Xn8AQv/Y6pdvgYXXfOuMffR/W3XjVgMOYfQntkaQbRZ/smuRlFpvD6L+qHM21JPdOjXTgzLGKauxS0c29jXCAeYaTRl589z9Ug+vZ1YDXIBNwrm8X1k6vEf3rKmrXmS2WXmFPMgH3nXX8XXXXmY8XEJ37H/cWc68WnDdW+DXSjXtXZj9c6v33n6aa6W9bhYu/c8XIXui83m5U1gFUJzxqJzxoGUqNSYXpFY2Xio3O5Ja/dw/NP2X5X3oFjcWf2r9znqaJQ2LQr7homIr5X3oFPjnXMr9znqaJQ2LQr7homIr2XsBHwJhSSRygCnh3ufTc1v/8V8YZsiz/D4raoj9XLRtOYv9a53D2kZcWV8YcHUAa/mrXmS25X3oFPjvS2r9znqaJQ2LQr7homIr5XjoFPjvrMr9DIGaUiwYmYYrXslqs+7bRz2kEuonW=

(2)返回示例:

{"success":true,"token":"37AD877DC3953CA1116E487DFBF6DB435DFE7C4CD204B8DC861D5857BE2FDDCF4565648C95BAFD15030AA555713B5DA1FD5D57C82427F4C7D222E5990F47AB83B3F13ED08965032CFF26FA37B82012FF","msg":null,"tp":null,"sv":null,"retry":0}

返回token则表示成功。但注意此时token未必有效,如果c1请求使用appKey与v1请求使用的不同,是无法通过check校验的。

4、check

在获取token之后会通过check接口,进行token时效性与正确性校验。使用方通过调用顶象的open api进行token校验。通过则说明,验证码完成。

五、部分服务化源码

greenseer.js部分服务化代码

function getParamUa(sid, position, referer, browserVersion) {
    var _ua = "";
    var ua = "";
    var tm = new Date().getTime();
    delete require.cache[require.resolve('../builder/dingxiang_greenseer_finish.js')];
    var encryptionFunc = require('../builder/dingxiang_greenseer_finish.js');
    var replace_encrypt = encryptionFunc.replace_encrypt;

    delete require.cache[require.resolve('../builder/dingxiang_version_finish.js')];
    var versionFunc = require('../builder/dingxiang_version_finish.js');
    var replace_version = versionFunc.replace_encrypt;
    let mouseMove = buildMouseMove(position);
    let mouseMoveEvent = buildMouseMoveEvent(mouseMove);
    let mouseDownEvent = buildMouseDownEvent(mouseMoveEvent);
    app = function (u, c) {
         ....
        ua.replace("xxxxxxxxx", "");
    }
    process = function (t) {
        var c = [].slice.call(arguments);
        return t = c.length === 1 && (0, isArray)(t) ? t : c, t = (0, flatten)(t), (0, toStr)(t)
    }
    getTM = function () {
        var a = process((0, replace_bs8)(tm));
        app(1, (0, replace_encrypt.encryptTM)(a))
    }
    //浏览器版本
    getBR = function (browserVersion) {
        ....
        app(2, (0, replace_encrypt.encryptBR)(a))
    }
    //屏幕信息
    getSC = function () {
        ....
        app(3, (0, replace_encrypt.encryptSC)(n))
    }
    //网址
    getLO = function (referer) {
         ....
        app(4, (0, replace_encrypt.encryptLO)(i))
    }
    //函数
    getCF = function () {
        let cfParam = buildCFParam();
         ....
        app(5, (0, replace_encrypt.encryptCF)(s))
    }
    //是否开启控制台
    getDI = function () {
         ....
        app(6, (0, replace_encrypt.encryptDI)(a))
    }
    //检测是否使用webdriver等方式抓取
    getEM = function () {
         ....
        app(7, (0, replace_encrypt.encryptEM)(s))
    }
    //版本
    getJSV = function () {
         ....
        app(8, (0, replace_encrypt.encryptJSV)(o))
    }
    //token
    getTK = function (sid) {
         ....
            app(9, (0, replace_encrypt.encryptTK)(a)))
    }
    getMM = function (mouseMove) {
        var v = mouseMove.eventName
            , h = mouseMove.tm
            , d = mouseMove.x
            , p = mouseMove.y
           ....
        this.app(11, (0, replace_encrypt.encryptMM)(l))
    }
    getMD = function (mouseDown) {
        var f = mouseDown.eventName
            , s = mouseDown.button
            , v = mouseDown.tm
            , h = mouseDown.x
            , d = mouseDown.y
             ....
        this.app(12, (0, replace_encrypt.encryptMD)(p))
    }
    var _sa = [];
    recordSA = function (mouseMove) {
        var i = mouseMove.tm
            , u = mouseMove.x
            , c = mouseMove.y
             ....
        _sa.push((0, replace_encrypt.encryptSA)(f))
    }
    sendSA = function (r) {
        this.app(17, r);
    }
    sendTemp = function (t) {
        var n = process((0, replace_bs2)(t.length), (0, replace_bss)(t));
        app(10, (0, replace_encrypt.encryptTEMP)(n))
    }

    var tm = getTM();
    var br = getBR(browserVersion);
    var LO = getLO(referer);
    var CF = getCF();
    var DI = getDI();
    var EM = getEM();
    var JSV = getJSV();
    var TK = getTK(sid);
    var SC = getSC();
    var MM = getMM(mouseMoveEvent[mouseMoveEvent.length - 1]);
    var MD = getMD(mouseDownEvent[0]);
    var DI = getDI();
    for (let mveIndex = mouseMoveEvent.length - 2; mveIndex >= 0; mveIndex--) {
        var MM = getMM(mouseMoveEvent[mveIndex]);
    }
    for (let mvIndex = mouseMove.length - 1; mvIndex >= 0; mvIndex--) {
        var SA1 = recordSA(mouseMove[mvIndex]);
    }
    for (let saIndex = 0; saIndex < _sa.length; saIndex++) {
        var SA2 = sendSA(_sa[saIndex]);
    }
    var temp = sendTemp(position);
    return ua;
}

Java服务化代码

@Override
    public CrackResult crackDingXiang(DingXiangParam dingXiangParam, Integer captchaType, String caller) throws IOException {
        Preconditions.checkNotNull(dingXiangParam, "crackDingXiang dingXiangParam is null");
        Preconditions.checkNotNull(StringUtils.isNotBlank(caller), "caller is null");

        String userAgent = HeaderBuilder.buildChrome();
        String browserVersion = getBrowserVersion(userAgent);
        dingXiangParam.setUserAgent(userAgent);
        //Lid请求
        String lidResult = getDingXiangLidFunc(dingXiangParam);
        dingXiangParam = changeDingXiangParam(dingXiangParam, lidResult);
        //C请求
        String cFunctionResult = getDingxiangCFunc(dingXiangParam);
        CFunctionResponse cFunctionResponse = buildCFunctionResponse(cFunctionResult);
        AFunctionParam aFunctionParam = buildPictureRequestParam(cFunctionResponse, dingXiangParam);
        //A请求
        String aFunctionResult = getDingXiangAFunc(aFunctionParam);
        AFunctionResponse aFunctionResponse = buildAFunctionResponse(aFunctionResult);
        //分析图片
        PictureAnalysisParam pictureAnalysisParam = buildPictureAnalysisParam(dingXiangParam, aFunctionResponse, browserVersion);
        String pictureAnalysisResult = analysePicture(pictureAnalysisParam);
        PictureAnalysisResponse pictureAnalysisResponse = buildPictureAnalysisResponse(pictureAnalysisResult, pictureAnalysisParam);
        //V请求
        VFunctionParam vFunctionParam = buildVFunctionParam(pictureAnalysisResponse, aFunctionParam, aFunctionResponse, dingXiangParam);
        List<NameValuePair> vFunctionPostParam = buildDingXiangVFuncPostParam(vFunctionParam);
        String vFunctionResult = getDingXiangVFunc(vFunctionPostParam, dingXiangParam);
        VFunctionResponse vFunctionResponse = buildDingXiangVFuncResponse(vFunctionResult);
        CrackResult crackResult = buildCrackResult(vFunctionResponse, cFunctionResponse, dingXiangParam, captchaType);

        return crackResult;
    }

六、服务化关键

1、图片还原

极验完整流程
极验完整流程

2、随机加密算法解析(重点设计部分)

加密算法会随着js混淆的改变而改变,如何服务化?

极验完整流程
极验完整流程

(1)语法树思路

极验完整流程
极验完整流程

(2)举例子

(1)未处理的index.js。

极验完整流程
极验完整流程

(2)创建模板并生成其语法树。

极验完整流程
极验完整流程

(3)将加密算法转化成语法树-> 与模板语法树结合 -> 生成新的语法树 -> 生成新的js文件

极验完整流程
极验完整流程

(4)启用定时任务,每天固定时间去生成新的加密算法js文件。

七、成果

极验完整流程
极验完整流程

八、顶象无感验证流程

(1)顶象无感验证流程图

极验完整流程
极验完整流程

(2)顶象风控流程图

极验完整流程
极验完整流程

九、总结

(1)顶象相对于极验产品设计更加清晰。步骤非常明确 "设备数据->行为数据->验证";

(2)通过每日更新混淆js文件、加密算法提升破解服务化难度;

(3)通过验证码下发策略,进行验证码种类变换,提升验证码识别难度;

(4)验证码产品创新能力强,例如:空间语义验证、乱序拼图验证、面积验证、旋转验证等;

(5)整体而言,顶象对于验证码的理解应该是业界领先的。

十、最后

1、目前国内在安全产品方面的文章较少,我们很难全面了解与学习安全产品,希望我的文章能够帮助到更多人。

2、如果想系统地了解第三代验证码,可以结合我的另几篇篇文章
(1)《第三代验证码研究》https://www.cnblogs.com/boycelee/p/11363611.html(推荐)

(2)《顶象验证码破解与研究》https://www.cnblogs.com/boycelee/p/14269941.html(推荐)

(3)《极验验证码破解与研究》https://www.cnblogs.com/boycelee/p/14021048.html(推荐)

(4)《极验无感验证破解》https://www.cnblogs.com/boycelee/p/13951819.html

(5)《同盾小程序指纹破解》https://www.cnblogs.com/boycelee/category/1819211.html

3、本文不提供完整解决方案和完整数据,仅用于理论研究,维护网络安全,人人有责。

标签:顶象,请求,极验,replace,var,验证码,test
来源: https://www.cnblogs.com/boycelee/p/14445765.html