joomla SQL Injection 漏洞防御
环境搭建
之前在演示SQL注入攻击的时候,使用了xampp应用在window上搭建了集成环境,虽然很方便,但不够灵活,不能根据自己的需求进行环境配置。由于需要在服务器中安装WAF,所以要重新搭建环境,将joomla搭建在ubuntu上。
Step 1: 安装Apache服务器
更新ubunntu源
apt-get update
安装Apache服务器
apt-get install apache2
Step 2: 安装MySQL数据库
- Joomla需要在LAMP的基础环境中运行,首先需要安装MySQL数据库并和PHP连接
apt-get install mysql-server php7.0-mysql
Step 3: 安装 PHP
- 安装PHP 7.0 和几个PHP模块
apt-get install php7.0 libapache2-mod-php7.0 php7.0-mcrypt php7.0-xml php7.0-curl php7.0-json php7.0-cgi
Step 4: 验证LAMP环境安装成功
打开浏览器,输入服务器本机IP,如果看到Apache默认页面,说明Apache服务器已经成功安装了
为了验证PHP安装成功,需要修改默认主页
rm /var/www/html/index.html
创建新文件
touch /var/www/html/index.php
编辑文件
vim /var/www/html/index.php
将下列PHP语句添加到文件中
<?php
phpinfo();
?>
进入浏览器,刷新刚才的默认Apache页面,如果看到页面显示PHP版本信息,则说明PHP安装成功,最后删除该文件
rm /var/www/html/index.php
Step 5: 准备Joomla安装文件
- 成功安装LAMP环境后,就能进行joomla的安装了,切换当前目录到服务器根目录,下载joomla相应版本的安装文件并解压
cd /var/www/html
下载安装文件
wget https://downloads.joomla.org/cms/joomla3/3-7-5/Joomla_3-7.5-Stable-Full_Package.zip
安装unzip
apt-get install unzip
解压文件
unzip Joomla_3-7.5-Stable-Full_Package.zip
修改权限
chown -R www-data.www-data /var/www/html
chmod -R 755 /var/www/html
Step 6: 为Joomla创建数据库
在安装joomla之前,需要为joomla在本地创建一个数据库,输入密码进入MySql控制台
mysql -u root -p
创建名称为joomla的数据库
mysql>CREATE DATABASE joomla;
为joomla数据库创建用户
mysql>GRANT ALL PRIVILEGES on joomla.* to 'username'@'localhost' identified by 'password';
mysql>FLUSH PRIVILEGES;
退出MySql控制台
mysql>exit
Step 7: 开始安装Joomla
重启Apache服务器
systemctl restart apache2
进入浏览器,输入服务器IP,会看到joomla欢迎页面,根据提示输入,就能成功安装joomla,注意输入的数据库名称,用户名和密码要和之前第6步创建的数据库的信息一致
Database Type: MySQLi
Host Name: localhost
Username: username
Password: password
Database Name: joomla
Table Prefix: joomla_
Old Database Process: Remove
WAF安装
Step 1:安装modsecurity模块
- 使用Ubuntu的包管理器安装libapache2-modsecurity模块及其依赖包
使用源码安装会出现各种小问题导致安装失败,Ubuntu的包管理器非常好用,在安装过程中基本不会有困难
apt-get install libxml2 libxml2-dev libxml2-utils libaprutil1
apt-get install libapache2-modsecurity
Step 2:配置modsecurity,启用拦截模式
重载Apache服务,
service apache2 reload
修改默认配置,启用拦截模式
cd /etc/modsecurity/
mv modsecurity.conf-recommended modsecurity.conf
vim /etc/modsecurity/modsecurity.conf
修改文件中SecRuleEngine状态为On
SecRuleEngine On
Step 3:选择modsecurity规则
将希望启用的规则放入下列文件夹中
cd /usr/share/modsecurity-crs/activated_rules/
选择启用下列规则,包含了基本的SQL注入攻击拦截规则
modsecurity_crs_41_sql_injection_attacks.conf
修改apache模块配置,启用规则集
vim /etc/apache2/mods-available/security2.conf
修改文件内容如下
<IfModule security2_module>
# Default Debian dir for modsecurity's persistent data
SecDataDir /var/cache/modsecurity
# Include all the *.conf files in /etc/modsecurity.
# Keeping your local configuration in that directory
# will allow for an easy upgrade of THIS file and
# make your life easier
IncludeOptional /etc/modsecurity/*.conf
IncludeOptional /usr/share/modsecurity-crs/*.conf
IncludeOptional /usr/share/modsecurity-crs/activated_rules/*.conf
</IfModule>
Step 4:启用modsecurity模块
a2enmod headers
a2enmod security2
Step 5:测试真实的攻击payload
发起下列HTTP请求,未开启WAF前,该请求会导致构造的SQL语句被执行
http://192.168.254.130/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=if(1=1,1,(SELECT(1)FROM(SELECT(SLEEP(500)))test))
可以看到,服务器拦截了这次攻击请求,返回了403页面,SQL注入攻击失败
可以查看服务器日志文件来查看具体的拦截信息
第一段记录了HTTP请求的相关信息,包括发起请求的时间,客户端IP,还有整个完整的HTTP请求头部信息都完整的记录了下来。
--60c14f24-A--
[03/Jul/2018:06:06:00 --0700] Wzt0uO5VTqHWiSTB7HaLtQAAAAM 192.168.254.1 7204 192.168.254.130 80
--60c14f24-B--
GET /index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=if(1=1,1,(SELECT(1)FROM(SELECT(SLEEP(500)))test)) HTTP/1.1
Host: 192.168.254.130
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: c40b869f52497e9591df3658e267d1ba=e9kqsd8kenepp0gekrfihodt21
X-Forwarded-For: 113.55.110.2
这一段记录的是服务器对该异常HTTP请求的响应,包含响应的头部信息和内容。可以看到,服务器返回的HTTP状态码为403 Forbidden,表示该条请求被服务器拒绝,而响应内容是HTML代码,简单的显示了禁止访问的提示。
--60c14f24-F--
HTTP/1.1 403 Forbidden
Content-Length: 299
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1
--60c14f24-E--
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /index.php
on this server.<br />
</p>
<hr>
<address>Apache/2.4.29 (Ubuntu) Server at 192.168.254.130 Port 80</address>
</body></html>
最后一段记录了WAF拦截本次请求的原因等相关信息。第一个字段Message中,显示出服务器对该请求的响应是拒绝服务并返回403错误。后面给出了拦截发生的阶段,(phase 2) 表示在服务器读取到请求内容时执行了拦截操作。Pattern match给出了所匹配的规则,匹配到了modsecurity_crs_41_sql_injection_attacks.conf文件中第80行id 950901 号规则,显示了该规则的部分正则表达式。消息中给出了可能的web攻击的种类,在该次请求中为SQL Injection Attack: SQL Tautology Detected,也就是SQL注入攻击。还显示出了在请求内容中匹配到规则的那一部分数据, 即(1=1 ,正是因为请求内容有这部分数据,才被特定规则识别出来。下面两个参数muturity和accuracy用来判断该次拦截的准确率。
--60c14f24-H--
Message: Access denied with code 403 (phase 2). Pattern match "(?i:([\\s'\"`\xc2\xb4\xe2\x80\x99\xe2\x80\x98\\(\\)]*?)\\b([\\d\\w]++)([\\s'\"`\xc2\xb4\xe2\x80\x99\xe2\x80\x98\\(\\)]*?)(?:(?:=|<=>|r?like|sounds\\s+like|regexp)([\\s'\"`\xc2\xb4\xe2\x80\x99\xe2\x80\x98\\(\\)]*?)\\2\\b|(?:!=|<=|>=|<>|<|>|\\^|is\\s+not ..." at ARGS:list[fullordering]. [file "/usr/share/modsecurity-crs/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf"] [line "80"] [id "950901"] [rev "2"] [msg "SQL Injection Attack: SQL Tautology Detected."] [data "Matched Data: (1=1 found within ARGS:list[fullordering]: if(1=1,1,(SELECT(1)FROM(SELECT(SLEEP(500)))test))"] [severity "CRITICAL"] [ver "OWASP_CRS/2.2.9"] [maturity "9"] [accuracy "8"] [tag "OWASP_CRS/WEB_ATTACK/SQL_INJECTION"] [tag "WASCTC/WASC-19"] [tag "OWASP_TOP_10/A1"] [tag "OWASP_AppSensor/CIE1"] [tag "PCI/6.5.2"]
Action: Intercepted (phase 2)
Apache-Handler: application/x-httpd-php
Stopwatch: 1530623160351414 2841 (- - -)
Stopwatch2: 1530623160351414 2841; combined=1194, p1=529, p2=634, p3=0, p4=0, p5=30, sr=74, sw=1, l=0, gc=0
Response-Body-Transformed: Dechunked
Producer: ModSecurity for Apache/2.9.0 (http://www.modsecurity.org/); OWASP_CRS/2.2.9.
Server: Apache/2.4.29 (Ubuntu)
Engine-Mode: "ENABLED"
下面是请求触发的规则的具体定义,在modsecurity规则的核心是建立在正则匹配上的,可以看到下面的规则对SQL注入的检测依赖于一段很长的正则表达式,如果正则匹配成功,则说明检测到攻击。
#
# -=[ SQL Tautologies ]=-
#
SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "(?i:([\s'\"`´’‘\(\)]*?)\b([\d\w]++)([\s'\"`´’‘\(\)]*?)(?:(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*?)\2\b|(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*?)(?!\2)([\d\w]+)\b))" \
"phase:2,rev:'2',ver:'OWASP_CRS/2.2.9',maturity:'9',accuracy:'8',capture,multiMatch,t:none,t:urlDecodeUni,t:replaceComments,ctl:auditLogParts=+E,block,msg:'SQL Injection Attack: SQL Tautology Detected.',id:'950901',logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',severity:'2',tag:'OWASP_CRS/WEB_ATTACK/SQL_INJECTION',tag:'WASCTC/WASC-19',tag:'OWASP_TOP_10/A1',tag:'OWASP_AppSensor/CIE1',tag:'PCI/6.5.2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sql_injection_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-OWASP_CRS/WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{tx.0}"
先来看一下在modsecurity中配置规则的主要指令SecRule,这个命令用于分析数据并根据分析结果执行相应动作。
下面是该指令的格式,VARIABLES描述哪些数据会被检测,例如REQUEST_HEADERS表示检测HTTP请求头中的内容, ARGS表示请求中的参数。第二部分的OPERATOR表示如何检测数据,一般会用一个正则表达式作为规则的第二个参数。第三个参数[ACTIONS]是可选的,因为在modsecurity配置文件中指定了默认动作列表。如果这个值被设定了,会联合预设的默认动作列表最终产生一个执行的动作,来对检测结果做出响应。
SecRule VARIABLES OPERATOR [ACTIONS]
在上述规则中,VARIABLES的值为REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/ *
就是需要检测HTTP请求的cookie内容和cookie名字,以及HTTP请求中包含的参数和参数名字,如果是GET请求,则参数和参数名称在请求头部的URL中;如果是POST请求,那参数和参数名称就在请求的载荷中。此外,对cookie排除了__utm的值,经过搜索,这个参数来自于google的网站统计,可以过滤。
然后我们再来详细分析一下规则中作为OPERATOR的正则表达式
(?i:(
[\s'\"`´’‘\(\)]*?) # 匹配各种引号和括号
\b([\d\w]++) # 匹配数字
([\s'\"`´’‘\(\)]*?) # 匹配各种引号和括号
(?:(
?: =|<=>|r?like|sounds\s+like|regexp) # 匹配关系运算符
([\s'\"`´’‘\(\)]*?)\2\b| # 匹配各种引号和括号
(?:
!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp) # 匹配关系运算符
([\s'\"`´’‘\(\)]*?)
(?!\2)([\d\w]+)\b) # 匹配数字,和第1个分组的数字要相同
)
可以从匹配结果看出,这条正则能够匹配到通过关系运算实施的SQL注入攻击
最后,看一下这条规则的动作,在modsecurity配置文件/usr/share/modsecurity-crs/modsecurity_crs_10_setup.conf中,设定的默认动作列表如下,即,默认拒绝检测到异常的HTTP请求,并形成记录写入日志。 所以这条规则检测到攻击后,会按默认动作拒绝请求,并记录日志
SecDefaultAction "phase:1,deny,log"
SecDefaultAction "phase:2,deny,log"
我们看到在动作列表中有一个phase参数,这个参数说明了规则生效的阶段,在 ModSecurity中,规则可以在五个阶段执行,,分别为:
- 请求头(REQUEST_HEADERS)
- 请求体(REQUEST_BODY)
- 响应头(RESPONSE_HEADERS)
- 响应体(RESPONSE_BODY)
- 记录(LOGGING)
下图是标准的 apache 请求流程,5 个 ModSecurity 处理阶段显示在其中
大多数规则在下列两个阶段执行
请求头阶段
这个阶段的规则会在 apache 完成HTTP请求头的读取后立即被执行,这时,还没有读取请求体,意味着不是所有的参数都可用。如果你必须让规则尽早运行,应把规则放在这个阶段(在 apache 使用这个请求做某些事前),在请求体被读取前做些事情,从而决定是否缓存这个请求体,或者决定你将希望这个请求体如何被处理(如是否以 XML 格式解析或不解析)。
请求体阶段
这个阶段,服务器完成对请求载荷的解析,服务器端可以拿到所有请求的参数,上面的那条规则就是在本阶段执行的