Initial YakPanel commit

This commit is contained in:
Niranjan
2026-04-07 02:04:22 +05:30
commit 2826d3e7f3
5359 changed files with 1390724 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
#!/usr/bin/python
# coding: utf-8
import os, re, public
_title = 'Check alias configuration'
_version = 1.0 # 版本
_ps = "Check if the ls and rm commands set aliases" # 描述
_level = 1 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_alias_ls_rm.pl")
_tips = [
"Add or modify alias ls=\'ls -alh\' and alias rm=\'rm -i\' in the file [~/.bashrc]",
"Execute [source ~/.bashrc] to make the configuration take effect",
]
_help = ''
_remind = 'This scheme can make ls command list more detailed file information and reduce the risk of rm command deleting files by mistake, but it may affect the original operation habits.'
def check_run():
'''
@name 开始检测
@return tuple (status<bool>,msg<string>)
'''
# 存放配置不当的命令,分别用正则判断是否配置别名
result_list = []
cfile = '/root/.bashrc'
if not os.path.exists(cfile):
return True, 'Risk-free'
conf = public.readFile(cfile)
# rep1 = 'alias(\\s*)ls(\\s*)=(\\s*)[\'\"]ls(\\s*)-.*[alh].*[alh].*[alh]'
# tmp1 = re.search(rep1, conf)
# if not tmp1:
# result_list.append('ls')
rep2 = 'alias(\\s*)rm(\\s*)=(\\s*)[\'\"]rm(\\s*)-.*[i?].*'
tmp2 = re.search(rep2, conf)
if not tmp2:
result_list.append('rm')
if len(result_list) > 0:
return False, '{} The command does not have an alias configured or is configured incorrectly'.format(''.join(result_list))
else:
return True, 'Risk-free'

View File

@@ -0,0 +1,34 @@
#!/usr/bin/python
#coding: utf-8
import os, re, public
_title = 'Whether to enable Docker log audit check'
_version = 1.0 # 版本
_ps = "Whether to enable Docker log audit check" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-13' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_audit_docker.pl")
_tips = [
"Add -w /usr/bin/docker -k docker from [/etc/audit/rules.d/audit.rules] file",
"Restart auditd process: systemctl restart auditd"
]
_help = ''
def check_run():
'''
@name 开始检测
@return tuple (status<bool>,msg<string>)
'''
audit_path = '/etc/audit/audit.rules'
if not os.path.exists(audit_path):
return False, 'Risky, the auditd audit tool is not installed'
# auditctl -l命令列出当前auditd规则匹配是否有对docker做审计记录
result = public.ExecShell('auditctl -l')[0].strip()
rep = '/usr/bin/docker'
if re.search(rep, result):
return True, 'Risk-free'
else:
return False, 'Risky, the docker audit log is not enabled'

View File

@@ -0,0 +1,31 @@
#!/usr/bin/python
#coding: utf-8
import os, re, public
_title = 'Audit logs are kept forever'
_version = 1.0 # 版本
_ps = "Check whether the audit log is automatically deleted when it is full" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-15' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_audit_log_keep.pl")
_tips = [
"In [/etc/audit/auditd.conf] max_log_file_action changes ROTATE to KEEP_LOGS",
"Restart auditd service: systemctl restart auditd"
]
_help = ''
def check_run():
cfile = '/etc/audit/auditd.conf'
if not os.path.exists(cfile):
return False, 'RiskyThe auditd audit tool is not installed'
result = public.ReadFile(cfile)
# 默认是rotate日志满了后循环日志keep_logs会保留旧日志
rep = r'max_log_file_action\s*=\s(.*)'
tmp = re.search(rep, result)
if tmp:
if 'keep_logs'.lower() == tmp.group(1).lower():
return True, 'Risk-free'
return False, 'The current max_log_file_action value is {}, it should be KEEP_LOGS'.format(tmp.group(1))

View File

@@ -0,0 +1,46 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 用户缺省权限检查
# -------------------------------------------------------------------
# import sys, os
# os.chdir('/www/server/panel')
# sys.path.append("class/")
import os, sys, re, public
_title = '[/etc/bashrc] User default permission check'
_version = 1.0 # 版本
_ps = "/etc/bashrc User default permission check" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-08-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_bashrc.pl")
_tips = [
"[/etc/bashrc] The umask set in the file is 002, and it is recommended to set it to 027",
"Solution: Modify the /etc/bashrc file permission to 027",
]
_help = ''
_remind = 'This scheme can strengthen the protection of system user rights, but it may affect the original operation habits.'
def check_run():
# 判断是否存在/etc/profile文件
if os.path.exists("/etc/bashrc"):
# 读取文件内容
profile = public.ReadFile("/etc/bashrc")
# 判断是否存在umask设置
if re.search("umask 0",profile):
# 判断是否设置为027
if re.search("umask 027",profile):
return True,"Risk-free"
else:
return False,"umask is not set to 027"
else:
return False,"umask not set"

View File

@@ -0,0 +1,36 @@
#!/usr/bin/python
# coding: utf-8
import os, sys, public
_title = 'Check temporary directory for sticky bit'
_version = 1.0 # 版本
_ps = "Check if the temporary directory has the sticky bit permission set" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-09' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_chmod_stickybit.pl")
_tips = [
"Use the chmod +t [file name] command to modify the permissions of the file",
]
_help = ''
_remind = 'This solution prevents system users from accidentally deleting files on the server. '
def check_run():
'''
@name 开始检测
@return tuple (status<bool>,msg<string>)
'''
# result_list存放未配置粘滞位的目录名
result_list = []
tmp_path = ['/var/tmp', '/tmp']
for t in tmp_path:
# 文件不存在则跳过,保险操作。
if not os.path.exists(t):
continue
result_str = public.ExecShell('find {} -maxdepth 0 -perm /01000 -type d'.format(t))[0].strip()
if not result_str[1]:
result_list.append(t)
if result_list:
result = ''.join(result_list)
return False, 'The following directories do not have sticky bit permissions set{}'.format(result)
else:
return True, 'Risk-free'

View File

@@ -0,0 +1,47 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 用户缺省权限检查
# -------------------------------------------------------------------
# import sys, os
# os.chdir('/www/server/panel')
# sys.path.append("class/")
import os, sys, re, public
_title = '[/etc/csh.cshrc] User default permission check'
_version = 1.0 # 版本
_ps = "[/etc/csh.cshrc] User default permission check" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-08-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_cshrc.pl")
_tips = [
"[/etc/csh.cshrc] The umask set in the file is 002, which does not meet the requirements. It is recommended to set it to 027",
"The operation is as follows: Modify umask to 027",
]
_help = ''
_remind = 'This scheme can strengthen the protection of user privileges on the system. '
def check_run():
# 判断是否存在/etc/profile文件
if os.path.exists("/etc/csh.cshrc"):
# 读取文件内容
profile = public.ReadFile("/etc/csh.cshrc")
# 判断是否存在umask设置
if re.search("umask 0",profile):
# 判断是否设置为027
if re.search("umask 027",profile):
return True,"Risk-free"
else:
# return False,"umask not set to 027"
return True, "Risk-free"
else:
# return False,"umask not set"
return True, "Risk-free"

View File

@@ -0,0 +1,45 @@
#!/usr/bin/python
#coding: utf-8
import os, public, re
_title = 'CVE-2019-5736容器逃逸漏洞检测'
_version = 1.0 # 版本
_ps = "检测CVE-2019-5736容器逃逸漏洞" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-27' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_cve_2019_5736.pl")
_tips = [
"docker version查看docker版本是否小于18.09.2runc版本小于1.0-rc6",
]
_help = ''
_remind = 'An attacker can use this vulnerability to gain access to the server. '
# https://nvd.nist.gov/vuln/detail/CVE-2019-5736#match-7231264
def check_run():
'''
@name 开始检测
@return tuple (status<bool>,msg<string>)
'''
docker = public.ExecShell("docker version --format=\'{{ .Server.Version }}\'")[0].strip()
if 'command not found' in docker or 'Command not found' in docker:
return True, 'Risk-freedocker is not installed'
if not re.search(r'\d+.\d+.\d+', docker):
return True, 'Risk-free'
docker = docker.split('.')
if len(docker[0]) < 2:
return False, 'RiskyThe current docker version has security risks and needs to be upgraded to a safe version'
elif int(docker[0]) < 18:
return False, 'RiskyThe current docker version has security risks and needs to be upgraded to a safe version'
elif int(docker[0]) == 18:
if int(docker[1]) < 9:
return False, 'RiskyThe current docker version has security risks and needs to be upgraded to a safe version'
elif int(docker[1]) == 9:
if int(docker[2][0]) < 2:
return False, 'RiskyThe current docker version has security risks and needs to be upgraded to a safe version'
else:
return True, 'Risk-free'
else:
return True, 'Risk-free'
else:
return True, 'Risk-free'

View File

@@ -0,0 +1,92 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: lkq <lkq@yakpanel.com>
# -------------------------------------------------------------------
# Time: 2022-08-10
# -------------------------------------------------------------------
# CVE-2021-4034 polkit pkexec 本地提权漏洞检测
# -------------------------------------------------------------------
# import sys, os
# os.chdir('/www/server/panel')
# sys.path.append("class/")
import public, os
_title = 'CVE-2021-4034 polkit pkexec Local Privilege Escalation Vulnerability Detection'
_version = 1.0 # 版本
_ps = "CVE-2021-4034 polkit pkexec Local Privilege Escalation Vulnerability Detection" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-8-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_cve_2021_4034.pl")
_tips = [
"Update polkit components"
]
_help = ''
_remind = 'There is a risk to upgrade the software version. It is strongly recommended that the server do a snapshot backup first, in case the operation fails to restore in time! '
def check_run():
'''
@name CVE-2021-4034 polkit pkexec 本地提权漏洞检测
@time 2022-08-12
@author lkq@yakpanel.com
'''
st = os.stat('/usr/bin/pkexec')
setuid, setgid = bool(st.st_mode & stat.S_ISUID), bool(st.st_mode & stat.S_ISGID)
if not setuid: return True, 'Risk-free'
redhat_file = '/etc/redhat-release'
if os.path.exists(redhat_file):
data=public.ReadFile(redhat_file)
if not data:return True, 'Risk-free'
if data.find('CentOS Linux release 7.') != -1:
polkit=public.ExecShell("rpm -q polkit-0.*")
if not polkit[0]:return True, 'Risk-free'
polkit_list = polkit[0].strip()
if polkit_list.find('polkit-0') != -1:return True, 'Risk-free'
p = polkit_list.strip().split(".")
if len(p)<2:return True, 'Risk-free'
if p[1] == '112-26':return True,'Risk-free'
p2=p[1].split("-")
if p2[1] <26:
return False, 'Please update polkit'
return True,'Risk-free'
#CentOS 8.0
elif data.find('CentOS Linux release 8.0') == 0:
polkit = public.ExecShell("rpm -q polkit-0.*")
if not polkit[0]: return True, 'Risk-free'
polkit_list = polkit[0].strip()
if polkit_list.find('polkit-0') != -1: return True, 'Risk-free'
# Centos 7
p = polkit_list.strip().split(".")
if len(p) < 2: return True, 'Risk-free'
if p[1] == '115-13': return True, 'Risk-free'
p2 = p[1].split("-")
if p2[1] < 13:
return False, 'Please update polkit'
return True, 'Risk-free'
elif data.find("CentOS Linux release 8.2") == 0:
polkit = public.ExecShell("rpm -q polkit-0.*")
if not polkit[0]: return True, 'Risk-free'
polkit_list = polkit[0].strip()
if polkit_list.find('polkit-0') != -1: return True, 'Risk-free'
# Centos 7
p = polkit_list.strip().split(".")
if len(p) < 2: return True, 'Risk-free'
if p[1] == '115-11': return True, 'Risk-free'
p2 = p[1].split("-")
if p2[1] < 11:
return False, 'Please update polkit'
return True, 'Risk-free'
elif data.find("CentOS Linux release 8.5") == 0:
polkit = public.ExecShell("rpm -q polkit-0.*")
if not polkit[0]: return True, 'Risk-free'
polkit_list = polkit[0].strip()
if polkit_list.find('polkit-0.115-12') ==0:
return False, 'Please update polkit'
return True, 'Risk-free'
return True, 'Risk-free'

