├── requirements.txt ├── imgs └── image-20210805102136882.png ├── LICENSE ├── README.md └── eduSRC.py /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | bs4 3 | matplotlib -------------------------------------------------------------------------------- /imgs/image-20210805102136882.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kracer127/eduSRC-statistic/HEAD/imgs/image-20210805102136882.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, kracer127 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

eduSRC-statistic

2 | 3 |

善于总结,方能突破

4 | 5 |

6 | eduSRC-statistic 7 | eduSRC-statistic 8 | eduSRC-statistic 9 |

10 | 11 | 12 | ## 🏝 0x01 介绍 13 | 作者:kracer 14 | 15 | 定位:研究eduSRC网站提交的漏洞数据,对往年所提交的漏洞的进行总结分类 16 | 17 | 语言:python3开发 18 | 19 | 功能:多线程收集[教育行业漏洞报告平台](https://src.sjtu.edu.cn/)所提交漏洞数据,并对数据进行整理分析,得出往年各类型漏洞提交的频率饼图及漏洞排名,方便新手入手和确定批量刷洞方向。 20 | 21 | 22 | 23 | ## 🎸0x02 安装使用 24 | 25 | 1、所需库安装 26 | 27 | ```python 28 | pip3 install requirements.txt 29 | ``` 30 | 31 | 2、使用 32 | 33 | ```python 34 | 开启:python eduSRC.py 35 | 输入: input 》是否需要进行数据爬取(y|n)::eg.(y|n) 36 | 输入: input 》请输入要爬取的年份:eg.(2021|2020|2019...) 37 | ``` 38 | 39 | 3、说明 40 | 41 | ```python 42 | 文件:edusrc.txt --- 根据年份进行爬取得到的漏洞数据,每条形如:广东省教育厅存在文件上传漏洞 小远 高危 43 | 文件:edu_rank.txt --- 该年份下大学漏洞总数的排名及具体漏洞类型分类。 44 | 文件:submitter_rank.txt --- 该年份下漏洞提交者的提交总数排名及所提交漏洞类型统计。 45 | 另外说明:现存的这三个文件为爬取的2021年数据。 46 | ``` 47 | 48 | 49 | 50 | ## 💡0x03 效果展示 51 | 1、2020-2021年提交漏洞的统计饼图:image-20210805102136882 52 | 53 | 2、2020-2021年各大学校漏洞统计: 54 | 55 | ``` 56 | 年份漏洞总条数:30000 57 | 58 | 上海交通大学:786个漏洞 59 | 江苏省教育厅:496个漏洞 60 | 四川省教育厅:430个漏洞 61 | 安徽省教育厅:398个漏洞 62 | 同济大学:372个漏洞 63 | 浙江省教育厅:359个漏洞 64 | 山东省教育厅:347个漏洞 65 | 浙江大学:332个漏洞 66 | 河南省教育厅:307个漏洞 67 | 福建省教育厅:304个漏洞 68 | 河北省教育厅:277个漏洞 69 | 广东省教育厅:275个漏洞 70 | 华东师范大学:261个漏洞 71 | 兰州大学:251个漏洞 72 | 清华大学:247个漏洞 73 | 陕西省教育厅:230个漏洞 74 | 电子科技大学:225个漏洞 75 | 北京市教育委员会:218个漏洞 76 | 广西壮族自治区教育厅:208个漏洞 77 | 上海市教育委员会:195个漏洞 78 | 湖南省教育厅:186个漏洞 79 | 江西省教育厅:159个漏洞 80 | 四川大学:156个漏洞 81 | 武汉大学:153个漏洞 82 | 重庆市教育委员会:149个漏洞 83 | 湖北省教育厅:148个漏洞 84 | 南开大学:145个漏洞 85 | 中国科学技术大学:140个漏洞 86 | 华东理工大学:138个漏洞 87 | 贵州省教育厅:137个漏洞 88 | 云南省教育厅:133个漏洞 89 | 甘肃省教育厅:130个漏洞 90 | 山西省教育厅:130个漏洞 91 | 辽宁省教育厅:127个漏洞 92 | 山东大学:121个漏洞 93 | 福州大学:113个漏洞 94 | 山东理工大学:113个漏洞 95 | ...... 96 | ``` 97 | 98 | 3、2020-2021年学校漏洞排行榜: 99 | 100 | ``` 101 | 上海交通大学 102 | 低危:147个 103 | 中危:147个 104 | 高危:67个 105 | 严重:23个 106 | 总数:384个 107 | SQL:42个 108 | CSRF:4个 109 | SSRF:4个 110 | XSS:17个 111 | 代码执行:13个 112 | 其他:0个 113 | 命令执行:6个 114 | 垂直权限:21个 115 | 弱口令:145个 116 | 敏感信息:100个 117 | 文件上传:21个 118 | 水平权限:11个 119 | 点击劫持:0个 120 | 江苏省教育厅 121 | 高危:25个 122 | 低危:59个 123 | 中危:37个 124 | 严重:6个 125 | 总数:127个 126 | SQL:18个 127 | CSRF:0个 128 | SSRF:0个 129 | XSS:0个 130 | 代码执行:4个 131 | 其他:0个 132 | 命令执行:4个 133 | 垂直权限:1个 134 | 弱口令:37个 135 | 敏感信息:50个 136 | 文件上传:13个 137 | 水平权限:0个 138 | 点击劫持:0个 139 | 同济大学 140 | 低危:47个 141 | 中危:62个 142 | 高危:13个 143 | 严重:1个 144 | 总数:123个 145 | SQL:17个 146 | CSRF:0个 147 | SSRF:0个 148 | XSS:6个 149 | 代码执行:0个 150 | 其他:0个 151 | 命令执行:7个 152 | 垂直权限:4个 153 | 弱口令:43个 154 | 敏感信息:37个 155 | 文件上传:5个 156 | 水平权限:4个 157 | 点击劫持:0个 158 | 华东师范大学 159 | 中危:49个 160 | 高危:20个 161 | 低危:49个 162 | 严重:3个 163 | 总数:121个 164 | SQL:29个 165 | CSRF:0个 166 | SSRF:2个 167 | XSS:10个 168 | 代码执行:0个 169 | 其他:0个 170 | 命令执行:6个 171 | 垂直权限:4个 172 | 弱口令:28个 173 | 敏感信息:32个 174 | 文件上传:3个 175 | 水平权限:7个 176 | 点击劫持:0个 177 | ...... 178 | ``` 179 | 180 | 4、2020-2021年大佬提交漏洞排行榜: 181 | 182 | ``` 183 | 姜洪杰 184 | 中危:252个 185 | 低危:1565个 186 | 高危:47个 187 | 严重:10个 188 | 总数:1874个 189 | SQL:7个 190 | CSRF:0个 191 | SSRF:0个 192 | XSS:2个 193 | 代码执行:3个 194 | 其他:69个 195 | 命令执行:5个 196 | 垂直权限:0个 197 | 弱口令:876个 198 | 敏感信息:911个 199 | 文件上传:1个 200 | 水平权限:0个 201 | 点击劫持:0个 202 | 远海 203 | 高危:191个 204 | 低危:20个 205 | 中危:207个 206 | 严重:1个 207 | 总数:419个 208 | SQL:167个 209 | CSRF:0个 210 | SSRF:0个 211 | XSS:0个 212 | 代码执行:0个 213 | 其他:32个 214 | 命令执行:1个 215 | 垂直权限:30个 216 | 弱口令:34个 217 | 敏感信息:6个 218 | 文件上传:140个 219 | 水平权限:8个 220 | 点击劫持:1个 221 | 鲁中代表 222 | 高危:12个 223 | 中危:35个 224 | 低危:372个 225 | 总数:419个 226 | SQL:7个 227 | CSRF:0个 228 | SSRF:0个 229 | XSS:0个 230 | 代码执行:6个 231 | 其他:11个 232 | 命令执行:2个 233 | 垂直权限:1个 234 | 弱口令:52个 235 | 敏感信息:337个 236 | 文件上传:3个 237 | 水平权限:0个 238 | 点击劫持:0个 239 | flank 240 | 高危:36个 241 | 低危:123个 242 | 中危:101个 243 | 严重:11个 244 | 总数:271个 245 | SQL:11个 246 | CSRF:0个 247 | SSRF:0个 248 | XSS:11个 249 | 代码执行:23个 250 | 其他:101个 251 | 命令执行:10个 252 | 垂直权限:2个 253 | 弱口令:86个 254 | 敏感信息:28个 255 | 文件上传:2个 256 | 水平权限:1个 257 | 点击劫持:0个 258 | 教主assassin 259 | 中危:99个 260 | 低危:93个 261 | 高危:33个 262 | 严重:7个 263 | 总数:232个 264 | SQL:15个 265 | CSRF:0个 266 | SSRF:1个 267 | XSS:10个 268 | 代码执行:2个 269 | 其他:56个 270 | 命令执行:15个 271 | 垂直权限:15个 272 | 弱口令:64个 273 | 敏感信息:33个 274 | 文件上传:8个 275 | 水平权限:13个 276 | 点击劫持:0个 277 | ...... 278 | ``` 279 | 280 | -------------------------------------------------------------------------------- /eduSRC.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # by:kracer 3 | import re 4 | import requests 5 | import time 6 | from threading import * 7 | from multiprocessing import Process 8 | from bs4 import BeautifulSoup as bs 9 | import matplotlib.pyplot as plt 10 | 11 | url0 = "https://src.sjtu.edu.cn/list/?page=" 12 | submitter_index_dic, edu_index_dic = {}, {} 13 | datas = [] #承载爬虫获取的数据(列表形式) 14 | bug_name = ["SQL", "CSRF", "SSRF", "XSS", "代码执行", "其他", "命令执行", "垂直权限", "弱口令", "敏感信息", "文件上传", "水平权限", "点击劫持"] 15 | lock = Lock() 16 | #爬取平台网站数据函数 17 | def getData(a, num): 18 | with open(r'edusrc.txt', 'w+', encoding='utf-8') as f: 19 | for page in range((num + a - 300), (a+1)): 20 | url = url0 + str(page) 21 | r = requests.get(url=url) 22 | r.encoding = r.apparent_encoding 23 | soup = bs(r.text, 'lxml') 24 | result = soup.find_all(name='tr', attrs={'class':'row'}) 25 | soup1 = bs(str(result), 'lxml') 26 | result0 = soup1.find_all(name='a') #初始的a标签数据 27 | result1 = [i.string for i in result0] 28 | result1_new = [] #正则获取学校漏洞名称 29 | for i in range(len(result1)): 30 | if(i%2 == 0): 31 | text = re.findall(r'(\w.*)', result1[i]) 32 | result1_new.append(text[0]) 33 | else: 34 | continue 35 | result2 = re.findall(r'(.*)', str(result0)) #正则匹配用户名 36 | result3 = soup1.find_all(name='span') #高危 低危... 37 | result3 = [i.string for i in result3] 38 | for i in range(len(result1_new)): #写进txt文件 39 | f.write(str(result1_new[i]) + '\t' + str(result2[i]) + '\t' + str(result3[i]) + '\n') 40 | 41 | #设置多线程爬取函数 42 | def Th(fuc, num): 43 | t = [] 44 | for i in range(1, 21): 45 | Th1 = Thread(target=fuc, args=(100*i, num,)) 46 | t.append(Th1) 47 | for i in t: 48 | i.start() 49 | for j in t: 50 | j.join() 51 | 52 | #设置多进程爬取函数 53 | def Pr(fuc, num): 54 | t = [] 55 | for i in range(1, 11): 56 | Pr1 = Process(target=fuc, args=(300*i, num,)) 57 | t.append(Pr1) 58 | for i in t: 59 | i.start() 60 | for j in t: 61 | j.join() 62 | 63 | #对爬取所得数据进行处理 64 | def process(): 65 | global datas, edu_index_list, submitter_index_dic 66 | times = 0 67 | edu_dic, submitter_dic = {}, {} 68 | with open('edusrc.txt', 'r+', encoding='utf-8') as f: 69 | for i in f.readlines(): 70 | i.rstrip('\n') 71 | lis = i.split('\t') 72 | if len(lis) == 3: #处理特殊数据报错情况 73 | datas.append(i.split('\t')) 74 | submitter_dic.setdefault(datas[times][1], {}) #初始化外层字典的key值 75 | submitter_dic[datas[times][1]].setdefault(datas[times][2].rstrip('\n'), 0) #初始化内层字典的key值,并且赋值value=0 76 | submitter_dic[datas[times][1]][datas[times][2].rstrip('\n')] += 1 #内层字典的value值 +1 77 | try: 78 | name = re.findall(r'(.*["学"|"院"|"厅"|"部"|"会"|"司"|"局"|"区"|"T"|"馆"|"他"|"心"])', datas[times][0])[0] #正则匹配学校名 79 | except Exception as e: 80 | print(datas[times][0]) 81 | edu_dic.setdefault(name, {}) 82 | edu_dic[name].setdefault(datas[times][2].rstrip('\n'), 0) 83 | edu_dic[name][datas[times][2].rstrip('\n')] += 1 84 | times += 1 85 | else: 86 | continue 87 | for k_1, v_1 in edu_dic.items(): #计算每个大学的漏洞总数 88 | v_1["总数"] = 0 89 | for k_2 in v_1.keys(): 90 | if "总数" == k_2: 91 | continue 92 | else: 93 | v_1["总数"] += v_1[k_2] 94 | edu_dic_new = sorted(edu_dic, key=lambda x: edu_dic[x]["总数"], reverse=True) 95 | for k_3, v_3 in submitter_dic.items(): #计算每个submitter的漏洞总数 96 | v_3["总数"] = 0 97 | for k_4 in v_3.keys(): 98 | if "总数" == k_4: 99 | continue 100 | else: 101 | v_3["总数"] += v_3[k_4] 102 | edu_dic_new = sorted(edu_dic, key=lambda x: edu_dic[x]["总数"], reverse=True) 103 | submitter_dic_new = sorted(submitter_dic, key=lambda x: submitter_dic[x]["总数"], reverse=True) 104 | for edu in edu_dic_new: #根据漏洞总数进行二重字典排序 105 | edu_index_dic[edu] = edu_dic[edu] 106 | for submitter in submitter_dic_new: 107 | submitter_index_dic[submitter] = submitter_dic[submitter] 108 | return datas, submitter_index_dic, edu_index_dic 109 | 110 | #对用户输入查询年份的预处理函数 111 | def processYear(year): 112 | if year == "2021": 113 | print("正在爬取{0}年数据......".format(year)) 114 | Pr(getData, 1) 115 | print("数据采集完毕, 请选择下一步操作......") 116 | processFinish() 117 | elif year == "2020": 118 | print("正在爬取{0}年数据......".format(year)) 119 | Pr(getData, 3000) 120 | print("数据采集完毕, 请选择下一步操作......") 121 | processFinish() 122 | elif year == "2019": 123 | print("正在爬取{0}年数据......".format(year)) 124 | Pr(getData, 5000) 125 | print("数据采集完毕, 请选择下一步操作......") 126 | processFinish() 127 | else: 128 | print("正在爬取{0}年数据......".format(year)) 129 | Pr(getData, 7000) 130 | print("数据采集完毕, 请选择下一步操作......") 131 | processFinish() 132 | 133 | #数据采集完成后的分析操作预处理函数 134 | def processFinish(): 135 | print("正在处理数据并进行分析可视化......") 136 | process() 137 | print("对edu大学|提交者进行排名分析并写进txt文件......") 138 | edu_submitter_rank(datas, edu_index_dic, submitter_index_dic) 139 | print("数据写入文件完成.......") 140 | print("处理完毕,统计各类型漏洞数据......") 141 | Tongji_bug(datas) 142 | print("统计完毕,进行漏洞类型画饼图可视化......") 143 | Huatu(dic_bug) 144 | 145 | #对edu大学|提交者进行排名分析, 写进txt文件 146 | def edu_submitter_rank(datas, edu_index_dic, submitter_index_dic): 147 | for bug in bug_name: 148 | for index_edu in edu_index_dic.keys(): 149 | edu_index_dic[index_edu].setdefault(bug, 0) 150 | for index_submitter in submitter_index_dic.keys(): 151 | submitter_index_dic[index_submitter].setdefault(bug, 0) 152 | for i in datas: 153 | name = re.findall(r'(.*["学"|"院"|"厅"|"部"|"会"|"司"|"局"|"区"|"T"|"馆"|"他"|"心"])', i[0])[0] # 正则匹配学校名 154 | submitter = i[1] 155 | for j in bug_name: 156 | if j in i[0]: 157 | edu_index_dic[name][j] += 1 158 | submitter_index_dic[submitter][j] += 1 159 | with open('edu_rank.txt', 'w+', encoding='utf-8') as f, open('submitter_rank.txt', 'w+', encoding='utf-8') as f1: 160 | for i in edu_index_dic.keys(): 161 | f.write(str(i) + '\n') 162 | for j in edu_index_dic[i]: 163 | f.write('\t' + str(j) + ":" + str(edu_index_dic[i][j]) + "个" + '\n') 164 | for k in submitter_index_dic.keys(): 165 | f1.write(str(k) + '\n') 166 | for l in submitter_index_dic[k]: 167 | f1.write('\t' + str(l) + ":" + str(submitter_index_dic[k][l]) + "个" + '\n') 168 | 169 | #对各类型漏洞数据进行统计画饼图可视化 170 | def Tongji_bug(datas): 171 | global dic_bug 172 | dic_bug = {"SQL": 0, "CSRF": 0, "SSRF": 0, "XSS": 0, "代码执行": 0, "其他": 0, "命令执行": 0, "垂直权限": 0, "弱口令": 0, "敏感信息": 0, "文件上传": 0, "水平权限": 0, "点击劫持": 0} 173 | for i in datas: 174 | for j in bug_name: 175 | if j in i[0]: 176 | dic_bug[j] += 1 177 | dic_bug = dict(sorted(dic_bug.items(), key=lambda k: k[1], reverse=True)) 178 | 179 | #对统计好的漏洞类型数据进行可视化(饼图) 180 | def Huatu(data): 181 | # 准备数据 182 | data_list, label_list = [], [] 183 | for k, v in data.items(): 184 | data_list.append(v) 185 | label_list.append(k) 186 | title = "2020-2021年教育业漏洞排行榜" 187 | plt.figure(figsize=(15, 15)) 188 | #显示的中文字体设置 189 | plt.rcParams['font.family'] = 'SimHei' 190 | # 将排列在第4位的语言(Python)分离出来 191 | explode = [0, 0, 0, 0, 0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5] 192 | # 使用自定义颜色 193 | colors = ['silver', 'cyan', 'khaki', 'pink', 'magenta', 'darkseagreen', 'm', 'teal', 'skyblue', 'tomato', 'green', 'yellowgreen', 'lime'] 194 | # colors = ['red', 'pink', 'magenta', 'purple', 'orange'] 195 | # 将横、纵坐标轴标准化处理,保证饼图是一个正圆,否则为椭圆 196 | plt.axes(aspect='equal') 197 | # 控制X轴和Y轴的范围(用于控制饼图的圆心、半径) 198 | plt.xlim(0, 12) 199 | plt.ylim(0, 12) 200 | # 不显示边框 201 | plt.gca().spines['right'].set_color('none') 202 | plt.gca().spines['top'].set_color('none') 203 | plt.gca().spines['left'].set_color('none') 204 | plt.gca().spines['bottom'].set_color('none') 205 | # 绘制饼图 206 | plt.pie(x=data_list, # 绘制数据 207 | labels=label_list, # 添加编程语言标签 208 | explode=explode, # 突出显示Python 209 | colors=colors, # 设置自定义填充色 210 | autopct='%0.1f%%', # 设置百分比的格式,保留3位小数 211 | pctdistance=0.8, # 设置百分比标签和圆心的距离 212 | labeldistance=1.1, # 设置标签和圆心的距离 213 | startangle=180, # 设置饼图的初始角度 214 | center=(6, 5), # 设置饼图的圆心(相当于X轴和Y轴的范围) 215 | radius=6, # 设置饼图的半径(相当于X轴和Y轴的范围) 216 | counterclock=False, # 是否为逆时针方向,False表示顺时针方向 217 | wedgeprops={'linewidth': 1, 'edgecolor': 'red'}, # 设置饼图内外边界的属性值 218 | textprops={'fontsize': 11, 'color': 'black'}, # 设置文本标签的属性值 219 | frame=1) # 是否显示饼图的圆圈,1为显示 220 | # 不显示X轴、Y轴的刻度值 221 | plt.xticks(()) 222 | plt.yticks(()) 223 | # 显示图形 224 | # 添加图形标题 225 | plt.title(title) 226 | plt.show() 227 | 228 | def main(): 229 | userChooes = input("是否需要进行数据爬取(y|n):") 230 | if userChooes == "y": 231 | chooesYear = input("请输入要爬取的年份:") 232 | processYear(chooesYear) 233 | process() 234 | elif userChooes == "n": 235 | processFinish() 236 | else: 237 | print("错误!请输入'Y'或者'n'") 238 | 239 | 240 | if __name__ == "__main__": 241 | main() --------------------------------------------------------------------------------