回炉重造之 PortSwigger

133

前言

菜,就多练!

入口:https://portswigger.net/web-security/all-topics

身份验证漏洞

用户名枚举-通过响应时间

用户名枚举有多种方式,比如:

  • 返回长度的差异

  • 错误消息差异

  • 响应时间差异(此例如下)

已知用户名 wiener 是存在的,先输入一个错误的密码,看看响应时间 357 ms

然后输入一个较长的密码,发现响应时间变长

这时我们就可以通过观察响应时间来枚举用户名

交替登录绕过 IP 封锁

防止暴力攻击的两种最常见方法是:

  • 如果远程用户尝试登录失败次数过多,则锁定其尝试访问的帐户

  • 如果远程用户连续多次尝试登录,则阻止其 IP 地址

这两种方法都提供不同程度的保护,但都不是无懈可击的,特别是如果使用有缺陷的逻辑来实现。

例如,有时您可能会发现,如果登录失败次数过多,您的 IP 就会被封锁。在一些实现中,如果IP所有者成功登录,则失败尝试次数的计数器重置。这意味着攻击者只需每隔几次尝试就登录自己的帐户,以防止达到此限制。

登录失败 3 次锁定 IP 一分钟

该程序的逻辑是登录成功后,会重置登录失败次数,所以我们可以不断地交替正确与错误的账号密码,来不断地重置登录失败次数以达到爆破的目的

就像这样,交替发包

找到了正确的账号密码

单请求多凭证绕过 IP 封锁

在上一个思路中,需要只要至少一个后台账号密码才可绕过该限制,如果我们什么信息都没有,可以尝试该骚操作。

普通爆破,错误几次就封锁 IP

将密码字符串替换为密码数组,登录成功。

2FA 简单绕过

使用 wiener:peter 登录,点击邮件客户端,查看验证码

输入正确的验证码后,进入个人中心页面,记录当前的URL:/my-account?id=wiener

登录 carlos:montoya,此时是需要验证码的,我们不知道验证码,但是我们可以访问 /my-account?id=carlos 绕过

2FA 逻辑错误

有时,双因素身份验证中存在缺陷的逻辑意味着用户完成初始登录步骤后,网站无法充分验证同一用户是否正在完成第二步。

登录 wiener 账号后,观察 2FA 验证过程

需要邮箱验证码,此时注意到 Cookie 中 verify=wiener,并且有一个 wiener 账号的 session 值。

猜测 verify 参数用于确定正在访问哪个用户的帐户,因此改为 carlos,向 carlos 发送验证码

随后,输入任意验证码,提交数据包到 Intruder

对验证码进行爆破,最后成功登录 carlos

2FA 验证码爆破(宏)

一些网站试图通过在用户输入一定数量的错误验证码时自动注销用户来防止这种情况。

观察登录过程,输入正确的账号密码后,还需要输入邮箱验证码

如果您两次输入错误代码,将被注销

需要使用 Burp 的会话处理功能在发送每个请求之前自动重新登录

打开设置 - Project - Sessions

添加宏,选择登录过程

添加规则

规则中选择创建的宏

登录 carlos:montoya,输入验证码进行爆破,因为有 CSRF 保护,所以要将线程调为 1,在执行宏时便会自动填充 CSRF

最后成功爆破出验证码

密码重置投毒

对重置密码过程进行分析,输入需要重置的用户名

然后我们将收到一封邮件,该链接中携带了 token

点击该链接,可进行密码重置操作

我们发现 X-Forwarded-Host 可以控制生成的重置密码链接

因此我们可以伪造 X-Forwarded-Host 值,受害者点击后,即可获取它的 token

向 carlos 发送邮件,成功获取其 token

然后就可以更改其密码了。

密码重置缺陷

先看一个数据包

正常我在测密码重置漏洞时,肯定是直接爆破前面两个参数

此时,原密码错误跳转到登录页面

