Burp Web Academy 鉴权漏洞
0x01. PortSwigger Web Security Academy
PortSwigger Web Security Academy 是 Burp Suite 官方推出的免费 Web 安全学习靶场,在学习 Web 安全知识的同时,还可以练习 Burp Suite 的实战技能。
本篇文章讲解 Web Security Academy 之中的鉴权漏洞(Authentication Vulnerabilities)章节。
0x02. 鉴权漏洞
2.1 Lab: Username enumeration via different responses
This lab is vulnerable to username enumeration and password brute-force attacks. It has an account with a predictable username and password, which can be found in the following wordlists:
To solve the lab, enumerate a valid username, brute-force this user’s password, then access their account page.
给定了用户名字典、密码字典,分两步操作:
- 首先,确认用户名是哪一个
- 其次,爆破密码
输入任意的用户名和密码,提示 Invalid username
。因此,可以先爆破用户名,根据返回的页面 BODY 是否包含 Invalid username
来确认真正的用户名。
- 选中登录的 POST 请求,选择
Send to Intruder
- 在 Intruder 中,先清理掉自动设置的字段,仅将
username
设置为字段 - 将用户名字典导入到
Payload
页面下的Payload Options
中 - 在
Options
页面中设置Grep - Match
匹配选项Invalid username
然后点击 Start attack
开始爆破,很快就可以确认用户名是 applications
,而密码错误的提示是 Incorrect password
。使用同样的方法,可以对密码进行爆破,结果为 123456
。
2.2 Lab: 2FA simple bypass
This lab’s two-factor authentication can be bypassed. You have already obtained a valid username and password, but do not have access to the user’s 2FA verification code. To solve the lab, access Carlos’s account page.
- Your credentials:
wiener:peter
- Victim’s credentials
carlos:montoya
先使用 wiener:peter
登录,需要输入动态口令,后者可以通过 Email client
中的邮件查看,而完成登陆后,则可以修改自己的 Email,原本的邮件地址是:
1 | wiener@exploit-0a86006803574d84814d446001b40022.exploit-server.net |
尝试把 wiener
的邮件地址改为 carlos@xxx
,尝试用 wiener
的验证码登录,发现验证码绑定了账户,会直接登录 wiener
的账户。此外,还有一个 Exploit Server,没看出来有什么用。
看了提示,发现解法非常简单:
- 登录
wiener
,使用验证码进入后,确认个人页面的 PATH 为/my-account
- 登录
carlos
,在需要输入验证码的时候,直接访问/my-account
2.3 Lab: Password reset broken logic
This lab’s password reset functionality is vulnerable. To solve the lab, reset Carlos’s password then log in and access his “My account” page.
- Your credentials:
wiener:peter
- Victim’s username:
carlos
进入登陆页面,发现有一个重置密码的链接,访问后可以通过用户名或者邮箱来找回密码,先测试下 wiener
,通过邮箱中的链接重置密码,实际重置密码的表单内容如下所示:
1 | <form class=login-form method=POST> |
其中有两个隐藏的字段,一个是重置密码用的 Token,另一个是 Username,尝试把这里的用户名修改为 carlos
,提交表单即可修改 carlos
的密码。
2.4 Lab: Username enumeration via subtly different responses
This lab is subtly vulnerable to username enumeration and password brute-force attacks. It has an account with a predictable username and password, which can be found in the following wordlists:
To solve the lab, enumerate a valid username, brute-force this user’s password, then access their account page.
跟前面的题不太一样,随意输入用户名和密码,登录失败时返回 Invalid username or password.
。还是使用 Intruder 来爆破以下用户名,观察返回结果有何不同之处:用户名 atlas
返回了 Invalid username or password
,末尾是空格而不是 .
。
之后,尝试给 atlas
爆破密码,根据返回结果的长度或者状态码,可以很快确定密码是 joshua
。
2.5 Lab: Username enumeration via response timing
This lab is vulnerable to username enumeration using its response times. To solve the lab, enumerate a valid username, brute-force this user’s password, then access their account page.
- Your credentials:
wiener:peter
- Candidate usernames
- Candidate passwords
根据服务器的响应时间来确认真实的账户名称,把 POST 登录请求包发送到 Intruder 进行爆破处理,但是有两点需要注意。
首先,Burp 的 Intruder 默认不会展示服务器的响应时间,需要在 Intruder 攻击完毕的窗口中通过菜单项选择开启:点击 Columns
菜单项,然后依次选择 Response received
和 Response completed
。说实话,这个顶部的菜单栏放到了标题栏里面,看着有点迷糊,找了好久才发现。
其次,当我们发送大量登录请求时,会被服务器检测出来,提示 30 分钟之后再尝试登录:
1 | You have made too many incorrect login attempts. Please try again in 30 minute(s). |
这需要我们调整攻击策略:在 Intruder 中,将 Attack type
从 Sniper
改为 Pitchfork
,这允许我们为不同的字段指定不同的攻击字典。
我们可以通过 X-Forwarded-For
字段来变更 IP 地址,实现 IP 拦截绕过。由于用户名大概只有 100
个,因此可以直接以数字形式迭代 IP 地址 X-Forwarded-For: 222.222.222.§1§
。
1 | POST /login |
完成攻击后,可以通过 Response received
排序,然后快速确认哪些请求耗时过长。当然,响应时间存在多方面的影响,所以最好多试几次,找出总是耗时很长的响应。确认用户名之后,使用同样的策略对密码进行爆破,根据响应的状态码来确认密码是否正确。
还有一个需要注意的点:默认的发包模式是 10
个并发请求,且两个包之间没有时间间隔,这可能给响应时间带来影响,可以尝试调整这个发包策略。
2.6 Lab: Broken brute-force protection, IP block
This lab is vulnerable due to a logic flaw in its password brute-force protection. To solve the lab, brute-force the victim’s password, then log in and access their account page.
- Your credentials:
wiener:peter
- Victim’s username:
carlos
- Candidate passwords
同样存在 IP 拉黑操作,而且 X-Forwarded-For
也没有用,大概是连续 2
次失败,就会提示如下错误信息:
1 | You have made too many incorrect login attempts. Please try again in 1 minute(s). |
尝试生成用户名和密码字典,每次尝试爆破 carlos
密码之后,立即使用 wiener
登陆一次,看是否可以绕过这里的限制:
- 测试之后,发现很快还是被拉黑了
- 查看官方答案,发现思路是对的,但是忘了默认的发包模式是
10
个并发请求,这里需要改为1
个,防止产生干扰
之后在 Intruder 发包爆破,可以确认 carlos
的密码是 love
,生成 Payload 的 Python 代码如下:
1 | def gen_dict(pwdfile): |
2.7 Lab: Username enumeration via account lock
This lab is vulnerable to username enumeration. It uses account locking, but this contains a logic flaw. To solve the lab, enumerate a valid username, brute-force this user’s password, then access their account page.
在 Intruder 中,直接选择 Cluster bomb
模式,尝试所有的用户名和密码枚举,直接就给爆破了:
Invalid username or password.
表示用户名或者密码错误You have made too many incorrect login attempts. Please try again in 1 minute(s).
表示用户名存在,但密码连续多次错误- 剩下的一个,就是正确的用户名和密码了
当然,这样的爆破搞下来就得发送上万次的 POST 请求包,其实可以尝试剪枝优化:
- 每一个用户名,只尝试少量登录尝试,比如
10
次登录,这样遇到不一样的错误,大概就是用户名存在,后面就不用测了- 实际上,连续
4
次登录错误,就能返回不一样的错误提示了
- 实际上,连续
- 找到用户名后,再进行爆破操作
至于题目提到的逻辑错误,可能是实际上并没有进行锁定操作:只是锁了特定账户的登录请求,没有把 IP 拉黑。
2.8 Lab: 2FA broken logic
This lab’s two-factor authentication is vulnerable due to its flawed logic. To solve the lab, access Carlos’s account page.
- Your credentials:
wiener:peter
- Victim’s username:
carlos
You also have access to the email server to receive your 2FA verification code.
没有 carlos
的密码,还要进入 carlos
的个人页面。使用 wiener:peter
登录,发现 Cookie 中存在用户名 verify=wiener
,尝试拦截修改:
1 | POST /login2 |
使用 wiener
的验证码进行登录,提示 Incorrect security code
,然后使用 Burp Intruder 进行爆破,4
位的验证码,爆破了 10000
次,这个方法还是不行,似乎仅仅更改 Cookie 中的用户名是不行的。
查看答案之后,才发现需要先触发生成验证码的逻辑,才可以进行爆破!
1)访问 /login2
触发验证码生成逻辑
1 | GET /login2 |
2)注意服务器返回的 Response Header,里面有个 Cookie,在 Intruder 中更新一下
1 | 200 OK |
3)爆破验证码
1 | POST /login2 |
4)可以根据 HTTP 状态码 302
或者 Length
来确认是否已经成功爆破,OK 之后停止 Intruder 继续发包,然后在 Intruder 中选中对应的发包记录,弹出右键菜单后依次选择 Request in browser
、In original session
,然后复制生成的 URL 并在浏览器中访问即可。
2.9 Lab: Brute-forcing a stay-logged-in cookie
This lab allows users to stay logged in even after they close their browser session. The cookie used to provide this functionality is vulnerable to brute-forcing.
To solve the lab, brute-force Carlos’s cookie to gain access to his My account page.
- Your credentials:
wiener:peter
- Victim’s username:
carlos
- Candidate passwords
使用 wiener
登陆时,选择保持登录,登陆后看到 Cookie 如下:
1 | Cookie: stay-logged-in=d2llbmVyOjUxZGMzMGRkYzQ3M2Q0M2E2MDExZTllYmJhNmNhNzcw |
进行 Base64 解码得到:
1 | wiener:51dc30ddc473d43a6011e9ebba6ca770 |
51dc30ddc473d43a6011e9ebba6ca770
即密码 peter
的 MD5 哈希值。
弄清楚 Cookie 的格式之后,还需要观察一下正常 Cookie 和异常 Cookie 访问页面后的不同响应,以方便我们快速确认正确的密码是哪个!
- 正确的 Cookie,返回 HTTP 状态码
200
- 错误的 Cookie,返回 HTTP 状态码
302
接下来,先使用 Python 对密码进行处理以生成 Cookie 字典:
1 | import base64 |
然后就可以在 Burp Intruder 中进行爆破操作了:
1 | GET /my-account?id=carlos |
最终的密码是:1234567890
。
0x03. 小结
- 根据登录时给出的错误提示信息判断用户名、密码的状态
- 不管返回的错误提示是什么,都可以尝试对比下不同请求返回的结果
- 使用 Burp Intruder 进行爆破操作,注意不同的攻击类型之间的差异和使用场景
- 爆破时,可能会拉黑 IP 地址,可以尝试使用
X-Forwarded-For
来绕过
- 根据登录时的 HTTP 请求响应时间来判断表单字段可能的值
- 存在/不存在的值,响应的时间可能不一样
- 响应时间可能被多种因素影响,因此要进行多次测试
- 默认的发包模式是
10
个并发请求,且两个包之间没有时间间隔,这可能给响应时间带来影响,可以尝试调整这个发包策略
- 连续登录失败次数限制绕过
- 在触发限制前,可以使用正确的用户名、密码登录一次,以重置连续失败次数
- 默认的发包模式是
10
个并发请求,可能干扰爆破思路,可以将并发模式改为1
- 思路要放宽,尝试任何可能性,不要拘泥于特定思路
- 能不能直接访问指定 PATH
- 爆破验证码时,确认有没有先触发验证码生成逻辑
- 关注 POST 表单中的隐藏字段
- Burp Intruder 的不同攻击模式
- Sniper
- Battering ram
- Pitchfork
- Cluster bomb
- Burp Intruder
Request in browser
- Cookie 过于简单很容易被爆破