Vulnerabilities > CVE-2016-8027 - SQL Injection vulnerability in Mcafee Epolicy Orchestrator

047910
CVSS 7.5 - HIGH
Attack vector
NETWORK
Attack complexity
LOW
Privileges required
NONE
Confidentiality impact
PARTIAL
Integrity impact
PARTIAL
Availability impact
PARTIAL
network
low complexity
mcafee
CWE-89
nessus

Summary

SQL injection vulnerability in core services in Intel Security McAfee ePolicy Orchestrator (ePO) 5.3.2 and earlier and 5.1.3 and earlier allows attackers to alter a SQL query, which can result in disclosure of information within the database or impersonation of an agent without authentication via a specially crafted HTTP post.

Common Attack Pattern Enumeration and Classification (CAPEC)

  • Command Line Execution through SQL Injection
    An attacker uses standard SQL injection methods to inject data into the command line for execution. This could be done directly through misuse of directives such as MSSQL_xp_cmdshell or indirectly through injection of data into the database that would be interpreted as shell commands. Sometime later, an unscrupulous backend application (or could be part of the functionality of the same application) fetches the injected data stored in the database and uses this data as command line arguments without performing proper validation. The malicious data escapes that data plane by spawning new commands to be executed on the host.
  • Object Relational Mapping Injection
    An attacker leverages a weakness present in the database access layer code generated with an Object Relational Mapping (ORM) tool or a weakness in the way that a developer used a persistence framework to inject his or her own SQL commands to be executed against the underlying database. The attack here is similar to plain SQL injection, except that the application does not use JDBC to directly talk to the database, but instead it uses a data access layer generated by an ORM tool or framework (e.g. Hibernate). While most of the time code generated by an ORM tool contains safe access methods that are immune to SQL injection, sometimes either due to some weakness in the generated code or due to the fact that the developer failed to use the generated access methods properly, SQL injection is still possible.
  • SQL Injection through SOAP Parameter Tampering
    An attacker modifies the parameters of the SOAP message that is sent from the service consumer to the service provider to initiate a SQL injection attack. On the service provider side, the SOAP message is parsed and parameters are not properly validated before being used to access a database in a way that does not use parameter binding, thus enabling the attacker to control the structure of the executed SQL query. This pattern describes a SQL injection attack with the delivery mechanism being a SOAP message.
  • Expanding Control over the Operating System from the Database
    An attacker is able to leverage access gained to the database to read / write data to the file system, compromise the operating system, create a tunnel for accessing the host machine, and use this access to potentially attack other machines on the same network as the database machine. Traditionally SQL injections attacks are viewed as a way to gain unauthorized read access to the data stored in the database, modify the data in the database, delete the data, etc. However, almost every data base management system (DBMS) system includes facilities that if compromised allow an attacker complete access to the file system, operating system, and full access to the host running the database. The attacker can then use this privileged access to launch subsequent attacks. These facilities include dropping into a command shell, creating user defined functions that can call system level libraries present on the host machine, stored procedures, etc.
  • SQL Injection
    This attack exploits target software that constructs SQL statements based on user input. An attacker crafts input strings so that when the target software constructs SQL statements based on the input, the resulting SQL statement performs actions other than those the application intended. SQL Injection results from failure of the application to appropriately validate input. When specially crafted user-controlled input consisting of SQL syntax is used without proper validation as part of SQL queries, it is possible to glean information from the database in ways not envisaged during application design. Depending upon the database and the design of the application, it may also be possible to leverage injection to have the database execute system-related commands of the attackers' choice. SQL Injection enables an attacker to talk directly to the database, thus bypassing the application completely. Successful injection can cause information disclosure as well as ability to add or modify data in the database. In order to successfully inject SQL and retrieve information from a database, an attacker:

Nessus

NASL familyWindows
NASL idMCAFEE_EPO_SB10187.NASL
descriptionThe remote Windows host is running a version of McAfee ePolicy Orchestrator 5.1.x prior to 5.1.3 hotfix 1167014, 5.3.x prior to 5.3.1 hotfix 1179709, or 5.3.x prior to 5.3.2 hotfix 1167013. It is, therefore, affected by a blind SQL injection vulnerability in the ePolicy Orchestrator (ePO) Core Services component due to a failure to properly sanitize user-supplied input to unspecified parameters. An unauthenticated, remote attacker can exploit this vulnerability, via a specially crafted HTTP POST request, to inject or manipulate SQL queries, resulting in the disclosure or manipulation of arbitrary data.
last seen2020-06-01
modified2020-06-02
plugin id97352
published2017-02-23
reporterThis script is Copyright (C) 2017-2019 and is owned by Tenable, Inc. or an Affiliate thereof.
sourcehttps://www.tenable.com/plugins/nessus/97352
titleMcAfee ePolicy Orchestrator 5.1.x < 5.1.3 HF1167014 / 5.3.x < 5.3.1 HF1179709 / 5.3.x < 5.3.2 HF1167013 Blind SQL Injection (SB10187)
code
#
# (C) Tenable Network Security, Inc.
#

include("compat.inc");

