#先说好,这玩意要是能做到全覆盖全兼容,咱们等保就没活干了,根据实际情况选择合适的方法次啊是上乘啊啊啊啊啊。这个文章是记录脚本撰写过程。脚本采用python语言完成。
首先,对于我的脚本,我要设计一个酷炫的开头页面。我要打印一个酷炫的字符,就像那些酷炫的脚本一样。就叫NCC哈哈哈,没有啥意义,咱也要有自己的b格。看我画的还不错把~ ^_^
banner = r"""
======================================================================
____ == ___ == == ______ ===== _______ ======
/ \ / / ==== ` _____ / == ` _____ / ===========
/ /\ \ / / == == / / ====== / / ==========
/ / \ \/ / ====== | | == ===== | | =========
/ / \ / ===== \ `-____ ==== \ `-____ Author:NCC
`_/ `__/ === `-_____ / === `-_____ / data:2024-9-19
=====================================================================
"""
print(banner)
然后我们先把系统框架搭建出来,提示是否一键执行巡检,做一个小的操作台出来。既然是一键巡检,这里需要将问你要一下主机的账号和密码,有些操作需要超级权限才能做,这里看着权限脚本会自动给。
这里输入密码感觉需要将它匿名起来,然后要求输入两次核对一下密码感觉会好一点。可以参考下文章:[145]python实现控制台密码星号输入_python input 显示 *号-CSDN博客
可以采用getpass进行,但是再使用pycharm需要设置一下”在输出控制台中模拟终端“。解决pycharm不支持getpass.getpass及类似需要输入但不支持的问题_python getpass.getpass没反应-CSDN博客
新版的pycharm要找一下这个设置,和旧版的有点不一样。
这部分代码为:
def login():
print("请输入您主机的用户名和密码\n"'\033[91m' + "!!仅用于系统检测!!" + '\033[0m')
login_name = input('\033[92m' + "请输入用户名(无则直接回车,下同):" + '\033[0m')
login_pwd1 = getpass.getpass('\033[92m'"请输入密码:" + '\033[0m')
login_pwd2 = getpass.getpass('\033[92m'"请再输入一次密码:" + '\033[0m')
while login_pwd1 != login_pwd2:
print("刚刚两次输入的密码不相同哦")
login_pwd1 = getpass.getpass('\033[92m'"请输入密码:" + '\033[0m')
login_pwd2 = getpass.getpass('\033[92m'"请再输入一次密码:" + '\033[0m')
return login_name, login_pwd1
现在可以开始写一些测试的函数了,首先等保的第一项就是对身份进行验证。这部分需要掌握re库的使用,需要查看一些配置然后匹配嘛。需要学习re的可以去看看下面这个佬的文章。python——正则表达式(re模块)详解_python re正则-CSDN博客
回到我们等保,我们需要关注的点是主机的身份鉴别配置。比方说在这里的一项要求是:应对登录的用户进行身份标识和鉴别,身份标识具有唯一性,身份鉴别信息具有复杂度要求并定期更换。
测评要求就需要我们查看身份是否有重复的,密码是否是简单甚至是空口令。以及是否系统采用了一些身份鉴别策略。
一般会使用命令来查看登陆用户的一些信息,比如说查看影子文件,在这里你可以看到以下几个字段。
用户名:加密密码:最后一次修改时间:最小修改时间间隔:密码有效期:密码需要变更前的警告天数:密码过期后的宽限时间:账号失效时间:保留字段
Linux /etc/shadow(影子文件)内容详解_etc shadow-CSDN博客
命令:
cat /etc/shadow
这里我们能够看到用户名,以及加密后的密钥,以及他的一些账号设置。图片上面可以看到只有第一行的root当中没有*或者!的符号,其他的那些实际上是系统用户,那么他们的密码是锁定的,例如,bin
用户的密码字段显示为*
,表示这个账户可能被锁定,无法登录。
根据以上特点,于是我们编写如下脚本对代码进行处理:
account_list = []
cmd = os.popen("echo %s | sudo -S cat /etc/shadow"%(psd)).read()
user_list = re.split(r'\n', cmd)
for i in user_list:
try:
c = re.search(r'\*|!', i).group()
except:
try:
ok_user = re.findall(r'(.+?):', i)[0]
account_list.append(ok_user)
except:
pass
anonymous_account = os.popen("awk -F: 'length($2)==0 {print $1}' /etc/shadow").read()
account = '存在的账户:{0}\n空口令用户:{1}\n'.format(account_list, anonymous_account)
然后对于这里的密码弱口令问题,这里保存的密码是单向不可逆的。目前 Linux 的密码采用的是 SHA512 散列加密算法,原来采用的是 MD5 或 DES 加密算法。SHA512 散列加密算法的加密等级更高,也更加安全。在 CentOS 7 中,密码部分采用SHA-512 加密算法进行加密。CentOS 7.6 下如何查看当前用户密码的加密算法是什么?_如何查看centos是否采用sha512校验-CSDN博客
那么我们这里写一个简单口令匹配,将常用弱口令明文转换成加密密文,然后附带在脚本文件的环境目录当中。常见的弱口令字典1000~一石三鸟-CSDN博客这样就可以快速匹配了。
python中采用的加密模块是hashlib:Python hashlib库解析:数据安全加密必备指南 - 知乎 (zhihu.com)
写一个脚本转换如下:
import hashlib
# 用于存储加密后的内容
encrypted_contents = []
with open('弱口令-明文.txt', 'r') as file:
line = file.readline()
while line:
# 去除行末的换行符
clean_line = line.strip()
# 计算 SHA-256 哈希值
sha256_hash = hashlib.sha256(clean_line.encode()).hexdigest()
# 将加密后的内容添加到列表中
encrypted_contents.append(sha256_hash + '\n')
line = file.readline()
# 将加密后的内容写入新文件
with open('encrypted.txt', 'w') as output_file:
output_file.writelines(encrypted_contents)
转换后的密文截图如下:
到这然后我们写一个自动匹配算法,就可以啦!?
真的就可以了么?
少年,要是你聪明认真的话,你应该知道咱们的sha512是有加盐的步骤的
深入解析Linux系统中/etc/shadow文件密码的加密方式 (baidu.com)
然后你也会发现你看你影子文件的几个密文,他长短可能还不一样,可能还不是512位的。在下面的博文中或许你会找到答案。
Linux shadow文件中密码的加密方式 - gxy* - 博客园 (cnblogs.com)
(上面的博主的研究思路和求知精神令我崇拜,真的是大佬呜呜呜
所以嘛哈哈,对于自动化弱口令这里开一个坑嘻嘻,我先完成全部脚本。我得好好学学linux那本书了 开始发癫
那么回到我们脚本制作,对于用户身份信息还需要考虑是否具有登录失败处理功能,应配置并启用结束会话、限制非法登录次数和当登录连接超时自动退出等相关措施;
这个可以查看策略文件:
cat /etc/pam.d/system-auth
这里写一个简单的匹配:在两个文件当中查找下是否有匹配的字段。
import os
def check_parameters():
system_auth_command = "cat /etc/pam.d/system-auth"
profile_command = "cat /etc/profile"
system_auth_output = os.popen(system_auth_command).read()
profile_output = os.popen(profile_command).read()
system_auth_pattern = "auth required pam_tally2.so onerr=fail deny=[0-9]+ unlock_time=[0-9]+ even_deny_root root_unlock_time=[0-9]+"
profile_pattern = "export TMOUT=[0-9]+"
system_auth_match = False
profile_match = False
if system_auth_pattern in system_auth_output:
system_auth_match = True
if profile_pattern in profile_output:
profile_match = True
return system_auth_match, profile_match
后面是查询一下主机在远程链接的时候有没有开启一些加密服务,比方说有如下步骤:
访谈系统管理员,进行远程管理的方式。
1)以root身份登录进入Linux查看是否运行了sshd服务,service - status-all | grep sshd
查看相关的端口是否打开,netstat -an|grep 22
若未使用SSH方式进行远程管理,则查看是否使用了Telnet 方式进行远程管理
service - -status-all|grep running, 查看是否存在Telnet服务
2)可使用wireshark等抓包工具,查看协议是否为加密
3)本地化管理,N/A
2、3步骤需要使用工具,这里先写1的查询脚本。
这个地方可以直接查看使用命令:systemctl status sshd.service 查看服务状态,下面的就算是开启了
def check_remote_access():
# 检查 SSHD 服务是否运行
sshd_status = os.popen("systemctl status sshd.service").read()
sshd_running = "Active: active (running)" in sshd_status
# 检查 SSH 端口(22)是否打开
port_status = os.popen("netstat -an|grep 22").read()
port_open = len(port_status) > 0
# 检查 Telnet 服务是否运行
telnet_status = os.popen("service --status-all|grep running").read()
telnet_running = "telnet" in telnet_status
return sshd_running, port_open, telnet_running