View File

@@ -0,0 +1,55 @@
#!/usr/bin/python
#coding: utf-8
import os, re, public
_title = 'CVE-2022-2068 OpenSSL任意命令执行漏洞检测'
_version = 1.0 # 版本
_ps = "CVE-2022-2068 OpenSSL任意命令执行漏洞检测" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_cve_2022_2068.pl")
_tips = [
"升级OpenSSL至最新版本或是安全版本",
"1.0.2zf、1.1.1p、3.0.4及以上版本",
]
_help = ''
def check_run():
'''
@name 开始检测
@return tuple (status<bool>,msg<string>)
'''
# https://nvd.nist.gov/vuln/detail/CVE-2022-2068#range-8768393
openssl = public.ExecShell("openssl version")[0].strip()
openssl = openssl.split(' ')[1]
openssl = openssl.split('.')
if openssl[0] == '1':
if openssl[1] == '0' and openssl[2][0] == '2':
if len(openssl[2]) < 3:
return False, 'There are security risks in the current version of openssl; you need to update to a secure version'
elif not openssl[2][1].islower():
return False, 'There are security risks in the current version of openssl; you need to update to a secure version'
elif openssl[2][1] < 'z':
return False, 'There are security risks in the current version of openssl; you need to update to a secure version'
elif openssl[2][1] == 'z' and openssl[2][2] < 'f':
return False, 'There are security risks in the current version of openssl; you need to update to a secure version'
else:
return True, 'Risk-free'
elif openssl[1] == '1' and openssl[2][0] == '1':
if len(openssl[2]) < 2:
return False, 'There are security risks in the current version of openssl; you need to update to a secure version'
elif not openssl[2][1].islower():
return False, 'There are security risks in the current version of openssl; you need to update to a secure version'
elif openssl[2][1] < 'p':
return False, 'There are security risks in the current version of openssl; you need to update to a secure version'
else:
return True, 'Risk-free'
elif openssl[0] == '3' and openssl[1] == '0':
if openssl[2][0] < '4':
return False, 'There are security risks in the current version of openssl; you need to update to a secure version'
else:
return True, 'Risk-free'
else:
return True, 'Risk-free'

View File

@@ -0,0 +1,100 @@
#!/usr/bin/python
#coding: utf-8
import os
import public
import re
_title = 'CVE-2023-0386 Linux Kernel OverlayFS Vulnerability'
_version = 1.0 # 版本
_ps = "CVE-2023-0386 Linux Kernel OverlayFS Vulnerability" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-06-06' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_cve_2023_0386.pl")
_tips = [
"Check whether the kernel version is lower than the specified version according to the prompt [uname -r]",
"If is CentOS 8 Stream, execute [yum install kernel] command to upgrade the kernel version, and restart the server",
"If it Ubuntu 22.04, execute [apt install linux-image] to check the installable version number, select version number higher than 5.15.0-70, execute [apt install linux-image-version_number] again, and restart the server"
]
_help = ''
_remind = 'The above kernel upgrade operation has certain risks, it is strongly recommended that the server do a snapshot backup first, in case the operation fails to restore in time! '
# https://nvd.nist.gov/vuln/detail/CVE-2023-0386
def check_run():
'''
@name 开始检测
@return tuple (status<bool>,msg<string>)
'''
kernel = public.ExecShell('uname -r')[0]
result = re.search("^(\\d+.\\d+.\\d+-\\d+)", kernel)
# centos8
if os.path.exists('/etc/redhat-release'):
ver = public.ReadFile('/etc/redhat-release')
if ver.startswith('CentOS Stream release 8'):
if result:
result = result.group(1).split('.')
result = result[:2] + result[2].split('-')
if len(result) == 4:
if result[0] == '4' and result[1] == '18' and result[2] == '0':
if len(result[3]) <= 3:
fin = contrast(result[3], 425)
if not fin:
return False, 'The current kernel version [{}] has security risks, please upgrade to 4.18.0-425 and above as soon as possible'.format(kernel)
if os.path.exists('/etc/issue'):
ver = public.ReadFile('/etc/issue')
if ver.startswith('Ubuntu 22.04'):
if result:
result = result.group(1).split('.')
result = result[:2] + result[2].split('-')
print(result)
if len(result) == 4:
if result[0] == '5' and result[1] == '15' and result[2] == '0':
if len(result[3]) <= 3:
fin = contrast(result[3], 70)
if not fin:
return False, 'The current kernel version [{}] has security risks, please upgrade to 5.15.0-70 and above as soon as possible'.format(kernel)
return True, 'The current kernel version [{}] is risk-free'.format(kernel)
def contrast(a, b):
if len(a) >= 3:
if a[0].isdigit() and a[1].isdigit() and a[2].isdigit():
if int(a[0:3]) >= int(b):
return True
else:
return False
elif a[0].isdigit() and a[1].isdigit():
if int(a[0:2]) >= int(b):
return True
else:
return False
elif a[0].isdigit():
if int(a[0]) >= int(b):
return True
else:
return False
else:
return False
elif len(a) == 2:
if a[0].isdigit() and a[1].isdigit():
if int(a[0:2]) >= int(b):
return True
else:
return False
elif a[0].isdigit():
if int(a[0]) >= int(b):
return True
else:
return False
else:
return False
elif len(a) == 1:
if a[0].isdigit():
if int(a[0]) >= int(b):
return True
else:
return False
else:
return False
else:
return False

View File

@@ -0,0 +1,59 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 数据库定时备份检测
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'Database backup'
_version = 1.0 # 版本
_ps = "Checks whether all databases are set up for periodic backup" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-04' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_database_backup.pl")
_tips = [
"On the [ Cron ] page, set the database that is not backed up, or set all databases to be backed up",
"Tip: if the database is not set up for regular backup, once the data is lost accidentally and cannot be recovered, the loss will be huge"
]
_help = ''
_remind = 'This solution prevents data loss in the database and keeps data safe. '
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-03>
@return tuple (status<bool>,msg<string>)
'''
if os.path.exists('/www/server/panel/plugin/enterprise_backup'):
return True,'Risk-free'
if public.M('crontab').where('sType=? AND sName=?',
('database', 'ALL')).count():
return True, 'Risk-free'
db_list = public.M('databases').field('name').select()
not_backups = []
sql = public.M('crontab')
for db in db_list:
if sql.where('sType=? AND sName=?',('database',db['name'])).count():
continue
not_backups.append(db['name'])
if not_backups:
return False ,'The following databases are not set up for regular backup: <br />' + ('<br />'.join(not_backups))
return True,'Risk-free'

View File

@@ -0,0 +1,57 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: linxiao
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 数据库备份权限检测
# -------------------------------------------------------------------
import os, re, public, panelMysql
_title = 'Database backup permission detection'
_version = 1.0 # 版本
_ps = "Check whether the MySQL root user has database backup privileges" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-09-19' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_database_priv.pl")
_tips = [
"To temporarily enter the database without authorization, it is recommended to restore all permissions of the root user.",
]
_help = ''
_remind = 'This scheme ensures that the root user has the permission to backup the database and ensures that the database backup work is carried out. '
def check_run():
"""检测root用户是否具备数据库备份权限
@author linxiao<2020-9-18>
@return (bool, msg)
"""
mycnf_file = '/etc/my.cnf'
if not os.path.exists(mycnf_file):
return True, 'Risk-free'
mycnf = public.readFile(mycnf_file)
port_tmp = re.findall(r"port\s*=\s*(\d+)", mycnf)
if not port_tmp:
return True, 'Risk-free'
if not public.ExecShell("lsof -i :{}".format(port_tmp[0]))[0]:
return True, 'Risk-free'
base_backup_privs = ["Lock_tables_priv", "Select_priv"]
select_sql = "Select {} FROM mysql.user WHERE user='root' and " \
"host=SUBSTRING_INDEX((select current_user()),'@', " \
"-1);".format(",".join(base_backup_privs))
select_result = panelMysql.panelMysql().query(select_sql)
if not select_result:
return False, "The root user has insufficient privileges to perform mysqldump backups."
select_result = select_result[0]
for priv in select_result:
if priv.lower() != "y":
return False, "The root user has insufficient privileges to perform mysqldump backups."
return True, 'Risk-free'

View File

@@ -0,0 +1,40 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 检测是否开debug模式
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'Developer Mode'
_version = 1.0 # 版本
_ps = "Checks whether panel developer mode is enabled" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-05' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_debug_mode.pl")
_tips = [
"Turn off developer mode on the [ Settings ] page",
"Note: Developer mode is only used for panel plug-in or API development, do not use in production environment"
]
_help = ''
_remind = 'This solution prevents the disclosure of sensitive information and reduces the risk of your website being compromised. '
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-05>
@return tuple (status<bool>,msg<string>)
'''
if os.path.exists('/www/server/panel/data/debug.pl'):
return False,'[Developer mode] has been opened, and risks such as data communication and information leakage exist'
return True,'Risk-free'

View File