if (description)
{
  script_id(97352);
  script_version("1.6");
  script_cvs_date("Date: 2019/11/13");

  script_cve_id("CVE-2016-8027");
  script_bugtraq_id(95981);
  script_xref(name:"MCAFEE-SB", value:"SB10187");

  script_name(english:"McAfee ePolicy Orchestrator 5.1.x < 5.1.3 HF1167014 / 5.3.x < 5.3.1 HF1179709 / 5.3.x < 5.3.2 HF1167013 Blind SQL Injection (SB10187)");
  script_summary(english:"Checks the version of ePolicy Orchestrator.");

  script_set_attribute(attribute:"synopsis", value:
"The remote Windows host is affected by a blind SQL injection
vulnerability.");
  script_set_attribute(attribute:"description", value:
"The remote Windows host is running a version of McAfee ePolicy
Orchestrator 5.1.x prior to 5.1.3 hotfix 1167014, 5.3.x prior to 5.3.1 
hotfix 1179709, or 5.3.x prior to 5.3.2 hotfix 1167013. It is,
therefore, affected by a blind SQL injection vulnerability in the
ePolicy Orchestrator (ePO) Core Services component due to a failure to
properly sanitize user-supplied input to unspecified parameters. An
unauthenticated, remote attacker can exploit this vulnerability, via a
specially crafted HTTP POST request, to inject or manipulate SQL
queries, resulting in the disclosure or manipulation of arbitrary
data.");
  script_set_attribute(attribute:"see_also", value:"https://kc.mcafee.com/corporate/index?page=content&id=SB10187");
  script_set_attribute(attribute:"see_also", value:"http://www.talosintelligence.com/reports/TALOS-2016-0229/");
  script_set_attribute(attribute:"solution", value:
"Upgrade to McAfee ePO version 5.1.3 hotfix 1167014 / 5.3.1 hotfix
1179709 / 5.3.2 hotfix 1167013 or later.");
  script_set_cvss_base_vector("CVSS2#AV:N/AC:L/Au:N/C:P/I:P/A:P");
  script_set_cvss_temporal_vector("CVSS2#E:U/RL:OF/RC:C");
  script_set_cvss3_base_vector("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H");
  script_set_cvss3_temporal_vector("CVSS:3.0/E:U/RL:O/RC:C");
  script_set_attribute(attribute:"cvss_score_source", value:"CVE-2016-8027");

  script_set_attribute(attribute:"exploitability_ease", value:"No known exploits are available");
  script_set_attribute(attribute:"exploit_available", value:"false");

  script_set_attribute(attribute:"vuln_publication_date", value:"2017/02/01");
  script_set_attribute(attribute:"patch_publication_date", value:"2017/02/01");
  script_set_attribute(attribute:"plugin_publication_date", value:"2017/02/23");

  script_set_attribute(attribute:"plugin_type", value:"local");
  script_set_attribute(attribute:"cpe", value:"cpe:/a:mcafee:epolicy_orchestrator");
  script_end_attributes();

  script_category(ACT_GATHER_INFO);
  script_family(english:"Windows");

  script_copyright(english:"This script is Copyright (C) 2017-2019 and is owned by Tenable, Inc. or an Affiliate thereof.");

  script_dependencies("mcafee_epo_installed.nasl");
  script_require_keys("SMB/Registry/Enumerated", "installed_sw/McAfee ePO");
  script_require_ports(139, 445);

  exit(0);
}

include("audit.inc");
include("smb_func.inc");
include("smb_hotfixes.inc");
include("smb_hotfixes_fcheck.inc");
include("misc_func.inc");
include("install_func.inc");
include("bsal.inc");
include("byte_func.inc");
include("zip.inc");

app_name = "McAfee ePO";
install = get_single_install(
  app_name : app_name,
  exit_if_unknown_ver : TRUE
);
dir = install['path'];
build_ver = install['version'];
report = NULL;

# Only version 5.1.x and 5.3.x branches are affected.
# We need the build numbers to construct the Hotfix path later
# to prevent it from auditing out during the EPOCore.jar version
# check:
# https://kc.mcafee.com/corporate/index?page=content&id=KB61057
if(build_ver =~ "^5\.1\.0\..*$")
{
  hf_jar_fix_ver = '5.1.3.272';
  req_build_ver = '5.1.0.509';
  hf_report = 'Upgrade to ePO 5.1.3 and then apply hotfix EPO513HF1167014.zip.';
}
else if(build_ver =~ "^5\.1\.1\..*$")
{
  hf_jar_fix_ver = '5.1.3.272';
  req_build_ver = '5.1.1.357';
  hf_report = 'Upgrade to ePO 5.1.3 and then apply hotfix EPO513HF1167014.zip.';
}
else if(build_ver =~ "^5\.1\.2\..*$")
{
  hf_jar_fix_ver = '5.1.3.272';
  req_build_ver = '5.1.2.348';
  hf_report = 'Upgrade to ePO 5.1.3 and then apply hotfix EPO513HF1167014.zip.';
}
else if(build_ver =~ "^5\.1\.3\..*$")
{
  hf_jar_fix_ver = '5.1.3.272';
  req_build_ver = '5.1.3.188';
  hf_report = 'Apply hotfix EPO513HF1167014.zip.';
}
else if(build_ver =~ "^5\.3\.0\..*$")
{
  hf_jar_fix_ver = '5.3.1.271';
  req_build_ver = '5.3.0.400';
  hf_report = 'Upgrade to ePO 5.3.1 and then apply hotfix EPO531HF1179709.zip.';
}
else if(build_ver =~ "^5\.3\.1\..*$")
{
  hf_jar_fix_ver = '5.3.1.271';
  req_build_ver = '5.3.1.188';
  hf_report = 'Apply hotfix EPO531HF1179709.zip.';
}
else if(build_ver =~ "^5\.3\.2\..*$")
{
  hf_jar_fix_ver = '5.3.2.229';
  req_build_ver = '5.3.2.156';
  hf_report = 'Apply hotfix EPO532HF1167013.zip.';
}
else audit(AUDIT_INST_PATH_NOT_VULN, app_name, build_ver, dir);

# Based on the required build number version, extract the "Specification-Version"
# from the EPOCore.jar file's META-INF\MANIFEST.MF if it exists.

# Get one of the modified JAR files.
hf_jar_path = "\server\extensions\installed\EPOCore\" + req_build_ver + "\webapp\WEB-INF\lib\EPOCore.jar";
jar_path = hotfix_append_path(path:dir, value:hf_jar_path);
jar_contents = hotfix_get_file_contents(jar_path);
hotfix_handle_error(error_code:jar_contents['error'], file:jar_path, exit_on_fail:TRUE);
hotfix_check_fversion_end();

# Get the version from the manifest.
manifest = zip_parse(blob:jar_contents['data'], "META-INF/MANIFEST.MF");
match = pregmatch(string:manifest, pattern:"Specification-Version: ((\d+\.?)+)");
if (isnull(match)) exit(1, "Failed to parse specification version from manifest.");
jar_ver = match[1];

port = kb_smb_transport();

# Compare EPOCore.jar's reported file version to the version the patches replace.
if(ver_compare(ver:jar_ver, fix:hf_jar_fix_ver, strict:FALSE) < 0)
{
  report =
    '\n Application : McAfee ePolicy Orchestrator ' + build_ver +
    '\n Path        : ' + jar_path +
    '\n Version     : ' + jar_ver +
    '\n Fix Version : ' + hf_jar_fix_ver +
    '\n Fix         : ' + hf_report +
    '\n';
  security_report_v4(severity:SECURITY_HOLE, port:port, extra:report, sqli:TRUE);
  exit(0);
}
else audit(AUDIT_INST_VER_NOT_VULN, app_name + "'s EPOCore.jar", jar_ver);

Seebug

bulletinFamilyexploit
description### Summary An exploitable blind sql injection vulnerability exists within McAfee's ePolicy Orchestrator 5.3.0 that is accessible without authentication. A specially crafted HTTP post can allow an aggressor to alter a sql query which can result in disclosure of information within the database or impersonation of an agent. An attacker can use any HTTP client to trigger this vulnerability. ### Tested Versions McAfee's ePolicy Orchestrator 5.3.0 ### Product URLs http://www.mcafee.com/us/products/epolicy-orchestrator.aspx(http://www.mcafee.com/us/products/epolicy-orchestrator.aspx) ### CVSSv3 Score 8.2 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:L ### Details McAfee's ePolicy Orchestrator is a centralized security management suite that is used to manage antivirus and policies within the enterprise. These types of software are also known as an HBSS or Host-based Security System. It is used to manage a number of agents which are deployed in the enterprise and can be used to enforce defenses and software policies in a scalable manner. McAfee's ePolicy Orchestrator is composed of a number of components. This consists of a load-balancer which is driven by Apache and extended via custom modules. The Console itself which is based on Tomcat, and is used by staff to manage the entirety of the software. The last component are the agents themselves which are deployed on each client machine. The agents communicate over a proprietary protocol known as SPIPE to Apache which is then forwarded to the Console. This specific vulnerability is located within the application server and is reachable over SPIPE or via the Console directly. Within the Tomcat server component, which may be reachable on port 8443 in most configurations, are a number of servlets which serve as the management component of the application. The DataChannel servlet is actually mapped to a POST request received against "https://<server:port>/receiveDataChannelMsg.dcp" and is implement by the class "com.mcafee.epo.dataChannel.servlet.EPODataChannelServlet". This resource is normally not reachable without authentication, however there is another servlet that is responsible for forwarding requests to this servlet for an agent. This servlet is the "com.mcafee.epo.dataChannel.servlet.redirect.EPODataChannelRedirectServlet" class and is mapped to "https://<server:port>/dcRedirect/dataChannelMsg.dc". This resource will receive a POST request without authentication and then forward it to the "/receiveDataChannelMsg.dcp" for processing without needing authentication. Once the POST request is received by the EPODataChannelServlet class, the following code will be executed. When calling the ProcessIncomingMessage function, this will eventually call the EPOBaseDataChannelData.unpackLittleEndian_DataPacket method. This method will decode a structure from the POST's content which contains the message type, it's origin, and most importantly the Agent's GUID as well as some other fields. Afterwards this object will then get passed to the EPODataChannelMessagingService.receiveAgentMessage method. ``` com.mcafee.epo.dataChannel.servlet.EPODataChannelServlet:49 protected void doPost(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse) throws ServletException, IOException { ... try { BeanFactory localBeanFactory = (BeanFactory)getServletContext().getAttribute("beanFactory"); EPODataChannelReceiveAction localEPODataChannelReceiveAction = (EPODataChannelReceiveAction)localBeanFactory.getBean("epo.dataChannel.action"); localEPODataChannelReceiveAction.ProcessIncomingMessage(paramHttpServletRequest, paramHttpServletResponse); // \ } \ byte[] arrayOfByte = readBytesFromRequest(paramHttpServletRequest); // XXX: reads bytes from POST request try { EPOBaseDataChannelData localEPOBaseDataChannelData = EPOBaseDataChannelData.unpackLittleEndian_DataPacket(arrayOfByte); // XXX: Decodes bytes into an object boolean bool = this.m_service.receiveAgentMessage(localEPOBaseDataChannelData); // XXX if (!bool) { m_log.error("could not process incoming message"); } } ``` The EPODataChannelMessagingService.receiveAgentMesage method will then forward the object containing the unpacked data to the DataChannelMessagingServiceInternal.receiveAgentMessage method. This method will check to see that the Agent GUID in the packet is defined, and then call the EPOComputerService.getByAgentGUIDNoUserCheck method using the AgentGUID as its only argument. ``` com.mcafee.epo.dataChannel.service.DataChannelMessageServiceInternal:325 public boolean receiveAgentMessage(EPOBaseDataChannelData paramEPOBaseDataChannelData) throws EPODataChannelException { if (paramEPOBaseDataChannelData == null) { throw new EPODataChannelException("Empty message received"); } String str = paramEPOBaseDataChannelData.getMessageType(); if ((str == null) || (str.length() < 1)) { throw new EPODataChannelException("Invalid length of message type received"); } ... localConnection = getDatabase().getConnection(localOrionUser); localOrionUser = getUserForMessage(localConnection, paramEPOBaseDataChannelData); // \ \ private OrionUser getUserForMessage(Connection paramConnection, EPOBaseDataChannelData paramEPOBaseDataChannelData) { OrionUser localOrionUser = getUserLoader().getDefaultTenantSystemUser(); try { String str = paramEPOBaseDataChannelData.getAgentGUID(); // XXX: from POST request if ((str != null) && (str.length() > 0)) { EPOComputer localEPOComputer = getComputerService().getByAgentGUIDNoUserCheck(paramConnection, str); // XXX ``` In the EPOComputerService class, the getByAgentGUIDNoUserCheck method is contains the sql injection vulnerability. This method will simply take the provided Agent GUID and use it to build a query using the EPOComputerDataMapper class which will then be executed over the jdbc connection. ``` com.mcafee.epo.core.services.EPOComputerServiceInternal:159 public EPOComputer getByAgentGUIDNoUserCheck(Connection paramConnection, String paramString) throws SQLException { if ("N/A".equals(paramString)) { return null; } String str = getComputerMapper().getSelectSql(false) + "where (AgentGUID = '" + paramString + "')"; // XXX List localList = getComputerMapper().getByQuery(paramConnection, str); if ((localList == null) || (localList.isEmpty())) { return null; } EPOComputer localEPOComputer = (EPOComputer)localList.get(0); loadLdapPropsForComputer(paramConnection, localEPOComputer); return localEPOComputer; } ``` This results in the EPOComputerDatabaseMapper class building a query that looks like the following. ``` select AutoID, Type, NodeName, ParentID, AgentPlatform, ResortEnabled, AgentGUID, SequenceErrorCount, SequenceErrorCountLastUpdate, SuperAgent, TenantId from [EPOLeafNode] where (AgentGUID = '%s') ``` ### Protocol Implementation In some configurations, the console may not be directly reachable by an agent. The method by which an agent communicates to the console, however, is through the Apache based load balancer using a proprietary protocol known as SPIPE. This can be reached via the uri "https:///spipe". This request is implemented by an Apache extension module named mod_epo.dll which can perform a number of operations. To perform these operations, the module initially registers a couple handlers, one of which is responsible for forwarding the request to the library responsible for implementing the SPIPE protocol. When a request is made to the "/spipe" resource, the following code will be executed. Afterwards, the VERB will be checked if it's an HTTP POST which will then cause the module to initialize the EPO Handler if it hasn't been initialized already and then call a function responsible for handling the POST request. ``` .text:54609BBC loc_54609BBC: ; CODE XREF: epo_handler_9a60+D0j .text:54609BBC 0B0 6A 06 push 6 ; size_t .text:54609BBE 0B4 68 0C DA 60 54 push offset str./spipe ; "/spipe" .text:54609BC3 0B8 8B 86 E0 00 00 00 mov eax, [esi+0E0h] .text:54609BC9 0B8 50 push eax ; char * .text:54609BCA 0BC FF 15 E8 C1 60 54 call ds:strncmp ; [library] MSVCR100.dll .text:54609BD0 0BC 83 C4 0C add esp, 0Ch ... .text:54609C1D loc_54609C1D: ; CODE XREF: epo_handler_9a60+17Aj .text:54609C1D 0B0 8B 46 4C mov eax, [esi+4Ch] .text:54609C20 0B0 83 F8 02 cmp eax, 2 .text:54609C23 0B0 74 72 jz short loc_54609C97 ... .text:54609C97 loc_54609C97: ; CODE XREF: epo_handler_9a60+1C3j .text:54609C97 0B0 E8 E4 05 00 00 call epoStart_a280 .text:54609C9C 0B0 8B D8 mov ebx, eax ... .text:54609F02 0B0 8D 8D 78 FF FF FF lea ecx, [ebp+lv_apacheObject?_88] ; [object] gvtbl_f25c .text:54609F08 0B0 E8 23 06 00 00 call mod_epo_ProcessPostRequest_a530 ; [completed] 0x0 .text:54609F0D 0B0 89 45 A8 mov [ebp+lv_result_58], eax ``` This function is simply responsible for checking that the Content-Length of the POST request is larger than 0xea bytes and will then proceed to call into the NAIMSERV.DLL library which contains the majority of the SPIPE implementation. This size represents the header of the SPIPE protocol. ``` .text:5460A74C loc_5460A74C: ; CODE XREF: mod_epo_ProcessPostRequest_a530+1D5j .text:5460A74C 0C0 B9 EA 00 00 00 mov ecx, 0EAh .text:5460A751 0C0 3B CB cmp ecx, ebx .text:5460A753 0C0 1B D2 sbb edx, edx .text:5460A755 0C0 F7 DA neg edx .text:5460A757 0C0 89 55 8C mov [ebp+var_74], edx .text:5460A75A 0C0 75 47 jnz short loc_5460A7A3 ... .text:5460A7A3 0C0 A1 84 26 61 54 mov eax, gpf_naimserv(?)_12684 ; [external] naimserv.dll!ProcessPostRequest_fe40 .text:5460A7A8 0C0 85 C0 test eax, eax .text:5460A7AA 0C0 74 10 jz short error(noProcessPostRequestEntryPoint)_a7bc .text:5460A7AC .text:5460A7AC 0C0 56 push esi .text:5460A7AD 0C4 53 push ebx .text:5460A7AE 0C8 57 push edi .text:5460A7AF 0CC FF D0 call eax ; gpf_naimserv(?)_12684 .text:5460A7B1 0C0 89 45 94 mov [ebp+lv_httpStatus_6c], eax ``` NAIMSERV.DLL registers a couple of callbacks, one of which is responsible for processing the POST request. Eventually after some checks, the module will encounter the following code which will xor all the bytes in the POST's content with the byte 0xAA. Immediately after decoding, the application will process the header and store it into an object which is used to determine the version of the SPIPE package as well as store extra data that's interpreted as a list of key/value pairs. The version of the SPIPE package can be one of the following values: 0x40000001, 0x50000001, or 0x60000001. ``` .text:54C0FEE5 1110 8D 95 DC EF FF FF lea edx, [ebp+lv_supports2048bitRsa_1024] .text:54C0FEEB 1110 52 push edx .text:54C0FEEC 1114 8B 45 0C mov eax, [ebp+av_contentLength_4] .text:54C0FEEF 1114 50 push eax .text:54C0FEF0 1118 E8 AB 0D 05 00 call sub_54C60CA0 ; [synopsis] xor's every byte in content with 0xaa .text:54C0FEF5 1118 83 C4 08 add esp, 8 ... .text:54C0FF97 1110 8D 8D D0 FD FF FF lea ecx, [ebp+lvo_string_230] .text:54C0FF9D 1110 51 push ecx .text:54C0FF9E 1114 8B 55 0C mov edx, [ebp+av_contentLength_4] .text:54C0FFA1 1114 52 push edx .text:54C0FFA2 1118 8D 95 B4 FD FF FF lea edx, [ebp+lvo_string_24c] .text:54C0FFA8 1118 8B B5 C8 EF FF FF mov esi, [ebp+lp_content_1038] .text:54C0FFAE 1118 8B CE mov ecx, esi .text:54C0FFB0 1118 E8 DB 8A 01 00 call sub_54C28A90 ; [input] %ecx=packetData?,%edx=v_string .text:54C0FFB0 ; [synopsis] checks the packet header for the minimum Spipe version and a few other things. .text:54C0FFB0 ; [output] %eax=v_headerResult ``` If a version 4 packet is used, then the application will use the DES3 algorithm to decrypt the extra data. Version 6, however relies on using SSL. Within this same function, the library will extract the SupportedSPIPEVersion string which could be "4.0", "5.0", or "6.0". ``` .text:54C1024E 1110 8B 45 0C mov eax, [ebp+av_contentLength_4] .text:54C10251 1110 50 push eax .text:54C10252 1114 8B D6 mov edx, esi .text:54C10254 1114 8D 85 D0 F6 FF FF lea eax, [ebp+lvo_spipeExtraDataObject_930] .text:54C1025A 1114 E8 C1 70 00 00 call sub_54C17320 ; [note] stored to 271(%eax) and 0x400 bytes in size .text:54C1025A ; [input] %edx=postData,%eax=someObject .text:54C1025A ; [synopsis] extracts from an epo packet the string for "SupportedSPIPEVersion" ... .text:54C102D8 1110 8B 45 0C mov eax, [ebp+av_contentLength_4] .text:54C102DB 1110 50 push eax .text:54C102DC 1114 8B D6 mov edx, esi .text:54C102DE 1114 8D 85 D0 F6 FF FF lea eax, [ebp+lvo_spipeExtraDataObject_930] .text:54C102E4 1114 E8 C7 6D 00 00 call sub_54C170B0 ; [note] stored to 1f0(%eax) and 0x81 bytes in size .text:54C102E4 ; [synopsis] extracts from an epo packet the string for "ServerKeyHash". .text:54C102E9 1110 89 85 D4 EF FF FF mov [ebp+lp_extraPacketRequest_102c], eax ... .text:54C10445 1110 8B 45 0C mov eax, [ebp+av_contentLength_4] .text:54C10448 1110 50 push eax .text:54C10449 1114 8B D6 mov edx, esi .text:54C1044B 1114 8D 85 D0 F6 FF FF lea eax, [ebp+lvo_spipeExtraDataObject_930] .text:54C10451 1114 E8 2A 6C 00 00 call sub_54C17080 ; [note] stored to 671(%eax) and 0x40 bytes in size .text:54C10451 ; [synopsis] extracts from an epo packet the string for "TenantId" ``` Afterwards, the module will then use these values to locate the Agent's public key. This public key will be used to verify that the SPIPE package has not been tampered with. Once this is done, then the application will check the Server's key against the value of the "ServerKeyHash" field provided in the packet. A few more checks later and the module will finally encounter the function responsible for actually handling the Agent's request. ``` .text:54C10683 1110 8B BD C8 EF FF FF mov edi, [ebp+lp_content_1038] .text:54C10689 1110 8D 4F 16 lea ecx, [edi+16h] ; lpString .text:54C1068C 1110 89 8D D0 EF FF FF mov [ebp+lp_tenantIdString?_1030], ecx .text:54C10692 1110 8D 95 A0 EF FF FF lea edx, [ebp+lv_databaseId_1060] .text:54C10698 1110 52 push edx ; int .text:54C10699 1114 8D 85 A4 EF FF FF lea eax, [ebp+lv_105C] .text:54C1069F 1114 50 push eax ; int .text:54C106A0 1118 8D 95 9C EF FF FF lea edx, [ebp+lv_size_1064] .text:54C106A6 1118 52 push edx ; int .text:54C106A7 111C 8D 85 EC FD FF FF lea eax, [ebp+lv_buffer(512)?_214] .text:54C106AD 111C 50 push eax ; int .text:54C106AE 1120 E8 3D 10 01 00 call GetAgentPublicKey_216f0 ... .text:54C10754 1110 8B 95 C4 EF FF FF mov edx, [ebp+var_103C] .text:54C1075A 1110 52 push edx .text:54C1075B 1114 8B 45 0C mov eax, [ebp+av_contentLength_4] .text:54C1075E 1114 50 push eax .text:54C1075F 1118 8D 95 CC EF FF FF lea edx, [ebp+var_1034] .text:54C10765 1118 8B CF mov ecx, edi .text:54C10767 1118 E8 34 06 05 00 call VerifySignedKeyPkgSignature_60da0 .text:54C1076C 1118 83 C4 08 add esp, 8 .text:54C1076F 1110 89 85 E8 EF FF FF mov [ebp+lv_flag?_1018], eax ... .text:54C107E3 1110 8B 55 0C mov edx, [ebp+av_contentLength_4] .text:54C107E6 1110 52 push edx .text:54C107E7 1114 8B D7 mov edx, edi .text:54C107E9 1114 8D 8D D0 F6 FF FF lea ecx, [ebp+lvo_spipeExtraDataObject_930] .text:54C107EF 1114 E8 7C 5F 00 00 call CEPODataPackage::Buffer2Data_16770 ... .text:54C10CE3 1110 8B 8D CC EF FF FF mov ecx, [ebp+var_1034] .text:54C10CE9 1110 51 push ecx .text:54C10CEA 1114 8B 95 A4 EF FF FF mov edx, [ebp+lv_105C] .text:54C10CF0 1114 52 push edx .text:54C10CF1 1118 8D 95 EC EF FF FF lea edx, [ebp+lv_someSPIPEObject_1014] .text:54C10CF7 1118 8D 8D D0 F6 FF FF lea ecx, [ebp+lvo_spipeExtraDataObject_930] .text:54C10CFD 1118 E8 0E 0F 01 00 call AgentRequestHandler_21c10 ; [input] %ecx=spipeExtraObject ``` Inside the AgentRequestHandler function, the application will then check the PackageType field from the packet in order to determine how to handle an Agent's request. When encountering the following function, the library will populate the object at @ebp-0x17d8 with values from the packet. One of these is the Agent's GUID. ``` .text:54C22107 187C 8B C1 mov eax, ecx .text:54C22109 187C 8B 95 14 E8 FF FF mov edx, [ebp+var_17EC] .text:54C2210F 187C 52 push edx .text:54C22110 1880 50 push eax .text:54C22111 1884 8D B5 28 E8 FF FF lea esi, [ebp+lv_agentInfoObject_17D8] .text:54C22117 1884 8B CF mov ecx, edi .text:54C22119 1884 E8 32 E5 02 00 call server_GetAgentInfoFromSPIPE_50650 ; [input] %ecx=p_someObject,%esi=p_giantDestinationObject .text:54C22119 ; [synopsis] fetches a bunch of attributes from %ecx and writes them to the object at %esi .text:54C2211E 1884 83 C4 08 add esp, 8 .text:54C22121 187C 8B F0 mov esi, eax .text:54C22123 187C 89 B5 1C E8 FF FF mov [ebp+lp_agentInfo_17E4], esi ; [alias] v_flag? ``` After extracting the GUID from the package, the library will then execute the following code which ensures that the GUID isn't contained in a blacklist. After this is done, the library will check the sequence number and then enter a series of loops that will check which "PackageType" is being requested. If the package type specified by the agent is "MsgUpload", then the application will call a function, server_OnMsgUpload, which will forward the data to the application server. ``` .text:54C2222D 187C C6 45 FC 02 mov byte ptr [ebp+var_4], 2 .text:54C22231 187C 8D 85 50 FF FF FF lea eax, [ebp+lp_guidString?_B0] .text:54C22237 187C 50 push eax .text:54C22238 1880 B8 DC D2 E1 54 mov eax, offset dword_54E1D2DC .text:54C2223D 1880 E8 BE AA 0F 00 call sub_54D1CD00 .text:54C22242 187C 8A D8 mov bl, al ... .text:54C22334 187C 8D 9D 28 E8 FF FF lea ebx, [ebp+lv_agentInfoObject_17D8] .text:54C2233A 187C E8 81 2A 02 00 call servdal_ProcessAgentReportedSequenceNumber_44dc0 ; [input] %ebx=p_agentInfoObject .text:54C2233A ; [synopsis] validates the sequence number for an agentInfoObject and logs it .text:54C2233F 187C 89 85 24 E8 FF FF mov [ebp+var_17DC], eax ... .text:54C2278F compare(MsgUpload)_2278f: ; CODE XREF: AgentRequestHandler_21c10+B62j .text:54C2278F 187C B9 F8 55 DB 54 mov ecx, offset str.MsgUpload ; "MsgUpload" .text:54C22794 187C 8D 85 6C FF FF FF lea eax, [ebp+lv_packageTypeString?_94] .text:54C2279A 187C 8D 9B 00 00 00 00 lea ebx, [ebx+0] ... .text:54C227CF 187C 8D 95 28 E8 FF FF lea edx, [ebp+lv_agentInfoObject_17D8] ; [XXX] calls server_onMsgUpload .text:54C227D5 187C 52 push edx .text:54C227D6 1880 8B D3 mov edx, ebx .text:54C227D8 1880 8B 8D 20 E8 FF FF mov ecx, [ebp+lv_spipeExtraObject_17E0] .text:54C227DE 1880 E8 FD 01 03 00 call server_OnMsgUpload_529e0 ; [input] %ecx=packetData? ``` This function will tokenize data provided by the agent, and then enter the following loop which forwards the data directly to the application server using the ForwardDataChannelMessageToJava function. ``` .text:54C52ACE loop_tokens_52ace: ; CODE XREF: server_OnMsgUpload_529e0+3BAj .text:54C52ACE 128 8B 44 24 28 mov eax, [esp+124h+lp_@ecx_fc] .text:54C52AD2 128 50 push eax ; int .text:54C52AD3 12C 8D 7C 24 14 lea edi, [esp+128h+lv_size_114] .text:54C52AD7 12C 33 D2 xor edx, edx .text:54C52AD9 12C 8B CE mov ecx, esi ; void * .text:54C52ADB 12C 89 5C 24 14 mov [esp+128h+lv_size_114], ebx .text:54C52ADF 12C E8 3C 7D 00 00 call sub_54C5A820 ; [input] %edx=p_destBuffer ... .text:54C52C99 128 56 push esi .text:54C52C9A 12C 8B 74 24 1C mov esi, [esp+128h+lp_dataChannelContent_10c] .text:54C52C9E 12C E8 5D EB FF FF call ForwardDataChannelMessageToJava_51800 ; [input] %esi=content .text:54C52CA3 12C 83 C4 04 add esp, 4 ... .text:54C52D82 continue_tokens_52d82: ; CODE XREF: server_OnMsgUpload_529e0+36Cj .text:54C52D82 128 8D 44 24 2C lea eax, [esp+124h+lv_Context_f8] .text:54C52D86 128 50 push eax ; Context .text:54C52D87 12C 68 C4 9F DB 54 push offset str., ; "," .text:54C52D8C 130 53 push ebx ; Str .text:54C52D8D 134 FF 15 3C 45 DA 54 call ds:strtok_s .text:54C52D93 134 8B F0 mov esi, eax .text:54C52D95 134 83 C4 0C add esp, 0Ch .text:54C52D98 128 3B F3 cmp esi, ebx .text:54C52D9A 128 0F 85 2E FD FF FF jnz loop_tokens_52ace ``` The ForwardDataChannelMessageToJava function will simply take the input that was extracted from the Agent's request, and then forward it to the "/dcRedirect/dataChannelMsg.dc" resource that's located directly on the application server component. ``` .text:54C51847 0F0 8D 8D 34 FF FF FF lea ecx, [ebp+lvo_secureHttp_cc] .text:54C5184D 0F0 FF 15 60 4B DA 54 call ds:CSecureHttp::CSecureHttp(void) .text:54C51853 .text:54C51853 0F0 89 7D FC mov [ebp+var_4], edi .text:54C51856 0F0 8B 4D 08 mov ecx, [ebp+av_size_14] .text:54C51859 0F0 8D 85 30 FF FF FF lea eax, [ebp+ap_resultHeaders_18] .text:54C5185F 0F0 50 push eax ; ap_resultHeaders_18 .text:54C51860 0F4 A1 78 CB E1 54 mov eax, gp_dataChannelObject_21cb78 .text:54C51865 0F4 51 push ecx ; av_optionalDataLength_14 .text:54C51866 0F8 56 push esi ; ap_optionalData_10 .text:54C51867 0FC 68 64 9E DB 54 push offset gv_request(mimetype)_1b9e64 ; "application/octet-stream" .text:54C5186C 100 89 BD 30 FF FF FF mov [ebp+ap_resultHeaders_18], edi .text:54C51872 100 8B 90 5C 02 00 00 mov edx, [eax+25Ch] .text:54C51878 100 52 push edx ; av_nServerPort_8 .text:54C51879 104 05 70 02 00 00 add eax, 270h .text:54C5187E 104 50 push eax ; ap_serverName_4 .text:54C5187F 108 68 98 9E DB 54 push offset gv_request(dataChannelMsg)_1b9e98 ; "/dcRedirect/dataChannelMsg.dc" .text:54C51884 10C 8D 8D 34 FF FF FF lea ecx, [ebp+lvo_secureHttp_cc] ; this .text:54C5188A 10C FF 15 68 4B DA 54 call ds:CSecureHttp::PostSecureHttpRequest(wchar_t const *,wchar_t const *,int,wchar_t const *,void const *,uint,ulong &) ``` ### Protocol The POST request that is made to the application server is made to the DataChannel servlet. The servlet implement's the Data Channel which has the following format. ``` [0] <class pint.uint16_t> getHeaderSize ??? [2] <class pint.uint16_t> version ??? [4] <class pint.uint32_t> m_expiration ??? [8] <class pint.uint32_t> CorrelationID ??? [c] <class pint.uint8_t> getFlag ??? [0] <class StringPacket> m_originNameBytes ??? [0] <class StringPacket> m_messageTypeBytes ??? [0] <class StringPacket> m_agentGUIDBytes ??? [0] <class Data> m_data ??? ``` A StringPacket structure is a byte which defines the number of bytes that define a string. ``` <class StringPacket> [0] <class pint.uint8_t> size ??? [1] <class dyn.block(size)> data ??? ``` A Data structure is similar to a StringPacket except it uses a uint32_t to define the length of the data. ``` <class Data> [0] <class pint.uint32_t> size ??? [4] <class dyn.block(size)> data ??? ``` In the proof-of-concept, the following packet is POSTed. The only requirements of this packet are that the version is set to 1, the mmessageTypeBytes is larger than one character in length, and the mdata field contains at least one byte of data. If all of these fields are valid, then the m_agentGUIDBytes can contain up to 256 characters used for the sql injection. ``` <class DataPacket> [0] <instance pint.uint16_t 'getHeaderSize'> 0x004e (78) [2] <instance pint.uint16_t 'version'> 0x0001 (1) [4] <instance pint.uint32_t 'm_expiration'> 0x00000000 (0) [8] <instance pint.uint32_t 'CorrelationID'> 0x00000000 (0) [c] <instance pint.uint8_t 'getFlag'> 0x07 (7) [d] <instance StringPacket 'm_originNameBytes'> "\x10\x58\x58\x58\x4f\x52\x49\x47\x49\x4e\x4e\x41\x4d\x45\x58\x58\x58" [1e] <instance StringPacket 'm_messageTypeBytes'> "\x11\x58\x58\x58\x4d\x45\x53\x53\x41\x47\x45\x54\x59\x50\x45\x58\x58\x58" [30] <instance StringPacket 'm_agentGUIDBytes'> "\x0f\x58\x58\x58\x41\x47\x45\x4e\x54\x47\x55\x49\x44\x58\x58\x58" [40] <instance Data 'm_data'> "\x0a\x00\x00\x00\x58\x58\x58\x44\x41\x54\x41\x58\x58\x58" ``` ### Mitigation To ensure that an attacker does not have direct access to the vulnerability and instead has to use just SPIPE as an agent, verify that port 8443 that the McAfee ePolicy Orchestrator Console is bound to is inaccessible by ePolicy Orchestrator's agents and can only by accessed by Administrators. ### Timeline * 2016-11-04 - Vendor Disclosure * 2017-02-01 - Public Release ### CREDIT * Discovered by a member of the Talos Vulnerability Development Team.
idSSV:96582
last seen2017-11-19
modified2017-09-26
published2017-09-26
reporterRoot
titleMcAfee ePolicy Orchestrator DataChannel Blind SQL Injection Vulnerability(CVE-2016-8027)

Talos

idTALOS-2016-0229
last seen2019-05-29
published2017-02-01
reporterTalos Intelligence
sourcehttp://www.talosintelligence.com/vulnerability_reports/TALOS-2016-0229
titleMcAfee ePolicy Orchestrator DataChannel Blind SQL Injection Vulnerability