1. 环境
靶场地址:https://portswigger.net/web-security/learning-paths/authentication-vulnerabilities
用户名字典:https://portswigger.net/web-security/authentication/auth-lab-usernames
密码字典:https://portswigger.net/web-security/authentication/auth-lab-passwords
Yakit地址:https://www.yaklang.com/
每次新开的实验环境的用户名密码都是随机的,因此每个人爆破出来的可登录用户名和密码都是不一样的。
2. Lab: Username enumeration via different responses
随意输入一个用户名和密码进行登录测试,可以发现提示”Invalid username”,说明可以对用户名进行枚举:
1 | username={{file:line(D:\Apps\Yakit\Yakit\yakit-projects\temp\tmp3168031194.txt)}}&password=123 |
发送请求后观察响应大小,其中最大的一个响应包为”Incorrect password”,说明这个用户名是存在的:

继续爆破此用户密码:
1 | username=appserver&password={{file:line(D:\Apps\Yakit\Yakit\yakit-projects\temp\tmp1905317715.txt)}} |
唯一的一个302状态码为登录成功的响应:

最终用户名和密码为appserver/computer,成功登录后完成实验:

3. Lab: Username enumeration via response timing
随机输入一个用户名和密码进行登录测试,提示”Invalid username or password.”,无法确认用户名是否存在,但可以考虑通过观察响应时间来进行用户名枚举,因为如果用户名存在,服务器可能会进行密码验证,导致响应时间较长;如果用户名不存在,服务器可能会直接返回错误消息,响应时间较短,同时可以将密码设置长一些,例如100个字符,这样可以延长正确用户的响应时间:
1 | username={{file:line(D:\Apps\Yakit\Yakit\yakit-projects\temp\tmp133041859.txt)}}&password={{randstr(100)}} |

遍历到第四个包后,提示”You have made too many incorrect login attempts. Please try again in 30 minute(s).”,可能是IP被封禁了,可以尝试伪造请求IP:

为了让每次请求的IP都不一样,还需替换127.0.0.1为随机字符标签 {{randstr}},渲染模式选择”草叉/同步”:

对响应时间最长的用户名进行爆破:

得出用户名和密码为agent/tigger,成功登录后完成实验。
4. Lab: Broken brute-force protection, IP block
直接对目标用户carlos进行密码爆破:
1 | username=carlos&password={{file:line(D:\Apps\Yakit\Yakit\yakit-projects\temp\tmp2380983918.txt)}} |
超过三次直接提示”You have made too many incorrect login attempts. Please try again in 1 minute(s).”,说明IP被封禁了,尝试伪造请求IP,还是无效,说明服务端是根据真实IP进行封禁的,不依赖于请求头中的IP。
因为题目给了我们一个可用的凭证wiener:peter,可以考虑,如果成功登录,服务端是否会清除IP的封禁状态,尝试使用这个凭证进行登录:

可以正常登录,继续登录目标用户没有提示IP被封禁了,说明服务端在成功登录后会清除IP的封禁状态。
新开一个web fuzzxer,不停循环登录wiener:peter,以此来保持IP的封禁状态被清除,:

同时在另一个fuzzer中对carlos进行密码爆破,并发线程数设置为1:

得到密码为159753,成功登录后完成实验。
5. Lab: Username enumeration via account lock
使用任意用户名和密码进行登录测试,提示”Invalid username or password.”,无法确认用户名是否存在,但是根据题目的提示可以考虑,对用户名字典的每个用户名进行密码爆破,观察是否会提示账户被锁定,如果提示账户被锁定,说明这个用户名是存在的:
1 | username={{file:line(D:\Apps\Yakit\Yakit\yakit-projects\temp\tmp816829847.txt)}}&password={{int(1-5)}} |
使用交叉乘积进行爆破,并添加规则,丢弃包含”Invalid username or password.”的响应:

azureuser用户出现了账户被锁定的提示,说明这个用户名是存在的,接下来对这个用户进行密码爆破:
1 | username=azureuser&password={{file:line(D:\Apps\Yakit\Yakit\yakit-projects\temp\tmp3805451464.txt)}} |
爆破完成后,在规则模块中添加匹配器,丢弃包含”Invalid username or password.”以及”You have made too many incorrect login attempts. Please try again in 1 minute(s).”的响应:

存在一个没有任何提示的响应,密码为aaaaaa,成功登录后完成实验。
6. Lab: 2FA simple bypass
使用提供的凭据wiener:peter进行登录,提示需要输入2FA验证码:

点击 Email Client 获取验证码:

提交验证码后完成登录:

目标账户 carlos:montoya 也需要输入2FA验证码,尝试对验证码进行爆破:
1 | mfa-code={{int(0-9999|4)}} |

出现内部网关错误,说明无法爆破验证码。
前面成功登录wiener:peter后的页面URL为 https://0a83000d04d272f080b4946900b900d3.web-security-academy.net/my-account?id=wiener ,其中URL中的id参数值为当前登录用户的用户名,可以尝试将URL中的用户名替换为目标用户carlos,访问 https://0a83000d04d272f080b4946900b900d3.web-security-academy.net/my-account?id=carlos :

成功绕过2FA登陆进来。通过查看HTTP记录可以发现,在提交完用户名密码的后,服务端便直接下发了Session Cookie,并让浏览器重定向到2FA验证页面:

此时无需在这个页面输入任何验证码,直接在浏览器地址栏中输入需要访问的受保护页面路径 /my-account?id=carlos,浏览器会自动携带刚才获得的有效 Session Cookie 发起请求,服务器端没有强制检查用户是否已经完成了 2FA 步骤,直接允许用户访问:

7. Lab: 2FA broken logic
使用已有凭证wiener:peter进行登录,通过Email Client获取验证码,完成登录。
由于题目没有提供攻击目标carlos的凭证,因此需要考虑,能否直接通过获取carlos的2FA验证码来登录carlos的账户。查看HTTP记录,可知浏览器是通过GET /login2 后进行验证码填写的,而login2的cookie中包含了当前登录用户的用户名:

尝试将cookie中的用户名替换为carlos,以此触发获取carlos的2FA验证码:

渲染的页面出现了输入验证码的提示,说明carlos的2FA验证码已经发送到邮箱,接下来尝试对 POST /login2 提交的验证码进行爆破:
1 | Cookie: verify=carlos; session=SscYjcjX1gq4IwoTlZOYqua3NizqAPJj |
无法对 GET /email 进行爆破,因为这个接口只是用来测试已知凭证wiener:peter的。

观察到存在302状态码的响应,说明验证码爆破成功了,右键在浏览器中打开URL,即可成功登录carlos的账户。
未完待续…





















