挖洞遇到验证码那些事
本帖最后由 wangguang 于 2023-7-13 21:26 编辑# 前言:
好无聊啊!!!前段时间去网吧打暑假工,说是干前台的,结果去上班了是干外场搞卫生的。50块一天把我当狗使!我真的是会谢。然后现在在家躺尸。最近也在研究滑块,也想着自己写一个滑块玩玩。当然不可能写出极验数美易盾那种安全公司的验证码。于是我便去想着去研究一下某些网站的自研验证码。看看他们的代码怎么写的。不过好像都是假验证码偏多(防人不防ai)大多小型网站都存在验证码重复使用漏洞和客户端验证码绕过漏洞。写这篇文章也是在安全方面分析验证码和过掉验证码。
# 网址:
aHR0cDovL3d3dy54aW5neGluZ3R1YW4uY29tLw==
某相似网站。疑似分站:aHR0cHM6Ly93d3cudXU1NXUuY24v
温馨提示:网站上面的东西不可信(如若被骗,与作者无关)。本文章仅供学习交流使用,切勿用于违法用途。未经授权切勿进行非法肾透!
# 正文:
## 验证码数据包和图片数据包分析:
在登录界面输入账号密码登录,会弹出一个滑块验证码
)
刷新验证码,服务器传下来两个数据包
![](C:\Users\wg\AppData\Roaming\marktext\images\2023-07-08-15-41-15-image.png)
第一个数据包是一张背景图
此刻应该有疑问—>缺口图呢(被六花吃掉了)
我就是因为他没有缺口图所以才觉得这个验证码存在可重复利用的漏洞,我的分析是他在前端做了校验,只有缺口对齐了才发送那个识别成功的数据包。然后后端没有校验,便导致了这个漏洞的产生。不过更多的原因还是因为后面参数分析的时候发现他许多参数都加了随机数。
第二个数据包是验证码的数据包,有两个参数type跟randstr。type是验证码类型,randstr见名知意都知道是随机字符串的意思。至于他是随机的嘛,完全可以写固值的。不过我们还是去扣一下他代码吧。
### 验证码数据包参数randstr
直接在search搜索参数名randstr
在58行下断点,刷新验证码。
randstr是由i方法参进去了一个$_x生成的。
直接搜索$_x。
$_x是由n方法传进了t和e参数生成的。
经过多次刷新,t和e是固定值。t是73,e是207。
那么就去扣n方法的代码
把断点下到50行,刷新验证码,进入到n方法内部。
看到这熟悉的一幕我便知道这个参数可以写固定了。
n方法代码:
function n(t, e) {
return Math.round(Math.random() * (t - e) + e)
}
刷新验证码让断点跳到58行,进入到i方法内部
i方法内部调用了两个方法,n方法和o方法
进入i方法内部的时候下面两个方法就是n方法和o方法,一并扣下来。
i($_x)代码:
```
function n(t, e) {
return Math.round(Math.random() * (t - e) + e)
}
function i(t) {
var e = n(11, 40)
, i = n(11, 40);
return e + "" + o(e) + t + o(i) + i
}
function n(t, e) {
return Math.round(Math.random() * (t - e) + e)
}
function o(t) {
for (var e = "", i = 0; i < t; i++)
e += String.fromCharCode(Math.floor(26 * Math.random()) + "a".charCodeAt(0));
return e
}
var $_x = n(73,207)
function randstr(){
return i($_x)
}
```
py请求代码
```
import requests
import execjs
context = execjs.compile("""
function n(t, e) {
return Math.round(Math.random() * (t - e) + e)
}
function i(t) {
var e = n(11, 40)
, i = n(11, 40);
return e + "" + o(e) + t + o(i) + i
}
function n(t, e) {
return Math.round(Math.random() * (t - e) + e)
}
function o(t) {
for (var e = "", i = 0; i < t; i++)
e += String.fromCharCode(Math.floor(26 * Math.random()) + "a".charCodeAt(0));
return e
}
var $_x = n(73,207)
function randstr(){
return i($_x)
}
""")
# 调用 JavaScript 函数并获取结果
randstr = context.call("randstr")
params = {
'type': 'slider',
'randstr': randstr
}
response = requests.get(
'http://www.xingxingtuan.com/wp-content/themes/zibll/action/captcha.php',
params=params,
)
print(response.text)
```
请求成功截图
## 验证码校验数据包分析
网站每次校验失败只返回图片数据包跟captcha数据包。只有自己手动过了验证码才会返回校验验证码的数据包,这个网站对轨迹检测不严格,收集几个轨迹可以用很多很多次数。一些参数过了一定时间继续使用会触发风控。
验证码通过返回admin-ajax数据包
返回值可以证明这个数据包就是验证码校验成功之后的登录数据包。
参数很多,如下:
```
username: cascas
password: scasc
captcha_mode: slider
remember: forever
action: user_signin
captcha: 33xpdvpejvjsvksowalyuzjaidmmvkzekcn200xajmvkfujwnxdakymyeocxaakjefcalhhbqgyo38
captcha: 83975a14a5dd633223
captcha: true
captcha: 65907ab379c6ecd66f434c82adbd5f08
captcha[]: 1
captcha[]: 1
captcha[]: 1
captcha[]: 1
captcha[]: 1
captcha[]: 1
captcha[]: 1
captcha[]: 2
captcha[]: 5
captcha[]: 7
captcha[]: 8
captcha[]: 9
captcha[]: 9
captcha[]: 9
captcha[]: 9
captcha[]: 9
captcha[]: 9
captcha[]: 9
captcha[]: 9
captcha[]: 9
captcha[]: 8
captcha[]: 7
captcha[]: 7
captcha[]: 7
captcha[]: 6
captcha[]: 5
captcha[]: 5
captcha[]: 5
captcha[]: 5
captcha[]: 5
captcha[]: 5
captcha[]: 5
captcha[]: 5
captcha[]: 6
captcha[]: 6
captcha[]: 6
captcha[]: 6
captcha[]: 6
captcha[]: 6
captcha[]: 6
captcha[]: 6
captcha[]: 6
captcha[]: 6
captcha[]: 6
captcha[]: 7
captcha[]: 7
captcha[]: 8
captcha[]: 7
captcha[]: 7
captcha[]: 6
captcha[]: 0
captcha[]: 0
captcha[]: 0
captcha[]: 1
captcha[]: 2
captcha[]: 2
captcha[]: 4
captcha[]: 5
captcha[]: 6
captcha[]: 8
captcha[]: 9
captcha[]: 11
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 12
captcha[]: 13
captcha[]: 13
captcha[]: 13
captcha[]: 13
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 13
captcha[]: 13
captcha[]: 13
captcha[]: 1
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 2
captcha[]: 3
captcha[]: 4
captcha[]: 5
captcha[]: 5
captcha[]: 6
captcha[]: 6
captcha[]: 7
captcha[]: 7
captcha[]: 8
captcha[]: 9
captcha[]: 9
captcha[]: 9
captcha[]: 9
captcha[]: 9
captcha[]: 9
captcha[]: 10
captcha[]: 11
captcha[]: 12
captcha[]: 13
captcha[]: 13
captcha[]: 13
captcha[]: 13
captcha[]: 14
captcha[]: 14
captcha[]: 14
captcha[]: 15
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 16
captcha[]: 17
captcha[]: 17
captcha[]: 17
captcha[]: 17
captcha[]: 17
captcha[]: 18
captcha[]: 18
captcha[]: 18
captcha[]: 18
captcha[]: 18
captcha[]: 18
captcha[]: 18
captcha[]: 18
captcha[]: 18
captcha[]: 18
captcha[]: 18
captcha[]: 19
captcha[]: 19
captcha[]: 19
captcha[]: 20
captcha[]: 20
captcha[]: 20
captcha[]: 20
captcha[]: 20
captcha[]: 20
captcha[]: 21
captcha[]: 21
captcha[]: 21
captcha[]: 21
```
captcha参数就是缺口加密。
captcha参数与captcha验证码数据包返回的randstr值有关,生成这个参数需要获取captcha验证码数据包返回的randstr值。
captcha参数是captcha验证码数据包返回的check值
captcha是个固定值
captcha[]就是轨迹。
在Initiator界面可以看到js代码除了jq便是slidercaptcha文件。进入到slidercaptcha文件里面。
一进入到函数内部就看到几个关键字。
这几个参数前两个参数都是随机生成的,完全可以写固值的。但是这个网站对于这几个参数有时间限制的,大概多少多少时间就会失效。如果用了过期的参数就会触发风控!但是短时间内使用固值完全可以的!
### captcha参数:
这个i方法跟验证码captcha数据的i方法是同一个的。
t.distance就是缺口识别的x值,他都没有图我们怎么识别缺口呀,由于这个ticket是随机值,即使我的缺口给的是固定值,他也是会变化的。我便把缺口写固定了。
### captcha参数:
randstr是由这段a + "" + o.substring(a, r) + r代码生成的。
a和r都是由n方法传进了两个数字生成的。n在上面已经扣过了,就是生成随机值的方法。
o是第一个验证码数据包captcha的rand_str值。用py爬取导入就行了。
## 结尾:
这个漏洞其实危害还是比较低的,因为他还是得逆向出来那几个值才能一直过滑块。
不逆出来的话会使用过期的参数会触发风控。当然不逆出来这个滑块验证码也可以短时间重复利用的。至于更多的细节我都录进视频里面了。
第一次录视频蛮紧张的,只录了一半。太紧张了,有点口吃。
视频链接:
[挖洞遇到验证码那些事](https://b23.tv/3SBgpHY)
温馨提示:未经合法授权不得进行非法肾透。 本帖最后由 mfvpnhaha 于 2023-7-19 17:47 编辑
那这样说的话,小程序是否可以使用这样的思路来分析滑块?,但是小程序没有F12调式咋看代码啊 学习了,感谢分享。 感谢分享
学习了,感谢分享 楼主也是人才,大好的青年去当网吧服务员。。。 谢谢你!! 网站被大佬玩坏了{:1_918:} 所以老板看到这个帖子还会让搞卫生嘛 方法内部必须要打断点还是啥 看到请求截图成功后面看不下去咯 谢谢分享 厉害了 又看到了一种新的思路
、