30条新Semgrep规则:Ansible、Java、Kotlin、Shell脚本等安全检测全覆盖

Trail of Bits发布30条自定义Semgrep规则,覆盖Ansible剧本、Java/Kotlin代码、Shell脚本和Docker Compose配置文件的安全检测,重点识别未加密传输、SSL验证禁用等漏洞,并深入解析Semgrep的通用模式和YAML支持特性。

30条新Semgrep规则:Ansible、Java、Kotlin、Shell脚本等

我们发布了30条自定义Semgrep规则,用于检测Ansible剧本、Java/Kotlin代码、Shell脚本和Docker Compose配置文件中的常见安全漏洞。这些规则已用于审计所列技术中的安全隐患。此次发布的Semgrep规则与我们的公共CodeQL查询和测试手册一起,旨在向安全社区分享我们的技术专长。本文将简要介绍新规则,然后深入探讨创建这些规则时使用的两个较少人知的Semgrep特性:通用模式和YAML支持。

在此次内部Semgrep规则发布中,我们重点关注了未加密网络传输(HTTP、FTP等)、禁用SSL证书验证、常见命令行工具的不安全标志、无限制IP地址绑定、各种Java/Kotlin问题等。以下是我们新增的规则:

模式 规则ID 规则描述
Generic container-privileged 发现具有扩展权限的容器命令
Generic container-user-root 发现以root身份运行的容器命令
Generic curl-insecure 发现禁用SSL验证的curl命令
Generic curl-unencrypted-url 发现使用未加密URL(如HTTP、FTP等)的curl命令
Generic gpg-insecure-flags 发现使用不安全标志的gpg命令
Generic installer-allow-untrusted 发现允许不受信任安装的安装程序命令
Generic openssl-insecure-flags 发现使用不安全标志的openssl命令
Generic ssh-disable-host-key-checking 发现禁用主机密钥检查的ssh命令
Generic tar-insecure-flags 发现使用不安全标志的tar命令
Generic wget-no-check-certificate 发现禁用SSL验证的wget命令
Generic wget-unencrypted-url 发现使用未加密URL(如HTTP、FTP等)的wget命令
Java, Kotlin gc-call 调用gc会建议JVM运行垃圾回收器并回收内存,但这仅是建议,无法保证任何操作。依赖此行为实现正确性或内存管理是一种反模式
Java, Kotlin mongo-hostname-verification-disabled 发现禁用SSL主机名验证的MongoDB客户端
YAML (Ansible) apt-key-unencrypted-url 发现使用未加密URL(如HTTP、FTP等)的apt密钥下载
YAML (Ansible) apt-key-validate-certs-disabled 发现禁用SSL验证的apt密钥
YAML (Ansible) apt-unencrypted-url 发现使用未加密URL(如HTTP、FTP等)的apt deb
YAML (Ansible) dnf-unencrypted-url 发现使用未加密URL(如HTTP、FTP等)的dnf下载
YAML (Ansible) dnf-validate-certs-disabled 发现禁用SSL验证的dnf
YAML (Ansible) get-url-unencrypted-url 发现使用未加密URL(如HTTP、FTP等)的文件下载
YAML (Ansible) get-url-validate-certs-disabled 发现禁用SSL验证的文件下载
YAML (Ansible) rpm-key-unencrypted-url 发现使用未加密URL(如HTTP、FTP等)的RPM密钥下载
YAML (Ansible) rpm-key-validate-certs-disabled 发现禁用SSL验证的RPM密钥
YAML (Ansible) unarchive-unencrypted-url 发现使用未加密URL(如HTTP、FTP等)的解压下载
YAML (Ansible) unarchive-validate-certs-disabled 发现禁用SSL验证的解压下载
YAML (Ansible) wrm-cert-validation-ignore 发现禁用证书验证的Windows远程管理连接
YAML (Ansible) yum-unencrypted-url 发现使用未加密URL(如HTTP、FTP等)的yum下载
YAML (Ansible) yum-validate-certs-disabled 发现禁用SSL验证的yum
YAML (Ansible) zypper-repository-unencrypted-url 发现使用未加密URL(如HTTP、FTP等)的Zypper仓库
YAML (Ansible) zypper-unencrypted-url 发现使用未加密URL(如HTTP、FTP等)的Zypper包
YAML (Docker Compose) port-all-interfaces 服务端口在所有接口上暴露

Semgrep 201:中级特性

Semgrep是一种用于查找代码模式的静态分析工具。这包括安全漏洞、错误变体、秘密检测、性能和正确性问题等。虽然Semgrep包含专有的云服务和更高级的规则,但Semgrep CLI可以免费安装并在本地运行。您可以使用以下命令运行Trail of Bits的规则,包括上述规则:

1
semgrep scan --config p/trailofbits /path/to/code

本文不会详细介绍上述每条规则。Semgrep的基础知识已被Trail of Bits和更广泛的安全社区广泛讨论,因此本文将更深入地讨论两个较少人知的Semgrep特性:通用模式和YAML支持。

通用模式

Semgrep的通用模式提供了一种搜索任意文本的简便方法。与Semgrep对Java和Python等编程语言的语法支持不同,通用模式是一种高级文本搜索。自然,这既有优点也有缺点:通用模式倾向于产生更多误报,但也会减少漏报。换句话说,它会产生更多发现,但您可能需要筛选它们。限制规则路径是避免误报的一种方法。然而,使用通用模式的主要原因在于其可以搜索的数据广度。

