文章首发于先知社区:轻量级代码审计工具: Semgrep - 先知社区
Semgrep 介绍
什么是 Semgrep?
Semgrep 是一个开源的静态代码分析工具,旨在帮助开发人员和安全专家发现和修复软件代码中的安全漏洞、代码质量问题和最佳实践违规等。Semgrep 支持多种编程语言,包括但不限于 Python、JavaScript、Go、Java、PHP 等。
以下是 Semgrep 的一些主要特点和优势:
- 易于使用: Semgrep 的语法简单直观,使用 YAML 或者纯文本格式的规则定义,使得规则编写和理解变得容易。您可以根据特定的需求编写自定义规则,或者使用社区维护的规则库。
- 快速扫描: Semgrep 使用高效的静态分析算法,能够在大型代码库中进行快速扫描。它具有可扩展性,适用于小型项目和大型企业应用程序。
- 广泛的规则库: Semgrep 提供了一个丰富的规则库,涵盖了安全漏洞、常见的代码错误、最佳实践和性能问题等多个方面。您可以直接使用这些规则,也可以根据自己的需求进行定制和扩展。
- 多语言支持: Semgrep 支持多种流行的编程语言,如 Python、JavaScript、Go、Java 等。这使得它成为跨多个技术栈的团队或项目的理想选择。
- 集成和扩展性: Semgrep 可以与各种 CI/CD 工具和代码编辑器集成,例如 GitLab、GitHub Actions、Jenkins 等。此外,Semgrep 还提供了 API 和 CLI 接口,使您能够轻松集成到现有的工作流程中。
- 可定制性: Semgrep 允许您根据自己的需求创建自定义规则。您可以使用 Semgrep 提供的丰富的模式匹配语法来编写适合特定代码风格和规范的规则。
- 活跃的社区: Semgrep 拥有活跃的开源社区支持,社区维护了大量的规则库,并定期更新和改进 Semgrep 的功能和性能。
以上介绍来自于 ChatGPT ,本文的主要目的是讲解 Semgrep 使用方法以及注意事项。
Semgrep 环境搭建
Semgrep 的官方文档提供了详细的安装教程 。可参考 Semgrep Privacy Policy - Semgrep
安装 semgrep
python3 -m pip install semgrep
semgrep --version
更新 semgrep
python3 -m pip install --upgrade semgrep
Semgrep 语法教程
Semgrep 的语法非常简单,把官方的教程过一遍就可以入门了,学习成本比 CodeQL 要小很多。
Semgrep 使用
在终端使用
使用 semgrep 命令行操作时,可以通过 –help 查看 semgrep 支持的功能。
└─$ semgrep --help
Usage: semgrep [OPTIONS] COMMAND [ARGS]...
To get started quickly, run `semgrep scan --config auto`
Run `semgrep SUBCOMMAND --help` for more information on each subcommand
If no subcommand is passed, will run `scan` subcommand by default
Options:
-h, --help Show this message and exit.
Commands:
ci The recommended way to run semgrep in CI
install-semgrep-pro Install the Semgrep Pro Engine
login Obtain and save credentials for semgrep.dev
logout Remove locally stored credentials to semgrep.dev
lsp [EXPERIMENTAL] Start the Semgrep LSP server
publish Upload rule to semgrep.dev
scan Run semgrep rules on files
shouldafound Report a false negative in this project.
每一种模式对应不同的功能,其中最重要的是 scan 功能,用于扫描指定的源码,其他功能会在后续进行介绍。
└─$ semgrep scan --help
Usage: semgrep scan [OPTIONS] [TARGETS]...
Run semgrep rules on files
Searches TARGET paths for matches to rules or patterns. Defaults to searching entire
current working directory.
To get started quickly, run
semgrep --config auto .
This will automatically fetch rules for your project from the Semgrep Registry. NOTE:
Using `--config auto` will log in to the Semgrep Registry with your project URL.
For more information about Semgrep, go to https://semgrep.dev.
NOTE: By default, Semgrep will report pseudonymous usage metrics to its server if you
pull your configuration from the Semgrep registry. To learn more about how and why
these metrics are collected, please see https://semgrep.dev/docs/metrics. To modify
this behavior, see the --metrics option below.
Options:
--replacement TEXT An autofix expression that will be applied to any
matches found with --pattern. Only valid with a
command-line specified pattern.
...
使用官方规则库(Registry)进行扫描
官方维护了一个规则库(Registry)以便用户提交、查找以及选择特定的规则去扫描项目:Explore - Semgrep。其中包含了社区规则以及专业规则(Pro),社区规则存储在 github 仓库中 returntocorp/semgrep-rules: Semgrep rules registry。
Registry,根据常见的扫描需求,定制了一些扫描集合,例如 OWASP-TOP-10、CWE-TOP-25 等。
或是根据语言进行分类:
假如我们需要扫描 PHP,可以在 Registry 中进行搜索,查找结果包括 PHP 相关的规则集合,以及其中的所有规则:
可以看到官方为 PHP 归纳了三个规则集合,分别是 php、php-laravel、phpcs-security-audit。
└─$ semgrep --config "p/phpcs-security-audit" /mnt/share/project/ctf_archives/test/baijiacms
┌─────────────┐
│ Scan Status │
└─────────────┘
Scanning 2787 files tracked by git with 10 Code rules:
Scanning 748 files with 10 php rules.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:03
┌──────────────────┐
│ 89 Code Findings │
└──────────────────┘
/mnt/share/project/ctf_archives/test/baijiacms/includes/baijiacms/common.inc.php
php.lang.security.exec-use.exec-use
Executing non-constant commands. This can lead to command injection.
Details: https://sg.run/5Q1j
654┆ system('convert'.$quality_command.' '.$file_full_path.' '.$file_full_path);
⋮┆----------------------------------------
php.lang.security.weak-crypto.weak-crypto
Detected usage of weak crypto function. Consider using stronger alternatives.
Details: https://sg.run/KlBn
372┆ $seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35);
⋮┆----------------------------------------
1049┆ $package['sign'] = strtoupper(md5($string1));
...
┌──────────────┐
│ Scan Summary │
└──────────────┘
Some files were skipped or only partially analyzed.
Partially scanned: 2 files only partially analyzed due to parsing or internal Semgrep errors
Ran 10 rules on 748 files: 89 findings.
A new version of Semgrep is available. See https://semgrep.dev/docs/upgrading
使用本地规则库进行扫描
离线使用时,可以将 semgrep 官方维护的社区规则库下载到本地,使用 --config
参数指定规则库的路径进行扫描。
└─$ semgrep --config /mnt/share/Tools/web/code_audit/semgrep-rules/php /mnt/share/project/ctf_archives/test/baijiacms
┌─────────────┐
│ Scan Status │
└─────────────┘
Scanning 2788 files tracked by git with 57 Code rules:
Scanning 748 files with 40 php rules.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:12
┌──────────────┐
│ Scan Summary │
└──────────────┘
Some files were skipped or only partially analyzed.
Partially scanned: 2 files only partially analyzed due to parsing or internal Semgrep errors
Scan skipped: 5 files larger than 1.0 MB, 195 files matching .semgrepignore patterns
For a full list of skipped files, run semgrep with the --verbose flag.
Ran 57 rules on 748 files: 257 findings.
A new version of Semgrep is available. See https://semgrep.dev/docs/upgrading
semgrep 提供了 -o 参数可以输出到文件,但无论是否加不加 --force-color / --no-force-color
参数,输出到文件中的内容都会带上颜色字符,导致在文件中查看并不方便,确实有点坑,但借助 sed 可以消除这些字符。
semgrep scan --config /mnt/share/Tools/web/code_audit/semgrep-rules/php /mnt/share/project/ctf_archives/test/baijiacms --no-force-color --dataflow-traces | sed 's/\x1B\[[0-9;]*[mK]//g' > result.txt
在 vscode 中使用
vscode 中的 semgrep 插件主要用于配置规则文件路径、排除文件等,配置项如下:
其中 configuration 可以配置规则文件路径用于离线场景下的扫描,如果没有指定, semgrep 会从官方社区获取规则文件内容。
配置完后,vscode 会根据配置规则自动扫描当前 workspace,扫描结果会直接显示在 vscode 的 problem 窗口中,为了方便观察漏洞类型,可以切换树视图。
树视图下的第一列显示了匹配的规则名:
如果同时安装了对应语言的插件,Problem 窗口也会出现其他的错误信息,此时可以通过关键词过滤出 semgrep 条目。
在 Semgrep Cloud Platform (SCP) 中使用
Semgrep 云平台提供了所有 semgrep 的支持,其良好的查询以及结果展示功能是终端以及 vscode 插件所不具备的,缺点在于必须在线使用。
云平台支持 Locally 和 CI/CD 两种方式。
Locally 方式可以直接在终端中执行扫描命令,然后将结果发送到云平台。需要注意的是,这种方式需要先将源码目录初始化为一个 git 项目,否则会报错,并且无法指定特定的扫描规则,默认使用所有的规则,如下所示,这一次扫描使用了所有的 1591 条规则,其中包含了 513 条 Pro 规则。
─$ semgrep ci
┌─────────────┐
│ Scan Status │
└─────────────┘
Scanning 2763 files tracked by git with 1591 Code rules, 513 Pro rules:
Language Rules Files Origin Rules
───────────────────────────── ───────────────────
<multilang> 76 7689 Community 1078
php 60 748 Pro rules 513
js 242 273
html 1 72
yaml 27 2
bash 4 2
json 4 1
Semgrep Pro Engine may be slower and show different results than Semgrep OSS.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╸ 100% 0:23:45
...
┌──────────────┐
│ Scan Summary │
└──────────────┘
Some files were skipped or only partially analyzed.
Scan was limited to files tracked by git.
Partially scanned: 8 files only partially analyzed due to parsing or internal Semgrep errors
Scan skipped: 196 files matching --exclude patterns, 4 files larger than 1.0 MB
For a full list of skipped files, run semgrep with the --verbose flag.
CI scan completed successfully.
Found 502 findings (0 blocking) from 22014 rules.
Uploading scan results
Finalizing scan
View results in Semgrep Cloud Platform:
https://semgrep.dev/orgs/dr34d/findings
https://semgrep.dev/orgs/dr34d/supply-chain
No blocking findings so exiting with code 0
扫描完成之后,就可以在云平台中查看到扫描结果:
云平台中的查找功能还是比较好用的。
Pro 版本与社区版本
根据官方公告:Unlocking advanced security for all: Semgrep’s latest update, Semgrep 官方将对所有用户开放团队版功能,其中就包括了 Pro 引擎、规则的使用。
我们还将免费向每个由最多10个月度贡献者组成的团队提供 Semgrep Code 的团队版功能(请参阅常见问题解答)。这包括通过 Pro 引擎进行高级代码扫描,跨文件和函数边界查找漏洞,并使用由我们的安全研究团队编写的具有高可信度的 Pro 规则。我们认为这些功能对于运行现代安全程序至关重要。现在在“设置”中打开 Pro 引擎 →
为了让供应链和Code的专业功能对所有人都可用,我们将所有账户升级到团队版,并停用社区版,以求简单明了。我们认为在不同等级之间划分功能或保留功能是不利的,并希望每个用户从一开始就体验到Semgrep的全部价值。此外,为了与我们的创业计划为小团队提供的定价保持一致,并且因为我们提供更多免费的产品和功能,我们还将贡献者限制降低到10个(从20个)。
对于我们现有的团队版用户,如果您的使用量在修改后的限制范围内,并且已经付费,我们将与您联系调整账单。如果您超过了新的限制,您将有时间到 2023 年 7 月 31 日调整使用量和/或购买额外的席位。我们希望确保每个人过渡顺利;您可以通过发送电子邮件至 support@semgrep.com 咨询或反馈问题,或阅读有关定价、计费或使用限制的文档。
Pro 规则有什么不同?
Pro 规则是 Semgrep 官方维护的高可信度、专业的规则集合,仅在团队级别及以上的功能中可用,由于官方已经对所有用户开放的团队版功能,所以现在可以直接使用了。
以 php 规则集合为例,该规则集合中有 29 条都是 Pro 规则。
不登陆的情况下,使用该规则集合扫描会显示仅有 16 条规则。
semgrep scan --config "p/php" /mnt/share/project/ctf_archives/test/baijiacms | sed 's/\x1B\[[0-9;]*[mK]//g' > result.txt
┌─────────────┐
│ Scan Status │
└─────────────┘
Scanning 2789 files tracked by git with 16 Code rules:
Scanning 748 files with 16 php rules.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00
登陆之后再进行扫描就可以使用所有规则了:
semgrep scan --config "p/php" /mnt/share/project/ctf_archives/test/baijiacms | sed 's/\x1B\[[0-9;]*[mK]//g' > result.txt
┌─────────────┐
│ Scan Status │
└─────────────┘
Scanning 2789 files tracked by git with 45 Code rules, 29 Pro rules:
Scanning 748 files with 43 php rules.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:03
对比社区规则与 Pro 规则中对命令注入的匹配规则:
社区规则:exec-use.yaml,仅仅只是匹配部分命令执行函数的调用,既不全面也没有使用污点分析。
patterns:
- pattern: $FUNC(...);
- pattern-not: $FUNC('...', ...);
- metavariable-regex:
metavariable: $FUNC
regex: exec|passthru|proc_open|popen|shell_exec|system|pcntl_exec
Pro 规则:tainted-command-injection,其中使用 pattern-sources 匹配来自 $_REQUEST
等输入源, pattern-sinks 配置了部分命令执行函数,但相比之下也并不是十分完备。
pattern-sources:
- patterns:
- pattern-either:
- pattern: $_REQUEST
- pattern: $_GET
- pattern: $_POST
- pattern: $_FILES
- pattern: $_COOKIE
pattern-sinks:
- patterns:
- pattern-either:
- pattern: exec(...)
- pattern: system(...)
- pattern: passthru(...)
- pattern: shell_exec(...)
- pattern: |
`...`
- patterns:
- focus-metavariable: $COMMAND
- pattern: proc_open($COMMAND, ...)
- patterns:
- focus-metavariable: $COMMAND
- pattern: popen($COMMAND, ...)
- pattern: pcntl_exec(...)
Pro 引擎有什么不同?
想要在云平台中使用 Pro 引擎,需要按照如下的步骤进行开启:
根据开启的提示,Pro 引擎引入了文件间分析可以消除误报、引入新的结果,并且可以增加扫描时间和内存使用量。但仅在完整扫描时启用,且仅在 Java 和 Javascript 文件上运行,但在实际测试时发现其他语言也同样有效。
终端中使用 Pro 引擎需要先进行登陆:
semgrep login
根据输出访问对应的链接进行登陆。
Login enables additional proprietary Semgrep Registry rules and running custom policies from Semgrep Cloud Platform.
Login at: xxxx
终端获得 token 之后,就可以安装 pro 引擎了。
semgrep install-semgrep-pro
安装完后可以使用 --pro
参数调用 pro 引擎。
semgrep --pro --config "p/default"
Pro 规则 + Pro 引擎扫描
Pro 引擎具备跨文件分析能力,Pro 规则更为精准,所以同时使用 Pro 引擎与 Pro 规则进行扫描效果是最好的,实际测试时可以先进行登陆,扫描时添加 --pro
参数。
semgrep scan --config "p/php" /mnt/share/project/ctf_archives/test/baijiacms --pro
┌─────────────┐
│ Scan Status │
└─────────────┘
Scanning 2789 files tracked by git with 45 Code rules, 29 Pro rules:
Scanning 748 files with 43 php rules.
Semgrep Pro Engine may be slower and show different results than Semgrep OSS.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:15
扫描到的结果确实相对更多,但输出的格式确实一言难尽,十分不方便查看,而 vscode 插件中也没有内置 pro 参数。为了良好的展示效果似乎只能通过 Semgrep 云平台了。
┌──────────────────┐
│ 16 Code Findings │
└──────────────────┘
/mnt/share/project/ctf_archives/test/baijiacms/includes/baijiacms/common.inc.php
php.lang.security.injection.tainted-filename.tainted-filename
File name based on user input risks server-side request forgery.
Details: https://sg.run/Ayqp
501┆ if(is_uploaded_file($filename)) {
Taint comes from:
597┆ $filename = random(15) . ".{$extention}";
Taint flows through these intermediate variables:
372┆ $seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 :
35);
382┆ $hash .= $seed{mt_rand(0, $max)};
then reaches:
372┆ $seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 :
35);
Taint flows through these intermediate variables:
597┆ $filename = random(15) . ".{$extention}";
602┆ $file_tmp_name = SYSTEM_WEBROOT . $path . $extpath. $filename;
This is how taint reaches the sink:
609┆ return file_save($file_tmp_name,$filename,$extention,$file_full_path,$file_relative_path);
Taint flows through these intermediate variables:
637┆ function
file_save($file_tmp_name,$filename,$extention,$file_full_path,$file_relative_path,$allownet=true)
then call to:
642┆ if(!file_move($file_tmp_name, $file_full_path)) {
Taint flows through these intermediate variables:
499┆ function file_move($filename, $dest) {
then reaches:
501┆ if(is_uploaded_file($filename)) {
⋮┆----------------------------------------
506┆ return is_file($dest);
Taint comes from:
581┆ $filename = random(15) . ".{$extention}";
Taint flows through these intermediate variables:
372┆ $seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 :
35);
382┆ $hash .= $seed{mt_rand(0, $max)};
then reaches:
372┆ $seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 :
35);
Taint flows through these intermediate variables:
581┆ $filename = random(15) . ".{$extention}";
584┆ $file_full_path = WEB_ROOT . $path . $extpath. $filename;
This is how taint reaches the sink:
586┆ return
file_save($file['tmp_name'],$filename,$extention,$file_full_path,$file_relative_path);
Taint flows through these intermediate variables:
637┆ function
file_save($file_tmp_name,$filename,$extention,$file_full_path,$file_relative_path,$allownet=true)
then call to:
642┆ if(!file_move($file_tmp_name, $file_full_path)) {
Taint flows through these intermediate variables:
499┆ function file_move($filename, $dest) {
then reaches:
506┆ return is_file($dest);
...
在等出的情况下使用 --pro
参数,semgrep 会提示要求登陆后使用,但扫描时间与扫描结果与不添加 --pro
参数时也不一样。,重新登陆之后再次扫描,发现结果居然与不登陆的时候一样(!!?)
└─$ semgrep scan --config /mnt/share/Tools/web/code_audit/semgrep-rules/php /mnt/share/project/ctf_archives/test/baijiacms --pro
┌─────────────┐
│ Scan Status │
└─────────────┘
Scanning 2767 files tracked by git with 57 Code rules:
Scanning 748 files with 40 php rules.
!!!This is a proprietary extension of semgrep.!!!
!!!You must be logged in to access this extension!!!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:30
注意:隐私策略
根据官方的隐私策略 Semgrep Privacy Policy - Semgrep 的相关描述。
$ semgrep --config=myrule.yaml # → no metrics (loading rules from local file)
$ semgrep --config=p/python # → metrics enabled (fetching Registry)
$ semgrep login && semgrep ci # → metrics enabled (logged in to semgrep.dev)
- 当仅使用本地配置文件或命令行搜索模式运行时,官方不会收集相关信息。
- 当使用 Registry 中的规则时,官方会收集所需数据以帮助维护人员完善规则。
- 当使用云平台时,官方也会收集这些数据,并且将结果存放在云平台中。
收集数据的具体内容可见:Data collected as metrics
用户也可以通过指定 --metrics
选项来控制数据的发送。
--metrics auto:(默认)每当从 Semgrep 注册表中提取规则时都会发送
--metrics on:每次 Semgrep 运行时都会发送
--metrics off:永远不会发送
如果有隐私考虑的话,建议离线使用规则库,并添加 --metrics off
参数。
其他资源
在线测试
官方提供了一个 Playground 来辅助规则的编写
一些开源规则库
github 中有一些开源出来的规则库可供参考。
- 0xdea/semgrep-rules: A collection of my Semgrep rules to facilitate vulnerability research.: C\C++
- federicodotta/semgrep-rules: A collection of my Semgrep rules
- trailofbits/semgrep-rules: Semgrep queries developed by Trail of Bits.: GO、JavaScript、Python、Rs
- dgryski/semgrep-go: Go rules for semgrep and go-ruleguard: GO
- elttam/semgrep-rules: C、C#、Java、Kotlin、Python、PHP
- frappe/semgrep-rules: Semgrep rules specific to Frappe Framework
- Decurity/semgrep-smart-contracts: Semgrep rules for smart contracts based on DeFi exploits:Solidity
- mindedsecurity/semgrep-rules-android-security: A collection of Semgrep rules derived from the OWASP MASTG specifically for Android applications.: Java
- vmnguyen/semgrep-rules: My custom semgrep rules:Java、Golang、Python、Javascript
结语
本文对 semgrep 的基本使用以及注意事项进行了介绍,本人也是第一次使用,如有错误请及时指出。从结果来看,semgrep 优点在于轻量级,扫描速度快、规则定制简单,但污点分析能力并不算强,如果去定制一些规则去做危险函数匹配,配合 vscode 插件,对代码审计还是有帮助的。
编写规则如果想省事也可以交给 chatGPT
I want you to act as a code audit expert specializing in semgrep rules. Your role will involve helping me understand and utilize semgrep effectively for code review purposes. You should be proficient in semgrep’s syntax, rules, and patterns. Your tasks will include explaining the purpose and functionality of existing semgrep rules, assisting in the interpretation of semgrep scan results, and guiding me in the customization and creation of custom semgrep rules. Your expertise in code auditing and semgrep will be crucial in ensuring the thoroughness and accuracy of our code reviews, helping us identify and address potential security vulnerabilities, bugs, and best practice violations.
prompt 取自:DummyKitty/Cyber-Security-chatGPT-prompt: some prompt about cyber security