极验滑动验证分析

本文只做分析,不提供任何源码。
对应的版本是fullpage.9.0.3.js,slide.7.7.7.js
这是最终的结果

90以上的正确率
网站的地址

aHR0cHM6Ly93d3cuZ2VldGVzdC5jb20vZGVtbw==

进入网站

我们要弄的是滑动模式-float
点击进入,演示一下全过程

可以看到network里面的请求,除去资源链接,像js,png,webp,css的加载不用管,滑动验证用到的链接有六条

这六条链接分别是干啥的呢
第一条:返回gt,challenge的,后面的链接都有用到
第二条:返回页面要加载的资源文件的
第三条:收集浏览器相关的信息上报,重点关注w参数
第四条:无感验证,上传浏览器信息,鼠标信息,这里也是w参数,不过生成办法略有不同
第五条: 返回滑块图片的地址,新的gt,challenge,第六条会用到的c,s参数
第六条:上传轨迹信息,也是w参数,加密方法和第三条的相同,加密前参数不一样。成功会返回validate

所以我们要做的就是模仿这六条链接,让它返回正确的值。
这样看来,事情还是看的到头的。
所以少年,按照这个步骤来,坚持下去,终会成功的。
下面我们逐条分析:

第一条:

https://www.geetest.com/demo/gt/register-slide?t=1617549357297

很明显t是个时间戳,伪造一下就可。
成功后返回gt,challenge

{"success":1,"challenge":"0f41739d7a9e789ab204d05b9db51ea2","gt":"019924a82c70bb123aae90d483087f94","new_captcha":true}

第二条

https://apiv6.geetest.com/gettype.php?gt=019924a82c70bb123aae90d483087f94&callback=geetest_1617549360375

gt,challenge是第一条的返回的,callback后面也是一个时间戳
返回的是资源文件的路径,貌似没啥用,不用管。

第三条

