在成功识别出有效用户后,基于密码的认证 (password-based authentication) 依赖于密码作为认证用户的唯一措施。由于用户倾向于选择容易记住的密码,攻击者可能会猜出或暴力破解 (brute-force) 它们。
暴力破解
暴力破解密码
密码仍然是最常见的在线认证方法之一,但它也存在许多问题。一个突出的问题是密码重用 (password reuse),即个人在多个账户中使用相同的密码。这种做法构成了严重的安全风险,因为如果一个账户被攻破,攻击者就有可能使用相同的凭据访问其他账户。
密码重用使得从密码泄漏事件中获取了密码列表的攻击者,可以在其他 Web 应用程序上尝试相同的密码(“Password Spraying”,即密码喷洒攻击)。
另一个问题是使用基于常用短语、字典单词或简单模式的弱密码 (weak passwords)。这些密码很容易受到暴力破解攻击的影响,攻击者使用自动化工具系统地尝试不同的组合,直到找到正确的密码,从而危及账户安全。
暴力破解攻击的成功完全取决于攻击者可以执行的尝试次数以及完成攻击所需的时间。因此,确保在攻击中使用一个好的字典 (wordlist) 至关重要。如果一个 Web 应用程序强制执行了密码策略 (password policy),我们应该确保我们的字典只包含符合该密码策略的密码。否则,我们就是在浪费宝贵的时间去尝试那些用户无法在该 Web 应用程序上使用的密码,因为密码策略不允许它们。
我们可以使用grep来符合密码策略
grep '[[:upper:]]' /opt/useful/seclists/Passwords/Leaked-Databases/rockyou.txt | grep '[[:lower:]]' | grep '[[:digit:]]' | grep -E '.{10}' > custom_wordlist.txt
或者使用awk也可以
awk 'length($0) >= 10 && /[a-z]/ && /[A-Z]/ && /[0-9]/' /opt/useful/seclists/Passwords/Leaked-Databases/rockyou.txt > custom_wordlist.txt
暴力密码重置token
许多 Web 应用程序都实现了密码恢复功能,以防用户忘记密码。这种密码恢复功能通常依赖于一次性重置令牌 (one-time reset token),该令牌会通过短信或电子邮件等方式发送给用户。然后,用户可以使用此令牌进行身份验证,从而重置密码并访问其账户。
因此,如果密码重置令牌较弱,攻击者就可能通过暴力破解或预测的方式获取对受害者账户的未经授权的访问。
识别弱重置token
重置令牌(以代码或临时密码的形式)是用户请求重置密码时由应用程序生成的机密数据。用户随后可以通过提供该重置令牌来更改其密码。
由于密码重置令牌允许攻击者在不知道密码的情况下重置账户密码,因此如果实施不当,它们就可能被利用为攻击向量 (attack vector),以接管受害者的账户。密码重置流程可能很复杂,因为它包含多个连续的步骤
要识别弱重置令牌,我们通常需要在目标 Web 应用程序上创建一个账户,请求一个密码重置令牌,然后对其进行分析以确定其强度。
攻击弱重置令牌
我们将使用 ffuf 来暴力破解所有可能的重置令牌。首先,我们需要创建一个包含从 0000 到 9999 所有可能令牌的字典,这可以通过 seq 来实现:
seq -w 0 9999 > tokens.txt
-w 标志通过前置零将所有数字填充到相同的长度
假设当前有用户正在重置密码,我们可以尝试暴力破解所有有效的重置令牌。如果我们想针对特定用户,我们应该首先为该用户发送一个密码重置请求以创建重置令牌。然后,我们可以在 ffuf 中指定该字典,以暴力破解所有有效的重置令牌:
ffuf -w ./tokens.txt -u http://weak_reset.htb/reset_password.php?token=FUZZ -fr "The provided token is invalid"
暴力破解2FA
双因素身份验证 (Two-factor authentication, 2FA) 提供了一个额外的安全层,以保护用户帐户免受未经授权的访问。通常,这是通过将基于知识的身份验证(例如密码)与基于所有权的身份验证(使用 2FA 设备)相结合来实现的。
但是,也可以通过组合我们之前讨论过的三个主要身份验证类别中的任意两个来实现 2FA。因此,即使攻击者设法获取了用户的凭据,2FA 也会使他们访问帐户变得异常困难。
通过要求用户提供第二种形式的身份验证,例如由身份验证器应用生成或通过短信 (SMS) 发送的一次性代码,2FA 降低了未经授权访问的风险。这个额外的安全层显著增强了帐户的整体安全态势,降低了帐户被成功入侵的可能性。
攻击2FA
最常见的 2FA 实现之一依赖于用户的密码和通过身份验证器应用或短信提供给用户智能手机的基于时间的一次性密码 (Time-based One-Time Password, TOTP)。这些 TOTP 通常仅由数字组成,如果其长度不足,并且 Web 应用程序没有实施措施来防止连续提交错误的 TOTP,它们就可能被猜到。
破解密码安全机制
速率限制
速率限制 (Rate limiting) 是软件开发和网络管理中采用的一项关键技术,用于控制进入系统或 API 的请求速率。其主要目的是防止服务器因过多请求而不堪重负,防止系统停机,并防范暴力破解攻击。通过在指定时间范围内限制允许的请求数量,速率限制有助于保持稳定性,并确保所有用户公平使用资源。它通过对请求频率强制执行最大阈值,来防范滥用行为,例如拒绝服务 (denial-of-service, DoS) 攻击或单个客户端的过度使用。
当攻击者进行暴力破解攻击并触发速率限制时,攻击将被挫败。速率限制通常会迭代地增加响应时间,直到暴力破解攻击变得不可行为止,或者在指定时间内阻止攻击者访问服务。
速率限制应仅对攻击者强制执行,而非普通用户,以防止 DoS 场景。许多速率限制的实现依赖 IP 地址来识别攻击者。然而,在现实场景中,获取攻击者的 IP 地址可能并不总是像看起来那么简单。例如,如果存在中间设备 (middleboxes),如反向代理、负载均衡器或 Web 缓存,请求的源 IP 地址将属于中间设备,而不是攻击者。因此,一些速率限制依赖于 X-Forwarded-For 等 HTTP 标头来获取实际的源 IP 地址。
然而,这带来了一个问题,因为攻击者可以在请求中设置任意的 HTTP 标头,从而完全绕过速率限制。这使得攻击者可以通过在每个 HTTP 请求中随机化 X-Forwarded-For 标头来实施暴力破解攻击,从而避开速率限制。
验证码
“全自动区分计算机和人类的公开图灵测试” (Completely Automated Public Turing test to tell Computers and Humans Apart, CAPTCHA) 是一种安全措施,用于防止机器人程序 (bots) 提交请求。通过强制由人类而非机器人程序或脚本发出请求,暴力破解攻击变成了一项手动任务,在大多数情况下使其变得不可行。
验证码通常会提出一些对人类来说容易解决但对机器人程序来说困难的挑战,例如识别扭曲的文本、从图像中选择特定对象或解决简单的谜题。通过要求用户在访问某些功能或提交表单之前完成这些挑战,CAPTCHA 有助于防止自动化脚本执行可能有害的操作。
虽然验证码在阻止自动化滥用方面起着至关重要的作用,但它们也可能给某些用户带来可用性挑战,特别是那些有视觉障碍或特定认知障碍的用户。
从安全角度来看,至关重要的是不要在响应中泄露验证码的答案。
默认凭证
许多 Web 应用程序 (web application) 在安装后会设置默认凭证 (default credentials) 以允许访问。但是,在 Web 应用程序初始设置后,需要更改这些凭证;否则,它们会为攻击者 (attacker) 提供一种获取经过身份验证的访问 (authenticated access) 的简单途径。根据 OWASP 的说法,常见的默认凭证包括 admin 和 password。
测试默认凭证
许多平台为各种 Web 应用程序提供了默认凭证列表
其他资源包括 SecLists Default Credentials 以及 SCADA GitHub 存储库,其中包含各种不同供应商的默认密码列表。
有针对性的互联网搜索是获取 Web 应用程序默认凭证的另一种方法。
密码重置漏洞
我们已经讨论了如何通过暴力破解密码重置令牌来获取受害者账户的访问权限。然而,即使 Web 应用程序采用了速率限制 (rate limiting) 和验证码 (CAPTCHA),密码重置功能中的业务逻辑漏洞 (business logic bugs) 仍然可能导致攻击者接管其他用户的账户。
可猜测的密码重置问题
通常,Web 应用程序会要求忘记密码的用户回答一个或多个安全问题来进行身份验证。在注册过程中,用户需要为预定义和通用的安全问题提供答案,而不允许用户输入自定义问题。因此,在同一个 Web 应用程序中,所有用户的安全问题都是相同的,这使得攻击者可以滥用它们。
假设我们在目标网站上发现了此类功能,我们应尝试利用它来绕过身份验证。在基于问题的密码重置功能中,薄弱环节通常在于答案的可预测性。常见的问题如下:
- “
你母亲的娘家姓是什么?” - “
你在哪个城市出生?”
虽然这些问题看似与个人用户紧密相关,但通常可以通过开源情报 (OSINT) 获取,或者在有足够多的尝试次数(即缺少暴力破解防护)的情况下被猜到。
操纵重置请求
密码重置逻辑存在缺陷的另一个例子是,用户可以操纵一个可能存在的隐藏参数来重置另一个不同账户的密码。
例如:用户名作为一个隐藏参数包含在表单中,并与安全问题答案一起发送。我们可以重置用户的密码,但是当我们截取数据包后发现是包含了重置用户名的,此时可以尝试给另一个不同的账户设置密码
直接访问逃过认证
绕过认证检查 (authentication checks) 最直接的方法是从一个未认证的上下文中直接请求受保护的资源。如果 Web 应用程序没有正确验证请求是否经过认证,未经认证的攻击者就可以访问受保护的信息。
例如,假设我们知道 Web 应用程序在用户成功认证后会将其重定向 (redirects) 到 /admin.php 端点 (endpoint),只向已认证的用户提供受保护的信息。如果 Web 应用程序仅依赖登录页面来认证用户,我们就可以通过直接访问 /admin.php 端点来访问受保护的资源。
虽然这种情况在现实世界中并不常见,但一种轻微的变体偶尔会出现在易受攻击的 Web 应用程序中。
使用Session来重定向
if(!$_SESSION['active']) {
header("Location: index.php");
}
如果会话 (session) 未激活,即用户未通过认证,这段代码会将用户重定向到 /index.php。然而,PHP 脚本并不会停止执行,导致页面内受保护的信息被发送到响应体 (response body) 中:
整个管理页面都包含在响应体中。但是,如果我们尝试在 Web 浏览器中访问该页面,浏览器会遵循重定向并显示登录提示,而不是受保护的管理页面。我们可以通过拦截 (intercepting) 响应并将状态码 (status code) 从 302 更改为 200,来轻松地欺骗浏览器显示管理页面。为此,请在 Burp 中启用 Intercept。然后,在 Web 浏览器中浏览到 /admin.php 端点。接下来,右键单击请求并选择 Do intercept > Response to this request 来拦截响应:
之后,点击 Forward 转发请求。由于我们拦截了响应,现在可以对其进行编辑。要强制浏览器显示内容,我们需要将状态码从 302 Found 更改为 200 OK