@@ -0,0 +1,82 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 检测关键目录权限是否正确
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'System directory permissions'
_version = 1.0 # 版本
_ps = "Checks if the System directory permissions are correct" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-05' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_dir_mode.pl")
_tips = [
"On the [ File ] page, set the correct permissions and owner for the specified directory or file",
"Note 1: When setting directory permissions through the [File] page, please cancel the [Apply to subdirectories] option",
"Note 2: Incorrect file permissions not only pose a security risk, but also may cause some software on the server to fail to work properly"
]
_help = ''
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-05>
@return tuple (status<bool>,msg<string>)
'''
dir_list = [
['/usr',755,'root'],
['/usr/bin',555,'root'],
['/usr/sbin',555,'root'],
['/usr/lib',555,'root'],
['/usr/lib64',555,'root'],
['/usr/local',755,'root'],
['/etc',755,'root'],
['/etc/passwd',644,'root'],
['/etc/shadow',600,'root'],
['/etc/gshadow',600,'root'],
['/etc/cron.deny',600,'root'],
['/etc/anacrontab',600,'root'],
['/var',755,'root'],
['/var/spool',755,'root'],
['/var/spool/cron',700,'root'],
['/var/spool/cron/root',600,'root'],
['/var/spool/cron/crontabs/root',600,'root'],
['/www',755,'root'],
['/www/server',755,'root'],
['/www/wwwroot',755,'root'],
['/root',550,'root'],
['/mnt',755,'root'],
['/home',755,'root'],
['/dev',755,'root'],
['/opt',755,'root'],
['/sys',555,'root'],
['/run',755,'root'],
['/tmp',777,'root']
]
not_mode_list = []
# for d in dir_list:
# if not os.path.exists(d[0]): continue
# u_mode = public.get_mode_and_user(d[0])
# if u_mode['user'] != d[2]:
# not_mode_list.append("{} 当前权限: {} : {} 安全权限: {} : {}".format(d[0],u_mode['mode'],u_mode['user'],d[1],d[2]))
# if int(u_mode['mode']) != d[1]:
# not_mode_list.append("{} 当前权限: {} : {} 安全权限: {} : {}".format(d[0],u_mode['mode'],u_mode['user'],d[1],d[2]))
# if not_mode_list:
# return False,'以下关键文件或目录权限错误: <br />' + ("<br />".join(not_mode_list))
return True,'Risk-free'

View File

@@ -0,0 +1,60 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: lkq <lkq@yakpanel.com>
# -------------------------------------------------------------------
# Time: 2022-08-10
# -------------------------------------------------------------------
# Docker API 未授权访问
# -------------------------------------------------------------------
# import sys, os
# os.chdir('/www/server/panel')
# sys.path.append("class/")
import public, os,requests
_title = 'Docker API unauthorized access'
_version = 1.0 # 版本
_ps = "Docker API unauthorized access" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-8-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_docker_api.pl")
_tips = [
"Authentication should be turned on to authenticate or turn off the Docker Api"
]
_help = ''
_remind = "This solution fixes Docker's unauthorized access vulnerability, preventing attackers from using Docker to break into the server. We need to restrict API access to ensure that it does not affect the original website business operation. "
#
def get_local_ip():
'''获取内网IP'''
import socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80))
ip = s.getsockname()[0]
return ip
finally:
s.close()
return '127.0.0.1'
def check_run():
'''
@name 面板登录告警是否开启
@time 2022-08-12
@author lkq@yakpanel.com
'''
try:
if os.path.exists("/lib/systemd/system/docker.service"):
data=public.ReadFile("/lib/systemd/system/docker.service")
if not data:return True, 'Risk-free'
if '-H tcp://' in data:
datas=requests.get("http://{}:2375/info".format(get_local_ip()),timeout=1)
datas.json()
if 'KernelVersion' in datas.text and 'RegistryConfig' in datas.text and 'DockerRootDir' in datas.text:
return False,"Unauthorized access to the Docker API"
return True, 'Risk-free'
except:return True,"Risk-free"

View File

@@ -0,0 +1,44 @@
#!/usr/bin/python
# coding: utf-8
import os, sys, re, public
_title = '设置关键文件底层属性'
_version = 1.0 # 版本
_ps = "检查关键文件的底层属性是否配置" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_file_lock.pl")
_tips = [
"给系统日志文件【/var/log/messages】添加只可追加属性chattr +a",
"给关键文件【/etc/passwd /etc/shadow /etc/group /etc/gshadow】添加锁属性chattr +i"
]
_help = ''
def check_run():
'''
@name 开始检测
@return tuple (status<bool>,msg<string>)
'''
result_list = []
result_str1 = public.ExecShell('lsattr -l /var/log/messages*')[0].strip()
tmp_list1 = result_str1.split('\n')
# 执行lsattr -l查看文件特殊属性若存在特殊属性则判断是否为“追加属性”若为否则加入到result_list最终显示到面板中
for tl1 in tmp_list1:
if not "Append_Only" in tl1:
log1 = re.search(r'.*?\s', tl1)
result_list.append(log1.group().strip())
result_str2 = public.ExecShell('lsattr -l /etc/passwd /etc/shadow /etc/group /etc/gshadow')[0].strip()
tmp_list2 = result_str2.split('\n')
# immutable判断是否为锁属性
for tl2 in tmp_list2:
if not "Immutable" in tl2:
log2 = re.search(r'.*?\s', tl2)
result_list.append(log2.group().strip())
if result_list:
return False, '以下文件未配置适当的底层属性:{}'.format(''.join(result_list))
else:
return True, 'Risk-free'

View File

@@ -0,0 +1,66 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 开启地址空间布局随机化
# -------------------------------------------------------------------
import sys, os
os.chdir('/www/server/panel')
sys.path.append("class/")
import os, sys, re, public
_title = 'Critical file permission checks'
_version = 1.0 # 版本
_ps = "Critical file permission checks" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-08-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_file_mod.pl")
_tips = [
"On the [File] page, set the correct permissions and owner for the specified directory or file",
]
_help = ''
def check_run():
dir_list = [
['/etc/shadow', 400, 'root'],
['/etc/security', 600, 'root'],
['/etc/passwd', 644, 'root'],
['/etc/services', 644, 'root'],
['/etc/group', 644, 'root'],
['/var/spool/cron/root',600, 'root'],
['/etc/ssh/sshd_config',644,'root'],
['/etc/sysctl.conf',644,'root'],
['/etc/crontab',644,'root'],
['/etc/hosts.deny',644,'root'],
['/etc/hosts.allow',644,'root'],
['/etc/gshadow',400,'root'],
['/etc/passwd',644,'root'],
['/etc/shadow',400,'root'],
['/etc/group',644,'root'],
['/etc/gshadow',400,'root'],
]
not_mode_list = []
for d in dir_list:
if not os.path.exists(d[0]): continue
u_mode = public.get_mode_and_user(d[0])
if u_mode['user'] != d[2]:
not_mode_list.append("{} Current permissions: {} : {} Suggested changes to: {} : {}".format(d[0],u_mode['mode'],u_mode['user'],d[1],d[2]))
if int(u_mode['mode']) != d[1]:
not_mode_list.append("{} Current permissions: {} : {} Suggested changes to: {} : {}".format(d[0],u_mode['mode'],u_mode['user'],d[1],d[2]))
if not_mode_list:
return False,'The following critical files or directories have permission errors: <br />' + ("<br />".join(not_mode_list))
else:
return True,"Risk-free"
# check_run()

View File

@@ -0,0 +1,39 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 检测是否开启文件回收站
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'File Recycle Bin'
_version = 1.0 # 版本
_ps = "Check whether the file recycle bin is open" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-05' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_files_recycle_bin.pl")
_tips = [
"On the [File] page, [Recycle Bin] - opens the [File Recycle Bin] function"
]
_help = ''
_remind = 'This solution prevents files from being deleted by mistake and restores them through the recycle bin in time. '
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-05>
@return tuple (status<bool>,msg<string>)
'''
if not os.path.exists('/www/server/panel/data/recycle_bin.pl'):
return False,'The function of [File Recycle Station] is not enabled at present. There is a risk that files cannot be retrieved in case of being deleted by mistake'
return True,'Risk-free'

View File

@@ -0,0 +1,43 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 系统防火墙检测
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'System firewall'
_version = 1.0 # 版本
_ps = "Check whether the system firewall is enable" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-05' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_firewall_open.pl")
_tips = [
"It is recommended to enable the system firewall to prevent all server ports from being exposed to the Internet. If the server has [security group] function, please ignore this prompt",
"Note: To open the system firewall, the ports that need to be opened, especially SSH and panel ports, should be added to the release list in advance, otherwise the server may not be able to access them"
]
_help = ''
_remind = 'This solution can reduce the risk surface of the server exposure and enhance the protection of the website. However, you need to add the port that needs to be opened at the port rule, otherwise the website will be unreachable. '
def check_run():
'''
@name 开始检测
@author hwliang<2022-08-18>
@return tuple (status<bool>,msg<string>)
'''
status = public.get_firewall_status()
if status == 1:
return True,'Risk-free'
elif status == -1:
return False,'System firewall is not installed, there are security risks'
else:
return False,'System firewall is not installed, there are security risks'

View File

@@ -0,0 +1,30 @@
#!/usr/bin/python
# coding: utf-8
import re, os, public
_title = 'Disable anonymous FTP login'
_version = 1.0 # 版本
_ps = "Disable Anonymous Login FTP Detection" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-3-15' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ftp_login.pl")
_tips = [
"Modify the value of NoAnonymous to yes in the [/www/server/pure-ftpd/etc/pure-ftpd.conf] configuration file",
]
_help = ''
_remind = 'This scheme can enhance the FTP server protection, prevent illegal intrusion into the server. Unable to log in to the FTP server using Anonymous after configuration. '
def check_run():
if os.path.exists('/www/server/pure-ftpd/etc/pure-ftpd.conf'):
try:
info_data = public.ReadFile('/www/server/pure-ftpd/etc/pure-ftpd.conf')
if info_data:
if re.search(r'.*NoAnonymous\s*yes', info_data):
return True, 'Risk-free'
else:
return False, 'Currently pure-ftpd does not disable anonymous login, modify/add the value of NoAnonymous to yes in the [pure-ftpd.conf] file'
except:
return True, 'Risk-free'
return True, 'Risk-free'

View File

@@ -0,0 +1,54 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: linxiao
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# FTP弱口令检测
# -------------------------------------------------------------------
# import sys, os
# os.chdir('/www/server/panel')
# sys.path.append("class/")
import os,public
_title = 'Weak password detection for FTP services'
_version = 2.0 # 版本
_ps = "Detect enabled weak passwords for FTP services" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-08-12' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ftp_pass.pl")
_tips = [
"Please go to [FTP] page to change the FTP password ",
"Note: Please do not use too simple account password, so as not to cause security risks ",
"Strong passwords are recommended: numeric, upper - and lowercase, special characters, and no less than seven characters long." ,
"Using [Fail2ban] plugin to protect FTP server"
]
_help = ''
_remind = 'This scheme can strengthen the protection of the FTP server, to prevent intruders from blasting into the FTP server. '
def check_run():
"""检测FTP弱口令
@author linxiao<2020-9-19>
@return (bool, msg)
"""
pass_info = public.ReadFile("/www/server/panel/config/weak_pass.txt")
if not pass_info: return True, 'Risk-free'
pass_list = pass_info.split('\n')
data = public.M("ftps").select()
ret = ""
for i in data:
if i['password'] in pass_list:
ret += "FTP" + i['name'] + "weak passwords exist" + i['password'] + "\n"
if ret:
# print(ret)
return False, ret
else:
return True, 'Risk-free'

View File

@@ -0,0 +1,33 @@
#!/usr/bin/python
# coding: utf-8
import re, os, public
_title = 'Forbid the root user to log in to FTP'
_version = 1.0 # 版本
_ps = "Prohibit the root user from logging in to FTP inspection" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-3-15' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ftp_root.pl")
_tips = [
"Modify the value of MinUID to 100 in the [/www/server/pure-ftpd/etc/pure-ftpd.conf] configuration file",
]
_help = ''
_remind = 'This solution can be used to enhance the protection of your FTP server. After configuration, the root user cannot login ftp, use with caution. '
def check_run():
if os.path.exists('/www/server/pure-ftpd/etc/pure-ftpd.conf'):
try:
info_data = public.ReadFile('/www/server/pure-ftpd/etc/pure-ftpd.conf')
if info_data:
tmp = re.search('\nMinUID\\s*([0-9]{1,4})', info_data)
if tmp:
if int(tmp.group(1).strip()) < 100:
return False, 'Currently pure-ftpd is not configured with security access, modify/add the value of MinUID to 100 in the [pure-ftpd.conf] file'
else:
return True, 'Risk-free'
else:
return False, 'Currently pure-ftpd is not configured with security access, modify/add the value of MinUID to 100 in the [pure-ftpd.conf] file'
except:
return True, 'Risk-free'
return True, 'Risk-free'

View File

