安全人员学习笔记——Web中间件之Nginx篇
Web中间件学习篇
本篇主要从IIS、Apache、Nginx、Tomcat四种常见中间件的Nginx入手,介绍相关安全知识,遵循“中间件简介→如何搭建网站→安全配置分析→安全日志分析”的顺序进行学习,旨在梳理常见Web中间件的知识点,为Web安全学习打好基础。
Nginx篇
作者:古月蓝旻@安全之光
Nginx简介
Nginx(发音同engine x)是一个网页服务器,它能反向代理HTTP, HTTPS, SMTP, POP3, IMAP的协议链接,以及一个负载均衡器和一个HTTP缓存。 Nginx是一款面向性能设计的HTTP服务器,相较于Apache、lighttpd具有占有内存少,稳定 性高等优势。与旧版本(<=2.2)的Apache不同,nginx不采用每客户机一线程的设计模型, 而是充分使用异步逻辑,削减了上下文调度开销,所以并发服务能力更强。 起初是供俄国大型的门户网站及搜索引擎Rambler(俄语:Рамблер)使用。此软件BSD-like 协议下发行,可以在UNIX、GNU/Linux、BSD、Mac OS X、Solaris,以及Microsoft Windows 等操作系统中运行。
Nginx站点搭建
Nginx站点的搭建其难点在于安装Nginx,不同于Apache可以直接使用yum或者apt-get的方式安装,Nginx不在系统标准源中,因此常见的安装方式主要有两个:编译安装和第三方yum源安装。由于编译安装Nginx需要安装的拓展比较多,此次我们使用第三方yum源方式安装Nginx,同时以此为基础,搭建Linux+Nginx+Mysql+Php的站点,分为以下几步:
- 配置第三方yum源;
- 安装Nginx;
- 安装Mysql、php、配置phpmyadmin;
- 部署php站点;
下面开始详细介绍如何搭建一个完整的Nginx站点:
环境介绍
操作系统:CentOS release 6.5 (Final) Nginx版本: nginx-1.6.2-23.el6.art.x86_64 站点类型:php
搭建步骤
配置第三方yum源
由于CentOS标准yum源中不提供Nginx的安装包,所以需要第三方yum源来补充一下,而第三方源的选择同样需要谨慎,不仅要保证软件要兼容本系统同时版本较新,最重要的是要保证安全,否则安装的软件可能都带着后门。此次我们选择的是Atomic源
Atomic支持哪些软件可以到这个地址查看:http://www.atomicorp.com/channels/atomic/ 最常见的有php、mysql、nginx、openvas、memcached、php-zend-guard-loader等软件。
配置步骤如下:
wget http://www.atomicorp.com/installers/atomic sh ./atomic yum check-update
其中在sh ./atomic一步,一路yes即可,同时安装相关拓展和依赖
yum -y install ntp make openssl openssl-devel pcre pcre-devel libpng libpng-devel libjpeg-6b libjpeg-devel-6b freetype freetype-devel gd gd-devel zlib zlib-devel gcc gcc-c++ libXpm libXpm-devel ncurses ncurses-devel libmcrypt libmcrypt-devel libxml2 libxml2-devel imake autoconf automake screen sysstat compat-libstdc++-33 curl curl-devel
如果之前有安装过mysql、apache、php,需要先全部卸载
yum remove httpd yum remove php yum remove mysql
安装Nginx
配置了第三方yum源后,安装就方便了很多
yum install nginx service nginx start chkconfig --levels 235 nginx on ////设置2、3、5级别开机启动
此时去访问localhost或者127.0.0.1或者本机访问本机ip就可以看见nginx界面
由于Atomic源的软件不是特别新,该版本是2014年4月发行,但是也足够使用了
此时其他主机还是无法通过ip的方式访问该主机的,和apache类似,需要开启80端口的访问规则
/sbin/iptables -I INPUT -p tcp --dport 80 -j ACCEPT //添加开启80端口规则 /etc/rc.d/init.d/iptables save //保存配置 /etc/rc.d/init.d/iptables restart //重启iptables /etc/init.d/iptables status //查看开放的端口,出现80
此时其它主机已经可以正常访问
安装Mysql、php、配置phpmyadmin
这些其实和apache是基本相同的
yum -y install mysql mysql-server mysql-devel //安装mysql和其相关拓展 chkconfig mysqld on //设置其开机启动 service mysqld start //启动mysqld服务 /usr/bin/mysql_secure_installation //设置mysql的一些安全配置 这一步还是很重要的,主要是设置mysql的root密码,是否需要删除匿名账号等等,根据实际需要设置
此时我们可以登录一下mysql
yum -y install php //安装php yum -y install php-mysql gd php-gd gd-devel php-xml php-common yum -y install php-mbstring php-ldap php-pear php-xmlrpc php-imap php-mcrypt //安装php常用拓展 yum install php-tidy php-common php-devel php-fpm //安装php-fpm service php-fpm start //启动php-fpm chkconfig --levels 235 php-fpm on //设置php-fpm2、3、5级别开机启动 service nginx restart //重启nginx服务,这一步非常重要
完成之后可以简单测试一下,在/usr/share/nginx/html/目录下新建phpinfo.php文件内容为phpinfo(),让其输出一下相关信息,然后发现。。。现在还是无法解析php文件,访问的话会直接下载该文件
因此我们需要配置一下Nginx支持解析php,配置文件名称为nginx.conf,具体路径的寻找方式有多种方法:
方法一: updatedb locate nginx.conf 方法二: ps aux |grep nginx
还有更简单的配置文件路径的查看方法,会在日志篇进行详细说明
具体的配置步骤如下:
mv /etc/nginx/nginx.conf /etc/nginx/nginx.confbak //将配置文件改为备份文件 cp /etc/nginx/nginx.conf.default /etc/nginx/nginx.conf //由于原配置文件要自己去写因此可以使用默认的配置文件作为配置文件 //修改nginx配置文件,添加fastcgi支持 vi /etc/nginx/nginx.conf index index.php index.html index.htm; //加入index.php,大约在45行左右 location ~ .php$ { root /usr/share/nginx/html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name; include fastcgi_params; } //将65行--71行处关于.php文件规则的注释符号删去
//配置/etc/php.ini,在文件末尾添加cgi.fix_pathinfo = 1
最后重启nginx和php-fpm service nginx restart service php-fpm restart
此时再访问/usr/share/nginx/html/目录下的phpinfo.php,可以正常显示服务器信息
下一步就是安装phpmyadmin,这个其实是可选步骤,只是为了方便图形化管理mysql,下载官网:phpmyadmin下载官网
在官网下载了phpMyAdmin-4.0.10.20-all-languages.tar.gz
和Apache一样,由于安装的php版本为5.4.45,低于php5.5,因此安装低版本的phpMyAdmin
tar -xvzf phpMyAdmin-4.0.10.20-all-languages.tar.gz mv phpMyAdmin-4.0.10.20-all-languages /usr/share/nginx/html/phpmyadmin cd /usr/share/nginx/html/phpmyadmin cp libraries/config.default.php config.inc.php
然后修改一下相关配置vi config.inc.php,一般改这些
$cfg['PmaAbsoluteUri'] = '';这里填写 phpMyAdmin 的访问网址。 $cfg['Servers'][$i]['host'] = 'localhost'; // MySQL hostname or IP address $cfg['Servers'][$i]['port'] = ''; // MySQL port - leave blank for default port $cfg['Servers'][$i]['user'] = 'root'; // 填写 MySQL 访问 phpMyAdmin 使用的 MySQL 用户名,默认为 root。 $cfg['Servers'][$i]['password'] = ''; // 填写对应上述 MySQL 用户名的密码。 $cfg['blowfish_secret'] = '1qaz2wsx3edc';//随意,长度不要太短
实际过程中其实我也只是修改了password一处为我的mysql密码,blowfish_secret其实也可以修改,否则登录后会给个警告,但是不影响使用最后重启一下nginx和php-fpm服务
service nginx restart service php-fpm restart
打开浏览器访问http://localhost/phpmyadmin 或者 http://ip/phpmyadmin
部署php站点
还是将apache中配置好的php源码包直接拿来使用,和apache不同,此时的db_config.php文件,主机host使用127.0.0.1不会报错
但是登录页面login.php显示乱码,登录成功后的页面index.php正常,这个很显然是编码的问题
于是在login.php的<?php下发第一行添加
header("Content-Type: text/html;charset=utf-8");
重启一下nginx和php-fpm,再次访问,可以登录,一切正常,至此nginx下的php站点搭建完成
nginx日志分析
和apache非常类似,nginx的主要日志也是access.log和error.log,那么该如何确认详细的路径?
执行以下命令即可
nginx -V
其实里面有很多详细的路径信息,可以在其中查到,同时顺便一提,关于一些配置信息可以查看phpinfo界面,不要忽略它
根据上图,我们可以得到访问日志和错误日志的具体路径
access.log=/var/log/nginx/access.log
error.log=/var/log/nginx/error.log
在打开这两种日志前,我们还是去配置文件/etc/nginx/nginx.conf里看看关于nginx日志的配置情况,直接搜索关键字log_format
,结果…
看起来比apache详细多了,而且还解释了各个字段的含义。但是…所有和日志有关的内容全被注释了…所以日志是怎么记录的?难道虽然被注释了,但是还是生效的?打开/var/log/nginx/access.log看一下
这个完全和apache的日志一样啊,根本没有什么http_x_forward_for
字段嘛,这个问题我困惑了很久,找了半天才发现原因:
也就是说:nginx默认使用了和apache相同的组合日志格式(Combined Log Format),但是它省略了,这个就比较坑了
其实一般情况下nginx日志记录格式会如上图所示,不会注释,但是可能是我安装的方式使用第三方yum源,有些配置被修改了
如果想自定义日志的不同字段,可以参考这篇文章:nginx系列-04-nginx日志配置
同时error.log的格式在nginx.conf中若未定义,同样使用apache对于错误日志的记录级别,该句亦省略
error_log /var/log/nginx/error.log warn;
还有一点很重要:查看一下/var/log/nginx下的文件
可以看见访问日志和错误日志均会按照天压缩成.gz文件,这个在nginx.conf中并未定义,是在哪里设置的?
其实类似这种log分片压缩成不同文件的,往往由logrotate完成
logratate根据不同应用生成多个log配置文件,路径在/etc/logrotate.d/目录下
两处关键点:
- daily 代表log按照天划分;
- compress 代表日志以gzip压缩转储以后的日志(.gz文本文件亦可直接使用vim打开)
如果对logrotate中nginx的配置比较感兴趣,可以看这篇文章:Nginx日志切割之Logrotate篇
Nginx日志分析Web攻击行为
Nginx日志同样可以用于分析Web攻击行为,本次使用AWVS扫描搭建的站点,然后查看日志情况
一切使用默认配置即可,稍等片刻即可完成扫描
打开日志看一下,内容挺多的,这次和IIS和Apache的web日志分析不同,这次主动查找AWVS的常用攻击行为
sql注入攻击
直接在access日志中搜索关键字“SELECT”
典型的GET型sql注入攻击,目的是获取数据库中所有的表
xss攻击
也非常简单,直接在access日志中搜索关键字“script”
如图所示,以上4处xss均为dom-xss,且添加测试字段均为wvstest
shellshock漏洞攻击
这个发现的比较偶然,自己之前甚至不怎么留意,因为在access日志中发现了一处16进制编码payload
配合前面的echo -e ,基本可以判断这是一处测试RCE漏洞的payload,于是乎想看看这个payload的原文
echo -e \x22\x5C0141\x5C0143\x5C0165\x5C0156\x5C0145\x5C0164\x5C0151\x5C0170\x5C0163\x5C0150\x5C0145\x5C0154\x5C0154\x5C0163\x5C0150\x5C0157\x5C0143\x5C0153\x22
\x是典型的16进制,\x22是双引号"的16进制,\5C是反斜杠\的16进制,所以转换一下上述字符串就是
echo -e”\0141\0143\0165\0156\0145\0164\0151\0170\0163\0150\0145\0154\0154\0163\0150\0157\0143\0153″
\0又是典型的8进制,所以接下来的问题是把8进制转换为对应字符串即可,直接转有点麻烦先转换为16进制吧
echo -e “6163756e657469787368656c6c73686f636b”
越来越短了,看见希望了,最后就是16进制转字符串,得到
echo -e “acunetixshellshock”
果然是awvs在测试shellshock(破壳漏洞),在测试命令执行,从最后漏洞扫描结果看,在我的服务器确实没找到这个漏洞,但是服务器真的没有这个漏洞吗?毕竟我是CentOS 6.5,自己跑下POC好了
env x='() { :;}; echo vulnerable' bash -c "echo this is a test "
如果输出vulnerable就说明有该漏洞,且该漏洞常见于bash版本低于4.2的主机,看一下结果
显然是有该漏洞的,但是为什么AWVS没扫出来?查了一些资料,应该是服务器的bash解释器修复了该漏洞,关于该漏洞的相关知识,可以参考以下文章:
目录遍历漏洞
除了access日志外,error日志中亦包含很多攻击信息,最常见的便是目录遍历导致服务器出错
典型的目录遍历查看/etc/passwd文件的,顺便一提由于变量会加上php后缀,所以我们要用%00来截断后缀这样才能正常显示文件内容
关于目录遍历漏洞,推荐一篇文章
尝试修改php.ini配置
还是error.log,这个payload就有点胆大妄为了,在尝试直接修改php.ini配置
典型的url编码,解密看下结果好了
-d allow_url_include=on -d safe_mode=off -d suhosin.simulation=on -d disable_functions="" -d open_basedir=none -d auto_prepend_file=php://input -d cgi.force_redirect=0 -d cgi.redirect_status_env=0 -n
真是敢做敢担当,直接把php默认的安全配置全改了,允许远程url包含,关闭安全模式…直接降低站点的安全系数
其实access日志和error日志中还有大量漏洞利用的payload,时间有限,就不过多介绍了
post方式访问
nginx默认情况下还是不记录POST方式提交的内容的,那么如何开启呢?其实非常简单,修改一下nginx.conf关于日志的部分,添加一个记录字段 "$request_body"
(请求体),启用一下access_log的配置为main中的配置
顺便一提access_log的路径为logs/access.log,完整路径为nginx根路径+logs/access.log,在我本机为/usr/share/nginx/logs/access.log,需要创建一下/usr/share/nginx/logs/目录,并改一下属主和权限
mkdir /usr/share/nginx/logs chown -R nginx:root /usr/share/nginx/logs chmod 644 /usr/share/nginx/logs
此时访问任意界面,POST传入相应数据,可以发现,POST请求体被记录在案啦
补充知识点
1. 如何修改Nginx默认端口号?
这个问题非常简单,打开nginx.conf文件,
找到Listen 80 一行,将80修改为想要设置的端口号,保存,重启nginx即可
测试时在本机浏览器输入http://127.0.0.1:新端口号 即可
注:外网主机此时可能无法通过http://IP:新端口号 方式访问,记得修改iptables,添加新端口号规则。
2. 以root身份启动nginx,该服务以什么用户运行?
使用ps aux|grep nginx|grep -v grep查看一下
第一列中既有root,又有nginx,Nginx在以Linux service脚本启动时,通过start-stop-domain启动,会以root权限运行master进程。
然后master进程读取/etc/nginx/nginx.conf文件中的user配置选项,默认这里的user=nginx,也就是用nginx用户启动worker process。且nginx.conf中会定义worker process的数量