网易易盾滑动验证码破解(下篇)
接着上篇文章,我们在这篇文章中将会介绍,如何获取验证码和token,然后计算验证码缺口距离以及模拟轨迹生成等操作。
获取验证码
先看下获取验证码的请求(get请求):
url=https://c.dun.163.com/api/v2/get?,参数如下:
1 | id: 07e2387ab53a4d6f930b8d9a9be71bdf |
需要动态变化的参数只有fp参数和cb参数,这里cb参数生成方式其实与我们上篇中的cb是一样的,所以重点是fp参数,也就是fingerprint(指纹)。
fingerprint指纹
在寻找fp参数的时候,我是定位到了这个位置(当然也不是一下就找到了,当时还在利用fp参数一直调试找调用栈,至今利用那种方法也没弄清怎么定位到这里,也是一些碰巧的发现让我定位到这里,对于新手你顶多多花点时间反正总是可以找到):

fingerprint就是window.gdxidpyhxde的值,我在代码里找了很久没找到在哪里给window.gdxidpyhxde进行的赋值,身边的大佬告诉我这种window对象要用Hook(钩子)来获取,并且要借助一个名叫油猴插件的工具来完成,这里有一篇介绍这个的文章,大家可以参考下。
安装完插件,按照教程上的操作,添加脚本,编译以下内容:

保存并启用脚本后,然后刷新网页,就能够捕获到window.gdxidpyhxde赋值的地方:

