客戶linux主機ssh存在高危漏洞,需要進行升級修復。
linux聯網后,直接命令行:
[root@gw ~]# yum update openssl -y
此命令只是小版本的升級,比如將openssl從1.0.1e-43版本升級到1.0.1e-57版本,但好多時候我們需要升級的是大版本,而不是這種小的修復。
yum remove openssl命令執行時,可以看到,非常非常多的軟件是依賴於openssl軟件。openssl是一個非常基礎的軟件。編譯安裝一個新版本的openssl覆蓋掉操作系統自帶的openssl。這就會導致那些依賴於openssl的軟件的openssl相關的功能變得不可用。
ssh命令是openssh軟件的一部分。因為上面提出的現象我們不直接升級操作系統的openssl,但是我們可以另外編譯一個openssl,放到單獨的應用目錄中,與操作系統的openssl互不影響。再基於新編譯出來的openssl,將新的openssh軟件編譯出來。 而操作系統的openssh是可以被替換的。如果你嘗試執行 yum remove openssh* 命令就可以看到,沒有其它軟件依賴於openssh。此外,openssh軟件提供了sshd服務。所以,我們只要還要配置並搭建好sshd服務,就可以替代操作系統自帶的openssh了。
接下來我們分析,如何升級openssh及其所依賴的openssl。
從openssh官網下載openssh 7.9.p1源碼包,查看里面的INSTALL文件,里面有對它的依賴關系做說明 可以依據blfs下載(http://www.linuxfromscratch.org/blfs/news.html)
openssh7.9p1下載安裝說明,可參考解壓后的install文件(http://www.linuxfromscratch.org/blfs/view/8.4/postlfs/openssh.html)
1,提前檢查必須安裝的(Zlib、libcrypto或者(LibreSSL或OpenSSL))
- Zlib 1.1.4或1.2.1.2或更高版本(早期1.2.x版本有問題) http://www.gzip.org/zlib/
- libcrypto(LibreSSL或OpenSSL> = 1.0.1 <1.1.0),這個庫可以用LibreSSL或OpenSSL替代,但應該將LibreSSL / OpenSSL編譯為與位置無關的庫(即使用-fPIC)
否則OpenSSH將無法與之鏈接。如果您必須使用非位置無關的libcrypto,那么您可能需要配置OpenSSH - without-pie。 請注意,由於API更改,目前不支持OpenSSL 1.1.x.
LibreSSL http://www.libressl.org/;
OpenSSL http://www.openssl.org/
2,還有一些是可選的安裝,例如PAM軟件等
1. Prerequisites ---------------- A C compiler. Any C89 or better compiler should work. Where supported, configure will attempt to enable the compiler's run-time integrity checking options. Some notes about specific compilers: - clang: -ftrapv and -sanitize=integer require the compiler-rt runtime (CC=clang LDFLAGS=--rtlib=compiler-rt ./configure) You will need working installations of Zlib and libcrypto (LibreSSL / OpenSSL) Zlib 1.1.4 or 1.2.1.2 or greater (earlier 1.2.x versions have problems): http://www.gzip.org/zlib/ libcrypto (LibreSSL or OpenSSL >= 1.0.1 < 1.1.0) LibreSSL http://www.libressl.org/ ; or OpenSSL http://www.openssl.org/ LibreSSL/OpenSSL should be compiled as a position-independent library (i.e. with -fPIC) otherwise OpenSSH will not be able to link with it. If you must use a non-position-independent libcrypto, then you may need to configure OpenSSH --without-pie. Note that because of API changes, OpenSSL 1.1.x is not currently supported. The remaining items are optional. NB. If you operating system supports /dev/random, you should configure libcrypto (LibreSSL/OpenSSL) to use it. OpenSSH relies on libcrypto's direct support of /dev/random, or failing that, either prngd or egd PRNGD: If your system lacks kernel-based random collection, the use of Lutz Jaenicke's PRNGd is recommended. http://prngd.sourceforge.net/ EGD: If the kernel lacks /dev/random the Entropy Gathering Daemon (EGD) is supported only if libcrypto supports it. http://egd.sourceforge.net/ PAM: OpenSSH can utilise Pluggable Authentication Modules (PAM) if your system supports it. PAM is standard most Linux distributions, Solaris, HP-UX 11, AIX >= 5.2, FreeBSD and NetBSD. Information about the various PAM implementations are available: Solaris PAM: http://www.sun.com/software/solaris/pam/ Linux PAM: http://www.kernel.org/pub/linux/libs/pam/ OpenPAM: http://www.openpam.org/ If you wish to build the GNOME passphrase requester, you will need the GNOME libraries and headers. GNOME: http://www.gnome.org/ Alternatively, Jim Knoble <jmknoble@pobox.com> has written an excellent X11 passphrase requester. This is maintained separately at: http://www.jmknoble.net/software/x11-ssh-askpass/ LibEdit: sftp supports command-line editing via NetBSD's libedit. If your platform has it available natively you can use that, alternatively you might try these multi-platform ports: http://www.thrysoee.dk/editline/ http://sourceforge.net/projects/libedit/ LDNS: LDNS is a DNS BSD-licensed resolver library which supports DNSSEC. http://nlnetlabs.nl/projects/ldns/ Autoconf: If you modify configure.ac or configure doesn't exist (eg if you checked the code out of git yourself) then you will need autoconf-2.69 to rebuild the automatically generated files by running "autoreconf". Earlier versions may also work but this is not guaranteed. http://www.gnu.org/software/autoconf/ Basic Security Module (BSM): Native BSM support is known to exist in Solaris from at least 2.5.1, FreeBSD 6.1 and OS X. Alternatively, you may use the OpenBSM implementation (http://www.openbsm.org). makedepend: https://www.x.org/archive/individual/util/ If you are making significant changes to the code you may need to rebuild the dependency (.depend) file using "make depend", which requires the "makedepend" tool from the X11 distribution.
安裝Zlib
Zlib用於壓縮和解壓縮的功能。操作系統已經自帶了zlib,可以查看是否符合要求。實際上,openssl和openssh都依賴於zlib。執行下面的命令,安裝zlib開發包:
rpm -qa|grep zlib
yum -y install zlib-devel
安裝PAM
PAM(Pluggable Authentication Modules,可插拔認證模塊)用於提供安全控制。操作系統也已經自帶了PAM,版本也是可以的。執行下面的命令,安裝PAM開發包:
rpm -qa|grep pam yum -y install pam-devel
安裝tcp_wrappers
tcp_wrappers是一種安全工具,通常,我們在/etc/hosts.allow或/etc/hosts.deny文件中配置的過濾規則就是使用的tcp_wrappers的功能了。openssh在編譯時的確是可以選擇支持tcp_wrappers的。執行下面的命令,安裝tcp_wrappers開發包:
rpm -qa|grep tcp_wrappers yum install tcp_wrappers-devel -y
系統最小化安裝時,需要安裝包
一般出現這個-bash: make: command not found提示,是因為安裝系統的時候使用的是最小化mini安裝,系統沒有安裝make、vim等常用命令,直接yum安裝下即可。 yum -y install gcc automake autoconf libtool make
安裝OpenSSL
由於OpenSSH 7.9p1要求OpenSSL的版本> = 1.0.1 <1.1.0,因此,當前符合要求的最新OpenSSL版本為1.0.2l https://www.openssl.org/source/old/1.0.2/。
首先,從openssl官網下載源碼包openssl-fips-2.0.16.tar.gz(https://www.openssl.org/source/old/fips/)將其安裝到/opt/fips-2.0目錄下。
編譯安裝FIPS宏(https://bbs.csdn.net/wap/topics/390830236):
mkdir /opt/fips-2.0
# export FIPSDIR=/opt/fips-2.0 --指定另外的安裝目錄,默認會安裝在/usr/local/ssl/fips2.0目錄 # tar -xvf openssl-fips-2.0.16.tar.gz # cd openssl-fips-2.0.16 # ./config # make # make install
從openssl官網下載源碼包openssl-1.0.2l.tar.gz,將其安裝到/opt/openssl1.0.2l_2019目錄下。將openssl安裝到專門的目錄,這是為了避免對操作系統自帶的openssl造成影響。
編譯安裝OpenSSL
mkdir /opt/openssl1.0.2l_2019
# tar -xvf openssl-1.0.2l.tar.gz # cd openssl-1.0.2l # ./config --prefix=/opt/openssl1.0.2l_2019 --openssldir=/opt/openssl1.0.2l_2019/openssl fips --with-fipsdir=/opt/fips-2.0 zlib-dynamic shared -fPIC # make depend # make # make test # make install
-
--prefix:指定openssl的安裝目錄。按本例中的安裝方式,安裝完成后該目錄下會包含bin(含二進制程序)、lib(含動態庫文件)、include/openssl(含報頭文件)及openssl(--openssldir選項指定的)這些子目錄。
-
--openssldir:指定openssl文件的安裝目錄。按本例中的安裝方式,安裝完成后該目錄下會包括certs(存放證書文件)、man(存放man文件)、misc(存放各種腳本)、private(存放私鑰文件)這些子目錄及openssl.cnf配置文件。
-
fips:集成FIPS模塊。
-
--with-fipsdir:指向FIPS模塊的安裝目錄位置。
-
zlib-dynamic:編譯支持zlib壓縮/解壓縮,讓openssl加載zlib動態庫。該選項只在支持加載動態庫的操作系統上才支持。這是默認選項。
-
shared:除了靜態庫以外,讓openssl(在支持的平台上)也編譯生成openssl動態庫。
-
-fPIC:將openssl動態庫編譯成位置無關(position-independent)的代碼。
安裝完成后,將OpenSSL的庫文件目錄添加到/etc/ld.so.conf文件中,並加載到系統內存緩存中:
# echo '/opt/openssl1.0.2l_2019/lib' >> /etc/ld.so.conf # ldconfig
安裝OpenSSH
從openssl官網下載源碼包openssh-7.9p1.tar.gz,將其安裝到/opt/openssh7.9.p1_2019目錄下。將openssh安裝到專門的目錄,這是為了避免與操作系統自帶的openssh造成不必要的沖突。
編譯安裝OpenSSH:
mkdir /opt/openssh7.9.p1_2019
# tar -xvf openssh-7.9p1.tar.gz # cd openssh-7.9p1 # ./configure --prefix=/opt/openssh7.9.p1_2019 --with-ssl-dir=/opt/openssl1.0.2l_2019 --with-pam --with-tcp-wrappers # make # make install
-
--prefix:指定安裝目錄
-
--with-ssl-dir=DIR:指向LibreSSL/OpenSSL庫的安裝目錄的所在路徑。
-
--with-pam:啟用PAM支持。根據OpenSSH的安裝說明,如果在編譯時啟用了PAM,那么在安裝完成后,也必須在sshd服務的配置文件sshd_config中啟用它(使用UsePAM指令)。
根據OpenSSH的安裝說明,如果有啟用PAM,那么就需要手工安裝一個給sshd程序使用的PAM配置文件,否則安裝好OpenSSH后你可能會無法使用密碼登錄系統。在編譯時,我使用 --with-pam 選項啟用了對PAM的支持,但是,編譯OpenSSH時並沒有編譯選項讓你指定PAM配置文件的位置,那么我們要怎么提供這個配置文件呢?
事實上,OpenSSH有另外一個編譯選項--with-pam-service=name可以指定PAM服務名,它的默認值是sshd。而操作系統自帶的PAM軟件默認將所有PAM配置文件都放置在/etc/pam.d目錄下。結合這兩個信息,就可確定OpenSSH的PAM配置文件應為/etc/pam.d/sshd文件。而這個文件原來就有了,所以我們不用額外手工創建一個。
設置PATH路徑:
# echo 'export PATH=/opt/openssh7.9.p1_2019/bin:/opt/openssh7.9.p1_2019/sbin:$PATH' >> /etc/profile.d/path.sh # . /etc/profile.d/path.sh
此時,使用ssh -V命令就可以看到新版本號了
ssh -V
配置OpenSSH
前面已經安裝好了openssh,但是我們還需要配置它,以保證sshd服務可以啟起來。我們可以先看一下原有的sshd服務(屬於openssh-server軟件包)都有哪些配置文件:
# rpm -ql openssh-server | grep -i --color etc /etc/pam.d/ssh-keycat /etc/pam.d/sshd /etc/rc.d/init.d/sshd /etc/ssh/sshd_config /etc/sysconfig/sshd
可以看到,sshd服務的配置文件為/etc/ssh/sshd_config,它的pam配置文件為/etc/pam.d/sshd和/etc/pam.d/ssh-keycat,啟動腳本文件為/etc/rc.d/init.d/sshd,啟動腳本里面有引用到文件/etc/sysconfig/sshd。
參照系統原有的配置文件修改我們軟件的sshd_config配置文件,這是sshd服務的配置文件(紅色字體的為新增或修改的部分):
# vim /opt/openssh7.9.p1_2019/etc/sshd_config Protocol 2 SyslogFacility AUTHPRIV PermitRootLogin yes AuthorizedKeysFile .ssh/authorized_keys PasswordAuthentication yes ChallengeResponseAuthentication no #GSSAPIAuthentication yes //該選項目前還不支持 #GSSAPICleanupCredentials yes //該選項目前還不支持 UsePAM yes AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE AcceptEnv XMODIFIERS X11Forwarding yes Subsystem sftp /opt/openssh7.9.p1_2019/libexec/sftp-server
注意,UsePAM一定要啟用,OpenSSH的安裝說明里有提到,如果編譯時啟用了PAM支持,那么就必須在sshd_config文件中啟用它。
拷貝系統原有的配置文件/etc/sysconfig/sshd到我們軟件下面,這個配置文件用於設置啟動sshd服務所需的環境變量,在sshd服務的啟動腳本里有調用到該配置文件:
# cp -a /etc/sysconfig/sshd /opt/openssh7.9.p1_2019/etc/sshd
接下來要修改sshd服務的啟動腳本/etc/rc.d/init.d/sshd。先將啟動腳本備份一份為sshd.old,並添加至chkconfig管理:
# cp /etc/rc.d/init.d/sshd /etc/rc.d/init.d/sshd.old # chkconfig --add sshd.old
再根據我們的OpenSSH的安裝路徑,來修改原有的啟動腳本(紅色字體為有新增或修改的部分-注:linux7之后沒有這個文件,可以自己新建一個啟動文件,手動添加這個服務,開機自啟動等啟動sshd):
修改配置文件權限 chmod u+x /etc/rc.d/init.d/sshdnew 添加sshd服務 chkconfig --add sshdnew
設置開機自啟動
chkconfig sshdnew on 驗證開機啟動 chkconfig --list|grep sshdnew service sshdnew start systemctl is-active sshdnew
vim /etc/rc.d/init.d/sshd #!/bin/bash # # sshd Start up the OpenSSH server daemon # # chkconfig: 2345 55 25 # description: SSH is a protocol for secure remote shell access. \ # This service starts up the OpenSSH server daemon. # # processname: sshd # config: /etc/ssh/ssh_host_key # config: /etc/ssh/ssh_host_key.pub # config: /etc/ssh/ssh_random_seed # config: /etc/ssh/sshd_config # pidfile: /var/run/sshd.pid ### BEGIN INIT INFO # Provides: sshd # Required-Start: $local_fs $network $syslog # Required-Stop: $local_fs $syslog # Should-Start: $syslog # Should-Stop: $network $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start up the OpenSSH server daemon # Description: SSH is a protocol for secure remote shell access. # This service starts up the OpenSSH server daemon. ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # pull in sysconfig settings [ -f /opt/openssh7.9.p1_2019/etc/sshd ] && . /opt/openssh7.9.p1_2019/etc/sshd RETVAL=0 prog="sshd" lockfile=/var/lock/subsys/$prog # Some functions to make the below more readable KEYGEN=/opt/openssh7.9.p1_2019/bin/ssh-keygen SSHD=/opt/openssh7.9.p1_2019/sbin/sshd RSA1_KEY=/etc/ssh/ssh_host_key RSA_KEY=/opt/openssh7.9.p1_2019/etc/ssh_host_rsa_key DSA_KEY=/opt/openssh7.9.p1_2019/etc/ssh_host_dsa_key PID_FILE=/var/run/sshd.pid # PID文件的所在路徑,這個變量的值不要改 runlevel=$(set -- $(runlevel); eval "echo \$$#" ) fips_enabled() { if [ -r /proc/sys/crypto/fips_enabled ]; then cat /proc/sys/crypto/fips_enabled else echo 0 fi } do_rsa1_keygen() { if [ ! -s $RSA1_KEY -a `fips_enabled` -eq 0 ]; then echo -n $"Generating SSH1 RSA host key: " rm -f $RSA1_KEY if test ! -f $RSA1_KEY && $KEYGEN -q -t rsa1 -f $RSA1_KEY -C '' -N '' >&/dev/null; then chmod 600 $RSA1_KEY chmod 644 $RSA1_KEY.pub if [ -x /sbin/restorecon ]; then /sbin/restorecon $RSA1_KEY.pub fi success $"RSA1 key generation" echo else failure $"RSA1 key generation" echo exit 1 fi fi } do_rsa_keygen() { if [ ! -s $RSA_KEY ]; then echo -n $"Generating SSH2 RSA host key: " rm -f $RSA_KEY if test ! -f $RSA_KEY && $KEYGEN -q -t rsa -f $RSA_KEY -C '' -N '' >&/dev/null; then chmod 600 $RSA_KEY chmod 644 $RSA_KEY.pub if [ -x /sbin/restorecon ]; then /sbin/restorecon $RSA_KEY.pub fi success $"RSA key generation" echo else failure $"RSA key generation" echo exit 1 fi fi } do_dsa_keygen() { if [ ! -s $DSA_KEY ]; then echo -n $"Generating SSH2 DSA host key: " rm -f $DSA_KEY if test ! -f $DSA_KEY && $KEYGEN -q -t dsa -f $DSA_KEY -C '' -N '' >&/dev/null; then chmod 600 $DSA_KEY chmod 644 $DSA_KEY.pub if [ -x /sbin/restorecon ]; then /sbin/restorecon $DSA_KEY.pub fi success $"DSA key generation" echo else failure $"DSA key generation" echo exit 1 fi fi } do_restart_sanity_check() { $SSHD -t RETVAL=$? if [ $RETVAL -ne 0 ]; then failure $"Configuration file or keys are invalid" echo fi } start() { [ -x $SSHD ] || exit 5 [ -f /opt/openssh7.9.p1_2019/etc/sshd_config ] || exit 6 # Create keys if necessary if [ "x${AUTOCREATE_SERVER_KEYS}" != xNO ]; then # do_rsa1_keygen # 注釋掉這條語句 do_rsa_keygen do_dsa_keygen fi echo -n $"Starting $prog: " $SSHD $OPTIONS && success || failure RETVAL=$? [ $RETVAL -eq 0 ] && touch $lockfile echo return $RETVAL } stop() { echo -n $"Stopping $prog: " killproc -p $PID_FILE $SSHD RETVAL=$? # if we are in halt or reboot runlevel kill all running sessions # so the TCP connections are closed cleanly if [ "x$runlevel" = x0 -o "x$runlevel" = x6 ] ; then trap '' TERM killall $prog 2>/dev/null trap TERM fi [ $RETVAL -eq 0 ] && rm -f $lockfile echo } reload() { echo -n $"Reloading $prog: " killproc -p $PID_FILE $SSHD -HUP RETVAL=$? echo } restart() { stop start } force_reload() { restart } rh_status() { status -p $PID_FILE openssh-daemon } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 start ;; stop) if ! rh_status_q; then rm -f $lockfile exit 0 fi stop ;; restart) restart ;; reload) rh_status_q || exit 7 reload ;; force-reload) force_reload ;; condrestart|try-restart) rh_status_q || exit 0 if [ -f $lockfile ] ; then do_restart_sanity_check if [ $RETVAL -eq 0 ] ; then stop # avoid race sleep 3 start else RETVAL=6 fi fi ;; status) rh_status RETVAL=$? if [ $RETVAL -eq 3 -a -f $lockfile ] ; then RETVAL=2 fi ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" RETVAL=2 esac exit $RETVAL
root輸入密碼登錄拒絕不成功可以:
在$SSHD $OPTIONS && success || failure這句話前面加一句: OPTIONS="-f /etc/ssh/sshd_config" 配置如下: echo -n $"Starting $prog:" OPTIONS="-f /opt/ssh7.9/etc/sshd_config" --同上目錄/opt/openssh7.9.p1_2019/etc/sshd_config
$SSHD $OPTIONS && success || failure RETVAL=$?
由於OpenSSH依賴的OpenSSL已不支持rsa1,所以我將啟動腳本中生成rsa1秘鑰的指令注釋掉了。
接下來,關鍵的一步來了,我們要關閉舊的sshd服務,啟動新的sshd服務。這個操作如果失敗了,不會導致現有的ssh遠程連接斷開。所以我們可以先關閉舊的sshd程序,再啟動新的sshd程序:
# service sshd.old stop
# service sshd start
如果新的sshd服務啟動成功了,我們可以先簡單測試下,比如,看看普通用戶和root用戶是否能正常通過ssh登錄。如果沒有沒有問題,我們可以在測測其它的,比如scp、sftp是否正常等。當然,如果有條件的話,可以使用漏洞掃描工具掃一下,看看有沒有什么我們沒有注意到的地方。
最后,就可以刪除掉舊sshd服務的啟動腳本了,以免沖突:
# rm -f /etc/init.d/sshd.old
openssl和openssh的編譯選項基本來說我也只是使用了必要的選項,我們編譯出來的openssl和openssh軟件在功能特性上只是盡可能地接近原有的,安全性和性能可能也是有差異。
復用了操作系統原有的sshd服務的配置文件和啟動腳本,這可能無法充分利用新版本openssh的特性。openssl和openssh本來也是挺復雜的東西,一時半會可能也很難完全弄明白。
這種升級方式,應該會比強制升級openssl和openssh的方式好很多。
參考https://blog.51cto.com/techsnail/2138927,獨指蝸牛 只做日常積累,不做商業用途,侵權即刪。