长亭百川云 - 文章详情

安全规则中的正则表达式

leveryd

44

2024-07-13

背景

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

比如 ^号是匹配每一行的开头还是匹配一个文件的开头呢?在 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/

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2