如果新密码不一致,提示当前密码错误(后端不严谨导致),此时我们就可以爆破账号密码了

原密码爆破成功,将会提示新密码不匹配

密码重置缺陷 2

登录自己的账户

修改密码时填入当前密码

由于后端校验密码存在缺陷,将当前密码置空或者完全删除该参数,可修改任意用户密码

路径遍历

在 Windows 上, 和../都是..\有效的目录遍历序列。

绝对路径绕过

这个就不说了,简单得很。

嵌套遍历绕过

后端非递归地将 ../ 删除后,可以绕过

比如:

/image?filename=..././..././..././..././..././etc/passwd
/image?filename=....//....//....//....//....//etc/passwd
/image?filename=....\/....\/....\/....\/etc/passwd

使用编码绕过

可以对字符进行 URL 编码,甚至双重 URL 编码来绕过 ../ 被清理

比如:

/image?filename=..%252f..%252f..%252f..%252fetc/passwd
/image?filename=%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd
/image?filename=%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252fetc/passwd
/image?filename=..%c0%af..%c0%af..%c0%af..%c0%afetc/passwd
/image?filename=..%ef%bc%8f..%ef%bc%8f..%ef%bc%8f..%ef%bc%8fetc/passwd

验证路径开头

应用程序可能需要用户提供的文件名以预期的基本文件夹开头,例如/var/www/images在这种情况下,可能可以包含所需的基本文件夹,后跟适当的遍历序列。例如:

filename=/var/www/images/../../../etc/passwd

空字节绕过文件扩展名验证

应用程序可能需要用户提供的文件名以预期的文件扩展名结尾,例如.png. 在这种情况下,可以使用空字节在所需扩展名之前有效地终止文件路径。例如:

/image?filename=../../../../etc/passwd%00.png

命令注入

盲命令注入

如果命令执行没有回显,或者 dnslog 无法接收该服务器的请求时,盲命令注入能够有效探测是否存在漏洞。

比如执行 ping 命令

x||ping+-c+10+b127.0.0.1||

业务逻辑漏洞

支付漏洞 - 负数

商品数量可以设置为负数,但是总价不能为负数。此时添加另一个商品的适当负数量,以将总价降低到低于您的剩余商店积分。

支付漏洞 - 整数溢出

整数溢出通常是由于对整数数据类型的范围进行不当操作或者超过了其表示范围引起的。下面是一些常见的导致整数溢出的原因:

  1. 超过数据类型的表示范围: 每种整数数据类型都有其表示范围,通常由位数决定。例如,32位有符号整数的表示范围是-2,147,483,648 到 2,147,483,647。如果一个操作导致结果超出这个范围,就会发生整数溢出。

  2. 累积错误: 在长时间的计算中,由于一系列的操作导致整数值逐渐增加或减少,最终可能超过了数据类型的表示范围。即使每次操作都在范围内,但它们的累积可能导致溢出。

  3. 缺乏边界检查: 在编程中,如果没有足够的边界检查或错误处理,用户输入或其他外部数据可能包含超出范围的值,从而导致整数溢出。

  4. 算术操作: 算术操作,如加法、减法、乘法等,可能导致整数溢出。例如,两个很大的正数相乘可能得到一个比数据类型最大值还要大的结果。

下面使用 go 语言代码简单演示整数溢出

int8 取值范围为 -128 ~ 127,如果超出范围,会导致溢出

package main

import "fmt"

func main() {
	var a int8 = 15
	var b int8 = 9
	var c int8 = a * b
	fmt.Printf("%d x %d = %d", a, b, c)
}

15 x 9 = -121

在这个例子中,商品价格无法修改,商品数量可控,但是不能为负数

但是我们可以不断增加商品数量,利用整数溢出,将商品价格变为负数

由于总价不能为负数,所以需要配合其它商品下单

支付漏洞 - 工作流程顺序错误

