声明
本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!
本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请在公众号【K哥爬虫】联系作者立即删除!
逆向目标
-
目标:某验三代滑块验证码,底图还原及 w 参数逆向
-
验证码 demo 列表:aHR0cHM6Ly93d3cuZ2VldGVzdC5jb20vZGVtby8=
-
滑块验证码:aHR0cHM6Ly93d3cuZ2VldGVzdC5jb20vZGVtby9zbGlkZS1mbG9hdC5odG1s
-
加密算法:RSA、AES、MD5
验证码流程分析
进入网页后,打开开发者人员工具进行抓包
1.未点击按钮进行验证之前,Network 中抓包到了以下信息:
- register-slide?t=xxx:
注册滑块请求,响应预览中返回的信息中重要的是 gt 和 challenge,gt 是固定值,不同网页对应不同的 gt 值,类似于特征码,challenge 的值每次刷新页面都会变化,gt 参数会通过 url string 的形式传递给 gettype.php:
- gettype.php?gt=xxx&callback=xxx:
获取验证码,HTTP 请求中不同的请求方式和设置不同的 Content-Type 时,参数传递的方式会不一样,一般为 Query String Parameters、Form Data、Request Payload,这里是 Query String Parameters,在 GET 请求时,参数会以 url string 的形式进行传递,即 ? 后的字符串则为其请求参数,并以 & 作为分隔符,这里传递了 gt 参数的值以及 callback,callback 为 geetest_ + 时间戳:
响应预览中返回了一些 js 文件及对应的版本号:
-
第一个 get.php?xxx,url 中传递了一些参数,关键部分如下:
- gt:register-slide 响应返回的 gt 值
- challenge:register-slide 响应返回的 challenge 值
- w:对轨迹、滑动时间等进行加密后的参数,该网站第一个 w 值可以直接置空
- callback:geetest_ + 时间戳
响应内容如下,这里没什么需要注意的,feedback 就是某验的帮助中心:
2.点击按钮进行验证之后,Network 中抓包到了以下信息:
-
第一个 ajax.php?xxx,url 中传递了一些参数,关键部分如下:
-
gt:register-slide 响应返回的 gt 值
-
challenge:register-slide 响应返回的 challenge 值
-
w:对轨迹、滑动时间等进行加密后的参数,该网站第二个 w 值也可以直接置空
-
callback:geetest_ + 时间戳
响应返回验证码模式,滑块验证码为 slide,点选验证码为 click:
-
-
第二个 get.php?xxx,url 中传递了一些参数,关键部分如下:
- gt:register-slide 响应返回的 gt 值
- challenge:register-slide 响应返回的 challenge 值
- callback:geetest_ + 时间戳
这个响应返回了很多关键内容:
- bg:被打乱的带缺口背景图,需要还原,372fe236d.webp
- fullbg:被打乱的完整背景图,需要还原,7bfaaa72b.webp
- slice:滑块图片,不需要还原,372fe236d.png
- c:关键参数,与后面 aa 参数的值有关,固定值
- s:关键参数,与后面 aa 参数的值有关
-
第二个 ajax.php?xxx,url 中传递了一些参数,关键部分如下:
- gt:register-slide 响应返回的 gt 值
- challenge:register-slide 响应返回的 challenge 值 + 两位字符串,注意多了两位,是第二个 get.php?xxx 返回值中得到的
- w:对轨迹、滑动时间等进行加密后的参数,需要通过逆向得到
- callback:geetest_ + 时间戳
滑动滑块验证通过即会返回以下内容:
失败则会返回:
逆向分析
w 参数
跟到 w 参数的值方法很多,以下讲两种:
1.很简便,w 参数在 js 文件中有特征码,点击按钮进行验证之后,ctrl + shift + f 全局搜索 "\u0077",然后点击进入 slide.7.8.9.js 文件中,7.8.9 为当前版本,注意没点击验证的话是不会有这个 js 文件的:
进入后点击左下角 { } 大括号,格式化文件,再 ctrl + f 局部搜索 "\u0077",只有一个结果,在第 6086 行,在第 6088 行打下断点,滑动滑块即会断住,h + u 即为 w 参数的值:
2.通过 Initiator 跟栈,跟进到 $_CId 中:
进去同样格式化后,会跳转到第 4583 行,在该行打下断点:
向上跟栈到 $_CCBv 中同样会找到刚刚的位置:
由以上分析可知,w 参数是 h 和 u 相加得到的,所以找到定义的位置,看看是怎么构造生成的,u 参数定义在第 6077 行,h 参数定义在第 6079 行,内容如下:
var u = r[$_CAIAt(754)]()
, l = V[$_CAIAt(353)](gt[$_CAIAt(218)](o), r[$_CAIAt(756)]())
, h = m[$_CAIAt(782)](l)
可以看到,h 参数是传入了 l 参数后经过 m[$_CAIAt(782)] 方法处理后得到的,所以依次往下分析,现在看看 u 参数是怎么生成的:
u 参数
u 参数通过 r[$_CAIAt(754)] 方法生成,选中后跟进到方法定义位置:
会跳转到第 6218 行,在 6227 行 return 处打下断点,重新拖动滑块,即会断住:
e 为 u 参数的值,其定义在第 6266 行:
e = new U()[$_CBGAZ(353)](this[$_CBGAZ(756)](!0));
在控制台中打印输出一下各部分内容:
e = new U()["encrypt"](this["$_CCEc"](!0));
从打印出来的结果可以看出,e 参数的值可能是将 16 位的随机字符串加密后得到的,跟进到 this[$_CBGAZ(756)] 中验证一下:
跳转到第 6208 行,在第 6214 行 return 处打下断点:
Ot 即 16 为字符串,Ot = rt(),跟进到 rt 函数中,在第 4213 行,于第 4219 行打下断点后会发现,16 位字符串是由四个 t() 方法的结果相加得到的:
跟进到 t() 方法的定义位置,在第 4203 行,第 4208 行即为随机字符串算法:
还原混淆后内容如下,Math.random() 是随机选取大于等于 0.0 且小于 1.0 的伪随机 double 值,toString(16) 为十六进制字符串:
(65536 * (1 + Math["random"]()) | 0)["toString"](16)["substring"](1)
java script 复现:
function random() {
var ran