系统漏洞修复:升级OpenSSH+OpenSSL

  • ​​一、背景​​
  • ​​二、系统及版本说明​​
  • ​​三、升级OpenSSL​​
  • ​​四、升级OpenSSH​​
  • ​​五、结束语​​

一、背景

公司生产环境上线,所有服务器上线前,都要经过系统安全检测。这个过程中发现很多系统安全问题是由于OpenSSH和OpenSSL版本太低导致的。在负责漏洞修复的过程中,遇到了很多坑,这里将升级OpenSSH和OpenSSL的步骤和遇到的问题进行一下总结分享下,希望对大家有所帮助

二、系统及版本说明

操作系统:CentOS6.5,CentOS7.3,CentOS7.0
OpenSSH升级版本:openssh-7.9p1
OpenSSL升级版本:openssl-1.1.1a

三、升级OpenSSL

  1. yum -y install gcc-c++ //首先安装gcc-c++,不然通过./config编译时会报错,同时避免rpm -e卸载openssl导致yum命令不可用
  2. openssl version //查看版本
  3. rpm -qa | grep openssl //查看rpm包安装的openssl
    \千万不要执行这个卸载命令,会删除 /usr/lib64/libssl.so.10和/usr/lib64/libcrypto.so.10,导致yum命令和ping不能用,ssh连接也会直接失败。影响非常严重
    ## 4、 rpm -e ​​rpm -qa | grep openssl​​ --nodeps //卸载通过rpm包安装的openssl
  4. cd /usr/local/src //进入源文件目录
  5. rz //通过rz命令上传下载好的openssl-1.1.1a.tar.gz包
  6. tar -zxvf openssl-1.1.1a.tar.gz //解压
  7. cd openssl-1.1.1a
  8. 编译安装
    ./config --prefix=/usr --shared && make && make install
  9. 添加软链接
    ln -s /usr/lib64/libcrypto.so.1.0.0 /usr/lib64/libcrypto.so.10
    ln -s /usr/lib64/libssl.so.1.0.0 /usr/lib64/libssl.so.10

如果执行了 rpm -e rpm -qa | grep openssl --nodeps 命令,则一定要重建软链接。
但是一定要先进入/usr/lib64目录里面查看libcrypto.so.1和libssl.so.1.是什么版本的
,我在新机器安装中,里面是libssl.so.1.0.2k,如果直接使用上面的语句创建链接,就会创建无效的链接,yum命令还是不能用。

  1. 版本检测
    openssl version

问题记录:
问题一、libcrypto.so.10: cannot open shared object file: No such file or directory

[root@localhost kibana]# openssl version
/usr/libexec/pk-command-not-found: error while loading shared libraries: libcrypto.so.10: cannot open shared object file: No such file or directory

解决:
执行添加软链接操作
ln -s /usr/lib64/libcrypto.so.1.0.0 /usr/lib64/libcrypto.so.10
ln -s /usr/lib64/libssl.so.1.0.0 /usr/lib64/libssl.so.10

问题二、openssl命令不能识别

[root@localhost openssl-1.1.1a]# openssl version
-bash: openssl: command not found

分析原因:
命令无效,一般是软件的/bin目录没有追加入到环境变量的path下的路径后面,或者程序安装时可执行文件没有加入到/usr/bin/目录下。
通过以下命令全局搜索openssl文件:
find / -name openssl
确实没有在/usr/bin下发现可执行的openssl文件,所以openssl命令无法执行。
产生原因,是自己通过源码编译安装最新的openssl时,没有先通过rpm -e ​​​rpm -qa | grep openssl​​​ --nodeps卸载老版本rpm安装的openssl。之后检测出漏洞后,只是直接使用了​​rpm -qa | grep openssl​​​ --nodeps卸载老版本,
导致/usr/bin/目录下的openssl文件也被删除。
修复办法:

cd openssl-1.1.1a
make && make install
openssl version