在该例中,正常的支付逻辑是先将商品添加到购物车,进入购物车下单时检验余额,然后支付成功。

然而我们可以直接越过检验余额这个步骤,将确认订单的包发送到 repeater

将皮夹克添加到购物车,不要进入购物车,直接重放 repeater,购买成功

支付漏洞 - 交替使用优惠券

优惠券正常来说只能使用一次,如果重复添加优惠券会提示优惠券已使用。

但是如果交替使用两个不同的优惠券就可能产生逻辑漏洞

支付漏洞 - 无限金钱逻辑漏洞

该例可通过优惠券购买礼品卡,礼品卡可兑换成余额,购买成功后优惠券可重复使用,这样就导致逻辑漏洞

录制宏,加入购物车 - 填入优惠券 - 检查余额 - 下单 - 兑换礼品卡

然后空爆,线程 1

余额蹭蹭蹭往上涨

对异常输入的处理不一致

该例子中,要想访问管理后台,需要邮箱是 @dontwannacry.com 结尾的账号。

我们的邮箱只能显示 @exploit-0a2400e90483d5a884c9f91701a00051.exploit-server.net 和所有子域

此时我们注册时输入一个超长的邮箱账号

登录账号发现邮箱被截断了

因此我们可以通过此漏洞,控制邮箱后缀,确保 @dontwannacry.com 末尾的 m 恰好是字符 255

1very-long-string-very-long-string-very-long-string-very-long-string-very-long-string-very-long-string-very-long-string-very-long-string-very-long-string-very-long-string-very-long-string-very-long-string-very-long-string-very-long-string@dontwannacry.com.exploit-0a2400e90483d5a884c9f91701a00051.exploit-server.net

通过有缺陷的状态机绕过身份验证

正常登录账号

此时让我们选择权限

如果我们丢弃掉这个包,后端存在逻辑缺陷,导致我们的权限默认为administrator

通过加密 Oracle 绕过身份验证(太骚了)

首先正常登录账号,并勾选 Stay logged in

找一篇文章进行评论,输入错误的电子邮件地址

显示错误的邮箱地址

观察数据包发现,notification 的值解密后就是 Invalid email address: 1.com

随后我们将 stay-logged-in 的值替换到 notification 中,进行解密,结果为:

wiener:1705912187781

此时,我们知道了 stay-logged-in 的格式为用户名: 时间戳

那么我们在邮箱处填入 administrator:1705912187781,进行加密

然后解密利用 /post?postId=2 数据包进行解密,发现存在多余的23个字符(Invalid email address: )

删掉 23 个字节

对处理后的 base64 字符串进行 URL 编码后,解密,提示输入长度必须是 16 的倍数,说明其使用基于块的加密算法。

为什么之前在加密时,输入的长度并非 16 的倍数,还能正常解密呢?

这是因为加密算法自动填充到了 64 位,当我们删除 23 个字节时,base64 字符串变为 41 位,就无法解密了

这时,我们不能直接删除 16 位字节,如果这样的话,解密结果就会是

dress: administrator:1705912187781

因此我们需要删除 32 个字节,为了避免 administrator 被删除,我们需要填充 32 - 23 = 9 个字节

然后删除 32 个字节

此时再来解密,就正常了

随后我们将该值替换到 stay-logged-in,删除 session 值,便可以超管身份登录

SSRF

针对本地服务器的 SSRF

有些网站后台只允许通过回环地址访问,外网是没办法访问的,如果存在 SSRF 漏洞,且可将解析的地址内容回显到页面上,那么就可以绕过该限制。

来到漏洞环境,直接访问 /admin,提示需要通过回环地址访问

点击检查库存

拦截数据包,发现参数 stockApi 后面跟了 URL 地址,这时我们就可以尝试 SSRF 攻击

图片-uhrc.png

修改 POST 参数,stockApi=http://localhost/admin,内网地址就回显到页面上了,之后我们要操作后台功能的话,就需要更改 stockApi 的值