https://apiv6.geetest.com/get.php?gt=019924a82c70bb123aae90d483087f94&challenge=0f41739d7a9e789ab204d05b9db51ea2&lang=zh-cn&pt=0&client_type=web&w=W2tongI6fSZnPuFuElQ8dsEEx7uAFxMLdffsUF)NLo5S97UXVxcs0c7)vrynm0DAGJxa3ha1C(mspAn)PfWMGTO5rIBlXzSElo57DMsEOndVWx4waJbvFdjRtkUZ7EmsqIZiQDvPpTFe1PRweAwgZDMcs4bMY8j16mkGCw37hmU)h86CfP2TmVfc5XcoIzPVegZlQfEnLEWxw1LxPmODIsWL0iWlG6Shcbohva700fj7V(58BQunDwnx8Isj1MMUKGPMbcf24y9vlIgTZAiJ1Y7QbY06g0Mn20(xF(ytFrXxobQw2hIku7jAxa8TBF2KCqPEjaRlGryWeIqRv)6SEbHE9JujmRSldjmavqDcNetmJYoz9k(LWv3QFrvQt7fV4mrG4)fkBAlDZP5Zrp30yNyD9f(4upM3JD1nEtEkwkZDgC3cJGb)x)OtaHaE6oifTNZBf5bgRKvckuFY4q5oXYT5smS2Ks5k1gCJWrd02jqKK4psfb1O)uYtVKWEigBFja9GhcKcB(8aRcFmkIlb(5xljGB5FVrc9jb4R5J6Iip4(jqZ4xFymb25lBr3YDbUY8vLGnQH7tX35FRQs84YkAmbN2hr6XXEm7k3ui)dbtqTYnrcAtX1siGAiSeK(Gy3iUHgitqasULeHsMsufeMX0OT19Ohou6tV1hLipakI2R5jEqMC(NEuWsLfST0Hi3jkjgBu8j33YX(Kk3YtX8Q4DQt503I9kRNKPGvbfnyriw9WnMhtkMDGAonsp0Hgy)qo3ihT7(xJh3or((xU(0lm6ZURDtJd)tSubIClPLeRSiJ4y3tFnbRt4uEwH7QU5fmhXzBphTvOK6gr0FZxvEpWHllrlwDsOrHeZIT(PnqnfBAzuzdLDIl6ohL(Xlpe5luUYH0bp1IcC13TBT)lj1Fgsfjf(l3bMThEoB9hSB7C3JNeuAZyyOBgV7BebvdLBqnDPskPZVVPREKE8NYtlUGIaLFHMTsKUHgogZFL8lw8BH6C6cinfswXQNGui21qJFo5BPyVzqEMHpJXpjg3Q2JWxC33fgxf67DQW)Gx1p9Cje26lXPw1svSDCv1WXGmxDcwPYEEjM3KuvdGvry(P6LWpwMrZBwjb2CQW6x17FRugdpufa17o(JhzNuWqRoltG7YybNODitdG8YaK7UWZ3QkF29ohra8Ub6UqKJdOpEJM6Bvk5Hudo0aVxulFoJZYh(7sNhYULO7lqktvfmnxasKzix7pv4DTno2rSp7Cth7IPOY1fLoYzOGLXsAy9qsTU(4wDQmfDoGbxSYr1U()T)Tg)cMnUZIsVtUSdVsl1LfJVYGTwEWsPf(DW(N8I6fHWiPQxUltIbEg2FDCMNIqbCw2FCKqxweHD6HKX0AVC4Sm1j0)L9rh(lIQz24eK8)EekKl7QuriSNWjIxZhStfASm(GUuaJCg9mkE3BgSM4)ef468yO8uzhFA1F(0QQm)oxTrV(jdaemkj5NxzZVHyZaaRxWsI5AnDD1rqGtBnjt6G2bkUqlTD0sMEOpviw53ZsZyS6)WqBJLpItsR1zmgPxABcKi1pOkzk0equ(QK3)aRgLLCGd1ix2A5xkONbS7CxUkRaQhw5jojYTqOZt4vtGnpVJFjEk2bLzhzEw(Ao9ir(b2)c)YrDyCH8xMPssp9(VgQR5MgrMR4PNkZPCtJGKjdSQu2z6H9cv9r(BEZ1WWDPK1x64noKkW6ydUwHp(dQONNaYKGU7PDRjYXwfxNKRGVZjXTb9DXTWnTShBsboral6ssmF9jKcbsnIFrFVhtsTHyHkwX6XgYngiBb4DHQqhWV8kVy09SDWiFFF7A0X(1fvSHi0127xFh4NmhY954KZUHM0Lsx0Up8lG)mx8pd9CGT5sNg1jN19mGdVAHIcVrGLsqTO6n7OJLUk6XsnqXt6T9z44g)wkAefIZVkOOjCKf3nFGXCcL0KXSP)g5gYnN)5QEuZf3HAqzrO0ak5cxSZVOaWdDPee0utdDCaSXXz)yNawI6C)we41AMu7HhRphRtDhkD9DtRAd1wyJKrvOYDnJljzwjeFTHyHNBfVAsPdAG3NUd6mhgdH0cJAwxWw11)Df97ACUfi7lOEQoZW8)pPO6u6oSxfFnHOosSbDMcmwrGpSHPgPMRnmXhOnZ0zYARynP1kiHiGitqYrOXJhlLBkhLGBGxG85qQ7UOrYwUeqjxUSWwQBvTdKEo05z5eoJhwcLIZEx1yTo9awkp84xmiZ6LUinJ2PYaVAVFedxFtUaKDQALn3mOImveW7vlTdFnTd4lIolW0fXvlLlvshvmARZHC8R2R(ytXwvmSwE3s)TGiiDDAKtMq5pkJ)7GPpfxMOFr53ViT4EisFL(s0jxkuKTpL3brWAUFdxvL20JzEfZE9V9x5DoL9teO7OvbuNFgZez7TNCIJylaPbxbSNimaXv)NMyjKDDLZLLNfgrbMkjlG7Atcfxkgxk3sG3cdQvz5BZdnGVHaJsjyFq(mbaaeb2dfb1fcec7ca5215ba886fd83a25cc494e736ac38c8c1b5612929afb5542ce2c0855421663e3148e1ef8c2a4d12baeb362cf3d8ffcdf76e0f72e38b01b895f4792eb9c2c4feb845314b8f15bf22afe616aca9daa299f21dde5390d6bb60d71e954d1dfc3c5cef38aa66e5a3d09ab8fdf134f2e1810b6ca43a9ff37aaa6c97&callback=geetest_1617549361263

