安全规则中的正则表达式
2023-12-17 23:49:37 Author: leveryd(查看原文) 阅读量:7 收藏

不论是商业安全产品还是开源安全产品,在规则运营中,写正则一直是很重要的一个事情,而正则使用中有一些基础知识,可能会被很多人忽视。

比如 ^号是匹配每一行的开头还是匹配一个文件的开头呢?在 yara、modsecurity、suricata 等开源安全产品引擎中答案都是一样的吗?

比如 捕获分组、断言 等用法是所有引擎都支持的吗?

每个产品用的正则引擎库可能是不同的,所以能支持的特性、写法会稍微有些差别。

在c语言中,pcre库[1]应该是应用最广泛的正则引擎库,modsecurity、早期的yara都是用的它。

你可以在 https://www.debuggex.com/cheatsheet/regex/pcre 这个站点查看 PCRE、JavaScript、Python 支持的用法区别。

举个例子,在应用广泛的waf规则集crs中,有一条规则是检查响应内容是不是以 #!/ 开头,已检查 #!/bin/bash 等脚本源码泄露,它的规则如下

SecRule RESPONSE_BODY "@rx ^#\!\s?/" \
    "id:950140,\
    ...

实际上这条规则就和预期不同。在 modsecurity v3版本中,实际上它是在匹配响应内容"每一行"是否以 #!/ 开头。

modsecurity的正则引擎是pcre,所以 ^号是匹配每一行的开头还是匹配一个文件的开头,这取决于 PCRE_MULTILINE 修饰符是否开启。

在 https://github.com/SpiderLabs/ModSecurity/blob/v3.0.9/src/utils/regex.cc#L68

PCRE2_SPTR pcre2_pattern = reinterpret_cast<PCRE2_SPTR>(pattern.c_str());
uint32_t pcre2_options = (PCRE2_DOTALL|PCRE2_MULTILINE);
if (ignoreCase) {

代码中看到 PCRE_MULTILINE选项 默认是开启的,所以^号匹配每一行的开头。所以上面的规则可以优化成

SecRule RESPONSE_BODY "@rx ^(.{10})" \          // 先取出响应头前十个字节
    "id:950140,\
    ...
    setvar:'tx.first_ten_chars=%{tx.1}',\
    chain"

    SecRule TX:FIRST_TEN_CHARS "@rx ^#\!\s?/" \   // 针对前十个字节做匹配
      ..."

更多讨论,可以看 https://github.com/coreruleset/coreruleset/issues/3266。modsecurity v3、modsecurity v2、Coraza 等表现都不一致。

其他语言的正则库提供的接口也会提供MULTILINE修饰符,比如Python如下

>>> import re
>>> re.findall("^2","1\n2\n3")        # 默认没有开启MULTILINE,^就只匹配文本的开头
[]
>>> re.findall("^2","1\n2\n3",re.MULTILINE)   # 开启MULTILINE,^就会匹配每一行的开头
['2']
>>> re.findall("(?m)^2","1\n2\n3")      # (?m) 也可以开启MULTILINE
['2']

虽然正则初学者可以用大模型去写正则,但是也应该了解到不同引擎支持的正则特性不同、正则的修饰符等基础知识。

在规则编写前,也应该清楚正则引擎默认开启的修饰符选项有哪些。

参考资料

[1]

pcre库: https://www.pcre.org/


文章来源: http://mp.weixin.qq.com/s?__biz=MzkyMDIxMjE5MA==&mid=2247485429&idx=1&sn=c3e6b7558d9c5d48e1d1a0546d44e728&chksm=c0142eb1a58bf369a07c033f4b9305504ad9abcd26ab1ba53f71986a92e85916450346c4973c&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh