CVE-2013-1915: Improper Restriction of XML External Entity Reference (CWE-611)
value: ModSecurity before 2.7.3 allows remote attackers to read arbitrary files, send HTTP requests to intranet servers, or cause a denial of service (CPU and memory consumption) via an XML external entity declaration in conjunction with an entity reference, aka an XML External Entity (XXE) vulnerability.
CWE description: The product processes an XML document that can contain XML entities with URIs that resolve to documents outside of the intended sphere of control, causing the product to embed incorrect documents into its output.
Published: 2013-04-25T23:55Z
Repository: https://github.com/SpiderLabs/ModSecurity
Language: C
Files changed: apache2/apache2_config.c, apache2/modsecurity.h, apache2/msc_xml.c
Commit date: 2013-03-04 16:54:20 -0400
Commit message: Added SecXmlExternalEntity

Diff: diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c
index 7437ffb..188af59 100644
--- a/apache2/apache2_config.c
+++ b/apache2/apache2_config.c
@@ -154,10 +154,13 @@ void *create_directory_config(apr_pool_t *mp, char *path)
     dcfg->crypto_hash_location_pm = NOT_SET;
     dcfg->crypto_hash_iframesrc_pm = NOT_SET;
     dcfg->crypto_hash_framesrc_pm = NOT_SET;
 
 
+    /* xml external entity */
+    dcfg->xml_external_entity = NOT_SET;
+
     return dcfg;
 }
 
 /**
  * Copies rules between one phase of two configuration contexts,
@@ -589,10 +592,14 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
     merged->crypto_hash_iframesrc_pm = (child->crypto_hash_iframesrc_pm == NOT_SET
         ? parent->crypto_hash_iframesrc_pm : child->crypto_hash_iframesrc_pm);
     merged->crypto_hash_framesrc_pm = (child->crypto_hash_framesrc_pm == NOT_SET
         ? parent->crypto_hash_framesrc_pm : child->crypto_hash_framesrc_pm);
 
+    /* xml external entity */
+    merged->xml_external_entity = (child->xml_external_entity == NOT_SET
+        ? parent->xml_external_entity : child->xml_external_entity);
+
     return merged;
 }
 
 /**
  * Initialise directory configuration. This function is *not* meant
@@ -709,10 +716,13 @@ void init_directory_config(directory_config *dcfg)
     if (dcfg->crypto_hash_faction_pm == NOT_SET) dcfg->crypto_hash_faction_pm = 0;
     if (dcfg->crypto_hash_location_pm == NOT_SET) dcfg->crypto_hash_location_pm = 0;
     if (dcfg->crypto_hash_iframesrc_pm == NOT_SET) dcfg->crypto_hash_iframesrc_pm = 0;
     if (dcfg->crypto_hash_framesrc_pm == NOT_SET) dcfg->crypto_hash_framesrc_pm = 0;
 
+    /* xml external entity */
+    if (dcfg->xml_external_entity == NOT_SET) dcfg->xml_external_entity = 0;
+
 }
 
 /**
  *
  */
@@ -2280,13 +2290,39 @@ static const char *cmd_sensor_id(cmd_parms *cmd, void *_dcfg, const char *p1)
     dcfg->sensor_id = p1;
 
     return NULL;
 }
 