如果发现openssl命令还是无法识别,那么就直接删除openssl-1.1.1a文件夹重新编译安装。这里要注意,通过源码编译安装的程序,要先使用make uninstall卸载程序

操作命令如下:

cd openssl-1.1.1a
make uninstall
cd ..
rm -fr openssl-1.1.1a
tar -zxvf openssl-1.1.1a.tar.gz
cd openssl-1.1.1a
./config --prefix=/usr --shared && make && make install
ln -s /usr/lib64/libcrypto.so.1.0.0 /usr/lib64/libcrypto.so.10
ln -s /usr/lib64/libssl.so.1.0.0 /usr/lib64/libssl.so.10
openssl version -a

四、升级OpenSSH

这部分的操作非常非常重要,一定要非常小心。因为OpenSSH控制着服务器的远程登录连接。稍有不慎,就会造成远程连接失败。笔者就在升级腾讯云服务器上的OpenSSH时,由于操作失误,导致SSH连接不上,最后不得不一键重装系统,这是非常惨痛的教学。
这里给大家一点忠告:网上的博客教程一定要先在测试机上实践,注意系统版本和软件版本的一致性,稍有不同就可能产生不一样的结果,所以一定要谨慎,不然那坑可能你伤不起。
下面进入正题:

  1. 环境检查

官方给出的文档中提到的先决条件openssh安装依赖zlib1.1.4并且openssl>=1.0.1版本就可以了。

[root@zabbix-serv ~]# openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013
[root@zabbix-serv ~]# rpm -q zlib
zlib-1.2.3-29.el6.x86_64
[root@zabbix-serv ~]# rpm -q zlib-devel
zlib-devel-1.2.3-29.el6.x86_64
[root@zabbix-serv ~]#ssh -V //查看ssh的版本
  1. 安装依赖包
yum install -y gcc openssh-clients openssl-devel pam-devel rpm-build pam-devel
  1. 备份ssh配置文件
#####cp -r /etc/ssh/ /home/ssh-bak

这一步非常非常重要,这个目录下的信息控制着ssh连接的秘钥和配置信息。

网上很多备份的做法使用的是移动命令

mv /etc/ssh/ /home/ssh-bak    //推荐        (##############推荐####################)

而我这里为什么使用复制命令,而不是移动命令呢?
我们在编译安装openssh的时候,执行make && make install命令的时候,系统会自动去检查/etc/ssh/目录下的文件,如果文件存在,是不会生产新文件覆盖原来的配置文件和秘钥的。
如果这里使用了移动命令,就会在/etc/ssh/生成新的内容。
当然,你也可以先使用移动命令,安装完openssl后,再删除/etc/ssh/里面的所有内容,然后将mv命令备份的文件全部移动回来。本质是保证配置文件和秘钥和原来保持一致。
这一步是升级OpenSSH后,ssh远程连接能正常进行的重要前提。

吃到了苦头,如果不用编译安装sshd新生成的sshd_config的配置文件,很容易出现配置项不兼容的情况。导致ssh连接失败。
所以,这里推荐使用mv /etc/ssh/ /home/ssh-bak 备份。

  1. 卸载老的OpenSSH
rpm -qa | grep openssh
rpm -e `rpm -qa | grep openssh` --nodeps
//下面是执行卸载操作的提升信息
warning: /etc/ssh/ssh_config saved as /etc/ssh/ssh_config.rpmsave
warning: /etc/ssh/moduli saved as /etc/ssh/moduli.rpmsave

注意:
(1)命令执行过程中的提示信息一定不要忽视,上面执行卸载命令时,提示信息很明显,告诉我们将原来的ssh_config配置文件保存到了ssh_config.rpmsave文件中,将原来的moduli保存到了moduli.rpmsave文件中。
(2)由于升级ssh过程中,很容易出现一些奇葩问题导致ssh连接断开,建议操作过程中先多开2,3个连接,防止出现意外。

  1. 解压、编译、安装
cd /usr/local/src/ && tar zxvf openssh-7.9p1.tar.gz &&  cd openssh-7.9p1
./configure --prefix=/usr --sysconfdir=/etc/ssh --with-pam --with-zlib --with-md5-passwords --with-tcp-wrappers && make && make install

