BurpLabs-业务逻辑漏洞
实验环境:
https://portswigger.net/web-security/all-labs#business-logic-vulnerabilities
0x01 对客户端控制的过度信任(国内常称 0 元支付)
要求:本实验未充分验证用户输入,可利用逻辑漏洞购买一件"Lightweight l33t leather jacket",测试账号为:wiener:peter
。
启动靶机,进入实验环境,登录账号后发现余额只有一百块,但商品价格却要一千多块,我们先打开Burp Suite拦截添加到购物车的包,查看是否存在可修改的数值(如价格参数)。
我们发现存在多个数值,解释如下:
productId 表示商品编号
quantity 表示添加数量
price 表示商品价格
我们尝试修改价格参数为1并放包,商品成功添加到购物车后我们进行查看,发现价格已经变成了$0.01,点击购买发现可以正常购买商品,表示实验成功。
0x02 负数绕过
要求:本实验未充分验证用户输入,利用逻辑漏洞购买一件"Lightweight l33t leather jacket",测试账号为:wiener:peter
。
同样我们先登录账号抓取添加到购物车的包查看是否存在可修改参数:
我们发现这里只可以修改数量参数,价格参数已经被定义在后端无法修改,我们尝试将数量修改为-1并放包添加到购物车,这时发现成功添加,这样一来我们就有了思路,添加一个实验需要购买的商品,然后添加其他商品修改为负的数量来抵消价格以实现低价购买目标商品。
0x03 数据溢出导致的支付问题
要求:本实验未充分验证用户输入,利用逻辑漏洞购买一件"Lightweight l33t leather jacket",测试账号为:wiener:peter
。
先登录账号抓取添加到购物车的包查看是否存在可修改参数,我们尝试修改参数量参数为负发现无效。
提示中说需要用到Intruder
模块,我们将POST /cart
包(就是将商品添加到购物车的包)发送到Intruder
,清除标识符并修改数量参数quantity
为99(经测试每款商品单个包最多添加99个),并修改Payload type
为Null payloads
,Payload Options
改为Continue Indefinitely
(即持续发包)
设置好后我们开始攻击并刷新购物车页面查看效果:
发送大概一两百个包后我们发现总价已经变成负数并向0递增,所以判断总价可能是是int类型,数据区间可能在此区间内(-2147483647,2147483647),因为 int (整型数据)允许存储的最大值为2147483647,超过这个值就会变成负数形式,这里会不会存在这个问题呢?
根据计算2*2147483647/1337
结果为3212391,我们发送多个包(修改资源池单次最大发包为1),当购物车页面中皮夹克数量为32123时,我们可以发现价格为-1221.96,这时我们尝试添加其他商品来将价格抵消为正数后即可低价购买。
ps:也可以单个包数量为99,发包数量改为323,之后在添加其他商品将价格抵消为正数,这里笔者追求极致低价所以选择了将皮夹克数量精准到32123,仅供参考。
0x04 异常输入的不一致处理
要求:本实验未充分验证用户输入,利用其帐户注册过程中的逻辑缺陷来访问管理面板,并删除 Carlos 用户。
看到题目需要访问管理页面,直接一个/admin
,发现需要一个DontWannaCry
用户,我们先注册一个账号试试。
Email client
是一个提供给我们的已经配置好的邮件客户端,可接收来自其任何子域的邮件:
我们尝试构造@dontwannacry.com
为子域的邮件地址,用户名随意,构造好的邮箱地址形如:
@dontwannacry.com.exploit-ac431fbf1f4f58a8c07449a701db0069.web-security-academy.net
注册好之后尝试访问/admin
页面发现依然不行,因为这时@dontwannacry.com
是子域而并非主域。
接下来我们重新注册账号,我们将用户名设置为长字符串,使其与@dontwannacry.com
相结合之后刚好为255位,测试邮件地址是否存在长字符截断,若存在截断,则后面我们的邮件主域会被截断,主域就变成了@dontwannacry.com
,由此我们就会被误判为拥有管理员权限的账号,构造好的邮箱地址如下:
1234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123@dontwannacry.com.exploit-ac431fbf1f4f58a8c07449a701db0069.web-security-academy.net
【!】下面这部分长度为 255
1234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123451234512345123@dontwannacry.com
这时发现已经有了Admin panel
按钮,我们点进去即为管理面板,删除指定的用户即可。
0x05 不一致的安全控制
要求:本实验存在逻辑漏洞,允许任意用户访问(原本只提供给公司员工的)管理功能,我们访问管理面板并删除 Carlos。
点击 Email Client
获取邮箱地址
点击 Register
,填写上面获取的邮箱,账号密码自定(如 z0sen/123456)。
点击Register
按钮,返回以下信息
回到刚才获取邮箱地址的页面,然后刷新该页面
获取下面页面后,点击激活账号的链接
发现账号注册成功
点击 My account
进入登录页面后,输入刚才设定的账号密码进行登录(z0sen/123456)
登录成功后,将 url 路径改为/admin
并访问
我们发现需要DontWannaCry
用户,也就是注册时提示我们使用@dontwannacry.com
注册的账号
构造 payload:[email protected]
,然后点击 Update email
可以看到,我们的邮箱已被成功修改,且没经过任何鉴权验证(就提升到了管理员权限)。然后点击 Admin panel
进入管理页面删除指定账号即可。
0x06 两用端点上的弱隔离
要求:本实验根据用户的输入对用户的权限级别做出了有缺陷的设计,要求访问管理员账户删除 Carlos。提供了一个测试账号wiener:peter
。
首先我们使用提供的账号进行登录:
登录后来到账户信息页面发现可以修改密码:
我们尝试修改密码并用 Burp Suite 进行抓包,查看有哪些可修改的数据:
我们可以明显看到,用户名密码均为明文传输,先将此包发送到Repeater
模块,由题目可知管理员账号为administrator
,我们尝试修改 username 参数值(即用户名)为管理员账号,并删除current-password
字段(即当前密码)发包,看看能不能直接修改管理员密码:
从返回包中我们可以发现管理员账户密码已被更改,接下来我们在浏览器中退出当前账号wiener
:
尝试使用修改后的管理员密码进行管理员账号登录(此时账号密码为:administrator/123):
成功登录管理员账号,发现已经出现Admin panel
按钮:
进入Admin panel
页面删除 carlos 账号则实验成功:
0x07 工作流程验证不足
要求:本实验对采购流程的事件顺序未进行验证,需要利用此逻辑漏洞购买一件"Lightweight l33t leather jacket",提供了一个测试账号wiener:peter
。
【!】此实验主要是练习对 Burp Suite 中 HTTP history
模块的使用,所以此实验务必全程开启 burp 并配置浏览器走 burp 代理或者直接使用 burp 自带浏览器。
先登录测试账号:
登录后跳转到账户信息页面,显示了余额信息:
接下来点击Home
回到网站首页查看商品目录:
为了尽量清除干扰项,我们在 burp 的 Proxy 模块中的 HTTP History 选项卡中右键,选择Clear history
清除历史记录:
接下来正式开始测试,我们先选择一个余额足以购买的商品(如Giant Grasshopper)点击其下方的View details
进入商品详情页:
然后点击底部的Add to cart
按钮将商品添加到购物车:
接着点击右上角购物袋图标即可进入购物车:
进入购物车之后点击Place order
按钮支付订单:
下单成功显示如下页面
以上为成功下单的流程,我们到 burp 中的HTTP history
模块查看历史请求数据记录,经过筛选发现两个重要的数据包,下单时先是发送POST /cart/checkout
包进行购买确认,此时服务端会判断余额是否足够并返回一个确认信息,余额足够则返回重定向状态码 303 与一个地址为/cart/order-confirmation?order-confirmed=true
的 URI(303 状态码表示重定向链接指向的不是新上传的资源,而是另外一个页面,比如消息确认页面或上传进度页面,而请求重定向页面的方法要总是使用 GET):
紧接着客户端发起订单确认成功的 GET 请求/cart/order-confirmation?order-confirmed=true
完成购买,成功购买商品:
我们按着同样的购买流程,将 Lightweight "l33t" Leather Jacket 添加到购物车并尝试购买:
点击Place order
按钮下单时提示余额不足,购买失败:
我们再回到 burp 中查看刚才的请求历史记录,发现余额不足时服务端会返回一个指向/cart?err=INSUFFICIENT_FUNDS
的重定向:
紧接着客户端发起订单确认失败的 GET 请求/cart?err=INSUFFICIENT_FUNDS
并在页面显示余额不足的提示消息:
了解了订单确认的流程,我们将购买皮夹克失败GET /cart?err=INSUFFICIENT_FUNDS
的包发送到Repeater
模块进行修改,将请求头 URI 修改为/cart/order-confirmation?order-confirmed=true
之后发包,发现未扣款直接购买成功,实验完成:
0x08 通过有缺陷的状态机制绕过身份验证(权限校验流程绕过)
要求:本实验对登录过程的事件顺序未进行验证,需要利用此逻辑漏洞绕过登录验证访问管理面板删除Carlos用户。提供了一个登录账号wiener:peter
。
先打开页面使用测试账号登录:
点击Log in
按钮之后发现有一个用户角色选择,我们先选择 User 进行登录:
登录之后回到了商城首页,接下来我们看到 Burp Suite 的HTTP history
模块查看刚才整个流程的请求数据,发现提交登录请求之后,服务端返回给我们一个重定向到/role/selector
,然后我们就进入了角色选择。也就是说整个登录流程,有两个请求,第一个验证账户密码,第二个请求决定了当前登录账户的角色属性。是否可以通过 drop 角色选择页面,来绕过角色选择而使用系统默认角色呢?
退出账号:
点击 My Account
进入登录页面:
打开Burp Suite来拦截登录包,第一个请求通过 forward:
第二个请求 drop:
这时浏览器页面已经变成了Burp Suite的丢包提示:
将 url 的路径改为/admin
,然后回车访问页面(注意先关闭 burp 拦截),发现此时已经是管理员账号,删除指定用户即可:
0x09 业务规则执行不力
要求:本实验采购流程中存在逻辑漏洞,需要利用此逻辑漏洞购买一件"Lightweight l33t leather jacket",提供了一个登录账号wiener:peter
。
打开页面我们就可以看到置顶的一个优惠码:NEWCUST5
滑到底部我们通过注册新用户(任意输入一个合法邮箱地址点击Sign up
按钮即可)又可以获得一个优惠码:SIGNUP30
拿到两个优惠码之后,我们登录测试账号开始测试,首先添加皮夹克到购物车:
接下来分别应用这俩个优惠码(在输入框中输入优惠码并点击Apply
按钮即可应用优惠码):
发现价格还是很高,我们尝试重复应用优惠码,发现不能连续应用同一个优惠码:
但可以两个优惠码交替应用:
我们反复交替叠加优惠码,最终价格变为 0,点击Place order
按钮下单:
成功实现 0 元购买,实验成功:
0x10 无限余额逻辑漏洞
要求:本实验采购流程中存在逻辑漏洞,需要利用此逻辑漏洞购买一件"Lightweight l33t leather jacket",提供了一个登录账号wiener:peter
。
打开页面我们先来到页面底部通过注册新用户(任意输入一个合法邮箱地址如[email protected]
然后点击Sign up
按钮即可)可以获得一个优惠码:SIGNUP30。
获取优惠码之后我们先登录测试账号,然后回到首页添加Gift Card
到购物车并应用优惠码进行购买;
点击Place order
按钮购买后获得礼品卡兑换码,点击My account
到账户信息页进行兑换:
将兑换码输入到Gift cards
下的输入框点击Redeem
按钮兑换,兑换之后账户余额相比之前多了3块:
重复输入礼品卡兑换码兑换发现兑换码只能使用一次。
接下来我们尝试再次购买礼品卡并使用之前的优惠码SIGNUP30
,发现优惠码可以重复使用,这样也就是说我们可以重复使用此优惠码购买礼品卡来进行兑换,每次一套流程下来多3块,重复进行这套操作余额就会不断增长。
看到 Burp Suite 的HTTP history
模块,这里已经记录了我们刚才一整套的操作流程:
可以使用 Burp Suite 的Macro
模块来自动化重复这套操作,首先在Project options
(项目设置)下的Sessions
(会话设置)选项卡中,点击Session handling rules
(会话处理规则)下的Add
按钮添加新规则,先进入Scope
将URL Scope
设置为Include all URLS
:
接着来到Details
中添加Rule Actions
操作规则,点击Add
按钮选择Run a macro
添加宏操作:
接着我们点击Select macro
设置项下的Add
按钮新建宏操作规则:
选择以下几个包之后点击 OK:
以下是对几个请求数据的解释:
POST /cart 添加礼品卡到购物车
POST /cart/coupon 应用优惠码
POST /cart/checkout 订单确认
GET /cart/order-confirmation?order-confirmed=true 订单确认成功获取到礼品卡兑换码
POST /gift-card 兑换礼品卡
接下来来到Macro Editor
界面,我们选中礼品卡兑换码获取请求(即第四个包)然后点击Configure item
进行设置:
点击Add
按钮添加自定义字段:
字段名可自定义,为了方便识别我这里直接取名为gift-card
,下方选中礼品卡兑换码之后点击两次OK
回到Macro Editor
界面;
接下来我们对礼品卡兑换请求(即第五个包)进行设置:
将 POST 请求中gift-card
值的获取方式改为derived from the prior response
意为由之前的响应获取而来,即从我们上一个请求的返回包中获取自定义字段gift-card
的值填入到本请求中,设置好后点击OK
回到Macro Editor
界面:
设置好后点击Test macro
按钮进行测试,第五个包中获取到gift-card
值则说明设置成功:
刷新浏览器页面发现余额增长 3 元也说明设置成功:
接下来我们点击多次OK
返回到 Burp Suite 主界面;
我们回到HTTP history
模块下找到GET /my-account
请求发送到Intruder
模块:
清除标识符,选择Sniper
模式:
Payloads 设置中Payload type
改为Null payloads
,Payload options
中生成的 Payload 个数填写412 及以上(使得余额足够买要求购买的皮夹克即可):
来到资源池设置线程为 1 然后点击Start attack
开始攻击;
随着不断发包,通过刷新浏览器中的账户信息页面可发现余额也在不断增长,当发送412个包时我们的余额便足以购买皮夹克:
0x11 利用已知加密机制绕过身份验证
要求:本实验包含一个向用户公开加密预言机制的逻辑漏洞,要求利用此逻辑漏洞访问管理面板删除Carlos,提供了一个登录账号wiener:peter
。
我们先勾选保持登录选项然后登录测试账号
接着来到首页我们随便找一篇文章查看,发现有评论系统,评论一条测试消息点击Post Comment
提交:
发现当我们输入不合规的邮件地址时会在页面上返回错误
接下来我们来到 Burp Sutie 的 HTTP history
模块查看刚才的那些操作的数据包,经过筛选我们留下以下几个包,分别是登录、查看账户信息页、提交评论、评论提交后的反馈;
我们观察登录包可以发现,勾选了保持登录选项后,服务器会返回一个stay-logged-in
字段的Set-Cookie
请求,再看到POST /post/comment
评论提交请求,提交评论后服务器会返回一个notification
字段的Set-Cookie
请求,紧接着GET /post?postId=4
包获取评论提交后的结果,这时这个包已经带上了stay-logged-in
和notification
两个Cookie值;
我们看到GET /post?postId=4
包的响应包,有一个notification-header
,这个字段是否和notification
相关,是否就是对notification
这个值的解密?我们直接将POST /post/comment
和GET /post?postId=4
两个请求发送到Repeater
模块进行测试;
分别命名为Encrypt
(POST /post/comment)与Decrypt
(GET /post?postId=4),即加密、解密;
我们尝试修改Decrypt
包中的email
字段,之前为test我们修改为abc123123,然后发包获取notification
值;
我们将返回的notification
值复制,替换掉Decrypt
中的notification
值然后发包查看结果;
总结一下,在email
字段更改之后notification
值也会更改,随后notification-header
块的内容也会更改,说明此内容很可能就是对notification
这个cookie值的解密;
那我们直接尝试将notification
值改为stay-logged-in
的值看看是否可以实现对cookie的解密;
查看返回包之后我们可以发现保持登录这个cookie值就是用户名:登录时间戳
,那么如果我们尝试构造出管理员用户名:时间戳
是否就有了管理员权限,那样不就可以删除指定用户完成实验了?
接下来我们回到Encrypt
包进行cookie构造,管理员账号为administrator
,时间戳直接使用前面获得的时间戳,也可以自己去获取时间戳(毫秒级),获取notification
值后到Decrypt
包粘贴发包查看结果;
我们看到结果多出来Invalid email address
字段,说明生成的notification
值相比stay-logged-in
值多了这样一段内容,我们需要对生成的cookie值进行删减便可获取到正确的cookie;
我们将notification
值发送到Decoder
模块进行修改,依次进行 URL 解码、Base64 解码,使用 Hex 格式进行编辑,我们删除掉23字节之后进行再次编码,将新的编码替换到Repeater
模块的Decrypt
包中进行发送,查看结果;
根据报错信息可知使用了基于块的加密算法,输入长度必须是 16 的倍数,那么我们重新构造用户名为xxxxxxxxxadministrator
,重复上述操作(这次删除32字节),再次查看结果;
此时我们发现管理员账户cookie已经构造成功,接下来我们到HTTP history
找一个GET /
的包(即登录账号后访问首页时的包)发送到Repeater
模块,将stay-logged-in
这个cookie值替换为我们构造好的管理员cookie值,删掉sessions
这个cookie值,修改请求参数为/admin
,发送请求,成功访问到管理面板,我们修改请求参数为/admin/delete?username=carlos
即可删除指定账号。