0x01 前言
前些天我为nginx配置安装了Naxsi WAF(安装naxsi为nginx提供WAF服务),它的规则对于入门者来说确实有点复杂。
我在这里记录一下这几天我学了解到的知识。
0x02 类型
首先naxsi有三种规则类型,相对应的功能如下:
- MainRule:定义检测规则和分数
- BasicRule:定义MainRule的白名单
- CheckRule:定义当分数达到阀值时所采取的动作
MainRule可以在这里找到:
naxsi/naxsi_config/naxsi_core.rules
BasicRule可以在这里找到:
而CheckRule则是文章(安装naxsi为nginx提供WAF服务)中需要添加到location块中的内容:
CheckRule "$SQL >= 8" BLOCK; CheckRule "$RFI >= 8" BLOCK; CheckRule "$TRAVERSAL >= 4" BLOCK; CheckRule "$EVADE >= 4" BLOCK; CheckRule "$XSS >= 8" BLOCK;
0x03 MainRule
规则例子:
MainRule "str:0x" "msg:0x, possible hex encoding" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:2" id:1002;
MainRule后看紧跟着的是匹配模式,模式有:
- str:字符串
- rx:正则表达式
- d:libinj_xss:libinjection检测为xss
- d:libinj_sql:libinjection检测为sql注入
例子中的”str:0x”,代表匹配 0x 这个字符。
然后是描述,仅用于描述规则,不会有其他动作:
"msg:0x, possible hex encoding"
然后是匹配区域Match Zones:
"mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie"
mz支持以下区域:
- ARGS: GET args 参数
- HEADERS:HTTP Headers
- BODY: POST args (和 RAW_BODY)
- URL:在?之前的URL
在例子中的HEADERS采取了更为详细的声明:$HEADERS_VAR:Cookie。同样的,其他区域也同样支持详细声明:
- $ARGS_VAR:string: named GET argument
- $HEADERS_VAR:string : named HTTP header
- $BODY_VAR:string: named POST argument
紧跟着的是评分Score:
"s:$SQL:2"
如果某个请求符合这条规则,那么名为$SQL的这个计数器就会加2;如果这个请求中有多个参数符合这条规则,那么计数器也会相应地增加。
当$SQL这个计数器符合在location中CheckRule对于$SQL计数器的定义时,将采取相对应的动作,如:
CheckRule "$SQL >= 8" BLOCK;
当计数器$SQL分数大于等于8,nginx将禁止访问。
最后是规则id,这id在编写白名单的时候会用到:
id:1002
0x04 BasicRule
白名单的添加最好能以日志为基础进行操作。如果你不想在配置Naxsi的时候导致服务无法访问,那么可以打开学习模式:
LearningMode; SecRulesEnabled; DeniedUrl "/RequestDenied"; CheckRule "$SQL >= 8" BLOCK; CheckRule "$RFI >= 8" BLOCK; CheckRule "$TRAVERSAL >= 4" BLOCK; CheckRule "$EVADE >= 4" BLOCK; CheckRule "$XSS >= 8" BLOCK;
在location块中加入 LearningMode; 即可。
首先来看看日志:
2013/11/10 07:36:19 [error] 8278#0: *5932 NAXSI_FMT: ip=X.X.X.X&server=Y.Y.Y.Y&uri=/phpMyAdmin-2.8.2/scripts/setup.php&learning=0&vers=0.52&total_processed=472&total_blocked=204&block=0&cscore0=$UWA&score0=8&zone0=HEADERS&id0=42000227&var_name0=user-agent, client: X.X.X.X, server: blog.memze.ro, request: "GET /phpMyAdmin-2.8.2/scripts/setup.php HTTP/1.1", host: "X.X.X.X"
一上面这个日志为例,可以看到访问请求出发了id为42000227,匹配区域为HEADERS,字符串为user-agent的规则。
那么白名单可以写成以下这种形式:
BasicRule wl:42000227 "mz:$URL:/phpMyAdmin-2.8.2/scripts/setup.php|$HEADERS:user-agent";
下一次访问以下地址的时候:
/phpMyAdmin-2.8.2/scripts/setup.php
id为42000227中HEADERS的检测就不会再匹配user-agent。
0x05 CheckRule
CheckRule "$SQL >= 8" BLOCK; CheckRule "$RFI >= 8" BLOCK; CheckRule "$TRAVERSAL >= 4" BLOCK; CheckRule "$EVADE >= 4" BLOCK; CheckRule "$XSS >= 8" BLOCK;
以上是加载在location中的CheckRule。他们的主要作用是读取计数器中的数值,与CheckRule中所设定的数值进行对比,一旦符合设定,那么将进行响应的动作。
以上的CheckRule意味着当名为$SQL、$RFI、$TRAVERSAL、$EVADE和$XSS这些计数器的值达到设定值后,将禁止访问。
动作不仅仅有BLOCK,还有以下这些:
- DROP:抛弃请求,不做任何回应
- BLOCK:根据DeniedUrl的设定进行跳转
- ALLOW:允许通过
- LOG:仅记录在日志中,不做任何动作
0x06 结语
最为方便的事规则支持正则表达式,这大大方便了我们的工作。
刚开始的时候是很难理解和使用规则,但尝试过一周后就能理解并熟悉应用了。