@@ -0,0 +1,39 @@
#!/usr/bin/python
# coding: utf-8
import re, os, public
_title = 'Apache version leak'
_version = 1.0 # 版本
_ps = "Apache Version leak check" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-14' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_httpd_version_leak.pl")
_tips = [
"Add ServerSignature Off and ServerTokens Prod to the [httpd.conf] file",
]
_help = ''
_remind = 'This solution can enhance the protection of your server and reduce the risk of your website being compromised. '
def check_run():
'''
@name
@author
@return tuple (status<bool>,msg<string>)
'''
if os.path.exists('/www/server/apache/conf/httpd.conf'):
try:
info_data = public.ReadFile('/www/server/apache/conf/httpd.conf')
if info_data:
if not re.search('ServerSignature', info_data) and not re.search('ServerTokens',
info_data):
return True, 'Risk-free'
if re.search('ServerSignature Off', info_data) and re.search('ServerTokens Prod',
info_data):
return True, 'Risk-free'
else:
return False, 'Currently Apache has a version leak problem, please add ServerSignature Off and ServerTokens Prod in the [httpd.conf] file'
except:
return True, 'Risk-free'
return True, 'Risk-free'

View File

@@ -0,0 +1,40 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 开启地址空间布局随机化
# -------------------------------------------------------------------
# import sys, os
# os.chdir('/www/server/panel')
# sys.path.append("class/")
import os, sys, re, public
_title = 'Enable kernel.randomize_va_space'
_version = 1.0 # 版本
_ps = "Enable kernel.randomize_va_space" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-08-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_kernel_space.pl")
_tips = [
"[/proc/sys/kernel/randomize_va_space] value is 2: ",
"How to setsysctl -w kernel.randomize_va_space=2",
]
_help = ''
_remind = 'This scheme can reduce the risk of intrusers using buffer overflow to attack the server, and strengthen the protection of the server. '
def check_run():
try:
if os.path.exists("/proc/sys/kernel/randomize_va_space"):
randomize_va_space=public.ReadFile("/proc/sys/kernel/randomize_va_space")
if int(randomize_va_space)!=2:
return False, 'Enable kernel.randomize_va_space'
else:
return True,"Risk-free"
except:
return True, "Risk-free"

View File

@@ -0,0 +1,37 @@
#!/usr/bin/python
#coding: utf-8
import os, re, public
_title = 'Check account authentication failure limit'
_version = 1.0 # 版本
_ps = "Check whether to limit the number of account authentication failures" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-20' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_login_fail_limit.pl")
_tips = [
"Add or modify the second line of the [/etc/pam.d/sshd] file",
"auth required pam_tally2.so onerr=fail deny=5 unlock_time=300 even_deny_root root_unlock_time=300"
]
_help = ''
_remind = 'This reduces the risk of a server being blown up. Be sure to remember your login password, though, in case you get locked out of your account for five minutes because of too many failed login attempts. '
def check_run():
'''
@name 开始检测
@return tuple (status<bool>,msg<string>)
'''
cfile = '/etc/pam.d/sshd'
if not os.path.exists(cfile):
return True, 'Risk-free'
conf = public.readFile(cfile)
rep = r".*auth(\s*)required(\s*)pam_tally[2]?\.so.*deny(\s*)=.*unlock_time(\s*)=.*even_deny_root.*root_unlock_time(\s*)="
tmp = re.search(rep, conf)
if tmp:
if tmp.group()[0] == '#':
return False, 'The limit on the number of authentication failures is not configured or is improperly configured'
return True, 'Risk-free'
else:
return False, 'The limit on the number of authentication failures is not configured or is improperly configured'

View File

@@ -0,0 +1,49 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 检测用户登录通知
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'SSH user login notification'
_version = 1.0 # 版本
_ps = "Check whether SSH user login notification is enabled" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-05' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_login_message.pl")
_tips = [
"On the [Security] page, [SSH security management] - [login alarm] enable the [monitor root login] function"
]
_help = ''
def return_bashrc():
if os.path.exists('/root/.bashrc'):return '/root/.bashrc'
if os.path.exists('/etc/bashrc'):return '/etc/bashrc'
if os.path.exists('/etc/bash.bashrc'):return '/etc/bash.bashrc'
return '/root/.bashrc'
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-04>
@return tuple (status<bool>,msg<string>)
'''
data = public.ReadFile(return_bashrc())
if not data: return True,'Risk-free'
if re.search('ssh_security.py login', data):
return True,'Risk-free'
else:
return False,'SSH user login notification is not configured, so it is impossible to know whether the server has been illegally logged in in the first place'

View File

@@ -0,0 +1,67 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 检测风险用户
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'Risk User'
_version = 1.0 # 版本
_ps = "Detect if there is a risk user in the system user list" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-05' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_login_user.pl")
_tips = [
"If these users are not added by the server administrator, the system may have been compromised and should be dealt with as soon as possible."
]
_help = ''
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-04>
@return tuple (status<bool>,msg<string>)
'''
u_list = get_ulist()
try_users = []
for u_info in u_list:
if u_info['user'] == 'root': continue
if u_info['pass'] == '*': continue
if u_info['uid'] == 0:
try_users.append(u_info['user'] + ' > Unknown administrator user [high risk]')
if u_info['login'] in ['/bin/bash','/bin/sh']:
try_users.append(u_info['user'] + ' > Logged-in user [medium risk]')
if try_users:
return False, 'There are security risks for the following users: <br />' + ('<br />'.join(try_users))
return True,'Risk-free'
#获取用户列表
def get_ulist():
u_data = public.readFile('/etc/passwd')
u_list = []
for i in u_data.split("\n"):
u_tmp = i.split(':')
if len(u_tmp) < 3: continue
u_info = {}
u_info['user'],u_info['pass'],u_info['uid'],u_info['gid'],u_info['user_msg'],u_info['home'],u_info['login'] = u_tmp
u_list.append(u_info)
return u_list

View File

@@ -0,0 +1,50 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# Memcached安全检测
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'Memcached security'
_version = 1.0 # 版本
_ps = "Check whether the current Memcached is safe" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-04' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_memcached_port.pl")
_tips = [
"Do not configure bindIP for Memcached as 0.0.0.0 unless necessary",
"If bindIP is 0.0.0.0, be sure to set IP access restrictions through the [SYS firewall] plugin or the Security group"
]
_help = ''
_remind = 'This solution can reduce the risk exposure of the server and strengthen the protection of the website. However, it is necessary to set the accessible IP according to the business requirements. '
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-03>
@return tuple (status<bool>,msg<string>)
'''
p_file = '/etc/init.d/memcached'
p_body = public.readFile(p_file)
if not p_body: return True,'Risk-free'
tmp = re.findall(r"^\s*IP=(0\.0\.0\.0)",p_body,re.M)
if not tmp: return True,'Risk-free'
tmp = re.findall(r"^\s*PORT=(\d+)",p_body,re.M)
result = public.check_port_stat(int(tmp[0]),public.GetClientIp())
if result == 0:
return True,'Risk-free'
return False,'The current Memcached port: {} allows arbitrary client access, which can lead to data leakage'.format(tmp[0])

View File

@@ -0,0 +1,33 @@
#!/usr/bin/python
#coding: utf-8
import os, re, public
_title = 'Whether to enable security authentication for MongoDB'
_version = 1.0 # 版本
_ps = "Check whether MongoDB security authentication is enabled" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-09' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_mongodb_auth.pl")
_tips = [
"Turn on the security authentication switch in the YakPanel Databases MongoDB",
]
_help = ''
_remind = 'This is a great way to protect your database against hackers trying to steal data from your mongo database. '
def check_run():
'''
@name 开始检测
@return tuple (status<bool>,msg<string>)
'''
if not public.process_exists("mongod"):
return True, 'Risk-freeThe MongoDB service has not been started'
cfile = '{}/mongodb/config.conf'.format(public.get_setup_path())
conf = public.readFile(cfile)
rep = r".*authorization(\s*):(\s*)enabled"
tmp = re.search(rep, conf)
if tmp:
return True, 'Risk-free'
else:
return False, 'MongoDB security authentication is not enabled'

View File

@@ -0,0 +1,46 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: lkq <lkq@yakpanel.com>
# -------------------------------------------------------------------
# Time: 2022-08-10
# -------------------------------------------------------------------
# Mysql 弱口令检测
# -------------------------------------------------------------------
import public, os
_title = 'Mysql weak password detection'
_version = 1.0 # 版本
_ps = "Mysql weak password detection" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-8-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_mysql_pass.pl")
_tips = [
"If a weak password is detected, please change the password in time"
]
_help = ''
_remind = 'This scheme increases the strength of the database password and reduces the risk of being successfully exploded. '
def check_run():
'''
@name Mysql 弱口令检测
@time 2022-08-12
@author lkq@yakpanel.com
'''
pass_info = public.ReadFile("/www/server/panel/config/weak_pass.txt")
if not pass_info: return True, 'Risk-free'
pass_list = pass_info.split('\n')
data=public.M("databases").select()
ret=""
for i in data:
if i['password'] in pass_list:
ret+="Database: "+i['name']+" has weak password: "+i['password']+"\n"
if ret:
return False, ret
else:
return True, 'Risk-free'

View File

@@ -0,0 +1,81 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# MySQL端口安全检测
# -------------------------------------------------------------------
import os,sys,re,public,json
_title = 'MySQL security'
_version = 1.0 # 版本
_ps = "Checks whether the current server's MySQL port is secure" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-03' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_mysql_port.pl")
_tips = [
"If not necessary, remove the MySQL port release from the [Security] page",
"Restrict IP access to MySQL port through the [System firewall] plug-in to enhance security",
"Use [ Fail2ban ] plug-in to protect MySQL service"
]
_help = ''
_remind = 'This scheme strengthens the protection of the MySQL database and reduces the risk of the server being stolen data. Before the repair, open up the accessible IP according to the business requirements to ensure that the website is working properly. '
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-03>
@return tuple (status<bool>,msg<string>)
@example
status, msg = check_run()
if status:
print('OK')
else:
print('Warning: {}'.format(msg))
'''
mycnf_file = '/etc/my.cnf'
if not os.path.exists(mycnf_file):
return True,'MySQL is not installed'
mycnf = public.readFile(mycnf_file)
port_tmp = re.findall(r"port\s*=\s*(\d+)",mycnf)
if not port_tmp:
return True,'MySQL is not installed'
if not public.ExecShell("lsof -i :{}".format(port_tmp[0]))[0]:
return True,'MySQL is not installed'
result = public.check_port_stat(int(port_tmp[0]),public.GetLocalIp())
#兼容socket能连通但实际端口不通情况
if result != 0:
res=''
if os.path.exists('/usr/sbin/firewalld'):
res=public.ExecShell('firewall-cmd --list-all')
elif os.path.exists('/usr/sbin/ufw'):
try:
res=public.ExecShell('sudo ufw status verbose')
except:
res=public.ExecShell('ufw status verbose')
else:
pass
check_str=' '+port_tmp[0]+'/'
if res[0].find(check_str) == -1:
return True,'Risk-free'
else:return True,'Risk-free'
fail2ban_file = '/www/server/panel/plugin/fail2ban/config.json'
if os.path.exists(fail2ban_file):
try:
fail2ban_config = json.loads(public.readFile(fail2ban_file))
if 'mysql' in fail2ban_config.keys():
if fail2ban_config['mysql']['act'] == 'true':
return True,'Fail2ban is enabled'
except: pass
return False,'MySQL port: {}, can be accessed by any server, which may cause MySQL to be cracked by brute force, posing security risks'.format(port_tmp[0])

