Files
yakpanel-core/class/panelWarning.py

1623 lines
67 KiB
Python
Raw Normal View History

2026-04-07 02:04:22 +05:30
# coding: utf-8
# +-------------------------------------------------------------------
# | YakPanel
# +-------------------------------------------------------------------
# | Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# +-------------------------------------------------------------------
# | Author: hwliang <2020-08-04>
# +-------------------------------------------------------------------
import os, sys, json, time, public, datetime
class panelWarning:
__path = '/www/server/panel/data/warning'
__ignore = __path + '/ignore'
__result = __path + '/result'
__risk = __path + '/risk'
_vuln_ignore = __path + '/ignore.json'
_vuln_result = __path + '/result.json'
__repair_count = __path + '/repair_count.json'
__vul_list = __path + '/high_risk_vul-9.json' # 空i那么皮的泡沫隔离
__report = '/www/server/panel/data/warning_report'
vul_num = 0
discov_count = 0 # 扫描中发现的漏洞数
score = 100 # 扫描中动态分数
yum_time = __path + '/yum_time.pl'
new_vul_list = __path + '/vul_centos7.json'
product_version = __path + '/product_version.json'
def __init__(self):
if not os.path.exists(self.__ignore):
os.makedirs(self.__ignore, 384)
if not os.path.exists(self.__result):
os.makedirs(self.__result, 384)
if not os.path.exists(self.__risk):
os.makedirs(self.__risk, 384)
if not os.path.exists(self.__path):
os.makedirs(self.__path, 384)
if not os.path.exists(self.__report):
os.makedirs(self.__report, 384)
if not os.path.exists(self._vuln_ignore):
result = []
public.WriteFile(self._vuln_ignore, json.dumps(result))
if not os.path.exists(self._vuln_result):
result = []
public.WriteFile(self._vuln_result, json.dumps(result))
self.new_system_result = []
# self.sys_version = self.get_sys_version()
# self.sys_product = self.new_get_sys_product()
def _get_list(self):
# 最终输出结果
self.data = {
'security': [],
'risk': [],
'ignore': [],
"is_autofix": [],
}
# 获取支持一键修复的列表
try:
is_autofix = public.read_config("safe_autofix")
except:
is_autofix = []
# 临时扫描结果,中断的时候返回
self.tmp_data = {
'security': [],
'risk': [],
'ignore': [],
'is_autofix': is_autofix,
'check_time': datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
}
context = {"status": "Ready to repair", "percentage": 0, "count": 0, "score": 100}
public.WriteFile(self.__path + '/bar.txt', json.dumps(context)) # 扫描进度条归零
bar_num = 0 # 进度条初始化
bar_limit = 0 # 进度条限制
self.discov_count = 0 # 扫描中发现漏洞数量初始化
self.score = 100 # 扫描中分数变化
sys_version = self.get_sys_version() # 获取系统版本
# self.compare_md5() # 比较漏洞库版本
# 下载新版漏洞库文件
if not self.download_new_vulns():
sys_version = None
# centos_7走新版漏洞扫描
if sys_version == 'centos_7' or sys_version == 'centos_8' or sys_version == 'centos_8_stream':
self.new_system_scan()
# ubuntu走新版2接口
elif sys_version == 'ubuntu_20.04' or sys_version == 'ubuntu_22.04' or sys_version == 'ubuntu_18.04' or sys_version == 'debian_12' or sys_version == 'debian_11' or sys_version == 'debian_10':
self.new_system_scan2()
# 旧版本漏洞检测
# else:
# self.system_scan() # 旧版本系统漏洞扫描
# 加载安全风险模块
p = public.get_modules('class/safe_warning')
for m_name in p.__dict__.keys():
ignore_file = self.__ignore + '/' + m_name + '.pl'
# 忽略的检查项
if p[m_name]._level == 0: continue
m_info = {
'title': p[m_name]._title,
'm_name': m_name,
'ps': p[m_name]._ps,
'version': p[m_name]._version,
'level': p[m_name]._level,
'ignore': p[m_name]._ignore,
'date': p[m_name]._date,
'tips': p[m_name]._tips,
'help': p[m_name]._help
}
try:
m_info['remind'] = p[m_name]._remind
except:
pass
result_file = self.__result + '/' + m_name + '.pl'
try:
s_time = time.time()
m_info['status'], m_info['msg'] = p[m_name].check_run()
m_info['taking'] = round(time.time() - s_time, 6)
m_info['check_time'] = int(time.time())
public.writeFile(result_file, json.dumps(
[m_info['status'], m_info['msg'], m_info['check_time'], m_info['taking']], ))
except:
continue
m_info['ignore'] = os.path.exists(ignore_file)
if m_info['ignore']:
self.data['ignore'].append(m_info)
self.tmp_data['ignore'].append(m_info) # 临时扫描结果
else:
if m_info['status']:
self.data['security'].append(m_info)
self.tmp_data['security'].append(m_info) # 临时扫描结果
else:
risk_file = self.__risk + '/' + m_name + '.pl'
public.writeFile(risk_file, json.dumps(m_info))
self.data['risk'].append(m_info)
self.tmp_data['risk'].append(m_info) # 临时扫描结果
self.discov_count += 1 # 扫描中发现风险数
self.score -= m_info['level']
if self.score < 0:
self.score = 0
bar = ("%.2f" % (float(bar_num) / float(len(p.__dict__.keys())) * 50 + 50))
# 通过进度条限制,防止写文件频繁占用高
if int(float(bar)) >= bar_limit:
context = {"status": "{}".format(m_info['title']), "percentage": int(float(bar)), "count": self.discov_count, "score": self.score}
public.WriteFile(self.__path + '/bar.txt', json.dumps(context))
self.dump_tmp_result() # 发现漏洞,先保存一份临时的
bar_limit += 10
bar_num += 1
# 新版漏洞检测无需读文件
# is_autofix被包含进tmp_data{}字典里,会动态增加
self.data['is_autofix'] = is_autofix
# self.data['is_autofix'] += is_autofix
# if sys_version == 'centos_7' or sys_version == 'ubuntu_20.04' or sys_version == 'ubuntu_22.04' or sys_version == 'ubuntu_18.04' or sys_version == 'debian_12' or sys_version == 'debian_11' or sys_version == 'debian_10':
# self.data['is_autofix'] += is_autofix
# 旧版本漏洞检测
# else:
# vuln_result = self.get_vuln_result()
# self.data['risk'] = self.data['risk'] + vuln_result['risk']
# self.data['ignore'] = self.data['ignore'] + vuln_result['ignore']
# vuln_is_autofix = []
# for vr in vuln_result['risk']:
# if not vr["reboot"]:
# vuln_is_autofix.append(vr["cve_id"])
# self.data['is_autofix'] = is_autofix + vuln_is_autofix
score = 100
for d in self.data['risk']:
score = score - d['level']
if score < 0:
self.data['score'] = 0
else:
self.data['score'] = score
self.data['risk'] = sorted(self.data['risk'], key=lambda x: x['level'], reverse=True)
self.data['security'] = sorted(self.data['security'], key=lambda x: x['level'], reverse=True)
self.data['ignore'] = sorted(self.data['ignore'], key=lambda x: x['level'], reverse=True)
self.data['check_time'] = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
# 将结果输出一份到报告目录下
with open("/www/server/panel/data/warning_report/data.json", "w") as f:
json.dump(self.data, f)
self.record_times()
context = {"status": "检测完成", "percentage": 100, "count": self.discov_count, "score": self.score}
public.WriteFile(self.__path + '/bar.txt', json.dumps(context))
# public.WriteFile(self.__path + '/bar.txt', "100") # 扫描进度条归零
return self.data
def download_new_vulns(self):
'''
根据系统版本确定漏洞库名
'''
sys_version = self.get_sys_version()
zip_file = ""
if sys_version == "centos_7":
self.new_vul_list = self.__path + '/vul_centos7.json'
zip_file = "vul_centos7.zip"
elif sys_version == "centos_8":
self.new_vul_list = self.__path + '/vul_centos8.json'
zip_file = "vul_centos8.zip"
elif sys_version == "centos_8_stream":
self.new_vul_list = self.__path + '/vul_centos8stream.json'
zip_file = "vul_centos8stream.zip"
elif sys_version == "ubuntu_20.04":
self.new_vul_list = self.__path + '/vul_ubuntu2004.json'
zip_file = "vul_ubuntu2004.zip"
elif sys_version == "ubuntu_22.04":
self.new_vul_list = self.__path + '/vul_ubuntu2204.json'
zip_file = "vul_ubuntu2204.zip"
elif sys_version == "ubuntu_18.04":
self.new_vul_list = self.__path + '/vul_ubuntu1804.json'
zip_file = "vul_ubuntu1804.zip"
elif sys_version == "debian_12":
self.new_vul_list = self.__path + '/vul_debian12.json'
zip_file = "vul_debian12.zip"
elif sys_version == "debian_11":
self.new_vul_list = self.__path + '/vul_debian11.json'
zip_file = "vul_debian11.zip"
elif sys_version == "debian_10":
self.new_vul_list = self.__path + '/vul_debian10.json'
zip_file = "vul_debian10.zip"
# 检查漏洞库文件是否存在
if not os.path.exists(self.new_vul_list):
if zip_file != '':
downfile = self.__path+'/'+zip_file
public.downloadFile("{}/safe_warning/{}".format(public.get_url(), zip_file), downfile)
o, e = public.ExecShell("unzip -o {} -d {}".format(downfile, self.__path))
# 解压报错
if e != "":
return False
else:
return False
return True
# cve_id
def get_list(self, args):
'''
@name 开始扫描并返回结果
@param args:
@return:
'''
import subprocess
public.set_module_logs("panelWarning", "get_list")
public.WriteFile(self.__path + '/kill.pl', "False") # 用来判断这次的扫描是否被中断,默认没中断
command = "btpython /www/server/panel/class/panelWarning.py"
process = subprocess.Popen(command, shell=True)
# 获取进程ID
pid = process.pid
public.WriteFile(self.__path + "/pid.txt", str(pid))
process.wait()
output = json.loads(public.ReadFile(self.__path+ '/resultresult.json'))
# 给前端判断这次的扫描结果是否中断
if public.ReadFile(self.__path + '/kill.pl') == "True":
output["interrupt"] = True
else:
output["interrupt"] = False
return output
def sync_rule(self):
'''
@name 从云端同步规则
@author hwliang<2020-08-05>
@return void
'''
# try:
# dep_path = '/www/server/panel/class/safe_warning'
# local_version_file = self.__path + '/version.pl'
# last_sync_time = local_version_file = self.__path + '/last_sync.pl'
# if os.path.exists(dep_path):
# if os.path.exists(last_sync_time):
# if int(public.readFile(last_sync_time)) > time.time():
# return
# else:
# if os.path.exists(local_version_file): os.remove(local_version_file)
# download_url = public.get_url()
# version_url = download_url + '/install/warning/version.txt'
# cloud_version = public.httpGet(version_url)
# if cloud_version: cloud_version = cloud_version.strip()
# local_version = public.readFile(local_version_file)
# if local_version:
# if cloud_version == local_version:
# return
# tmp_file = '/tmp/bt_safe_warning.zip'
# public.ExecShell('wget -O {} {} -T 5'.format(tmp_file,download_url + '/install/warning/safe_warning.zip'))
# if not os.path.exists(tmp_file):
# return
# if os.path.getsize(tmp_file) < 2129:
# os.remove(tmp_file)
# return
# if not os.path.exists(dep_path):
# os.makedirs(dep_path,384)
# public.ExecShell("unzip -o {} -d {}/ >/dev/null".format(tmp_file,dep_path))
# public.writeFile(local_version_file,cloud_version)
# public.writeFile(last_sync_time,str(int(time.time() + 7200)))
# if os.path.exists(tmp_file): os.remove(tmp_file)
# public.ExecShell("chmod -R 600 {}".format(dep_path))
# except:
# pass
def set_ignore(self, args):
'''
@name 设置指定项忽略状态
@author hwliang<2020-08-04>
@param dict_obj {
m_name<string> 模块名称
}
@return dict
'''
m_name = args.m_name.strip()
ignore_file = self.__ignore + '/' + m_name + '.pl'
if os.path.exists(ignore_file):
os.remove(ignore_file)
else:
public.writeFile(ignore_file, '1')
return public.returnMsg(True, public.lang("successfully set!"))
def check_find(self, args):
'''
@name 检测指定项
@author hwliang<2020-08-04>
@param dict_obj {
m_name<string> 模块名称
}
@return dict
'''
try:
m_name = args.m_name.strip()
p = public.get_modules('class/safe_warning')
m_info = {
'title': p[m_name]._title,
'm_name': m_name,
'ps': p[m_name]._ps,
'version': p[m_name]._version,
'level': p[m_name]._level,
'ignore': p[m_name]._ignore,
'date': p[m_name]._date,
'tips': p[m_name]._tips,
'help': p[m_name]._help
}
# 解决已经在忽略列表中,但是如果仍然需要检查的话可以检查
ignore_file = self.__ignore + '/' + m_name + '.pl'
if os.path.exists(ignore_file):
from cachelib import SimpleCache
cache = SimpleCache(5000)
ikey = 'warning_list'
cache.delete(ikey)
os.remove(ignore_file)
result_file = self.__result + '/' + m_name + '.pl'
s_time = time.time()
m_info['status'], m_info['msg'] = p[m_name].check_run()
m_info['taking'] = round(time.time() - s_time, 4)
m_info['check_time'] = int(time.time())
public.writeFile(result_file, json.dumps(
[m_info['status'], m_info['msg'], m_info['check_time'], m_info['taking']]))
return public.returnMsg(True, public.lang("It has been retested."))
except:
return public.returnMsg(False, public.lang("Detection failed"))
def system_scan(self):
'''
一键扫描系统
:param get:
:return: dict
'''
self.compare_md5()
sys_version = self.get_sys_version()
# if sys_version == 'None':
# return public.returnMsg(False, public.lang("当前系统暂不支持"))
sys_product = self.get_sys_product()
# if not os.path.exists(self.__vul_list):
# return public.returnMsg(False, public.lang("扫描失败"))
vul_list = self.get_vul_list()
new_risk_list = []
new_ignore_list = []
# error_list = []
result_dict = {}
# cp_list = []
vul_count = 0
ignore_list = self.get_ignore_list()
reboot_count = 0
self.vul_num = len(vul_list)
bar_num = 0 # 进度条初始化
bar_limit = 0 # 进度条限制
for vul in vul_list:
bar = ("%.2f" % (float(bar_num)/float(self.vul_num)*50))
# 限制进度条,限制写文件频率
if int(float(bar)) >= bar_limit:
context = {"status": "{}".format(vul['cve_id']), "percentage": int(float(bar)), "count": self.discov_count, "score": self.score}
public.WriteFile(self.__path+'/bar.txt', json.dumps(context))
self.dump_tmp_result() # 发现漏洞,先保存一份临时的
bar_limit += 10
bar_num += 1
vul_count += 1
for v in vul["affected_list"]:
if v["manufacturer"] == sys_version:
tmp = 1 # 默认命中
if not 'affected' in v: continue
arr = v['affected'].split("Up to (excluding)\n ")
if len(arr) < 2: continue
vul_version = arr[1]
try:
for soft in v["softname"]:
compare_result = self.version_compare(sys_product[soft], vul_version)
if compare_result >= 0:
tmp = 0 # 当有一个软件包版本不在漏洞范围内,则不命中
break
if tmp == 1:
# softname_list = [soft+'-'+sys_product[soft] for soft in v["softname"]]
# softname_list = [{soft: sys_product[soft]} for soft in v["softname"]]
self.discov_count += 1 # 扫描中发现漏洞数
softname_dict = {}
for soft in v["softname"]:
softname_dict[soft] = sys_product[soft]
level = self.get_score_risk(vul["score"])
vul_dict = {key: vul[key] for key in ["cve_id", "vuln_name", "vuln_time", "vuln_solution"]}
vul_dict["level"] = level
self.score -= level # 扫描中的动态分数
if self.score < 0:
self.score = 0
vul_dict["soft_name"] = softname_dict
vul_dict["vuln_version"] = vul_version
vul_dict["check_time"] = int(time.time())
vul_dict["reboot"] = ""
if "kernel" in [k for k in v["softname"]]:
vul_dict["reboot"] = "This vulnerability is a kernel vulnerability, and you need to upgrade the kernel version yourself. It is recommended to make snapshots and backups before upgrading"
reboot_count += 1
if vul["cve_id"] in ignore_list:
new_ignore_list.append(vul_dict)
self.tmp_data['ignore'].append(vul_dict) # 添加到临时字典
break
new_risk_list.append(vul_dict)
self.tmp_data['risk'].append(vul_dict) # 添加到临时字典
if vul_dict["reboot"]:
self.tmp_data['is_autofix'].append(vul_dict["cve_id"])
break
# cp_list.append(vul["cve_id"]+': '+str([soft+'-'+sys_product[soft] for soft in v["softname"]])+' >= '+vul_version)
except Exception as e:
# error_list.append(vul["cve_id"]+': '+str(e))
break
result_dict["vul_count"] = vul_count
result_dict["risk"] = new_risk_list
result_dict["ignore"] = new_ignore_list
# result_dict["reboot"] = self.__need_reboot
# result_dict["error"] = error_list
# result_dict["compare"] = cp_list
public.WriteFile(self.__path + '/system_scan_time', str(int(time.time())))
public.WriteFile(self._vuln_result, json.dumps(result_dict))
# try:
# public.WriteFile(self._vuln_result, json.dumps(result_dict))
# return public.returnMsg(True, public.lang("扫描完成"))
# except:
# return public.returnMsg(False, public.lang("扫描失败"))
# 版本比较
def version_compare(self, ver_a, ver_b):
'''
比较版本大小
:param ver_a: 软件版本
:param ver_b: 漏洞版本
:return: int 大于等于返回1或0小于返回-1
'''
sys_version = self.get_sys_version()
if "ubuntu" in sys_version or "debian" in sys_version:
if ver_b.startswith("1:"):
ver_b = ver_b[2:]
# if ver_a.startswith("1:"):
# ver_a = ver_a[2:]
result = public.ExecShell("dpkg --compare-versions " + ver_a + " ge " + ver_b + " && echo true")
if 'warning' in result[1].strip(): return None
if 'true' in result[0].strip():
return 1
else:
return -1
return self.vercmp(ver_a, ver_b)
def vercmp(self, first, second):
import re
R_NONALNUMTILDE = re.compile(br"^([^a-zA-Z0-9~]*)(.*)$")
R_NUM = re.compile(br"^([\d]+)(.*)$")
R_ALPHA = re.compile(br"^([a-zA-Z]+)(.*)$")
first = first.encode("ascii", "ignore")
second = second.encode("ascii", "ignore")
while first or second:
m1 = R_NONALNUMTILDE.match(first)
m2 = R_NONALNUMTILDE.match(second)
m1_head, first = m1.group(1), m1.group(2)
m2_head, second = m2.group(1), m2.group(2)
if m1_head or m2_head:
continue
if first.startswith(b'~'):
if not second.startswith(b'~'):
return -1
first, second = first[1:], second[1:]
continue
if second.startswith(b'~'):
return 1
if not first or not second:
break
m1 = R_NUM.match(first)
if m1:
m2 = R_NUM.match(second)
if not m2:
return 1
isnum = True
else:
m1 = R_ALPHA.match(first)
m2 = R_ALPHA.match(second)
isnum = False
if not m1:
return -1
if not m2:
return 1 if isnum else -1
m1_head, first = m1.group(1), m1.group(2)
m2_head, second = m2.group(1), m2.group(2)
if isnum:
m1_head = m1_head.lstrip(b'0')
m2_head = m2_head.lstrip(b'0')
m1hlen = len(m1_head)
m2hlen = len(m2_head)
if m1hlen < m2hlen:
return -1
if m1hlen > m2hlen:
return 1
if m1_head < m2_head:
return -1
if m1_head > m2_head:
return 1
continue
m1len = len(first)
m2len = len(second)
if m1len == m2len == 0:
return 0
if m1len != 0:
return 1
return -1
# 取系统版本
def get_sys_version(self):
'''
获取当前系统版本
:return: string
'''
sys_version = "None"
if os.path.exists("/etc/redhat-release"):
result = public.ReadFile("/etc/redhat-release")
if "CentOS Linux release 7" in result:
sys_version = "centos_7"
elif "CentOS Linux release 8" in result:
sys_version = "centos_8"
elif "CentOS Stream release 8" in result:
sys_version = "centos_8_stream"
elif os.path.exists("/etc/lsb-release"):
if "Ubuntu 20.04" in public.ReadFile("/etc/lsb-release"):
sys_version = "ubuntu_20.04"
elif "Ubuntu 22.04" in public.ReadFile("/etc/lsb-release"):
sys_version = "ubuntu_22.04"
elif "Ubuntu 18.04" in public.ReadFile("/etc/lsb-release"):
sys_version = "ubuntu_18.04"
elif os.path.exists("/etc/debian_version"):
result = public.ReadFile("/etc/debian_version")
if "10." in result:
sys_version = "debian_10"
elif "11." in result:
sys_version = "debian_11"
elif "12." in result:
sys_version = "debian_12"
return sys_version
def new_get_sys_product(self, flag=False):
'''
新版获取系统软件包及版本{"name":"version"}
@param flag bool 为True时直接扫一次
'''
# 修复完成需要重新获取一次软件包版本
if flag:
sys_product = self.get_sys_product()
public.WriteFile(self.product_version, json.dumps(sys_product))
sys_version = self.get_sys_version()
if sys_version == "centos_7":
# 根据yum日志判断是否用软件包更新
yumlog = "/var/log/yum.log"
elif sys_version == "centos_8" or sys_version == "centos_8_stream":
yumlog = "/var/log/dnf.log"
else:
yumlog = "/var/log/apt/history.log"
try:
# 先判断有没有yum.log
if os.path.exists(yumlog):
# 第一次将yum.log修改时间记录在文件里
if not os.path.exists(self.yum_time):
new_modi_time = str(int(os.path.getmtime(yumlog)))
public.WriteFile(self.yum_time, new_modi_time)
sys_product = self.get_sys_product()
public.WriteFile(self.product_version, json.dumps(sys_product))
else:
old_modi_time = public.ReadFile(self.yum_time)
new_modi_time = str(int(os.path.getmtime(yumlog)))
# 比较上一次记录的时间和这次获取的修改时间相等则根据rpm文件的修改时间
if old_modi_time == new_modi_time:
if os.path.exists(self.product_version):
# 若rpm文件修改日期大于七天则还是执行rpm检测
if self.is_file_too_old(self.product_version, 7):
sys_product = self.get_sys_product()
public.WriteFile(self.product_version, json.dumps(sys_product))
else:
sys_product = json.loads(public.ReadFile(self.product_version))
else:
sys_product = self.get_sys_product()
public.WriteFile(self.product_version, json.dumps(sys_product))
# 不相等证明最近有用yum安装过新软件更新文件并检测
else:
sys_product = self.get_sys_product()
public.WriteFile(self.product_version, json.dumps(sys_product)) # 将软件包版本写入文件
public.WriteFile(self.yum_time, new_modi_time)
# 没有yum.log则直接根据rpm文件修改日期
else:
if os.path.exists(self.product_version):
if self.is_file_too_old(self.product_version, 7):
sys_product = self.get_sys_product()
public.WriteFile(self.product_version, json.dumps(sys_product))
else:
sys_product = json.loads(public.ReadFile(self.product_version))
else:
sys_product = self.get_sys_product()
public.WriteFile(self.product_version, json.dumps(sys_product))
except Exception as e:
sys_product = self.get_sys_product()
public.WriteFile(self.product_version, json.dumps(sys_product))
# 其他系统版本
return sys_product
# 取软件包版本
def get_sys_product(self):
"""
获取系统软件包及版本
{"name":"version"}
:return dict 如果系统不支持则返回str None
"""
product_version = {}
sys_version = self.get_sys_version()
# if sys_version == 'None':return public.returnMsg(False, public.lang("当前系统暂不支持"))
if "centos" in sys_version:
result = public.ExecShell('rpm -qa --qf \'%{NAME};%{VERSION}-%{RELEASE}\\n\'')[0].strip().split('\n')
elif "ubuntu" in sys_version:
# result1 = subprocess.check_output(['dpkg-query', '-W', '-f=${Package};${Version}\n']).decode('utf-8').strip().split('\n')
result = public.ExecShell('dpkg-query -W -f=\'${Package};${Version}\n\'')[0].strip().split('\n')
elif "debian" in sys_version:
result = public.ExecShell('dpkg-query -W -f=\'${Package};${Version}\n\'')[0].strip().split('\n')
elif sys_version == "None":
return None
else:
return None
for pkg in result:
try:
product_version[pkg.split(";")[0]] = pkg.split(";")[1]
except:
return None
# product_version["kernel"] = subprocess.check_output(['uname', '-r']).decode('utf-8').strip().replace(".x86_64", "")
product_version["kernel"] = public.ExecShell('uname -r')[0].strip()
return product_version
def get_vuln_result(self):
'''
获取上一次扫描结果
:param get:
:return: dict
'''
d_risk = 0
h_risk = 0
m_risk = 0
vul_list = []
if not os.path.exists(self.__vul_list):
self.vul_num = 0
else:
self.vul_num = len(self.get_vul_list())
if not os.path.exists(self._vuln_result):
tmp_dict = {"vul_count": self.vul_num, "risk": [], "ignore": [],
"count": {"serious": 0, "high_risk": 0, "moderate_risk": 0}, "msg": "",
"repair_count": {"all_count": 0, "today_count": 0}, "all_check_time": "", "ignore_count": 0}
if os.path.exists("/etc/redhat-release"):
result = public.ReadFile("/etc/redhat-release")
if "CentOS Linux release 8" in result:
# tmp_dict["msg"] = "当前系统【centos_8】官方已停止维护为了安全起见建议升级至centos 8 stream\n详情参考教程https://www.yakpanel.com/bbs/thread-82931-1-1.html"
tmp_dict["msg"] = "The current system [centos_8] has been officially stopped maintenance, for security purposes, it is recommended to upgrade to centos 8 stream"
return tmp_dict
if public.ReadFile(self._vuln_result) == '[]':
tmp_dict = {"vul_count": self.vul_num, "risk": [], "ignore": [],
"count": {"serious": 0, "high_risk": 0, "moderate_risk": 0}, "msg": "",
"repair_count": {"all_count": 0, "today_count": 0}, "all_check_time": "", "ignore_count": 0}
if os.path.exists("/etc/redhat-release"):
result = public.ReadFile("/etc/redhat-release")
if "CentOS Linux release 8" in result:
# tmp_dict["msg"] = "当前系统【centos_8】官方已停止维护为了安全起见建议升级至centos 8 stream\n详情参考教程https://www.yakpanel.com/bbs/thread-82931-1-1.html"
tmp_dict["msg"] = "The current system [centos_8] has been officially stopped maintenance, for security purposes, it is recommended to upgrade to centos 8 stream"
return tmp_dict
result_dict = json.loads(public.ReadFile(self._vuln_result))
old_risk_list = result_dict["risk"]
old_ignore_list = result_dict["ignore"]
new_risk_list = old_risk_list.copy()
new_ignore_list = old_ignore_list.copy()
tmp_ignore_list = self.get_ignore_list()
for cve in old_risk_list:
if cve["cve_id"] in tmp_ignore_list:
new_ignore_list.append(cve)
new_risk_list.remove(cve)
for cve_ig in old_ignore_list:
if cve_ig["cve_id"] not in tmp_ignore_list:
new_risk_list.append(cve_ig)
new_ignore_list.remove(cve_ig)
for vul in new_ignore_list + new_risk_list:
vul_list.append(vul["cve_id"])
if vul["cve_id"] in tmp_ignore_list:
continue
if vul["level"] == 3:
d_risk += 1
elif vul["level"] == 2:
h_risk += 1
elif vul["level"] == 1:
m_risk += 1
list_sort = [3, 2, 1] # 排序列表
# result_dict["risk"] = old_risk_list
result_dict["risk"] = sorted(new_risk_list, key=lambda x: list_sort.index(x.get("level")))
# result_dict["ignore"] = old_ignore_list
result_dict["ignore"] = sorted(new_ignore_list, key=lambda x: list_sort.index(x.get("level")))
# result_dict["reboot"] = self.__need_reboot
result_dict["count"] = {"serious": d_risk, "high_risk": h_risk, "moderate_risk": m_risk}
result_dict["msg"] = ""
result_dict["repair_count"] = self.count_repair(vul_list)
result_dict["all_check_time"] = public.ReadFile(self.__path + '/system_scan_time')
result_dict["ignore_count"] = len(tmp_ignore_list)
if os.path.exists("/etc/redhat-release"):
result = public.ReadFile("/etc/redhat-release")
if "CentOS Linux release 8" in result:
result_dict[
"msg"] = "The current system [centos_8] has been officially stopped maintenance, for security purposes, it is recommended to upgrade to centos 8 stream"
public.WriteFile(self._vuln_result, json.dumps(result_dict))
return result_dict
# 按分数评等级
def get_score_risk(self, score):
'''
拿到分数返回危险等级
:param score:
:return: int 若没有符合的分数就报错需要捕获异常
'''
if float(score) >= 9.0:
risk = 3
elif float(score) >= 7.0:
risk = 2
elif float(score) >= 6.0:
risk = 1
return risk
def get_vul_list(self):
return json.loads(public.ReadFile(self.__vul_list))
def get_ignore_list(self):
return json.loads(public.ReadFile(self._vuln_ignore))
def set_vuln_ignore(self, args):
'''
设置忽略指定cve若已在列表里则删除不在列表里则添加
:param args:
:return: dict {status:true,msg:'设置成功/失败'}
'''
cve_list = json.loads(args.cve_list.strip())
ignore_list = self.get_ignore_list()
for cl in cve_list:
if cl in ignore_list:
ignore_list.remove(cl)
else:
ignore_list.append(cl)
public.WriteFile(self._vuln_ignore, json.dumps(ignore_list))
# public.WriteFile(self.__result, json.dumps(result_dict))
return public.returnMsg(True, public.lang("successfully set!"))
# except:
# return public.returnMsg(False, public.lang("{}设置失败!", cve_list))
def count_repair(self, now_list):
'''
获取总共修复漏洞的数量以及今日修复漏洞数量
:param now_list:
:return: dict
'''
cve_dict = {}
if not os.path.exists(self.__repair_count):
cve_dict["all_cve"] = now_list
cve_dict["today_cve"] = now_list
cve_dict["time"] = int(time.time())
public.WriteFile(self.__repair_count, json.dumps(cve_dict))
cve_dict = json.loads(public.ReadFile(self.__repair_count))
cve_dict["all_cve"].extend(set(now_list) - set(cve_dict["all_cve"]))
all_count = len(cve_dict["all_cve"]) - len(now_list)
cve_dict["today_cve"].extend(set(now_list) - set(cve_dict["today_cve"]))
today_count = len(cve_dict["today_cve"]) - len(now_list)
# if cve_dict["time"].split(" ")[0] != self.get_time().split(" ")[0]:
# cve_dict["today_cve"] = now_list
cve_dict["time"] = int(time.time())
public.WriteFile(self.__repair_count, json.dumps(cve_dict))
return {"all_count": all_count, "today_count": today_count}
def get_time(self):
return public.format_date()
def check_cve(self, args):
'''
检测单个漏洞
:param args:
:return: dict
'''
sys_product = self.get_sys_product()
if not sys_product:
return public.returnMsg(True, public.lang("Detection failed"))
cve_id = args.cve_id.strip()
result_dict = json.loads(public.ReadFile(self._vuln_result))
risk_list = result_dict["risk"]
ignore_list = result_dict["ignore"]
tmptmp = 1
for cve in risk_list:
if cve["cve_id"] == cve_id:
tmp = 1 # 默认命中漏洞
cve["check_time"] = int(time.time())
for soft in list(cve["soft_name"].keys()):
if self.version_compare(sys_product[soft], cve["vuln_version"]) >= 0:
tmp = 0 # 当有一个软件包不命中,则为已修复
tmptmp = 0
break
if tmp == 0:
risk_list.remove(cve)
for cve in ignore_list:
if cve["cve_id"] == cve_id:
tmp = 1 # 默认命中漏洞
cve["check_time"] = int(time.time())
for soft in list(cve["soft_name"].keys()):
if self.version_compare(sys_product[soft], cve["vuln_version"]) >= 0:
tmp = 0 # 当有一个软件包不命中,则为已修复
tmptmp = 0
break
if tmp == 0:
ignore_list.remove(cve)
result_dict["risk"] = risk_list
result_dict["ignore"] = ignore_list
public.WriteFile(self._vuln_result, json.dumps(result_dict))
if tmptmp == 0:
return public.returnMsg(True, public.lang("It has been retested."))
else:
return public.returnMsg(True, public.lang("It has been retested."))
def compare_md5(self):
'''
对比md5更新漏洞库
:return:
'''
import requests
# try:
# new_md5 = requests.get("https://www.yakpanel.com/vulscan_d11ad1fe99a5f078548b0ea355db42dc.txt").text
# except:
# return 0
# old_md5 = public.FileMd5(self.__vul_list)
# if old_md5 != new_md5 or not os.path.exists(self.__vul_list):
if not os.path.exists(self.__vul_list):
try:
public.downloadFile("{}/install/src/high_risk_vul.zip".format(public.get_url()),
self.__path + "/high_risk_vul.zip")
public.ExecShell("unzip -o {}/high_risk_vul.zip -d {}/".format(self.__path, self.__path))
except:
return 0
return 1
def get_logs(self, get):
'''
获取升级日志
:param get:
:return: dict
'''
import files
return public.returnMsg(True, files.files().GetLastLine(self.__path + '/log.txt', 20))
def record_times(self):
'''
记录近七日扫描次数
'''
date_obj = datetime.datetime.now()
weekday = datetime.datetime.now().weekday()
if not os.path.exists("/www/server/panel/data/warning_report/record.json"):
tmp = {"scan": [], "repair": []}
for i in range(6, -1, -1):
last_date = (date_obj - datetime.timedelta(days=i)).strftime("%Y/%m/%d")
tmp["scan"].append({"date": last_date, "times": 0})
tmp["repair"].append({"date": last_date, "times": 0})
public.WriteFile("/www/server/panel/data/warning_report/record.json", json.dumps(tmp))
with open("/www/server/panel/data/warning_report/record.json", "r") as f:
record = json.load(f)
if record["scan"][weekday]["date"] == datetime.datetime.now().strftime("%Y/%m/%d"):
record["scan"][weekday]["times"] += 1
else:
record["scan"][weekday]["date"] = datetime.datetime.now().strftime("%Y/%m/%d")
record["scan"][weekday]["times"] = 1
public.WriteFile("/www/server/panel/data/warning_report/record.json", json.dumps(record))
def get_scan_bar(self, args):
'''
获取扫描进度条
@param args:
@return: int
'''
if not os.path.exists(self.__path + '/bar.txt'):return 0
data = json.loads(public.ReadFile(self.__path + '/bar.txt'))
return data
def kill_get_list(self, args):
'''
杀掉扫描进程
@param args:
@return:
'''
if not os.path.exists(self.__path + '/pid.txt'):
return {"status": False, "msg": "Interrupt failure"}
pid = public.ReadFile(self.__path + '/pid.txt')
err = public.ExecShell("kill -9 {}".format(str(pid)))[1].strip()
if err:
return {"status": False, "msg": "Interrupt failure"}
else:
public.WriteFile(self.__path + '/kill.pl', "True")
return {"status": True, "msg": "Interrupt successfully"}
def dump_tmp_result(self):
'''
动态保存结果
@param args:
@return:
'''
public.WriteFile(self.__path + '/tmp_result.json', json.dumps(self.tmp_data))
def get_tmp_result(self, args):
'''
获取中途中断结果
@param args:
@return:
'''
if not os.path.exists(self.__path + '/tmp_result.json'):
return "err"
return json.loads(public.ReadFile(self.__path + '/tmp_result.json'))
def new_system_scan2(self):
'''
新版系统dpkg软件包漏洞检测
'''
if not os.path.exists(self.new_vul_list):
return
# 加载漏洞库文件
try:
vul_json = json.loads(public.ReadFile(self.new_vul_list))
packages_rule = vul_json['Packages']
detail = vul_json['Detail']
except Exception as e:
return
sys_product = self.new_get_sys_product()
if sys_product is None:
return
dpkg = Dpkg # 获取DPKG对象
# 符合
systemscan_result = {}
# 开始检测
# 第一层遍历系统软件包
for pk, ver in sys_product.items():
# 跳过内核漏洞检测
# if pk.startswith("kernel"):
# continue
# 是否有历史漏洞
if pk in packages_rule:
# 第二层遍历比较软件包涉及的漏洞版本
for rule in packages_rule[pk]:
# 判断软件包版本是否存在主版本号,有则漏洞版本一起保留主版本号,否则去掉漏洞版本的主版本号
pk_ver, vul_ver = self.adjust_ver(ver, rule[0])
try:
cp_result = dpkg.compare_versions(pk_ver, vul_ver)
except:
continue
# 任意一个命中
if cp_result == -1:
if rule[1] not in systemscan_result:
systemscan_result[rule[1]] = detail[str(rule[1])]
systemscan_result[rule[1]]["impact"] = [{"package": pk, "version": pk_ver, "vul_ver": vul_ver}]
else:
systemscan_result[rule[1]]["impact"].append({"package": pk, "version": pk_ver, "vul_ver": vul_ver})
# 为了兼容旧版本再次做处理
for sr in systemscan_result.values():
one_risk = {}
one_risk["title"] = "{}】Linux系统安全漏洞编号".format(sr["ref_id"])
one_risk["data"] = "2023-12-08"
one_risk["help"] = ""
one_risk["ignore"] = False
level = self.new_severity_to_num(sr["severity"])
one_risk["level"] = level
one_risk["m_name"] = sr["ref_id"]
pk_list = []
# 判断是否有内核漏洞在里面
is_kernel = False
soft_list = []
for impact in sr["impact"]:
if impact["package"].startswith("kernel"):
is_kernel = True
continue
soft_list.append("{} Versions below {}".format(impact["package"]+"-"+impact["version"], impact["vul_ver"]))
pk_list.append(impact["package"])
if is_kernel:
continue
one_risk["msg"] = "Security vulnerabilities are found in the following system software<br>{}<br>Vulnerabilities involved{}<br>Please refer to the official announcement for details{}".format('<br>'.join(soft_list), ''.join(sr["cve"]),sr["ref_url"])
one_risk["ps"] = "{}】Linux system vulnerability security vulnerability number".format(sr["ref_id"])
one_risk["remind"] = "Fixing vulnerabilities has certain risks, so it is recommended to take a good system snapshot to prevent system operation from being affected."
one_risk["status"] = False
one_risk["taking"] = 0.000001
one_risk["tips"] = ["Update the software to a safe version according to the risk description", "Or click [One-click Repair] to solve all security issues"]
one_risk["version"] = 1
one_risk["type"] = "vulnerability"
one_risk["package"] = pk_list
# 存储结果
self.data["risk"].append(one_risk)
self.data["is_autofix"].append(one_risk["m_name"])
# 扫描中发现的漏洞数
self.discov_count += 1
# 扫描中的动态分数
self.score -= level
if self.score < 0:
self.score = 0
# 扫描中的动态风险
self.tmp_data['risk'].append(one_risk)
# 可修复项
self.tmp_data['is_autofix'].append(one_risk["m_name"])
def new_system_scan(self):
'''
新版系统rpm软件包漏洞检测
提升扫描速度
:param get:
:return: dict
'''
# 判断新漏洞库存不存在
if not os.path.exists(self.new_vul_list):
return
context = {"status": "Checking system software", "percentage": 0, "count": 0, "score": 100}
public.WriteFile(self.__path + '/bar.txt', json.dumps(context))
sys_product = self.new_get_sys_product()
# 加载漏洞库文件
try:
vul_json = json.loads(public.ReadFile(self.new_vul_list))
packages_rule = vul_json['Packages']
detail = vul_json['Detail']
except Exception as e:
return
if sys_product is None:
return
# 符合
systemscan_result = {}
# 开始检测
# 第一层遍历系统软件包
for pk, ver in sys_product.items():
# 跳过内核漏洞检测
# if pk.startswith("kernel"):
# continue
# 是否有历史漏洞
if pk in packages_rule:
# 第二层遍历比较软件包涉及的漏洞版本
for rule in packages_rule[pk]:
# 判断软件包版本是否存在主版本号,有则漏洞版本一起保留主版本号,否则去掉漏洞版本的主版本号
pk_ver, vul_ver = self.adjust_ver(ver, rule[0])
cp_result = self.vercmp(pk_ver, vul_ver)
if cp_result == -1:
if rule[1] not in systemscan_result:
systemscan_result[rule[1]] = detail[str(rule[1])]
systemscan_result[rule[1]]["impact"] = [{"package": pk, "version": pk_ver, "vul_ver": vul_ver}]
else:
systemscan_result[rule[1]]["impact"].append({"package": pk, "version": pk_ver, "vul_ver": vul_ver})
# public.WriteFile("/tmp/centos7_result.json", json.dumps(systemscan_result, indent=4))
# 为了兼容旧版本再次做处理
for sr in systemscan_result.values():
one_risk = {}
one_risk["title"] = "{}】Linux system vulnerability security notice".format(sr["ref_id"])
one_risk["data"] = "2023-12-08"
one_risk["help"] = ""
one_risk["ignore"] = False
level = self.new_severity_to_num(sr["severity"])
one_risk["level"] = level
one_risk["m_name"] = sr["ref_id"]
pk_list = []
# 判断是否有内核漏洞在里面
is_kernel = False
soft_list = []
for impact in sr["impact"]:
if impact["package"].startswith("kernel"):
is_kernel = True
continue
soft_list.append("{} Versions below {}".format(impact["package"]+"-"+impact["version"], impact["vul_ver"]))
pk_list.append(impact["package"])
if is_kernel:
continue
one_risk["msg"] = "The following system software was found to have security vulnerabilities<br>{}<br>Vulnerabilities involved{}<br>Refer to the official announcement for details{}".format('<br>'.join(soft_list), ''.join(sr["cve"]),sr["ref_url"])
one_risk["ps"] = "{}】Linux system vulnerability security notice".format(sr["ref_id"])
one_risk["remind"] = "Fixing vulnerabilities has certain risks, so it is recommended to take a good system snapshot to prevent system operation from being affected."
one_risk["status"] = False
one_risk["taking"] = 0.000001
one_risk["tips"] = ["Update the software to a safe version according to the risk description", "Or click [One-click Repair] to solve all security issues"]
one_risk["version"] = 1
one_risk["type"] = "vulnerability"
one_risk["package"] = pk_list
# 存储结果
self.data["risk"].append(one_risk)
self.data["is_autofix"].append(one_risk["m_name"])
# 扫描中发现的漏洞数
self.discov_count += 1
# 扫描中的动态分数
self.score -= level
if self.score < 0:
self.score = 0
# 扫描中的动态风险
self.tmp_data['risk'].append(one_risk)
# 可修复项
self.tmp_data['is_autofix'].append(one_risk["m_name"])
# result_json = {
# "vul_count": len(detail),
# "risk": [],
# "ignore": [],
# "all_check_time": "",
# "ignore_count": 0,
# "msg": "",
# "repair_count": {"all_count": 0, "today_vount": 0},
# }
# for sr in systemscan_result.values():
# one_risk = {
# "cve_id": "",
# "vuln_name": "",
# "vuln_time": "2021-12-16",
# "vuln_solution": "",
# "level": 1,
# "soft_name": {},
# "vuln_version": "",
# "check_time": 1701910962,
# "reboot": ""
# }
# one_risk["cve_id"] = sr["ref_id"]
# one_risk["vuln_name"] = "【{}】Linux软件安全公告".format(sr["ref_id"])
# one_risk["vuln_solution"] = "更新涉及软件补丁,具体信息参考官方公告{}".format(sr["ref_url"])
# level = self.new_severity_to_num(sr["severity"])
# one_risk["level"] = level
# # 处理受影响的软件包(为了兼容旧版本暂时这样)
# soft_name = {}
# vuln_version = ""
# for impact in sr["impact"]:
# soft_name[impact["package"]] = impact["version"]
# vuln_version = impact["vul_ver"]
# one_risk["soft_name"] = soft_name
# one_risk["vuln_version"] = vuln_version
# risk_list.append(one_risk)
#
# # 扫描中发现的漏洞数
# self.discov_count += 1
# # 扫描中的动态分数
# self.score -= level
# if self.score < 0:
# self.score = 0
# # 扫描中的动态风险
# self.tmp_data['risk'].append(one_risk)
# # 可修复项
# self.tmp_data['is_autofix'].append(one_risk["cve_id"])
#
# result_json["risk"] = risk_list
# public.WriteFile(self.__path + '/system_scan_time', int(time.time()))
# public.WriteFile(self._vuln_result, json.dumps(result_json))
def is_file_too_old(self, file_path, days):
"""
判断文件是否过于陈旧
:param file_path: 文件路径
:param days: 超过的天数
:return: bool
"""
mtime = os.path.getmtime(file_path)
# 不存在直接返回True
if mtime is None:
return True
mod_time = datetime.datetime.fromtimestamp(mtime)
days_old = datetime.datetime.now() - mod_time
return days_old.days > days
def adjust_ver(self, ver_a, ver_b):
'''
确保两个版本主版本号统一一方存在另一方不存在则删除主版本要么都有要么都没有
'''
if ":" in ver_a:
if ":" in ver_b:
ver_1 = ver_a
else:
ver_1 = ver_a.split(":")[1]
ver_2 = ver_b
else:
if ":" in ver_b:
ver_2 = ver_b.split(":")[1]
else:
ver_2 = ver_b
ver_1 = ver_a
return ver_1, ver_2
def new_severity_to_num(self, severity):
'''
将漏洞级别转变成数字
'''
if severity == "Critical":
return 3
elif severity == "Important":
return 2
elif severity == "Moderate":
return 1
elif severity == "Low":
return 1
elif severity == "High":
return 3
elif severity == "Medium":
return 2
else:
return 2
# def new_rpmvercmp(self, sys_ver, vul_ver):
# output, err = public.ExecShell("rpmdev-vercmp {} {}".format(sys_ver, vul_ver))
# if err != '':
# return 1
# output = output.strip()
# if output == "{} > {}".format(sys_ver, vul_ver):
# return 1
# elif output == "{} == {}".format(sys_ver, vul_ver):
# return 0
# elif output == "{} < {}".format(sys_ver, vul_ver):
# return -1
# else:
# return 1
class Dpkg:
def __init__(self):
self._fileinfo = None
self._control_str = None
self._headers = None
self._message = None
self._upstream_version = None
self._debian_revision = None
self._epoch = None
@staticmethod
def get_epoch(version_str):
try:
e_index = version_str.index(":")
except ValueError:
return 0, version_str
try:
epoch = int(version_str[0:e_index])
except ValueError as ex:
print(f"Corrupt dpkg version '{version_str}': epochs can only be ints, and "
"epochless versions cannot use the colon character.")
return epoch, version_str[e_index + 1:]
@staticmethod
def get_upstream(version_str):
try:
d_index = version_str.rindex("-")
except ValueError:
return version_str, "0"
return version_str[0:d_index], version_str[d_index + 1:]
@staticmethod
def split_full_version(version_str):
epoch, full_ver = Dpkg.get_epoch(version_str)
upstream_rev, debian_rev = Dpkg.get_upstream(full_ver)
return epoch, upstream_rev, debian_rev
@staticmethod
def get_alphas(revision_str):
for i, char in enumerate(revision_str):
if char.isdigit():
if i == 0:
return "", revision_str
return revision_str[0:i], revision_str[i:]
return revision_str, ""
@staticmethod
def get_digits(revision_str):
if not revision_str:
return 0, ""
for i, char in enumerate(revision_str):
if not char.isdigit():
if i == 0:
return 0, revision_str
return int(revision_str[0:i]), revision_str[i:]
return int(revision_str), ""
@staticmethod
def listify(revision_str):
result = []
while revision_str:
rev_1, remains = Dpkg.get_alphas(revision_str)
rev_2, remains = Dpkg.get_digits(remains)
result.extend([rev_1, rev_2])
revision_str = remains
return result
@staticmethod
def dstringcmp(a, b):
if a == b:
return 0
try:
for i, char in enumerate(a):
if char == b[i]:
continue
if char == "~":
return -1
if b[i] == "~":
return 1
if char.isalpha() and not b[i].isalpha():
return -1
if not char.isalpha() and b[i].isalpha():
return 1
if ord(char) > ord(b[i]):
return 1
if ord(char) < ord(b[i]):
return -1
except IndexError:
if char == "~":
return -1
return 1
if b[len(a)] == "~":
return 1
return -1
@staticmethod
def compare_revision_strings(rev1, rev2):
if rev1 == rev2:
return 0
list1 = Dpkg.listify(rev1)
list2 = Dpkg.listify(rev2)
if list1 == list2:
return 0
try:
for i, item in enumerate(list1):
if i >= len(list2):
raise IndexError
if not isinstance(item, list2[i].__class__):
print(f"Cannot compare '{item}' to {list2[i]}, something has gone horribly awry.")
if item == list2[i]:
continue
if isinstance(item, int):
if item > list2[i]:
return 1
if item < list2[i]:
return -1
else:
return Dpkg.dstringcmp(item, list2[i])
except IndexError:
if list1[len(list2)][0][0] == "~":
return -1
return 1
if list2[len(list1)][0][0] == "~":
return 1
return -1
@staticmethod
def compare_versions(ver1, ver2):
if ver1 == ver2:
return 0
epoch1, upstream1, debian1 = Dpkg.split_full_version(str(ver1))
epoch2, upstream2, debian2 = Dpkg.split_full_version(str(ver2))
if epoch1 < epoch2:
return -1
if epoch1 > epoch2:
return 1
upstr_res = Dpkg.compare_revision_strings(upstream1, upstream2)
if upstr_res != 0:
return upstr_res
debian_res = Dpkg.compare_revision_strings(debian1, debian2)
if debian_res != 0:
return debian_res
return 0
if __name__ == "__main__":
# st = time.time()
panel = panelWarning()
# panel.new_system_scan()
public.WriteFile('/www/server/panel/data/warning/resultresult.json', json.dumps(panel._get_list()))
# et = time.time()
# #coding: utf-8
# # +-------------------------------------------------------------------
# # | YakPanel
# # +-------------------------------------------------------------------
# # | Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# # +-------------------------------------------------------------------
# # | Author: hwliang <2020-08-04>
# # +-------------------------------------------------------------------
#
# import os,sys,json,time,public
#
# class panelWarning:
# __path = '/www/server/panel/data/warning'
# __ignore = __path + '/ignore'
# __result = __path + '/result'
# __risk = __path + '/risk'
# def __init__(self):
# if not os.path.exists(self.__ignore):
# os.makedirs(self.__ignore,384)
# if not os.path.exists(self.__result):
# os.makedirs(self.__result,384)
# if not os.path.exists(self.__risk):
# os.makedirs(self.__risk, 384)
#
# def get_list(self,args):
# p = public.get_modules('class/safe_warning')
# data = {
# 'security':[],
# 'risk':[],
# 'ignore':[]
# }
#
# for m_name in p.__dict__.keys():
# ignore_file = self.__ignore + '/' + m_name + '.pl'
# # 忽略的检查项
# if p[m_name]._level == 0: continue
#
# m_info = {
# 'title': p[m_name]._title,
# 'm_name': m_name,
# 'ps': p[m_name]._ps,
# 'version': p[m_name]._version,
# 'level': p[m_name]._level,
# 'ignore': p[m_name]._ignore,
# 'date': p[m_name]._date,
# 'tips': p[m_name]._tips,
# 'help': p[m_name]._help
# }
# result_file = self.__result + '/' + m_name + '.pl'
#
# try:
# s_time = time.time()
# m_info['status'],m_info['msg'] = p[m_name].check_run()
# m_info['taking'] = round(time.time() - s_time,6)
# m_info['check_time'] = int(time.time())
# public.writeFile(result_file,json.dumps([m_info['status'],m_info['msg'],m_info['check_time'],m_info['taking']],))
# except:
# continue
#
# m_info['ignore'] = os.path.exists(ignore_file)
# if m_info['ignore']:
# data['ignore'].append(m_info)
# else:
# if m_info['status']:
# data['security'].append(m_info)
# else:
# risk_file = self.__risk + '/' + m_name + '.pl'
# public.writeFile(risk_file, json.dumps(m_info))
# data['risk'].append(m_info)
#
# data['risk'] = sorted(data['risk'],key=lambda x: x['level'],reverse=True)
# data['security'] = sorted(data['security'],key=lambda x: x['level'],reverse=True)
# data['ignore'] = sorted(data['ignore'],key=lambda x: x['level'],reverse=True)
# # 获取支持一键修复的列表
# try:
# is_autofix = public.read_config("safe_autofix")
# except:
# is_autofix = []
# data['is_autofix'] = is_autofix
# return data
#
#
# def sync_rule(self):
# '''
# @name 从云端同步规则
# @author hwliang<2020-08-05>
# @return void
# '''
# # try:
# # dep_path = '/www/server/panel/class/safe_warning'
# # local_version_file = self.__path + '/version.pl'
# # last_sync_time = local_version_file = self.__path + '/last_sync.pl'
# # if os.path.exists(dep_path):
# # if os.path.exists(last_sync_time):
# # if int(public.readFile(last_sync_time)) > time.time():
# # return
# # else:
# # if os.path.exists(local_version_file): os.remove(local_version_file)
#
# # download_url = public.get_url()
# # version_url = download_url + '/install/warning/version.txt'
# # cloud_version = public.httpGet(version_url)
# # if cloud_version: cloud_version = cloud_version.strip()
#
# # local_version = public.readFile(local_version_file)
# # if local_version:
# # if cloud_version == local_version:
# # return
#
# # tmp_file = '/tmp/bt_safe_warning.zip'
# # public.ExecShell('wget -O {} {} -T 5'.format(tmp_file,download_url + '/install/warning/safe_warning.zip'))
# # if not os.path.exists(tmp_file):
# # return
#
# # if os.path.getsize(tmp_file) < 2129:
# # os.remove(tmp_file)
# # return
#
# # if not os.path.exists(dep_path):
# # os.makedirs(dep_path,384)
# # public.ExecShell("unzip -o {} -d {}/ >/dev/null".format(tmp_file,dep_path))
# # public.writeFile(local_version_file,cloud_version)
# # public.writeFile(last_sync_time,str(int(time.time() + 7200)))
# # if os.path.exists(tmp_file): os.remove(tmp_file)
# # public.ExecShell("chmod -R 600 {}".format(dep_path))
# # except:
# # pass
#
#
#
# def set_ignore(self,args):
# '''
# @name 设置指定项忽略状态
# @author hwliang<2020-08-04>
# @param dict_obj {
# m_name<string> 模块名称
# }
# @return dict
# '''
# m_name = args.m_name.strip()
# ignore_file = self.__ignore + '/' + m_name + '.pl'
# if os.path.exists(ignore_file):
# os.remove(ignore_file)
# else:
# public.writeFile(ignore_file,'1')
# return public.returnMsg(True, public.lang("Successfully set!"))
#
# def check_find(self, args):
# '''
# @name 检测指定项
# @author hwliang<2020-08-04>
# @param dict_obj {
# m_name<string> 模块名称
# }
# @return dict
# '''
# try:
# m_name = args.m_name.strip()
# p = public.get_modules('class/safe_warning')
# m_info = {
# 'title': p[m_name]._title,
# 'm_name': m_name,
# 'ps': p[m_name]._ps,
# 'version': p[m_name]._version,
# 'level': p[m_name]._level,
# 'ignore': p[m_name]._ignore,
# 'date': p[m_name]._date,
# 'tips': p[m_name]._tips,
# 'help': p[m_name]._help
# }
#
# # 解决已经在忽略列表中,但是如果仍然需要检查的话可以检查
# ignore_file = self.__ignore + '/' + m_name + '.pl'
# if os.path.exists(ignore_file):
# from cachelib import SimpleCache
# cache = SimpleCache(5000)
# ikey = 'warning_list'
# cache.delete(ikey)
# os.remove(ignore_file)
#
# result_file = self.__result + '/' + m_name + '.pl'
# s_time = time.time()
# m_info['status'], m_info['msg'] = p[m_name].check_run()
# m_info['taking'] = round(time.time() - s_time, 4)
# m_info['check_time'] = int(time.time())
# public.writeFile(result_file, json.dumps(
# [m_info['status'], m_info['msg'], m_info['check_time'], m_info['taking']]))
# return public.returnMsg(True, public.lang("Retested"))
# except:
# return public.returnMsg(False, public.lang("Detection failed"))