这里有一个有意思的地方需要絮叨絮叨,顺着调用栈可以找到P方法,P方法的参数传进来就是fp,继续查看调用栈发现是Y()方法生成了fp,Y里面又调用了X,X方法时这样的:
1 | function X(e) { |
如果仔细观察,会发现G[u[160]]实际上是这样的值:
1 | __snaker__captcha=oRtq9nvAm0QouuvG; _qddac=3-3-1.1.5i4x48.kd9xulyf; _9755xjdesxxd_=32; __root_domain_v=.163.com; _qddaz=QD.jdy8os.x4rgyl.kd5r5e86; YD20160637306799%3AWM_NI=OI%2B1pcpJjmLWcaLwLFnU7l6Alay87tDl4%2B6%2F4pS4A0beBJoX90bwRdW8WMIzxsaQQDfRrXvTbwsEBjnY7hYtxa1sFTgrCD0ytgx5kixGZsS3rL%2BBjh0sLh5NsKYTSsgAVkw%3D; YD20160637306799%3AWM_TID=y1dRdZ6v4M5FBBVEBEY%2BGoL66uK9h7Y1; YD20160637306799%3AWM_NIKE=9ca17ae2e6ffcda170e2e6eed7ed3ba5ae9cd8fc33ad9e8fa2d45e879a8bbbf144b891fa97b55cfcb4babbef2af0fea7c3b92a8d97e5d2f369b496a68ecf5da1bf8498cf4eae8bf98db54bb0bfb7d9b68088b4fcccb525f8b09dd5c43ca2bb8eabee54fbf0ae98d17095e899aecc72bcadafb2d450a68ebeb9f560a2a9bda6c162ae87f989dc80bcbfff94c560a5ae8da5b373b8b9b8d6ea63bc999694d239b294e5a3e964f4ad8489b846b19597b5d279a59f9a8cf637e2a3; Hm_lvt_4671c5d502135636b837050ec6d716ce=1595489168,1596182503; _qdda=3-1.1; _qddab=3-5i4x48.kd9xulyf; _qddamta_2852175932=3-0; gdxidpyhxdE=0Mvsl573PzyW0pM%2BnVVaI7IjUXbqquQxvm6KroZg4tRV%2B70uYeaA1Q5E0wwZhn0%2FDy%5CuDA2Zte8Mm%2FvlnuKOi%2B%5CzTwEDaqsydVaPNLhAJR17o0vNtHQlCvCf87C5dJ1RlKuOebbgKIWVTVJORAIaQQtrbzdDp62IePWDwDSB%2B%2F88CE7Q%3A1596184305983; Hm_lpvt_4671c5d502135636b837050ec6d716ce=1596184180 |
其实就是cookie,这样就有一个问题,我们本身是获取不到cookie的,这里生成fp居然需要cookie,有点不对劲,其实这里面的逻辑是这样的:因为我们现在操作的页面(在浏览器中)是有cookie的(并且cookie在有效期内),所以生成fp参数的直接利用cookie就可以了,如果我们尝试着清掉cookie以及缓存,再刷新页面,会得到这样的结果:

发现调用栈这边比刚才多了一个W,实际上这才是我们要找的fp参数生成的地方。
有大佬是把W方法更外层一整个方法扣出来,然后自己找了一些DOM对象(这个操作做不来,我选择放弃)。
继续在W()内部研究一会可以发现,h = h + u[7] + p这是fp最后生成的代码

u[7]是冒号,p是一个时间戳,所以fp得格式是这样的:
1 | 60G6u4NNUxBAYgIk2G3wXUckAQ8GEBbbS+U4acoYQs+4ggT3XQRUYRmQQKMdcBvMjM6rrsw8ofKOp7BN3V0nLJjSt5ngLhQ3bkJ38ahyUvzM9R2M+Jbb8IHeUeWjBR3StpJBowR8kbcSs/od47bPIzD+klY46HTmNlm1/yLDqjiLZ+Jv:1611914097232 |
这里把W()方法抠出来,并做一定的调整,在运行的时候缺啥补啥就好了,我这里没细扣,用的同事的
fingerprint的生成方法:
1 | var host = "dun.163.com" |
这个W函数检测了许多有关window属性即浏览器指纹;这里面的一个fp是navigator和canvas等浏览器属性生成的(根据你浏览器版本不同生成的值也不同,可以写死,也可以多生成几个不同的随机切换),另一个h是网站host地址,这里使用时针对不同的网站要更换。
这里指纹的生成其实算比较核心的内容,一开始我以为指纹只影响get请求,实际上如果指纹有问题,还会影响最后的验证。
多说一些这里的扣得过程,根据执行过程中提示的错误,逐个去解决,比如某些变量值(window对象,属性之类的)未定义,那就去浏览器中调试看当前环境下其值什么的,将其替换,一般也不确定是不是定值,但是可以先去尝试。
验证
可以自己生成fp和cb后,我们就可以发送获取验证码的请求了,以此来验证自己生成的fp是否可用。这里发送请求很简单,不详细讲了,如果生成的指纹可用,那么请求将会得到下面这样的返回结果:
1 | __JSONP_vky5mlp_0({"data":{"bg":["https://necaptcha.nosdn.127.net/35167cc10b58441bb714e5b46e2a58fb.jpg","https://nos.netease.com/necaptcha/35167cc10b58441bb714e5b46e2a58fb.jpg"],"front":["https://necaptcha.nosdn.127.net/402fe7eb0c234117b6515f123213cef1.png","https://nos.netease.com/necaptcha/402fe7eb0c234117b6515f123213cef1.png"],"token":"8a5866b867134f8083c98daaad62bf62","type":2},"error":0,"msg":"ok"}); |
缺口计算
缺口计算在我的另一篇图像处理相关的文章中,利用像素值写传统算法和模板匹配都没有取得比较好的效果。所以最后使用深度学习目标检测的方法,最后初步获得了一个准确率在70%左右的模型。
模拟轨迹算法
模拟轨迹这部分主要参考这篇文章:
这里贴一下我写的模拟方法:
1 |
|
实际上并不确定此轨迹生成方法是否可行(理论上再继续优化优化应该是可以的),因为后面易盾出现了watchman检测,因为我不咋想继续搞它了,所以没法完整验证,每次check请求都没有成功,所以就放着了,如果后面有继续对watchman破解,再来更新……
后续补充:后来又搞了一下watchman,经过测试,这里的轨迹算法可用,周围有大佬是利用深度学习训练了一个轨迹生成模型,后面有机会可以尝试下
补充:干扰块的排除
易盾在2.14.1版本中对滑动验证码进行了一个小升级,就是背景图会有两个滑块,类似这样:

也就是增加了一个干扰块,恰巧可以利用小滑块来解决此问题,因为我们可以获取到小滑块的原始图片,小滑块是一个背景透明的png图片

这里我故意采用截图的方式来展示,因为直接看原图很难直接意识到滑块实际的长和宽,因为背景是透明的;使用PIL打开时,模式为RGBA模式,获取像素值返回四个,前三个是RGB值,最后一个是透明度值(0~255),0表示完全透明,255表明完全不透明。易盾这里背景部分的透明度值为0,其他地方的透明度值为255。
所以这里可以利用透明度值获取滑块左上角的坐标,从而排除不在同一水平线的干扰块。
1 | def get_top(response_content): |
这里根据经验,一般都在第二列,所以这里或许可以直接从上到下扫描第二列。