View File

@@ -0,0 +1,57 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: linxiao
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 数据库备份权限检测
# -------------------------------------------------------------------
import os, re, public, panelMysql
_title = 'Database backup permission detection'
_version = 1.0 # 版本
_ps = "Check whether the MySQL root user has database backup permissions" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-09-19' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_database_priv.pl")
_tips = [
"To temporarily access the database without authorization, it is recommended to restore all permissions of the root user.",
]
_help = ''
_remind = 'This scheme ensures that the root user has the permission to backup the database and ensures that the database backup work is carried out. '
def check_run():
"""检测root用户是否具备数据库备份权限
@author linxiao<2020-9-18>
@return (bool, msg)
"""
mycnf_file = '/etc/my.cnf'
if not os.path.exists(mycnf_file):
return True, 'Risk-free'
mycnf = public.readFile(mycnf_file)
port_tmp = re.findall(r"port\s*=\s*(\d+)", mycnf)
if not port_tmp:
return True, 'Risk-free'
if not public.ExecShell("lsof -i :{}".format(port_tmp[0]))[0]:
return True, 'Risk-free'
base_backup_privs = ["Lock_tables_priv", "Select_priv"]
select_sql = "Select {} FROM mysql.user WHERE user='root' and " \
"host=SUBSTRING_INDEX((select current_user()),'@', " \
"-1);".format(",".join(base_backup_privs))
select_result = panelMysql.panelMysql().query(select_sql)
if not select_result:
return False, "The root user has insufficient authority to execute mysqldump backup."
select_result = select_result[0]
for priv in select_result:
if priv.lower() != "y":
return False, "The root user has insufficient authority to execute mysqldump backup."
return True, 'Risk-free'

View File

@@ -0,0 +1,45 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: lkq <lkq@yakpanel.com>
# -------------------------------------------------------------------
# Time: 2022-08-10
# -------------------------------------------------------------------
# Nginx 版本泄露
# -------------------------------------------------------------------
import re, public, os
_title = 'Nginx version leaked'
_version = 1.0 # 版本
_ps = "Nginx version leaked" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-8-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_nginx_server.pl")
_tips = [
"Set [server_tokens off;] in the [/www/server/nginx/conf/nginx.conf] file;",
"Tipsserver_tokens off;"
]
_help = ''
_remind = 'This solution enhances server protection and reduces the risk of your website being compromised. '
def check_run():
'''
@name 检测nginx版本泄露
@author lkq<2020-08-10>
@return tuple (status<bool>,msg<string>)
'''
if os.path.exists('/www/server/nginx/conf/nginx.conf'):
try:
info_data = public.ReadFile('/www/server/nginx/conf/nginx.conf')
if info_data:
if re.search('server_tokens off;', info_data):
return True, 'Risk-free'
else:
return False, 'The current version of Nginx is leaked, please add or modify the parameter server_tokens to off; in the Nginx configuration file, for example: server_tokens off;'
except:
return True, 'Risk-free'
return True, 'Risk-free'

View File

@@ -0,0 +1,40 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: lkq <lkq@yakpanel.com>
# -------------------------------------------------------------------
# Time: 2022-08-10
# -------------------------------------------------------------------
# Mysql 弱口令检测
# -------------------------------------------------------------------
import public, os
_title = 'The panel is not monitoring'
_version = 1.0 # 版本
_ps = "The panel is not monitoring" # 描述
_level = 1 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-8-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_panel_control.pl")
_tips = [
"Open it in [Monitor] - [System Monitor]"
]
_help = ''
_remind = 'Enable server monitoring, you can record the recent operation of the server, to facilitate the troubleshooting of system anomalies. '
def check_run():
'''
@name 面板未开启监控
@time 2022-08-12
@author lkq@yakpanel.com
'''
global _tips
send_type = ""
if os.path.exists("/www/server/panel/data/control.conf"):
return True, 'Risk-free'
return False, _tips[0]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 面板安全入口检测
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'Safe entrance'
_version = 1.0 # 版本
_ps = "Check the security entrance security of the panel" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-04' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_panel_path.pl")
_tips = [
"Please modify the security entrance on the [Settings] page",
"Set the binding domain name on the [Settings] page, or set authorized IP restrictions",
"Note: Please do not set up too simple safety entrance, which may cause safety hazards"
]
_help = ''
_remind = 'This solution can strengthen the panel login entry protection, improve server security. '
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-03>
@return tuple (status<bool>,msg<string>)
'''
p_file = '/www/server/panel/data/domain.conf'
if public.readFile(p_file):
return True,'Risk-free'
p_file = '/www/server/panel/data/limitip.conf'
if public.readFile(p_file):
return True,'Risk-free'
p_file = '/www/server/panel/data/admin_path.pl'
p_body = public.readFile(p_file)
if not p_body: return False,'No security entrance is set, the panel is at risk of being scanned'
p_body = p_body.strip('/').lower()
if p_body == '': return False,'No security entrance is set, the panel is at risk of being scanned'
lower_path = ['root','admin','123456','123','12','1234567','12345','1234','12345678','123456789','abc','bt']
if p_body in lower_path:
return False,'The security entrance is: {}, too simple, there are potential safety hazards'.format(p_body)
lower_rule = 'qwertyuiopasdfghjklzxcvbnm1234567890'
for s in lower_rule:
for i in range(12):
if not i: continue
lp = s * i
if p_body == lp:
return False,'The security entrance is: {}, too simple, there are potential safety hazards'.format(p_body)
return True,'Risk-free'

View File

@@ -0,0 +1,43 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 面板端口检测
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'Panel port'
_version = 1.0 # 版本
_ps = "Check whether the current panel port is safe" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-03' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_panel_port.pl")
_tips = [
"Please modify the default panel port on the [Settings] page",
"Note: Servers with [Security Group] should release the new port in the [Security Group] in advance to prevent the new port cannot be opened"
]
_help = ''
_remind = 'This solution can strengthen the panel protection and reduce the risk of the panel being attacked. '
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-03>
@return tuple (status<bool>,msg<string>)
'''
port_file = '/www/server/panel/data/port.pl'
port = public.readFile(port_file)
if not port: return True,'Rick-free'
port = int(port)
if port != 7800:
return True,'Rick-free'
return False,'The panel port is the default port ({}), which may cause unnecessary security risks'.format(port)

View File

@@ -0,0 +1,42 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: lkq <lkq@yakpanel.com>
# -------------------------------------------------------------------
# Time: 2022-08-10
# -------------------------------------------------------------------
# Mysql 弱口令检测
# -------------------------------------------------------------------
import public, os
_title = 'Panel login alarm'
_version = 1.0 # 版本
_ps = "Panel login alarm" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-8-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_panel_swing.pl")
_tips = [
"Enable it in [Settings] - [Notification]"
]
_help = ''
_remind = 'This solution can strengthen the panel protection and reduce the risk of the panel being attacked. '
def check_run():
'''
@name 面板登录告警是否开启
@time 2022-08-12
@author lkq@yakpanel.com
'''
send_type = ""
tip_files = ['panel_login_send.pl','login_send_type.pl','login_send_mail.pl','login_send_dingding.pl']
for fname in tip_files:
filename = 'data/' + fname
if os.path.exists(filename):
return True, 'Risk-free'
return False, 'Please enable it in [Settings] - [Notification]'

View File

@@ -0,0 +1,36 @@
#!/usr/bin/python
#coding: utf-8
import os, re, public
_title = 'Check password reuse limit'
_version = 1.0 # 版本
_ps = "Detect whether to limit password reuse times" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_passwd_repeat.pl")
_tips = [
"Configuration file backup: cp -p /etc/pam.d/system-auth /etc/pam.d/system-auth.bak",
"Add or modify remember=5 after [password sufficient] in [/etc/pam.d/system-auth] file"
]
_help = ''
_remind = 'This scheme enhances server access control protection by limiting the number of times login passwords are reused. '
def check_run():
'''
@name 开始检测
@return tuple (status<bool>,msg<string>)
'''
try:
cfile = '/etc/pam.d/system-auth'
conf = public.readFile(cfile)
rep = r"password(\s*)sufficient.*remember(\s*)=(\s*)[1-9]+"
tmp = re.search(rep, conf)
if tmp:
return True, 'Risk-free'
else:
return False, 'Unlimited password reuse'
except:
return True, 'Risk-free'

View File

@@ -0,0 +1,67 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: lkq <lkq@yakpanel.com>
# -------------------------------------------------------------------
# Time: 2022-08-10
# -------------------------------------------------------------------
# PHP未禁用函数
# -------------------------------------------------------------------
import sys,os
os.chdir('/www/server/panel')
sys.path.append("class/")
import public,re,os
_title = 'PHP Dangerous Functions'
_version = 1.0 # 版本
_ps = "PHP Dangerous Functions" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-8-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_php_php_disable_funcation.pl")
_tips = [
"[disable_functions] is not set in the [php.ini] file to disable dangerous functions such as system, exec, passthru, shell_exec, popen, proc_open, etc.",
"Tips: [disable_functions] is not set in the [php.ini] file to disable dangerous functions such as system, exec, passthru, shell_exec, popen, proc_open, etc."
]
_help = ''
_remind = 'This solution can strengthen the protection of the website and reduce the risk of server intrusion. '
def check_run():
path ="/www/server/php"
#获取目录下的文件夹
dirs = os.listdir(path)
result={}
for dir in dirs:
if dir in ["52","53","54","55","56","70","71","72","73","74","80","81"]:
file_path=path+"/"+dir+"/etc/php.ini"
if os.path.exists(file_path):
#获取文件内容
try:
php_ini = public.readFile(file_path)
if re.search("\ndisable_functions\\s?=\\s?(.+)",php_ini):
disable_functions = re.findall("\ndisable_functions\\s?=\\s?(.+)",php_ini)
disa_fun=["system","exec","passthru","shell_exec","popen","proc_open","putenv"]
if len(disable_functions) > 0:
disable_functions= disable_functions[0].split(",")
for i2 in disa_fun:
if i2 not in disable_functions:
if dir in result:
result[dir].append(i2)
else:
result[dir]=[i2]
except:
pass
if result:
ret=""
for i in result:
ret+="[PHP "+i+"] Dangerous functions that are not disabled are as follows:"+",".join(result[i])+"\n"
return False,ret
else:
return True, "Risk-free"

View File

@@ -0,0 +1,62 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: lkq <lkq@yakpanel.com>
# -------------------------------------------------------------------
# Time: 2022-08-10
# -------------------------------------------------------------------
# PHP存在版本泄露
# -------------------------------------------------------------------
# import sys,os
# os.chdir('/www/server/panel')
# sys.path.append("class/")
import re,public,os
_title = 'PHP version leaked'
_version = 1.0 # 版本
_ps = "PHP version leaked" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-8-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_php_expose.pl")
_tips = [
"Set [expose_php] in the [php.ini] file and configure it to Off",
"Tips: Set [expose_php] in the [php.ini] file and configure it to Off"
]
_help = ''
_remind = 'This solution can prevent the disclosure of sensitive information on the website and reduce the possibility of server intrusion. '
def check_run():
path ="/www/server/php"
#获取目录下的文件夹
dirs = os.listdir(path)
resulit=[]
for dir in dirs:
if dir in ["52","53","54","55","56","70","71","72","73","74","80","81"]:
file_path=path+"/"+dir+"/etc/php.ini"
if os.path.exists(file_path):
#获取文件内容
try:
php_ini = public.readFile(file_path)
#查找expose_php
if re.search("\nexpose_php\\s*=\\s*(\\w+)",php_ini):
expose_php = re.search("\nexpose_php\\s*=\\s*(\\w+)",php_ini).groups()[0]
if expose_php.lower() == "off":
pass
else:
resulit.append(dir)
except:
pass
if resulit:
return False, "The affected php versions are as follows: ["+",".join(resulit)+"], please set expose_php to Off in php.ini"
else:
return True, "Risk-free"
# check_run()