在执行make install命令时,出现了如下提示,正如前面所说,升级过程中,如果/etc/ssh/已经存在的配置文件,是不会被覆盖的。

/etc/ssh/ssh_config already exists, install will not overwrite
/etc/ssh/sshd_config already exists, install will not overwrite
/etc/ssh/moduli already exists, install will not overwrite
  1. 修改配置
    根据步骤4卸载操作中的提示,将原来的配置文件还原即可。
mv  /etc/ssh/ssh_config   /etc/ssh/ssh_config.back
mv /etc/ssh/ssh_config.rpmsave /etc/ssh/ssh_config
mv /etc/ssh/moduli /etc/ssh/ssh_config.back
mv /etc/ssh/moduli.rpmsave /etc/ssh/moduli

网上很多教程说要对/etc/ssh/sshd_config配置文件进行修改,这里是升级操作,尽可能保证配置文件的原生性就好。
这里简单介绍下里面的一些核心配置项:
PermitRootLogin yes //允许root用户远程登录
PermitEmptyPasswords no //不允许使用空密码远程登录

如果执行了mv /etc/ssh/ /home/ssh-bak操作,那么这里一定修改新生成的sshd_config里面的PermitRootLogin yes 属性。

  1. 关闭selinux
    vi etc/selinux/config
SELINUX=disabled

使用这种方式对selinux关闭,要重启服务器才能生效。
这里由于ssh配置没有完成,显然是不适合做重启服务器操作的。
可以先通过命令临时关闭selinux
setenforce 0
getenforce

这里对selinux的安全级别进行下说明:
目前 SELinux 支持三种模式,分别如下:
•enforcing:强制模式,代表 SELinux 运作中,且已经正确的开始限制 domain/type 了;
•permissive:宽容模式:代表 SELinux 运作中,不过仅会有警告讯息并不会实际限制 domain/type 的存取。这种模式可以运来作为 SELinux 的 debug 之用;
•disabled:关闭,SELinux 并没有实际运作。
【问题】通过上面的学习我们知道,如果将启动着的SELinux改为禁用,需要重启电脑,我们不想重启电脑又不想开启SELinux该怎么办呢?
【答案】将强制模式改为宽松模!
[root@www ~]# setenforce [0|1]
选项与参数:
0 :转成 permissive 宽容模式;
1 :转成 Enforcing 强制模式

范例一:将 SELinux 在 Enforcing 与 permissive 之间切换与查看
[root@www ~]# setenforce 0
[root@www ~]# getenforce Permissive
[root@www ~]# setenforce 1
[root@www ~]# getenforce Enforcing

  1. 服务自启配置
cp contrib/redhat/sshd.init /etc/init.d/sshd
chkconfig --add sshd
chkconfig sshd on
service sshd start
service sshd restart
chkconfig --list sshd
ssh -V
  1. 检查root用户远程ssh登录是否正常

如果能正常登陆,说明我们的升级操作成功了。

问题记录:
问题一、执行configure编译时,出现OpenSSL headers missing……

configure: error: *** OpenSSL headers missing - please install first or check config.log ***

解决:
该问题是由于没有安装openssl-devel
yum install -y openssl-devel
yum install -y openssh-clients

如果安装失败,可以尝试如下命令使用rpm包安装:

cd /media/RHEL-7.0\ Server.x86_64/Packages/
rpm -ivh --nodeps libsepol-devel-2.1.9-3.el7.x86_64.rpm
rpm -ivh --nodeps openssl-devel-1.0.1e-34.el7.x86_64.rpm
rpm -ivh --nodeps zlib-devel-1.2.7-13.el7.x86_64.rpm

需要安装系统的时候将ios中rpm的镜像文件保存在本机的media目录下。

