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脚本和Docker Compose配置文件。这些规则专为审计这些技术中常见的安全漏洞而创建和使用。此次发布的Semgrep规则与我们的公共CodeQL查询和测试手册一同,旨在向安全社区分享我们的技术专长。本文将简要介绍新规则,并深入探讨创建这些规则时使用的两个较少人知的Semgrep特性:泛型模式和YAML支持。

规则焦点问题

本次发布的内部Semgrep规则重点关注以下问题:

  • 未加密的网络传输(如HTTP、FTP等)
  • 禁用的SSL证书验证
  • 常见命令行工具的不安全标志
  • 无限制的IP地址绑定
  • 杂项Java/Kotlin问题

新规则列表

泛型模式(Generic)

  • container-privileged: 检测具有扩展权限的容器命令
  • container-user-root: 检测以root身份运行的容器命令
  • curl-insecure: 检测禁用SSL验证的curl命令
  • curl-unencrypted-url: 检测使用未加密URL(如HTTP、FTP等)的curl命令
  • gpg-insecure-flags: 检测使用不安全标志的gpg命令
  • installer-allow-untrusted: 检测允许不受信任安装的安装程序命令
  • openssl-insecure-flags: 检测使用不安全标志的openssl命令
  • ssh-disable-host-key-checking: 检测禁用主机密钥检查的ssh命令
  • tar-insecure-flags: 检测使用不安全标志的tar命令
  • wget-no-check-certificate: 检测禁用SSL验证的wget命令
  • wget-unencrypted-url: 检测使用未加密URL(如HTTP、FTP等)的wget命令

Java/Kotlin

  • gc-call: 调用gc会建议JVM运行垃圾回收器并回收内存,但这仅是建议,不保证任何操作会发生。依赖此行为进行正确性或内存管理是一种反模式。
  • mongo-hostname-verification-disabled: 检测禁用SSL主机名验证的MongoDB客户端

YAML(Ansible)

  • apt-key-unencrypted-url: 检测使用未加密URL(如HTTP、FTP等)的apt密钥下载
  • apt-key-validate-certs-disabled: 检测禁用SSL验证的apt密钥
  • apt-unencrypted-url: 检测使用未加密URL(如HTTP、FTP等)的apt deb
  • dnf-unencrypted-url: 检测使用未加密URL(如HTTP、FTP等)的dnf下载
  • dnf-validate-certs-disabled: 检测禁用SSL验证的dnf
  • get-url-unencrypted-url: 检测使用未加密URL(如HTTP、FTP等)的文件下载
  • get-url-validate-certs-disabled: 检测禁用SSL验证的文件下载
  • rpm-key-unencrypted-url: 检测使用未加密URL(如HTTP、FTP等)的RPM密钥下载
  • rpm-key-validate-certs-disabled: 检测禁用SSL验证的RPM密钥
  • unarchive-unencrypted-url: 检测使用未加密URL(如HTTP、FTP等)的解压下载
  • unarchive-validate-certs-disabled: 检测禁用SSL验证的解压下载
  • wrm-cert-validation-ignore: 检测禁用证书验证的Windows远程管理连接
  • yum-unencrypted-url: 检测使用未加密URL(如HTTP、FTP等)的yum下载
  • yum-validate-certs-disabled: 检测禁用SSL验证的yum
  • zypper-repository-unencrypted-url: 检测使用未加密URL(如HTTP、FTP等)的Zypper仓库
  • 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规则感兴趣,请联系我们。

如果您喜欢这篇文章,请分享: Twitter LinkedIn GitHub Mastodon Hacker News

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