View File

@@ -0,0 +1,47 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 检测是否禁ping
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'ICMP detection'
_version = 1.0 # 版本
_ps = "Check whether ICMP access is allowed (Block ICMP)" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-05' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ping.pl")
_tips = [
"Turn on the [Block ICMP] function in the [Security] page",
"Note: The server IP or domain name cannot be Ping after it is turned on, please set according to actual needs"
]
_help = ''
_remind = 'This scheme can reduce the risk of the real IP of the server being found, and enhance the security of the server. '
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-05>
@return tuple (status<bool>,msg<string>)
'''
cfile = '/etc/sysctl.conf'
conf = public.readFile(cfile)
rep = r"#*net\.ipv4\.icmp_echo_ignore_all\s*=\s*([0-9]+)"
tmp = re.search(rep,conf)
if tmp:
if tmp.groups(0)[0] == '1':
return True,'Rick-free'
return False,'If the [Block ICMP] function is not enabled, there is a risk that the server will be attacked or scanned by ICMP'

View File

@@ -0,0 +1,47 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 检测是否禁ping
# -------------------------------------------------------------------
import os,sys,re,public
_title = '2222222'
_version = 1.0 # 版本
_ps = "222222222(禁Ping)" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-05' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ping_in.pl")
_tips = [
"Enable Disable Ping in Security page ",
"Note: You cannot ping the server IP or domain name after opening, please set it according to your actual needs"
]
_help = ''
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-05>
@return tuple (status<bool>,msg<string>)
'''
try:
cfile = '/proc/sys/net/ipv4/icmp_echo_ignore_all'
conf = public.readFile(cfile)
if conf:
if int(conf)!=1:
return False,'The "Ban Ping" function is not enabled at present, there is a risk that the server is attacked by ICMP or swept'
else:
return True,"Risk-free"
except:
return True,"Risk-free"

View File

@@ -0,0 +1,29 @@
#!/usr/bin/python
#coding: utf-8
import os, re, public
_title = 'Pypi supply chain poisoning detection'
_version = 1.0 # 版本
_ps = "Pypi supply chain poisoning detection" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-14' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_pip_poison.pl")
_tips = [
"Execute the command btpip uninstall [detected malicious library name]",
]
_help = ''
_remind = 'This solution can remove vulnerable packages from the server and prevent them from being exploited by hackers. Before executing the solution command, make sure that the malicious library name is not a dependency library of normal business, otherwise it may affect the operation of the website. '
def check_run():
pip = public.ExecShell("btpip freeze | grep -E \"istrib|djanga|easyinstall|junkeldat|libpeshka|mumpy|mybiubiubiu|nmap"
"-python|openvc|python-ftp|pythonkafka|python-mongo|python-mysql|python-mysqldb|python"
"-openssl|python-sqlite|virtualnv|mateplotlib|request=\"")[0].strip()
if 'command not found' in pip or 'command not found' in pip:
return True, 'Risk-freepip is not installed'
if pip:
pip = pip.split('\n')
return False, '{}】security risk in the python library, please deal with it as soon as possible'.format(''.join(pip))
else:
return True, 'Risk-free'

View File

@@ -0,0 +1,48 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# Redis 密码检测
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'Redis weak password'
_version = 1.0 # 版本
_ps = "Check if the current Redis password is secure" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-08-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_redis_pass.pl")
_tips = [
"1.Redis passwords are too simple"
"2.Please change your password in time"
]
_help = ''
_remind = 'This solution reduces the risk of server intrusion by strengthening the database login password. '
def check_run():
try:
p_file = '/www/server/redis/redis.conf'
p_body = public.readFile(p_file)
if not p_body: return True, 'Risk-free'
tmp = re.findall(r"^\s*requirepass\s+(.+)", p_body, re.M)
if not tmp: return True, 'Risk-free'
redis_pass = tmp[0].strip()
pass_info=public.ReadFile("/www/server/panel/config/weak_pass.txt")
if not pass_info: return True, 'Risk-free'
pass_list = pass_info.split('\n')
for i in pass_list:
if i==redis_pass:
return False, 'The Redis password [%s] is a weak password, please change the password'%redis_pass
return True, 'Risk-free'
except:
return True, 'Risk-free'

View File

@@ -0,0 +1,85 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# Redis安全检测
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'Redis security'
_version = 1.0 # 版本
_ps = "Check whether the current Redis is safe" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-04' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_redis_port.pl")
_tips = [
"If not necessary, please do not configure Redis bind to 0.0.0.0",
"If bind is 0.0.0.0, be sure to set an access password for Redis",
"Do not use too simple password as Redis access password",
"Strong passwords are recommended: numeric, upper - and lowercase, special characters, and no less than seven characters long.",
"If there is a security problem in Redis, it will lead to a high probability of server intrusion, please be sure to deal with it carefully."
]
_help = ''
_remind = 'This solution can strengthen the protection of Redis database and reduce the risk of server intrusion. When fixing the risk, make sure that you have opened the IP access of the relevant website, and change the access password synchronously to prevent the server from being unable to access Redis. '
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-03>
@return tuple (status<bool>,msg<string>)
'''
p_file = '/www/server/redis/redis.conf'
p_body = public.readFile(p_file)
if not p_body: return True,'Rick-free'
tmp = re.findall(r"^\s*bind\s+(0\.0\.0\.0)",p_body,re.M)
if not tmp: return True,'Rick-free'
tmp = re.findall(r"^\s*requirepass\s+(.+)",p_body,re.M)
if not tmp: return False,'Reids allows public internet connection, but no Redis password is set, which is extremely dangerous, please deal with it immediately'
redis_pass = tmp[0].strip()
if not is_strong_password(redis_pass):
return False, 'Redis access password is too simple, and there are security risks'
return True,'Risk-free'
def is_strong_password(password):
"""判断密码复杂度是否安全
非弱口令标准长度大于等于7分别包含数字、小写、大写、特殊字符。
@password: 密码文本
@return: True/False
"""
if len(password) < 7:
return False
import re
digit_reg = "[0-9]" # 匹配数字 +1
lower_case_letters_reg = "[a-z]" # 匹配小写字母 +1
upper_case_letters_reg = "[A-Z]" # 匹配大写字母 +1
special_characters_reg = r"((?=[\x21-\x7e]+)[^A-Za-z0-9])" # 匹配特殊字符 +1
regs = [digit_reg,
lower_case_letters_reg,
upper_case_letters_reg,
special_characters_reg]
grade = 0
for reg in regs:
if re.search(reg, password):
grade += 1
if grade == 4 or (grade >= 2 and len(password) >= 9):
return True
return False

View File

@@ -0,0 +1,40 @@
#!/usr/bin/python
# coding: utf-8
import os, public
_title = 'Check for dangerous remote access files'
_version = 1.0 # 版本
_ps = "Check for dangerous remote access files:hosts.equiv、.rhosts、.netrc" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-09' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_risk_file.pl")
_tips = [
"Delete the .rhosts and .netrc files in the home directory and delete the hosts.equiv file in the root directory",
"Follow the prompts to find the risk file and delete it"
]
_help = ''
_remind = 'This solution removes all vulnerable files, preventing them from being exploited by hackers to gain access to the server. You can backup files before deleting them to prevent them from affecting the operation of your website. '
def check_run():
'''
@name 开始检测
@return tuple (status<bool>,msg<string>)
'''
result_list = []
cfile = ['hosts.equiv', '.rhosts', '.netrc']
for cf in cfile:
file = public.ExecShell('find / -maxdepth 3 -name {}'.format(cf))
if file[0]:
result_list = result_list+file[0].split('\n')
result = ''.join(reform_list(result_list))
if result:
return False, 'High-risk files, delete the following files as soon as possible\"{}\"'.format(result)
else:
return True, 'Risk-free'
def reform_list(check_list):
"""处理列表里的空字符串"""
return [i for i in check_list if (i is not None) and (str(i).strip() != '')]

View File

@@ -0,0 +1,93 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 检测网站是否开启防跨站
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'Website anti-cross-site detection'
_version = 1.0 # 版本
_ps = "Check the website to prevent cross-site" # 描述
_level = 1 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-05' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_site_spath.pl")
_tips = [
"On the [WebSite] page, [Settings]-[Site Directory], turn on the [Anti-cross-site attack (open_basedir)] function"
]
_help = ''
_remind = 'This solution can prevent hackers from stealing server information across directories, and strengthen the protection of the website. '
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-05>
@return tuple (status<bool>,msg<string>)
'''
not_uini = []
site_list = public.M('sites').where('status=? AND project_type=?',(1,'PHP')).field('name,path').select()
for s in site_list:
path = get_site_run_path(s['name'],s['path'])
user_ini = path + '/.user.ini'
if os.path.exists(user_ini): continue
not_uini.append(s['name'])
if not_uini:
return False,'The following websites are not enabled for cross-site prevention:<br />' + ('<br />'.join(not_uini))
return True,'Rick-free'
webserver_type = None
setupPath = '/www/server'
def get_site_run_path(siteName,sitePath):
'''
@name 获取网站运行目录
@author hwliang<2020-08-05>
@param siteName(string) 网站名称
@param sitePath(string) 网站根目录
@return string
'''
global webserver_type,setupPath
if not webserver_type:
webserver_type = public.get_webserver()
path = None
if webserver_type == 'nginx':
filename = setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
if os.path.exists(filename):
conf = public.readFile(filename)
rep = r'\s*root\s+(.+);'
tmp1 = re.search(rep,conf)
if tmp1: path = tmp1.groups()[0]
elif webserver_type == 'apache':
filename = setupPath + '/panel/vhost/apache/' + siteName + '.conf'
if os.path.exists(filename):
conf = public.readFile(filename)
rep = r'\s*DocumentRoot\s*"(.+)"\s*\n'
tmp1 = re.search(rep,conf)
if tmp1: path = tmp1.groups()[0]
else:
filename = setupPath + '/panel/vhost/openlitespeed/' + siteName + '.conf'
if os.path.exists(filename):
conf = public.readFile(filename)
rep = r"vhRoot\s*(.*)"
path = re.search(rep,conf)
if not path:
path = None
else:
path = path.groups()[0]
if not path:
path = sitePath
return path

View File

