背景

虽然开源的CRS规则集[1]误报率很高,但是ModSecurity引擎还是很强大的,支持非常多的功能,包括丰富的HTTP解析后的字段。

不过虽然ModSecurity官方文档[2]中对于变量字段有说明,但是有一些细节仍然不清晰,比如 PATH_INFO变量是否经过url解码、存在参数污染时ARGS/ARGS_GET/ARGS_POST变量值是什么、为什么有时候REQUEST_BODY变量是空 等问题,不清楚这些细节容易写出存在漏报或者误报的规则。

本文介绍快速搞清变量的方法、几个重要且常用的变量。

搞清楚变量含义最快的方法

ModSecurity支持lua插件,你可以用SecRuleScript指令和lua脚本来做一些调试。

比如添加如下规则可以打印PATH_INFO变量到终端控制台

SecRuleScript "/tmp/1.lua" "id:23333,deny"

/tmp/1.lua 内容如下

function main()

local inspect = require("inspect") -- inspect库需要额外安装 https://github.com/kikito/inspect.lua

m.log(2,inspect(m.getvars("PATH_INFO"))) -- 将 PATH_INFO 变量打印到标准错误中

return nil;

end

ARGS_GET 和 参数污染

参数污染,简单的理解,也就是访问"http://网址/index.php?a=1&a=2&a=3",有的web容器解析请求后认为a的值是1,另一些web容器解析后认为a的值是3,这种就是存在参数污染问题。

那么ModSecurity解析参数时,会有参数污染问题吗?

结论是没有,测试过程如下

function main()

local inspect = require("inspect")

m.log(2,inspect(m.getvars("ARGS_GET")))

return nil;

end

curl "127.0.0.1:8081?a=1&a=2&a=3" 后,从下面日志中可以看到,ARGS_GET会存储参数a所有的值,这是符合预期的。

127.0.0.1:8081 是我本地安装了modsecurity的apache服务

Message: { {

name = "ARGS_GET:a",

value = "1"

}, {

name = "ARGS_GET:a",

value = "2"

}, {

name = "ARGS_GET:a",

value = "3"

} }

curl "127.0.0.1:8081?a=1&a=2&a=3" ,可以匹配到如下三条规则,也验证了 ARGS_GET 没有参数污染问题。

SecRule ARGS_GET:a "@rx 1" "id:946811,msg:"TEST1",phase:2,block,capture,severity:"CRITICAL",tag:"attack-rce",tag:"paranoia-level/1",t:none,setvar:tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}"

SecRule ARGS_GET:a "@rx 2" "id:946812,msg:"TEST2",phase:2,block,capture,severity:"CRITICAL",tag:"attack-rce",tag:"paranoia-level/1",t:none,setvar:tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}"

SecRule ARGS_GET:a "@rx 3" "id:946813,msg:"TEST3",phase:2,block,capture,severity:"CRITICAL",tag:"attack-rce",tag:"paranoia-level/1",t:none,setvar:tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}"

PATH_INFO 是否经过url解码等处理?

你觉得下面的自定义规则(禁止外部用户访问 security.xxx.com/login 接口),可以怎么绕过?

规则含义如下:

  • Host 完全匹配 security.xxx.com

  • URI 正则匹配 ^/login

上面的问题就不直接给出答案了。和路径相关的变量,你永远需要关注它有没有 url解码、../ 、./、/// 等处理逻辑:

  • /a/../b 会不会变成 /b

  • /a/./b 会不会变成 /a/b

  • ////a 会不会变成 /a

在ModSecurity中 REQUEST_URI、REQUEST_URI_RAW、PATH_INFO 三个常用的变量都和路径有关,v2版本测试结果如下

结论:

  • PATH_INFO 和 REQUEST_URI 会url解码、会处理../ 、./、///等字符

  • REQUEST_URI_RAW不做任何处理

REQUEST_BODY

根据文档所说,默认情况下,只有请求content-type是application/x-www-form-urlencoded时,REQUEST_BODY才会有值。

你也可以用forceRequestBodyVariable强制给REQUEST_BODY赋值,crs规则也是这么干的,如下

文档说REQUEST_BODY存储的是原始的请求body,那遇到chunked请求时,它存的是解码后还是解码前的呢?

Apache、ModSecurity-V2测试结论:是解码后的

总结

变量的细节影响规则质量,而ModSecurity的文档并不一定准确,我们可以用lua插件打印变量来测试。

参考资料

[1]开源的CRS规则集: https://github.com/coreruleset/coreruleset

[2]ModSecurity官方文档: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-%28v3.x%29

声明:本文来自leveryd,版权归作者所有。文章内容仅代表作者独立观点,不代表安全内参立场,转载目的在于传递更多信息。如有侵权,请联系 anquanneican@163.com。