里面的关键参数w
我们怎么找呢
正常是用搜索大法看看能不能搜出来
但我可以很确定的告诉你搜不出来
那就追追堆栈吧

这里的调用顺序是从上往下的,我一般习惯跟带有anonymous关键字的,这五个都点进去,打上断点。
重新加载一下页面,就会停在我们debugger的某个点,看看它附近有没有可疑的数据,没有就下一个。

上面我们可以发现w参数在那个debugger点前就生成了,在这个函数的开始的第一行打上断点,去掉其他debugger点,再次刷新页面,停在了debugger处,查看callback,往上个函数找。

重复这个步骤,最终会定位到这里

而\u0077就是w的unicode码
接下来就是抠代码操作了,没啥好说的,耐心加细心。
其实浏览器的数据固定就好,把gt,challenge加进去就好,还有就是参数a和n共用的是一个密钥,而且这个密钥是客户端随机生成的,估计是n参数服务端可以解密出来,然后再用解密出来的密钥把a解出来,后面第四条链接也是用的这个密钥,所以第四条链接不用n参数。

w参数伪造成功后,会返回类似下面的数据

geetest_1617613271619({"status": "success", "data": {"theme": "wind", "i18n_labels": {"goto_cancel": "\u53d6\u6d88", "loading_content": "\u667a\u80fd\u9a8c\u8bc1\u68c0\u6d4b\u4e2d", "ready": "\u70b9\u51fb\u6309\u94ae\u8fdb\u884c\u9a8c\u8bc1", "success_title": "\u901a\u8fc7\u9a8c\u8bc1", "error_title": "\u7f51\u7edc\u8d85\u65f6", "next": "\u6b63\u5728\u52a0\u8f7d\u9a8c\u8bc1", "read_reversed": false, "error": "\u7f51\u7edc\u4e0d\u7ed9\u529b", "reset": "\u8bf7\u70b9\u51fb\u91cd\u8bd5", "success": "\u9a8c\u8bc1\u6210\u529f", "fullpage": "\u667a\u80fd\u68c0\u6d4b\u4e2d", "next_ready": "\u8bf7\u5b8c\u6210\u9a8c\u8bc1", "copyright": "\u7531\u6781\u9a8c\u63d0\u4f9b\u6280\u672f\u652f\u6301", "refresh_page": "\u9875\u9762\u51fa\u73b0\u9519\u8bef\u5566\uff01\u8981\u7ee7\u7eed\u64cd\u4f5c\uff0c\u8bf7\u5237\u65b0\u6b64\u9875\u9762", "goto_homepage": "\u662f\u5426\u524d\u5f80\u9a8c\u8bc1\u670d\u52a1Geetest\u5b98\u7f51", "error_content": "\u8bf7\u70b9\u51fb\u6b64\u5904\u91cd\u8bd5", "goto_confirm": "\u524d\u5f80"}, "theme_version": "1.5.8", "logo": true, "s": "322c752f", "static_servers": ["static.geetest.com", "dn-staticdown.qbox.me"], "c": [12, 58, 98, 36, 43, 95, 62, 15, 12], "feedback": "https://www.geetest.com/contact#report", "api_server": "apiv6.geetest.com"}})

第四条

第四条就是用来无感验证的
主要就是w参数,按照第3条的方法来找即可。w参数加密前主要的数据就是轨迹数据,还有一些md5验证,这个无感验证的轨迹,直接取个通过的数据固定就好, MD5的话有3个是对浏览器数据进行md5,直接固定就好,它服务端也验证不了。还有一些md5是根据gt,challenge,passtime来md5的,这些就要按照它的规则来。

伪造成功后返回

geetest_1617614725080({"status": "success", "data": {"result": "slide"}})

第五条

