一、 背景

安全部门扫描发现,某业务主机存在以下漏洞:

nginx 安全漏洞(CVE-2019-9511)
nginx 安全漏洞(CVE-2019-9513)
nginx 安全漏洞(CVE-2019-9516)
受影响版本:Nginx 1.9.51 至 16.0版本及1.17.2.

按照建议升级到:Nginx 1.16.1,下载地址:https://nginx.org/download/nginx-1.16.1.tar.gz

nginx 目录穿越漏洞 nginx1.16.1漏洞_Nginx

二、升级过程

2.1、前要

Nginx 在启动后,会有一个 master 进程和多个 worker 进程。

master进程:接受外界的信号,向worker 发送信号,监控 worker 进程的运行状态,当 worker 进程退出后 (异常情况下),会自动重新启动新的 worker 进程

worker进程:接受客户端的请求,将请求一次送入各个功能模块进行过滤处理,与后端服务器通信,接收后端服务器处理结果,数据缓存 proxy_cache 模块,响应客户端请求

多个 worker 进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个 worker 进程中处理,一个 worker 进程,不可能处理其它进程的请求。

2.2、升级过程

1、登录云主机rz上述安装包到系统内,然后解压
2、备份旧版本的nginx的执行程序;
3、进入新版本源码包目录,编译处理(因业务需要https)

./configure --user=nginx --group=nginx --prefix=/usr/local/nginx/ --with-http_v2_module --with-http_ssl_module --with-http_sub_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-http_realip_module

nginx 目录穿越漏洞 nginx1.16.1漏洞_nginx_02


由上图可知nginx的目录后不应写/,再次编译:

nginx 目录穿越漏洞 nginx1.16.1漏洞_nginx 目录穿越漏洞_03

编译完成后,执行make:

nginx 目录穿越漏洞 nginx1.16.1漏洞_nginx_04


4、进入到源码包目录的objs目录:

nginx 目录穿越漏洞 nginx1.16.1漏洞_运维_05


新生成的:

nginx 目录穿越漏洞 nginx1.16.1漏洞_服务器_06

复制其下的nginx二进制文件到nginx应用目录的二进制sbin下;

5、发送USR2信号给旧版本主进程号,使nginx的旧版本停止接收请求,用nginx新版本接替,且老进程处理完所有请求,关闭所有连接后,停止或直接pkill掉nginx

kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`

验证:查看nginx pid目录,多了个nginx.pid.oldbin文件,存放了旧版本nginx的pid号

nginx 目录穿越漏洞 nginx1.16.1漏洞_运维_07


关闭旧进程:kill -QUIT cat nginx.pid.oldbin

6、进入nginx应用目录验证:

nginx 目录穿越漏洞 nginx1.16.1漏洞_Nginx_08


测试:

nginx 目录穿越漏洞 nginx1.16.1漏洞_Nginx_09


nginx 目录穿越漏洞 nginx1.16.1漏洞_nginx_10


重新编译到nginx的根目录下:

./configure --user=nginx --group=nginx --prefix=/usr/local/app/nginx --with-http_v2_module --with-http_ssl_module --with-http_sub_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-http_realip_module

再次测试OK:

nginx 目录穿越漏洞 nginx1.16.1漏洞_nginx_11


7、启动nginx并验证:

nginx 目录穿越漏洞 nginx1.16.1漏洞_Nginx_12


nginx 目录穿越漏洞 nginx1.16.1漏洞_nginx_13


8、浏览器登录站点

nginx 目录穿越漏洞 nginx1.16.1漏洞_Nginx_14

三、附录:

3.1 Kill命令信号说明

nginx 目录穿越漏洞 nginx1.16.1漏洞_nginx_15


nginx 目录穿越漏洞 nginx1.16.1漏洞_nginx_16


更多参看:signal.hkillControlling nginx

nginx 目录穿越漏洞 nginx1.16.1漏洞_nginx_17

QUIT :Graceful shutdown 优雅的关闭进程,即等请求结束后再关闭
HUP : Configuration reload ,Start the new worker processes with a new configuration Gracefully shutdown the old worker processes。改变配置文件,平滑的重读配置文件
USR1 :Reopen the log files 重读日志,在日志按月/日分割时有用
USR2 : Upgrade Executable on the fly 平滑的升级,使用新版本的nginx文件启动服务,之后平缓停止原有nginx进程,也就是所谓的“平滑升级”。
WINCH : Gracefully shutdown the worker processes 优雅关闭旧的进程(配合USR2来进行升级)

如上所示,SIGTERM或者SIGINT信号,会让nginx快速退出。SIGQUIT信号,会让nginx优雅退出,就是资源主动释放干净、日志正常关闭、SOCKET正常关闭,但会慢一些退出。SIGUSR1信号,会让nginx重新打开日志文件,这明显是一个nginx自己的独特行为。每个进程都可以将各种信号定义成自己的独特行为。USR1亦通常被用来告知应用程序重载配置文件;注意:在POSIX兼容的平台上,SIGUSR1和SIGUSR2是发送给一个进程的信号,它表示了用户定义的情况。它们的符号常量在头文件signal.h中定义。在不同的平台上,信号的编号可能发生变化,因此需要使用信号名称

USR1信号将导致以下步骤的发生:

停止接受新的连接,等待当前连接停止,重新载入配置文件,重新打开日志文件,重启服务器,从而实现相对平滑的不关机的更改。

nginx中你会发现,kill -HUP $PID时,进程被重启了。而使用kill -USR1 $PID时,则进程不会重启。

USR2信号过程:

Nginx服务接收到USR2信号后,首先将旧的nginx.pid文件(如果在配置文件中更改过这个文件的名字,也是相同的过程)添加后缀.oldbin,变为nginx.pid.oldbin文件;然后执行新版本Nginx服务器的二进制文件启动服务.如果新的服务启动成功,系统中将有新旧两个Nginx服务共同提供Web服务.之后,需要向旧的Nginx服务进程发送WINCH信号,使旧的Nginx服务平滑停止,并删除nginx.pid.oldbin文件.在发送WINCH信号之前,可以随时停止新的Nginx 服务。

注意事项:

1、 新的服务器安装路径应该和旧的保持一致、在升级之前最后备份旧的nginx 。
2、安装之前在旧的nginx的sbin目录下执行./nginx -V 查看nginx 安装并启用了那些模块。
3、新的nginx 安装时 不执行 make install!!!

3.2 killall

yum install -y psmisc
apt-get install -y psmisc

-Z 只杀死拥有scontext 的进程
-e 要求匹配进程名称
-I 忽略小写
-g 杀死进程组而不是进程
-i 交互模式,杀死进程前先询问用户
-l 列出所有的已知信号名称
-q 不输出警告信息
-s 发送指定的信号
-v 报告信号是否成功发送
-w 等待进程死亡
–help 显示帮助信息
–version 显示版本显示