+/**
+* \brief Add SecXmlExternalEntity configuration option
+*
+* \param cmd Pointer to configuration data
+* \param _dcfg Pointer to directory configuration
+* \param p1 Pointer to configuration option
+*
+* \retval NULL On failure
+* \retval apr_psprintf On Success
+*/
+static const char *cmd_xml_external_entity(cmd_parms *cmd, void *_dcfg, const char *p1)
+{
+    directory_config *dcfg = (directory_config *)_dcfg;
+    if (dcfg == NULL) return NULL;
+
+    if (strcasecmp(p1, "on") == 0)  {
+        dcfg->xml_external_entity = 1;
+    }
+    else if (strcasecmp(p1, "off") == 0)    {
+        dcfg->xml_external_entity = 0;
+    }
+    else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecXmlExternalEntity: %s", p1);
+
+    return NULL;
+}
+
 
 /**
-* \brief Add SecHash configuration option
+* \brief Add SecHashEngine configuration option
 *
 * \param cmd Pointer to configuration data
 * \param _dcfg Pointer to directory configuration
 * \param p1 Pointer to configuration option
 *
@@ -2304,11 +2340,11 @@ static const char *cmd_hash_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
     }
     else if (strcasecmp(p1, "off") == 0)    {
         dcfg->hash_is_enabled = HASH_DISABLED;
         dcfg->hash_enforcement = HASH_DISABLED;
     }
-    else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRuleEngine: %s", p1);
+    else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SexHashEngine: %s", p1);
 
     return NULL;
 }
 
 /**
@@ -3221,10 +3257,18 @@ const command_rec module_directives[] = {
         NULL,
         CMD_SCOPE_ANY,
         "On or Off"
     ),
 
+    AP_INIT_TAKE1 (
+        "SecXmlExternalEntity",
+        cmd_xml_external_entity,
+        NULL,
+        CMD_SCOPE_ANY,
+        "On or Off"
+    ),
+
     AP_INIT_FLAG (
         "SecRuleInheritance",
         cmd_rule_inheritance,
         NULL,
         CMD_SCOPE_ANY,
diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h
index 3f210b7..cb1a8d1 100644
--- a/apache2/modsecurity.h
+++ b/apache2/modsecurity.h
@@ -593,10 +593,13 @@ struct directory_config {
     int                 crypto_hash_href_pm;
     int                 crypto_hash_faction_pm;
     int                 crypto_hash_location_pm;
     int                 crypto_hash_iframesrc_pm;
     int                 crypto_hash_framesrc_pm;
+
+    /* xml */
+    int                 xml_external_entity;
 };
 
 struct error_message_t {
     const char          *file;
     int                  line;
diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c
index d9cb09c..87ab967 100644
--- a/apache2/msc_xml.c
+++ b/apache2/msc_xml.c
@@ -12,21 +12,32 @@
 * directly using the email address security@modsecurity.org.
 */
 
 #include "msc_xml.h"
 
+static xmlParserInputBufferPtr
+xml_unload_external_entity(const char *URI, xmlCharEncoding enc)    {
+    return NULL;
+}
+
 
 /**
  * Initialise XML parser.
  */
 int xml_init(modsec_rec *msr, char **error_msg) {
+    xmlParserInputBufferCreateFilenameFunc entity;
+
     if (error_msg == NULL) return -1;
     *error_msg = NULL;
 
     msr->xml = apr_pcalloc(msr->mp, sizeof(xml_data));
     if (msr->xml == NULL) return -1;
 
+    if(msr->txcfg->xml_external_entity == 0)    {
+        entity = xmlParserInputBufferCreateFilenameDefault(xml_unload_external_entity);
+    }
+
     return 1;
 }
 
 #if 0
 static void xml_receive_sax_error(void *data, const char *msg, ...) {

Vulnerable code: * \brief Add SecHash configuration option
    else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRuleEngine: %s", p1);
Fixed code:     /* xml external entity */
    dcfg->xml_external_entity = NOT_SET;

    /* xml external entity */
    merged->xml_external_entity = (child->xml_external_entity == NOT_SET
        ? parent->xml_external_entity : child->xml_external_entity);

    /* xml external entity */
    if (dcfg->xml_external_entity == NOT_SET) dcfg->xml_external_entity = 0;

/**
* \brief Add SecXmlExternalEntity configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On Success
*/
static const char *cmd_xml_external_entity(cmd_parms *cmd, void *_dcfg, const char *p1)
{
    directory_config *dcfg = (directory_config *)_dcfg;
    if (dcfg == NULL) return NULL;

    if (strcasecmp(p1, "on") == 0)  {
        dcfg->xml_external_entity = 1;
    }
    else if (strcasecmp(p1, "off") == 0)    {
        dcfg->xml_external_entity = 0;
    }
    else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecXmlExternalEntity: %s", p1);

    return NULL;
}

* \brief Add SecHashEngine configuration option
    else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SexHashEngine: %s", p1);
    AP_INIT_TAKE1 (
        "SecXmlExternalEntity",
        cmd_xml_external_entity,
        NULL,
        CMD_SCOPE_ANY,
        "On or Off"
    ),


    /* xml */
    int                 xml_external_entity;
static xmlParserInputBufferPtr
xml_unload_external_entity(const char *URI, xmlCharEncoding enc)    {
    return NULL;
}

    xmlParserInputBufferCreateFilenameFunc entity;

    if(msr->txcfg->xml_external_entity == 0)    {
        entity = xmlParserInputBufferCreateFilenameDefault(xml_unload_external_entity);
    }