一次离校系统越权排查:从 JS 接口到学生敏感信息遍历

本文根据实际安全测试记录整理,目标系统及相关敏感信息已进行匿名化处理,仅用于技术交流。

一、测试背景

这次测试的目标是某高校的离校系统。

最开始进入系统并没有发现明显异常,于是我按照正常业务流程进入相关系统,随后继续查看离校系统的功能和前端代码。

在分析过程中,我注意到一个比较值得关注的接口:

/lxxt/lxgl/xsxx/getLxXsxx.html

从接口命名来看,它似乎用于获取学生离校相关信息,因此我决定继续分析它的参数和访问控制。

二、进入离校系统

首先访问学校统一门户,使用测试账号完成登录。

账号、密码及真实域名已经脱敏,原始凭据不在本文中展示。

登录后进入外事综合管理系统。

过程中可能会再次跳转到统一身份认证页面,继续完成身份认证即可。

image-20260914104636992

进入系统后找到离校系统。

image-20260914104937506

打开后进入离校系统自助服务页面。

image-20260914105137109

到这里,正常业务流程基本完成。

真正有意思的地方,是后面的接口分析。

三、从 JS 文件发现可疑接口

在对前端 JS 文件进行代码审计时,我发现了下面这个接口:

/lxxt/lxgl/xsxx/getLxXsxx.html

当时我的第一反应是,这个接口看起来和学生信息获取有关,而且从路径本身来看,并没有明显体现当前登录用户身份绑定关系。

于是直接访问接口进行测试。

接口最开始返回:

null
image-20260914105256777

看到这里其实有点容易放弃。

因为单纯返回 null 并不能证明存在越权,更不能证明存在敏感信息泄露。

所以我继续往下看接口的参数。

四、尝试构造学号参数

进一步测试后,我发现接口支持 xh 参数。

于是尝试加入一个学号:

?xh=222113XX129

接口成功返回了学生相关数据信息。

image-20260914105458663

这时候基本可以确认:

getLxXsxx.html
        ↓
      xh 参数
        ↓
根据学号查询学生信息

但此时返回的数据里暂时没有看到身份证号等明显敏感信息。

当时我一度以为可能只是一个普通的信息查询接口,越权价值并不高。

不过既然已经确认 xh 可以控制查询对象,我还是决定继续研究学号本身的结构。

五、拆解学号结构

继续测试不同学号后,我发现不同年份、不同班级之间似乎存在一定规律。

在原始测试记录中,能够观察到的情况如下:

年级

测试结果

备注

2018

无返回

数据已清除

2019

存在身份证号、手机号

19机械工程(卓工)1

2020

存在身份证号

20机械工程(卓工)1

2021

存在身份证号

21电气工程2

2022

未发现 PII

22机械工程(卓工)1

2023

未发现 PII

23机械工程(卓工)1

这一阶段让我意识到,问题可能并不是简单的“修改一个参数就能看到另一个学生信息”。

真正需要确认的是:

学号是否存在可预测的结构,以及这种结构能不能进一步扩大可访问范围。

六、进一步确认敏感信息泄露

按照学号结构继续进行测试后,最终发现部分历史年级的学生信息中存在身份证号等敏感个人信息。

image-20260914105747637

从测试结果来看,2019—2021 三个年级均能够获取到身份证号相关信息。

其中 2019 年级的测试结果还包含手机号。

这意味着前面发现的 xh 参数并不只是能够查询普通的离校业务数据,而是可能进一步访问到学生敏感个人信息。

七、影响范围测试

在确认存在敏感信息后,我继续对可访问范围进行了验证。

根据原始测试记录,身份证信息的影响范围集中在 2019—2021 三届学生,共验证出:

2019:135 条
2020:135 条
2021:135 条
----------------
合计:405 条

原始记录中的学号结构测试结果为:

年级

C=1

C=2

C=3

小计

验证

2019

45

45

45

135

C=1,SS=01、35

2020

45

45

45

135

C=1,SS=01、35

2021

45

45

45

135

C=1,SS=01、35

总计

405

这里比较关键的一点是,并不是所有年级都存在相同程度的信息泄露

2018 年的数据已经无法正常获取,而 2022、2023 年级在本次测试中没有发现 PII。

因此,文章中的影响范围应当以实际验证结果为准,而不能简单描述成“所有学生信息均可泄露”。

八、漏洞成因的初步判断

从实际测试现象来看,核心问题在于接口允许客户端通过 xh 参数指定需要查询的学生。

也就是说,当前登录身份与被查询学生之间似乎没有形成充分的授权绑定。

抽象来看,业务逻辑类似:

当前登录用户
      │
      │ 请求
      ▼
getLxXsxx.html
      │
      │ xh=指定学号
      ▼
查询对应学生信息

如果服务端仅验证“用户是否登录”,而没有进一步验证:

当前用户
    ≠
被查询学生

那么攻击者就可能通过修改 xh 查询其他学生的数据。

这也是本次测试中最值得关注的地方。

不过,原始测试记录主要证明了接口行为和实际信息泄露结果,并没有包含后端完整代码,因此这里不对服务端具体授权实现方式作进一步推测。

九、这次测试给我的一个提醒

这次排查其实不是一开始就直接发现身份证信息泄露。

最开始看到接口返回 null 时,我也差点认为这个方向没有价值。

真正的突破点是继续分析接口参数,并意识到:

xh

可能并不是一个普通的业务参数,而是直接决定了后端查询哪一个学生。

从这里继续拆解学号结构,才逐渐确认了实际影响范围。

这类问题在测试过程中比较容易被忽略:

接口第一次返回的数据不一定就是最终结果。

如果一个接口允许客户端直接指定资源 ID,那么除了看当前响应内容,还应该进一步确认:

  • 参数是否可以被修改;

  • 修改后是否能够访问其他对象;

  • 服务端是否验证对象归属;

  • 对象 ID 是否具有可预测性;

  • 不同身份、不同对象之间是否存在权限边界;

  • 一旦越权成功,返回的数据到底包含什么。

本次案例中,真正的问题也不是“存在一个可以修改的 xh 参数”,而是服务端对这个参数所代表的学生对象缺少足够的访问控制,最终导致部分学生敏感个人信息可以被越权获取