@@ -0,0 +1,53 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 网站证书检测
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'Website certificate (SSL)'
_version = 1.0 # 版本
_ps = "Check whether all websites deploy SSL" # 描述
_level = 1 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-04' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_site_ssl.pl")
_tips = [
"Please consider deploying an SSL certificate for your website to improve its security"
]
_help = ''
_remind = 'SSL certificates ensure that the communication on your website is secure, preventing hackers from stealing data while it is in transit. '
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-04>
@return tuple (status<bool>,msg<string>)
'''
site_list = public.M('sites').field('id,name').select()
not_ssl_list = []
for site_info in site_list:
ng_conf_file = '/www/server/panel/vhost/nginx/' + site_info['name'] + '.conf'
if not os.path.exists(ng_conf_file): continue
s_body = public.readFile(ng_conf_file)
if not s_body: continue
if s_body.find('ssl_certificate') == -1:
not_ssl_list.append(site_info['name'])
if not_ssl_list:
return False ,'The following sites do not deploy SSL certificates: <br />' + ('<br />'.join(not_ssl_list))
return True,'Rick-free'

View File

@@ -0,0 +1,77 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 网站证书过期检测
# -------------------------------------------------------------------
import os,sys,re,public,OpenSSL,time
_title = 'Website certificate expired'
_version = 1.0 # 版本
_ps = "Check whether the websites SSL has expired" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-04' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_site_ssl_expire.pl")
_tips = [
"Please renew or replace with a new SSL certificate for your site to avoid affecting normal website access",
"After the SSL certificate expires, the user will be prompted by the browser to access the website as insecure, and most browsers will block access, seriously affecting online business"
]
_help = ''
_remind = 'SSL certificates ensure that the communication on your website is secure, preventing hackers from stealing data while it is in transit. '
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-04>
@return tuple (status<bool>,msg<string>)
'''
site_list = public.M('sites').field('id,name').select()
not_ssl_list = []
s_time = time.time()
for site_info in site_list:
ng_conf_file = '/www/server/panel/vhost/nginx/' + site_info['name'] + '.conf'
if not os.path.exists(ng_conf_file): continue
s_body = public.readFile(ng_conf_file)
if not s_body: continue
if s_body.find('ssl_certificate') == -1: continue
cert_file = '/www/server/panel/vhost/cert/{}/fullchain.pem'.format(site_info['name'])
if not os.path.exists(cert_file): continue
cert_timeout = get_cert_timeout(cert_file)
if s_time > cert_timeout:
not_ssl_list.append(site_info['name'] + ' Expiration: ' + public.format_date("%Y-%m-%d",cert_timeout))
if not_ssl_list:
return False ,'The following sites SSL certificate has expired: <br />' + ('<br />'.join(not_ssl_list))
return True,'Rick-free'
# 获取证书到期时间
def get_cert_timeout(cert_file):
try:
cert = split_ca_data(public.readFile(cert_file))
x509 = OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_PEM, cert)
cert_timeout = bytes.decode(x509.get_notAfter())[:-1]
return int(time.mktime(time.strptime(cert_timeout, '%Y%m%d%H%M%S')))
except:
return time.time() + 86400
# 拆分根证书
def split_ca_data(cert):
datas = cert.split('-----END CERTIFICATE-----')
return datas[0] + "-----END CERTIFICATE-----\n"

View File

@@ -0,0 +1,63 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: lkq <lkq@yakpanel.com>
# -------------------------------------------------------------------
# Time: 2022-08-10
# -------------------------------------------------------------------
# SSH 空闲超时时间检测
# -------------------------------------------------------------------
import re,public,os
_title = 'SSH idle timeout detection'
_version = 1.0 # 版本
_ps = "SSH idle timeout detection" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-8-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ssh_clientalive.pl")
_tips = [
"Set [ClientAliveInterval] in the [/etc/ssh/sshd_config] file to be between 600 and 900",
"Tip: The recommended SSH idle timeout time is: 600-900"
]
_help = ''
_remind = 'This scheme can enhance the security of SSH service, after the repair of SSH connection for a long time without operation will automatically quit, to prevent others from using. '
def check_run():
'''
@name SSH 空闲超时检测
@time 2022-08-10
@author lkq<2020-08-10>
@return tuple (status<bool>,msg<string>)
'''
if os.path.exists('/etc/ssh/sshd_config'):
try:
info_data=public.ReadFile('/etc/ssh/sshd_config')
if info_data:
if re.search(r'ClientAliveInterval\s+\d+',info_data):
clientalive=re.findall(r'ClientAliveInterval\s+\d+',info_data)[0]
#clientalive 需要大于600 小于900
if int(clientalive.split(' ')[1]) >= 600 and int(clientalive.split(' ')[1]) <= 900:
return True,'Rick-free'
else:
return False,'The current SSH idle timeout time is: '+clientalive.split(' ')[1]+', it is recommended to set it to 600-900'
else:
return True,'Rick-free'
except:
return True,'Rick-free'
return True,'Rick-free'
def repaired():
'''
@name 修复ssh最大连接数
@author lkq<2022-08-10>
@return tuple (status<bool>,msg<string>)
'''
# 暂时不处理
pass

View File

@@ -0,0 +1,30 @@
#!/usr/bin/python
#coding: utf-8
import sys,re,os,public
_title = 'Use the graphical interface to check after restricting SSH login'
_version = 1.0 # 版本
_ps = "Use the graphical interface to check after restricting SSH login" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-14' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ssh_forward.pl")
_tips = [
"Modify X11Forwarding to no in [/etc/ssh/sshd_config]",
]
_help = ''
_remind = 'This can be used to enforce SSH login security and speed up SSH connections. Notethe fix turns off X11 graphical forwarding, so do not configure it if you need to use it. '
def check_run():
conf = '/etc/ssh/sshd_config'
if not os.path.exists(conf):
return True, 'Risk-free'
result = public.ReadFile(conf)
rep = r'.*?X11Forwarding\s*?yes'
tmp = re.search(rep, result)
if tmp:
if tmp.group()[0] == '#':
return True, 'Risk-free'
else:
return False, 'SSH graphical forwarding is not disabled'
return True, 'Risk-free'

View File

@@ -0,0 +1,64 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: lkq <lkq@yakpanel.com>
# -------------------------------------------------------------------
# Time: 2022-08-10
# -------------------------------------------------------------------
# SSH 最大连接数检测
# -------------------------------------------------------------------
import re, public, os
_title = 'SSH connection attempts'
_version = 1.0 # 版本
_ps = "SSH connection attempts" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-8-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ssh_maxauth.pl")
_tips = [
"Set [MaxAuthTries] to 3-5 in the [/etc/ssh/sshd_config] file",
"Tips: Set [MaxAuthTries] to 3-5 in the [/etc/ssh/sshd_config] file"
]
_help = ''
_remind = 'This reduces the risk of server intrusion by reducing the maximum number of SSH connections. Note Before fixing, confirm the number of simultaneous connections that SSH needs to support to prevent affecting normal business operations. '
def check_run():
'''
@name 检测ssh最大连接数
@author lkq<2020-08-10>
@return tuple (status<bool>,msg<string>)
'''
if os.path.exists('/etc/ssh/sshd_config'):
try:
info_data = public.ReadFile('/etc/ssh/sshd_config')
if info_data:
if re.search(r'MaxAuthTries\s+\d+', info_data):
maxauth = re.findall(r'MaxAuthTries\s+\d+', info_data)[0]
# max 需要大于3 小于6
if int(maxauth.split(' ')[1]) >= 3 and int(maxauth.split(' ')[1]) <= 6:
return True, 'Rick-free'
else:
return False, 'The current maximum number of SSH connections is: ' + maxauth.split(' ')[1] + ', please set it to 3-5'
else:
return True, 'Rick-free'
except:
return True, 'Rick-free'
return True, 'Rick-free'
def repaired():
'''
@name 修复ssh最大连接数
@author lkq<2020-08-10>
@return tuple (status<bool>,msg<string>)
'''
# 暂时不处理
pass

View File

@@ -0,0 +1,44 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# SSH密码复杂度检查
# -------------------------------------------------------------------
# import sys, os
# os.chdir('/www/server/panel')
# sys.path.append("class/")
import os, sys, re, public
_title = 'SSH password complexity check'
_version = 1.0 # 版本
_ps = "SSH password complexity check" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-08-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ssh_minclass.pl")
_tips = [
"【/etc/security/pwquality.conf】 Set password complexity to require 3 or 4 types of characters, such as lowercase letters, uppercase letters, numbers, and special characters. like",
"minclass=3",
]
_help = ''
_remind = 'This scheme strengthens the complexity of the server login password and reduces the risk of being successfully exploded. '
def check_run():
try:
p_file = '/etc/security/pwquality.conf'
p_body = public.readFile(p_file)
if not p_body: return True, 'Risk-free'
tmp = re.findall(r"\s*minclass\s+=\s+(.+)", p_body, re.M)
if not tmp: return True, 'Risk-free'
minlen = tmp[0].strip()
if int(minlen) <3:
return False, '%s】set the minclass setting to 3 or 4 in the file' % p_file
return True, 'Risk-free'
except:
return True, 'Risk-free'

View File

@@ -0,0 +1,49 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: lkq <lkq@yakpanel.com>
# -------------------------------------------------------------------
# Time: 2022-08-10
# -------------------------------------------------------------------
# 禁止SSH空密码登录
# -------------------------------------------------------------------
import re,public,os
_title = 'Prohibit SSH login with empty password'
_version = 1.0 # 版本
_ps = "Prohibit SSH login with empty password" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-8-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ssh_notpasswd.pl")
_tips = [
"Set [PermitEmptyPasswords] in the [/etc/ssh/sshd_config] file to configure it to no",
"Tips: Set [PermitEmptyPasswords] in the [/etc/ssh/sshd_config] file to configure it to no"
]
_help = ''
_remind = 'This scheme prevents the server from logging in with an empty password. Note that the server cannot login with an empty password after the repair. Ensure that the login password is configured synchronously for related business access. '
def check_run():
'''
@name 检测禁止SSH空密码登录
@author lkq<2020-08-10>
@return tuple (status<bool>,msg<string>)
'''
if os.path.exists('/etc/ssh/sshd_config'):
try:
info_data = public.ReadFile('/etc/ssh/sshd_config')
if info_data:
if re.search('\nPermitEmptyPasswords\\s*yes', info_data):
return False, 'The [PermitEmptyPasswords] value is: yes, please set it to no'
else:
return True, 'Rick-free'
except:
return True, 'Rick-free'
return True, 'Rick-free'

View File

@@ -0,0 +1,46 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 检查SSH密码失效时间
# -------------------------------------------------------------------
import sys, os
os.chdir('/www/server/panel')
sys.path.append("class/")
import os, sys, re, public
_title = 'Check SSH password expiration time'
_version = 1.0 # 版本
_ps = "Check SSH password expiration time" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-08-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ssh_passmax.pl")
_tips = [
"[/etc/login.defs] Use a non-password login key pair. Please ignore this, and set the PASS_MAX_DAYS parameter to between 90-180 in /etc/login.defs",
"PASS_MAX_DAYS 90 You need to execute the command to set the root password expiration time at the same time. The command is as follows: chage --maxdays 90 root",
]
_help = ''
_remind = 'This solution reduces the risk of a breach by setting an expiration date for the root login password. Note that the repair scheme will invalidate the root password after the expiration date, so it is necessary to modify the password before the expiration date. If the modification is not timely, it may affect the operation of some services. '
def check_run():
try:
p_file = '/etc/login.defs'
p_body = public.readFile(p_file)
if not p_body: return True, 'Risk-free'
tmp = re.findall("\nPASS_MAX_DAYS\\s+(.+)", p_body, re.M)
if not tmp: return True, 'Risk-free'
maxdays = tmp[0].strip()
#60-180之间
if int(maxdays) < 90 or int(maxdays) > 180:
return False, '%s】Set PASS_MAX_DAYS to between 90-180 in the file' % p_file
return True, 'Risk-free'
except:
return True, 'Risk-free'

View File