通用模式可以大致视为正则表达式的更人性化替代方案。它们都执行任意文本搜索,但通用模式提供了改进的换行符和其他空格处理。它还提供了Semgrep熟悉的省略号运算符、元变量,并与Semgrep生态系统的其余部分紧密集成以管理发现。任何文本文件或基于文本的数据都可以在通用模式下进行分析,因此当您想要分析较少使用的格式(如Jinja模板、NGINX配置文件、HAML模板、TOML文件、HTML内容或任何其他基于文本的格式)时,它是一个很好的选择。

通用模式的主要缺点是对其解析的文本没有语义理解。这意味着,例如,模式可能会在注释代码或其他意外位置被错误检测——换句话说,就是误报。例如,如果我们在以下代码中同时使用通用模式和python模式搜索os.system(...),我们将得到不同的结果:

1
2
3
4
5
6
import os

# Uncomment when debugging
# os.system("debugger")

os.system("run_production")

图1:带注释行的Python代码

1
2
3
4
5
6
$ semgrep scan --lang python --pattern "os.system(...)" test.py 
...                       
    test.py 
            6┆ os.system("run_production")
...
Ran 1 rule on 1 file: 1 finding.

图2:python模式语义理解注释。

1
2
3
4
5
6
7
8
$ semgrep scan --lang generic --pattern "os.system(...)" test.py 
...                       
    test.py 
            4┆ # os.system("debugger")
            ⋮┆----------------------------------------
            6┆ os.system("run_production")
...
Ran 1 rule on 1 file: 2 findings.

图3:通用模式不语义理解注释。

通用模式的另一个缺点是它错过了Semgrep的广泛等价列表。尽管如此,我们仍然认为它是搜索这些特定模式的合适工具。如果这意味着我们不会错过关键的安全错误,筛选一些误报是可以接受的。

鉴于通用模式的缺点,为什么在本文发布的许多规则中使用它?毕竟,Semgrep官方支持Bash和Dockerfiles语言。但考虑一下ssh-disable-host-key-checking规则。使用通用模式将在Bash脚本、Dockerfiles、CI配置、文档文件、各种编程语言的系统调用或其他我们甚至没有考虑的地方找到禁用StrictHostKeyChecking的SSH命令。使用官方的Bash或Dockerfile支持仅覆盖单个用例。换句话说,使用通用模式为我们提供了适用于许多不同场景的相对简单启发式的最广泛覆盖。

有关更多信息,请参阅Semgrep关于通用模式匹配的官方文档。

YAML支持

除了通用模式,YAML支持使Semgrep成为在文件系统中搜索任何基于文本的文件中的代码或文本的一站式工具。而YAML正在吞噬世界:Kubernetes配置、AWS CloudFormation、Docker Compose、GitHub Actions、GitLab CI、Argo CD、Ansible、OpenAPI规范,甚至Semgrep规则本身都是用YAML编写的。事实上,Semgrep有最佳实践规则,用Semgrep规则为Semgrep规则编写。Sem-ception。

当然,您可以在您选择的编程语言中编写一个基本实用程序,使用主流YAML库解析YAML并搜索基本启发式,但这样您就会错过Semgrep生态系统的其余部分。您可以在一个地方管理所有这些不同类型的文件和文件格式,这是Semgrep的杀手级特性。YAML规则与Python规则相邻,Python规则与Java规则相邻,Java规则与通用规则相邻。它们都在CI中一起运行,并且可以在同一地方管理发现。不再需要十个工具来处理十种文件类型。

我们最近参与了一项审计,其中包括一个大型Ansible实现。考虑到这一点,我们着手覆盖Ansible.Builtin命名空间中可能预期的许多基本安全问题。使用Semgrep的YAML规则格式搜索YAML模式可能会让您头晕,但一旦习惯了,它就会变得相对公式化。JSON和YAML等格式的高度结构化性质使得搜索模式变得简单直接。本文顶部呈现的Ansible规则相对明确,因此让我们考虑port-all-interfaces规则模式,它更明显地突出了YAML功能:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
patterns:
  - pattern-inside: |
      services:
        ...
  - pattern: |
      ports:
        - ...
        - "$PORT"
        - ...
  - focus-metavariable: $PORT
  - metavariable-regex:
      metavariable: $PORT
      regex: '^(?!127.\d{1,3}.\d{1,3}.\d{1,3}:).+'

图4:搜索在所有接口上监听端口的模式

pattern-insidepattern运算符中使用的| YAML块样式指示符表示下面的文本是纯文本字符串,而不是额外的Semgrep规则语法。Semgrep然后将此纯文本字符串解释为YAML。同样,这是YAML中的YAML,起初需要一些眯眼,但规则的其余部分是相对直接的Semgrep语法。

规则本身是寻找绑定到所有接口的服务。Docker Compose文档指出,默认情况下,在指定端口时,服务将监听0.0.0.0。此规则查找不以环回地址(如127.0.0.1)开头的端口,这表明它们监听所有接口。这并不总是一个问题,但在某些情况下可能导致防火墙绕过等问题。

用Semgrep扩展您的覆盖范围

Semgrep是一个用于在许多不同技术中查找错误的优秀工具。本文介绍了30条新的Semgrep规则,并讨论了两个较少人知的特性:通用模式和YAML支持。将YAML和通用搜索添加到Semgrep广泛支持的编程语言列表中,使其成为一个更通用的工具。有问题代码或基础设施的启发式及其相应的发现可以在一个位置管理。

如果您想了解更多关于我们在Semgrep上的工作,我们以多种方式使用了其功能,例如保护机器学习管道、发现goroutine泄漏和保护Apollo GraphQL服务器。

如果您对为您的项目定制Semgrep规则感兴趣,请联系我们。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计