https://apiv6.geetest.com/get.php?is_next=true&type=slide3&gt=019924a82c70bb123aae90d483087f94&challenge=c5954bdcf12e61f80b0c067b60e70b39&lang=zh-cn&https=true&protocol=https%3A%2F%2F&offline=false&product=embed&api_server=apiv6.geetest.com&isPC=true&autoReset=true&width=100%25&callback=geetest_1617614729666

伪造成功后返回

geetest_1617614729666({"link": "", "fullbg": "pictures/gt/d401d55fc/d401d55fc.jpg", "version": "6.0.9", "width": "100%", "static_servers": ["static.geetest.com/", "dn-staticdown.qbox.me/"], "theme": "ant", "theme_version": "1.2.4", "height": 160, "template": "", "type": "multilink", "api_server": "https://apiv6.geetest.com", "gct_path": "/static/js/gct.399e58262da52825b9fb5463cb9ad7cd.js", "benchmark": false, "c": [12, 58, 98, 36, 43, 95, 62, 15, 12], "clean": false, "challenge": "c5954bdcf12e61f80b0c067b60e70b396q", "s": "2c317641", "feedback": "https://www.geetest.com/contact#report", "logo": true, "product": "embed", "https": true, "gt": "019924a82c70bb123aae90d483087f94", "fullpage": false, "so": 0, "slice": "pictures/gt/d401d55fc/slice/cebc1a5ef.png", "ypos": 55, "xpos": 0, "i18n_labels": {"close": "\u5173\u95ed\u9a8c\u8bc1", "logo": "\u7531\u6781\u9a8c\u63d0\u4f9b\u6280\u672f\u652f\u6301", "slide": "\u62d6\u52a8\u6ed1\u5757\u5b8c\u6210\u62fc\u56fe", "tip": "\u8bf7\u5b8c\u6210\u4e0b\u65b9\u9a8c\u8bc1", "refresh": "\u5237\u65b0\u9a8c\u8bc1", "error": "\u8bf7\u91cd\u8bd5", "voice": "\u89c6\u89c9\u969c\u788d", "cancel": "\u53d6\u6d88", "success": "sec \u79d2\u7684\u901f\u5ea6\u8d85\u8fc7 score% \u7684\u7528\u6237", "forbidden": "\u602a\u7269\u5403\u4e86\u62fc\u56fe\uff0c\u8bf7\u91cd\u8bd5", "fail": "\u8bf7\u6b63\u786e\u62fc\u5408\u56fe\u50cf", "read_reversed": false, "feedback": "\u5e2e\u52a9\u53cd\u9988", "loading": "\u52a0\u8f7d\u4e2d..."}, "mobile": true, "bg": "pictures/gt/d401d55fc/bg/cebc1a5ef.jpg", "show_delay": 250, "id": "ac5954bdcf12e61f80b0c067b60e70b39", "hide_delay": 800})

里面有我们要的图片链接
返回的图片是乱序的
网上找了下,有人写好了还原的算法。

import numpy as np
from PIL import Image,ImageChops
import matplotlib.pyplot as plt
def sequence():
    t = 0
    n = []
    e = "6_11_7_10_4_12_3_1_0_5_2_9_8".split("_")

    for r in range(0, 52):
        t = 2 * int(e[int(r%26/2)]) + r % 2
        if 0 == int(r/2)%2:
            t += -1 if (r%2) else 1

        t += 26 if (r<26) else 0
        n.append(t)

    return n

def gen(_seq, _img):
    """
    用于将图片还原
    @param _seq: 图片的序列号,也就是 Sequence 方法生成的结果
    @param _img: 图片
    @return new img
    """
    r = 160
    a = int(r / 2)
    np_image = np.array(_img)
    new_np_img = np.zeros((160, 312, 3), dtype=np.uint8)

    for u in range(0, 52):
        c = _seq[u] % 26 * 12 + 1
        _ = int(a if (25 < _seq[u]) else 0)

        xpos = u % 26 * 10
        ypos = a if (25 < u) else 0

        # var l = getImageData(c, _, 10, a);
        # putImageData(l, u % 26 * 10, 25 < u ? a : 0);
        slice_img = np_image[_:(_+a), c:(c+10)]
        n = len(slice_img[0])
        new_np_img[ypos:(ypos+a), xpos:(xpos+n)] = slice_img

    return new_np_img