@@ -0,0 +1,45 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 检查SSH密码失效时间
# -------------------------------------------------------------------
import sys, os
os.chdir('/www/server/panel')
sys.path.append("class/")
import os, sys, re, public
_title = 'Check minimum interval between SSH password changes'
_version = 1.0 # 版本
_ps = "Check minimum interval between SSH password changes" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-08-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ssh_passmin.pl")
_tips = [
"[/etc/login.defs] PASS_MIN_DAYS should be set to be greater than or equal to 7",
"PASS_MIN_DAYS 7 needs to execute the command at the same time to set the expiration time of the root password. The command is as follows: chage --mindays 7 root",
]
_help = ''
_remind = 'This solution sets the number of days after the SSH login password is changed, it cannot be changed again. '
def check_run():
try:
p_file = '/etc/login.defs'
p_body = public.readFile(p_file)
if not p_body: return True, 'Risk-free'
tmp = re.findall("\nPASS_MIN_DAYS\\s+(.+)", p_body, re.M)
if not tmp: return True, 'Risk-free'
maxdays = tmp[0].strip()
#7-14
if int(maxdays) < 7:
return False, '%s】In the file, PASS_MIN_DAYS is greater than or equal to 7' % p_file
return True, 'Risk-free'
except:
return True, 'Risk-free'

View File

@@ -0,0 +1,77 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# SSH安全检测
# -------------------------------------------------------------------
import os,sys,re,public,json
_title = 'SSH security'
_version = 1.0 # 版本
_ps = "Check whether the SSH port of the current server is safe" # 描述
_level = 1 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-04' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ssh_port.pl")
_tips = [
"Modify the SSH port on the [Security] page, and consider turning off [SSH password login] in [SSH security management], and turning on [SSH key login]",
"If SSH connection service is not required, it is recommended to disable SSH service on the [Security] page",
"Through the [System Firewall] plug-in or in the [Security Group] modify the release behavior of the SSH port to limit the IP to enhance security",
"Use [Fail2ban] plug-in to protect SSH service"
]
_help = ''
_remind = "This solution reduces the risk of a breach by changing the default SSH login port. Noteafter the fix, you'll need to change the SSH port that the relevant business logs on to. "
def check_run():
'''
@name 开始检测
@author hwliang<2022-08-18>
@return tuple (status<bool>,msg<string>)
@example
status, msg = check_run()
if status:
print('OK')
else:
print('Warning: {}'.format(msg))
'''
port = public.get_sshd_port()
version = public.readFile('/etc/redhat-release')
if not version:
version = public.readFile('/etc/issue').strip().split("\n")[0].replace('\\n','').replace(r'\l','').strip()
else:
version = version.replace('release ','').replace('Linux','').replace('(Core)','').strip()
status = public.get_sshd_status()
fail2ban_file = '/www/server/panel/plugin/fail2ban/config.json'
if os.path.exists(fail2ban_file):
try:
fail2ban_config = json.loads(public.readFile(fail2ban_file))
if 'sshd' in fail2ban_config.keys():
if fail2ban_config['sshd']['act'] == 'true':
return True,'Fail2ban is enable'
except: pass
if not status:
return True,'SSH service is not enabled'
if port != '22':
return True,'The default SSH port has been modified'
result = public.check_port_stat(int(port),public.GetLocalIp())
if result == 0:
return True,'Rick-free'
return False,'The default SSH port ({}) has not been modified, and the access IP limit configuration has not been done, there is a risk of SSH breaching'.format(port)

View File

@@ -0,0 +1,46 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 检查SSH root是否可以登录
# -------------------------------------------------------------------
import sys, os
os.chdir('/www/server/panel')
sys.path.append("class/")
import os, sys, re, public
_title = 'Check if SSH root can log in'
_version = 1.0 # 版本
_ps = "Check if SSH root can log in" # 描述
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-08-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ssh_root.pl")
_tips = [
"Add [ PermitRootLogin no ] parameter in [/etc/ssh/sshd_config]",
"PermitRootLogin no",
]
_help = ''
_remind = 'SSH remote login as root is not possible after this solution is fixed'
def check_run():
#ssh 检查root 登录
if os.path.exists('/etc/ssh/sshd_config'):
try:
info_data = public.ReadFile('/etc/ssh/sshd_config')
if info_data:
if re.search(r'PermitRootLogin\s+no', info_data):
return True, 'Risk-free'
else:
return True, 'Risk-free'
return False, 'The parameter [PermitRootLogin] in /etc/ssh/sshd_config is configured as: "yes", please set it to "no"'
except:
return True, 'Risk-free'
return True, 'Risk-free'

View File

@@ -0,0 +1,46 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# SSH密码复杂度检查
# -------------------------------------------------------------------
import sys,os
os.chdir('/www/server/panel')
sys.path.append("class/")
import os,sys,re,public
_title = 'SSH password length check'
_version = 1.0 # 版本
_ps = "SSH password length check" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-08-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_ssh_security.pl")
_tips = [
"In the [/etc/security/pwquality.conf] file, set minlen (minimum password length) to 9-32 bits",
"minlen=9",
]
_help = ''
_remind = 'This solution enforces a minimum login password length, reducing the risk of server blow-up. '
def check_run():
try:
p_file = '/etc/security/pwquality.conf'
p_body = public.readFile(p_file)
if not p_body: return True, 'Risk-free'
tmp = re.findall(r"\s*minlen\s+=\s+(.+)", p_body, re.M)
if not tmp: return True, 'Risk-free'
minlen = tmp[0].strip()
if int(minlen) < 9:
return False, 'In the [%s] file, set minlen (minimum password length) to 9-32 characters'%p_file
return True, 'Risk-free'
except:
return True, 'Risk-free'

View File

@@ -0,0 +1,32 @@
#!/usr/bin/python
#coding: utf-8
import os, re, public
_title = 'strace obtains login credentials backdoor detection'
_version = 1.0 # 版本
_ps = "Detect user information leakage via strace command during process" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-09' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_strace_backdoor.pl")
_tips = [
"The ps aux command checks whether there are sshd login credentials read through strace",
"ps aux | grep strace",
"If the process is filtered out, use the kill -9 [pid] command to stop the process"
]
_help = ''
_remind = 'detects the existence of hacker intrusion on the server, and the hacker behavior can be interrupted in time through the scheme command to prevent the server from being further invaded and controlled. '
def check_run():
'''
@name 开始检测
@return tuple (status<bool>,msg<string>)
'''
sshd_pid = public.ExecShell('ps aux|grep "sshd -D"|grep -v grep|awk {\'print$2\'}')[0].strip()
result = public.ExecShell('ps aux')[0].strip()
rep = 'strace.*' + sshd_pid + '.*trace=read,write'
tmp = re.search(rep, result)
if tmp:
return False, 'Malicious process that steals sshd login information through strace'
else:
return True, 'Risk-free'

View File

@@ -0,0 +1,36 @@
#!/usr/bin/python
# coding: utf-8
# Date 2022/1/12
import sys,os
_title = 'System backdoor user detection'
_version = 1.0 # 版本
_ps = "System backdoor user detection" # 描述
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2021-01-12' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_system_user.pl")
_tips = [
"Delete backdoor user in command line",
"Note: If there is a backdoor user, it means that your server has been invaded"
]
_help = ''
_remind = 'This scheme will remove the backdoor users with the same privileges as the root user, and enhance the protection of the server permission control. If it is a business requirement, this risk term is ignored. '
def check_run():
'''
@name 开始检测
@author lkq<2021-01-12>
@return tuple (status<bool>,msg<string>)
'''
ret=[]
cfile = '/etc/passwd'
if os.path.exists(cfile):
f=open(cfile,'r')
for i in f:
i=i.strip().split(":")
if i[2]=='0' and i[3]=='0':
if i[0]=='root':continue
ret.append(i[0])
if ret:
return False, 'There is a backdoor user: %s'%''.join(ret)
return True, 'No backdoor users are currently found'

View File

@@ -0,0 +1,24 @@
#!/usr/bin/python
# coding: utf-8
import sys, os, public
_title = 'Disable non-encrypted remote management telnet'
_version = 1.0 # 版本
_ps = "Turn off non-encrypted remote management telnet checks" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2023-03-15' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_telnet_server.pl")
_tips = [
"Use encrypted remote management sshd service as much as possible, and close unsafe telnet service",
"systemctl stop telnet.socket stop telnet service"
]
_help = ''
_remind = 'This scheme shuts down the insecure telnet service, reducing the risk of data leakage. If the business requires telnet, this risk term is ignored. '
def check_run():
result = public.ExecShell('systemctl is-active telnet.socket')[0].strip()
if 'active' == result:
return False, 'telnet service is not closed'
else:
return True, 'Risk-free'

View File

@@ -0,0 +1,45 @@
#!/usr/bin/python
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 用户缺省权限检查
# -------------------------------------------------------------------
# import sys, os
# os.chdir('/www/server/panel')
# sys.path.append("class/")
import os, sys, re, public
_title = 'User default permission check'
_version = 1.0 # 版本
_ps = "User Default Permission Check [/etc/profile]" # 描述
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2022-08-10' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_umask.pl")
_tips = [
"【/etc/profile] The umask set in the file is 002, which does not meet the requirements. It is recommended to set it to 027",
"Fix: modify umask to 027",
]
_help = ''
_remind = 'This scheme can strengthen the control of user permissions and avoid excessive user privileges. '
def check_run():
# 判断是否存在/etc/profile文件
if os.path.exists("/etc/profile"):
# 读取文件内容
profile = public.ReadFile("/etc/profile")
# 判断是否存在umask设置
if re.search("umask 0",profile):
# 判断是否设置为027
if re.search("umask 027",profile):
return True,"Risk-free"
else:
return True,"Risk-free"
# return False,"未设置umask为027"
else:
return True,"Risk-free"

View File

@@ -0,0 +1,67 @@
#!/usr/bin/python
#coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# 检测风险用户
# -------------------------------------------------------------------
import os,sys,re,public
_title = 'WAF firewall detection'
_version = 1.0 # 版本
_ps = "Detect whether a WAF firewall is installed" # 描述
_level = 1 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
_date = '2020-08-05' # 最后更新时间
_ignore = os.path.exists("data/warning/ignore/sw_waf_install.pl")
_tips = [
"It is recommended to install a WAF firewall, such as: Pagoda Nginx Firewall, Pagoda Apache Firewall, Nginx Free Firewall, etc.",
"Note: Only one type of WAF firewall can be installed. Installing too many WAF firewalls may cause your website to be abnormal and increase unnecessary server overhead"
]
_help = ''
_remind = "WAF firewall is the first line of defense to protect the server, can block external network attacks, to ensure the safe and stable operation of the website. "
def check_run():
'''
@name 开始检测
@author hwliang<2020-08-04>
@return tuple (status<bool>,msg<string>)
'''
web_list = [
'/www/server/nginx/sbin/nginx',
'/www/server/apache/bin/httpd',
'/usr/local/lsws/bin'
]
is_install_web = False
for w in web_list:
if os.path.exists(w):
is_install_web = True
break
if not is_install_web:
return True,'Risk-free'
waf_list = [
'/www/server/panel/plugin/btwaf/info.json',
'/www/server/panel/plugin/btwaf_httpd/info.json',
'/www/server/panel/plugin/free_waf/info.json',
'/usr/local/yunsuo_agent/uninstall',
'/etc/safedog',
'/usr/share/xmirror/scripts/uninstall.sh'
]
for waf in waf_list:
if os.path.exists(waf):
return True,'Risk-free'
return True,'If the WAF firewall is not installed, the server website is vulnerable to attacks and there is a security risk'