【HW实录】从一个诡异参数,到横跨十余年的六万师生档案“大裸奔”

作为一名还在象牙塔里死磕安全的网安新人,最近有幸参与了上海市级的某场重量级护网行动。本以为面对那些身经百战的防守方和层层加固的系统,这次会是一场头破血流的硬仗。然而,安全建设的阿喀琉斯之踵,往往隐藏在最不起眼的业务逻辑里。

今天,我想和大家复盘一个我在本次行动中打出的“暴击”——一个看似普通的查询接口,是如何因为经典的越权设计,最终导致该校横跨10多年、近6万名新生及毕业生的极致敏感档案全面暴露的。

0x01 故事背景

接手这个目标——某高校(我们就叫它 target.edu.cn 吧)时,外围资产已经被其他师傅们扫得差不多了,常规的 SQLi、XSS 防御都做得相当扎实。

作为一名大学生,我对高校的业务系统太熟悉了。教务处、学工系统、迎新系统……这些都是我们日常使用的玩意儿。凭着直觉,我将目光锁定在了该校微信公众号里的“新生报到系统”。

在公众号的角落里,我找到了线上报到的入口。系统要求输入“身份证号”和“录取通知书号”进行登录。这很合理,毕竟新生还没拿到统一的学号密码。但我的大脑里立刻弹出一个疑问:登录之后,系统是靠什么机制来绑定当前用户身份的?

0x02 信息收集

我立刻挂上代理,准备用 Yakit 探一探虚实。中间网络配置出了点小插曲,为了不耽误战机,我果断切回了老伙计 Burp Suite。

正常输入测试账号(这里感谢信息收集阶段拿到的一组学号信息)后,点击登录。在 HTTP 历史记录中,一个诡异的 GET 请求引起了我的极度舒适

GET /api_xszc/WelcomeNextServlet?ObjDescribe=101042262100341&bz=1 HTTP/1.1
Host: wzb.target.edu.cn
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...
Cookie: JSESSIONID=E2F8C4E2F40B5AD73EEB82B1BD9F9B6B
...

直觉告诉我,这个 ObjDescribe 参数大有问题。
101042262100341,这串数字太长了,不像是一个随机生成的 Token,反而像是由某种业务规则拼接而成的序列号。

我仔细拆解了这串数字:

  • 前面的 101042 可能是某种固定的业务代码。
  • 中间的 26210034… 等等!这不就是我刚才登录用的学生学号吗?!(26届,学号前缀262100)。

破案了。开发人员在前后端交互时,没有使用可靠的 Session 或 JWT 来鉴权,而是直接把包含用户学号的明文参数暴露在 URL 中,作为查询档案的凭证!

0x03 漏洞利用

如果是这样,那逻辑转换的瞬间就来了:我能不能把这个参数换成别人的学号?

为了验证这个假设,我将请求发送到了 Burp Intruder。
假设当前测试学号是 26210020,我尝试保留前缀 101042,将后面的学号末位随意更改了一下。

当点击 Start Attack 的那一刻,我看到 Response 的 Length 发生了变化,返回了 HTTP 200 OK。
点开 Response 响应体,满屏的 JSON 数据倾泻而出:

拉取几条具体的数据【脱敏后】

{
  "student_info": {
    "name": "李*",
    "id_card": "310119200810******",
    "phone": "1831709****",
    "address": "上海市**区**镇**村",
    "political_status": "群众",
    "health_history": "无疾病史"
  },
  "family_info": [
    {
      "relation": "父亲",
      "name": "李**",
      "phone": "1362191****",
      "workplace": "个体经营"
    },
    {
      "relation": "母亲",
      "name": "王**",
      "phone": "1352470****",
      "workplace": "无"
    }
  ],
  "education_history": [...]
}

通杀了!这是一个极其严重的平行越权漏洞(IDOR)

但是目前已知的泄露数据只有几百条,危害还不够,护网中评分不会高

难道到这里就结束了吗?

接着深入利用该漏洞

越权点ObjDescribe=10104226210020,通过对数字的分析,可以发现26210020是学生学号,占7-13位(但是1-13位都可爆破也就是有全校人信息),然后最后一位我们随便改还是原来学生,我们遍历10-13位,这是26届

我们尝试爆破25届的

ObjDescribe=101042252100400

尝试爆破后3位

我们查看该进度条,占了一半经计算大概也有400多名

尝试爆破24届的

也是四百多条

尝试爆破23年的(950多条)

我们依次按年份来,截至到13年都有学生档案

https://wzb.xxxx.edu.cn/sicfl_xszc/WelcomeNextServlet?ObjDescribe=101042132100400&bz=1

通过这样批量查询,发现全校的学生都能获取到档案

然后我们随机查看一名学生,发现泄露了身份证班级学生姓名,还有父母的手机号工作,以及先居住地址

0x04 漏洞影响

看着满屏流动的进度条,作为一名安全专业的学生,我不仅没有感到狂喜,反而后背发凉。

结合该校历年的官方招生数据,目前在校生约 6000-7000 人,而自建校以来累计毕业生已达 50000 余名。
这意味着什么?
通过这一个极其简单的越权漏洞,黑客可以不费吹灰之力,脱裤获取 近 6 万名学生,以及他们背后近 12 万名父母亲属的终极隐私档案

这不仅仅是姓名和电话。这包含了精准的家庭门牌号、父母的工作单位与职务、甚至是学生的生理健康病史。在电信诈骗和社工攻击如此猖獗的今天,一旦这些“全息立体”的画像数据落入黑产手中,后果简直不堪设想。

最终,我在护网平台提交了这份报告,因其极高的敏感度和极大的数据量级,毫无悬念地拿下了高分

0x05 防御与反思

从攻击者回归建设者的视角,我们必须问一个问题:为什么2024年了,这种“古董级”漏洞依然存在?

Root Cause(根本原因):
这个漏洞的本质是水平越权(Insecure Direct Object Reference, IDOR)
后端 API 在处理 /WelcomeNextServlet 请求时,过度信任了客户端传来的 ObjDescribe 参数。它只验证了“你是否登录”,却没有验证“你当前登录的身份,是否有权限查看 ObjDescribe 所指向的数据对象”。

给开发师傅们的加固建议:

  1. 绝对不要信任客户端传入的标识符鉴权:
    学生查询自己的档案,参数里根本不需要传学号!后端应该直接从当前用户的 Session 或鉴权 Token(如 JWT 解析出的 payload)中提取绑定的学号,以此去查数据库。
  2. 数据层面的权限校验(RBAC/ABAC):
    如果业务确实需要传入 ID(比如辅导员查询特定学生),必须在代码逻辑层加入严格的归属判断:if (requested_student_id not in currentUser.managed_students) { return HTTP_403; }。
  3. 拒绝规律性 ID,拥抱 UUID:
    即使存在权限漏洞,如果将 ObjDescribe 的值从规律的 学号 替换为无规律的、不可预测的 UUID(如 e4b3c2…),也能极大地拉高攻击者横向遍历爆破的成本。

这次护网虽然拿了高分,但也给我上了一课:网络安全没有阳春白雪,最致命的溃堤,往往源于最基础的疏漏。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注