# 图片还原
seq = sequence()
img = Image.open('bg.jpg')
newimg = gen(seq, img)
plt.imshow(newimg)
plt.imsave("k3_bg.jpg", newimg)

图片还原后定位到阴影点的x坐标

import numpy as np
from PIL import Image,ImageChops
import matplotlib.pyplot as plt
def compute_gap( img1, img2):
    """计算缺口偏移 这种方式成功率很高"""
    table = []
    for i in range(256):
        if i < 50:
            table.append(0)
        else:
            table.append(1)

    # 将图片修改为RGB模式
    img1 = img1.convert("RGB")
    img2 = img2.convert("RGB")
    # 计算差值
    diff = ImageChops.difference(img1, img2)
    # 灰度图
    diff = diff.convert("L")
    # 二值化
    diff = diff.point(table, '1')
    left = 43
    # 这里做了优化为减少误差 纵坐标的像素点大于5时才认为是找到
    # 防止缺口有凸起时有误差
    for w in range(left, diff.size[0]):
        lis = []
        for h in range(diff.size[1]):
            if diff.load()[w, h] == 1:
                lis.append(w)
            if len(lis) > 5:
                return w
img1 = Image.open('k3_fullbg.jpg')
img2 = Image.open('k3_bg.jpg')
x = compute_gap(img1, img2)

第六条

第六条主要就是轨迹的伪造了
我们要注意的是我们要划的长度是多少

在前面我们算出的x是如图所示的x,而我们要划的长度是:x-滑块和背景图之间的距离
它的轨迹数据是这样的

[[47, 23, 0], [1, 0, 223], [2, 0, 40], [1, 0, 16], [2, 0, 16], [1, 0, 16], [2, 0, 16], [1, 0, 16], [1, 0, 16], [1, 0, 8], [1, 0, 8], [1, 0, 8], [1, 0, 8], [1, 0, 8], [2, 0, 8], [1, 0, 16], [2, 0, 8], [1, 0, 8], [1, 0, 8], [2, 0, 8], [1, 0, 8], [3, 0, 8], [2, 0, 8], [3, 0, 8], [1, 0, 8], [1, 0, 8], [1, 0, 8], [1, 0, 8], [1, 0, 8], [1, 0, 24], [1, 0, 8], [1, 0, 8], [1, 0, 16], [1, 0, 8], [1, 0, 8], [1, 0, 8], [1, 0, 8], [1, 0, 8], [1, 0, 16], [1, 0, 8], [1, 0, 8], [1, 0, 24], [1, 0, 8], [1, 0, 8], [1, 0, 24], [1, 0, 8], [1, 0, 8], [1, 0, 8], [1, 0, 8], [1, 0, 8], [1, 0, 16], [1, 0, 8], [1, 0, 24], [1, 0, 72], [1, 0, 24], [1, 0, 24], [1, 0, 56], [1, 0, 8], [1, 0, 40], [1, 0, 32], [1, -1, 16], [1, 0, 8], [1, 0, 56], [1, 0, 24], [1, 0, 40], [2, -1, 88], [1, 0, 416], [0, 0, 24]]

第一个数据[47, 23, 0]代表的是图中的x,y,0是固定的

后面的数据就是[x坐标的移动距离,y坐标的移动距离,所用的时间]

轨迹主要分3个阶段起始的加速阶段,中间的匀速阶段,后面的调整阶段

我的做法就是,首先记录一段正常的轨迹数据,然后在这个正常的轨迹基础上,按照x的比率缩放这3个阶段的数据。

x不正确的话,会返回

geetest_1617617004437({"success": 0, "message": "fail"})

如果你的x是正确的,轨迹却被检测了,就会返回

geetest_1617268400314({"success": 0, "message": "forbidden"})

如果你的轨迹是正常的,就会返回validate

geetest_1617460258020({"score": "11", "success": 1, "message": "success", "validate": "3b44db3710f32edf21e34cbe3e46a7fc"})

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容