问题二、 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED
解决:
这个问题虽然只是通过ssh远程连接的一个警告问题,但是如果不解决,是无法进行远程连接的。
问题的本质是升级OpenSSH的过程中,删除了服务器/etc/ssh/目录下的秘钥。重新生成的秘钥和正在进行远程连接的服务器在初次ssh连接目标服务器记录的hostname信息匹配不上,导致识别不了。
打个比方,服务器A初次通过ssh登录到服务器B,这时会和服务器B下的秘钥文件进行一些认证,通过后,会在服务器A下的~/.ssh/known_hosts文件下记录服务器B的ip以及对应加密后的hostname信息。
现在服务器B中的秘钥变化了,那么服务A在~/.ssh/known_hosts文件下记录的服务器B的hostname信息显然是错误的了。
解决:
vi ~/.ssh/known_hosts
然后删除掉服务器B对应的那行信息。

这样服务器A再次进行SSH登录服务器B时,相当于初次认证,通过后,会在服务器A的~/.ssh/known_hosts文件中,生成新的服务器B的ip和加密后的hostname信息。

不过显然,这不是非常优雅的做法,升级过程,尽量不要造成其他的影响,保证/etc/ssh/下配置文件和秘钥的原生性

问题三、linux版本差异导致安装过程中产生的问题
在CentOS Linux release 7.3.1611 (Core) 下升级OpenSSH时,
编译通过后,执行安装时
make && make install
出现如果警告信息:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0640 for '/etc/ssh/ssh_host_ecdsa_key' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Error loading host key "/etc/ssh/ssh_host_ecdsa_key": bad permissions
Could not load host key: /etc/ssh/ssh_host_ecdsa_key
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0640 for '/etc/ssh/ssh_host_ed25519_key' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Error loading host key "/etc/ssh/ssh_host_ed25519_key": bad permissions
Could not load host key: /etc/ssh/ssh_host_ed25519_key
[root@localhost openssh-7.9p1]# cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)
[root@localhost openssh-7.9p1]# ssh -V
OpenSSH_7.9p1, OpenSSL 1.1.1a 20 Nov 2018

简单的来说,
由于备份过程中,采用了mv命令,导致/etc/ssh/目录下的秘钥都重新生成。但是生成的秘钥权限太高,导致私有秘钥被忽略。

解决:
如果编译过程没有注意查看警告信息,
可以在ssh连接失败后,通过systemctl status sshd 命令,查看目标服务器ssh连接失败的原因。
发现是秘钥权限的原因,那么我们直接根据提示修改秘钥的权限就OK了。

#秘钥读写权限修改,如果没有mv  /etc/ssh目录的内容,不会覆盖原始内容,可以不用执行
cd /etc/ssh
ll //查看文件权限
chmod 600 ssh_host_*

五、结束语

  1. 在linux下进行程序安装时,一定要注意提示语,特别是警告部分信息。
  2. 出现错误,一定要学会找日志分析问题,大部分异常,都能通过分析错误日志信息找到解决的方向。
  3. 软件升级时,一定要进行配置文件的备份,防止出现意外。
  4. 安装程序时,不要在原生的配置文件上进行修改,先对原始配置文件复制备份
    cp source.conf source.conf.default

后续补充,在之后的新机器的部署上,还是出现了问题。

主要集中在一下几个方面:
1、执行了rpm -e ​​​rpm -qa | grep openssh​​​ --nodeps卸载命令,导致yum命令不可用,影响非常严重
这里注意,一定要事先多开几个链接,以防一个连接断开后,还可以使用其他连接去拯救一下。

2、没有删除/etc/ssh里面的所有文件,而新编译安装ssh生成的sshd_config文件不会覆盖老的文件,而老文件中,默认开启的几项认证在新的ssh版本中,不支持或已经废弃,导致出现了问题。
3、忘了修改/etc/ssh下的秘钥的读写权限。
4、忘了关闭防火墙
5、出现登录不上的情况,一定要使用/var/log/message查看日志分析原因。

最后,写文不易,如果觉得我写的文章对你有些许帮助,请帮忙点赞,评论,在此不胜感激。