CVE-2014-125083 (Java, published 2023-01-19T10:15Z)
Description: value: A vulnerability has been found in Anant Labs google-enterprise-connector-dctm up to 3.2.3 and classified as critical. Affected by this vulnerability is an unknown functionality. The manipulation of the argument username/domain leads to sql injection. The patch is named 6fba04f18ab7764002a1da308e7cd9712b501cb7. It is recommended to apply a patch to fix this issue. The associated identifier of this vulnerability is VDB-218911.
Severity: nan (CVSS v3 base score: 9.8)
Weakness: CWE-89 \u2014 Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
Repository: https://github.com/AnantLabs/google-enterprise-connector-dctm
Files changed:
projects/dctm-core/source/java/com/google/enterprise/connector/dctm/DctmAuthenticationManager.java
projects/dctm-core/source/java/com/google/enterprise/connector/dctm/DqlUtils.java
projects/dctm-core/source/javatests/com/google/enterprise/connector/dctm/DctmMockAuthenticationManagerTest.java
projects/dctm-core/source/javatests/com/google/enterprise/connector/dctm/DqlUtilsTest.java
Commit message: Escape username and domain values to avoid SQL injection in string
concatenation (b/13399766, 2 of 2).

Code review: https://codereview.appspot.com/75770044


Vulnerable code:
      queryBuff.append(userLoginName);
        queryBuff.append(domainName);

Fixed code:
      queryBuff.append(DqlUtils.escapeString(userLoginName));
        queryBuff.append(DqlUtils.escapePattern(domainName.toString(), '\\'));
        queryBuff.append("' escape '\\");
  /**
   * Escapes single quotes (') in the given value by doubling them,
   * as per SQL.
   */
  public static String escapeString(String value) {
    StringBuilder buffer = new StringBuilder(value.length() + 2);
    for (int i = 0; i < value.length(); i++) {
      char c = value.charAt(i);
      switch (c) {
        case '\'':
          buffer.append("''");
          break;
        default:
          buffer.append(c);
          break;
      }
    }
    return buffer.toString();
  }

  /**
   * Escapes single quotes (') in the given value by doubling them, as
   * per SQL, and escapes the LIKE wildcards, percent (%) and
   * underscore (_), using the given escape character, as well as
   * escaping the escape character itself.
   */
  public static String escapePattern(String value, char escapeChar) {
    StringBuilder buffer = new StringBuilder(value.length() + 2);
    for (int i = 0; i < value.length(); i++) {
      char c = value.charAt(i);
      switch (c) {
        case '\'':
          buffer.append("''");
          break;
        case '%':
        case '_':
          buffer.append(escapeChar);
          buffer.append(c);
          break;
        default:
          if (c == escapeChar) {
            buffer.append(escapeChar);
          }
          buffer.append(c);
          break;
      }
    }
    return buffer.toString();
  }

  public void testSqlInjection_userNoDomain() throws Exception {
    testDomainFail("' or user_name = 'localuser", "");
  }

  public void testSqlInjection_userDomain() throws Exception {
    testDomainFail(
        "ldapuser' and user_ldap_dn like '%dc=ajax,dc=example,dc=com,dc=au' --",
        "ajax.example.com");
  }

  /** The post-processing using LdapName also blocks this. */
  public void testSqlInjection_domain() throws Exception {
    testDomainFail("ldapuser", "acme.example%");
  }

// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.enterprise.connector.dctm;

import junit.framework.TestCase;

public class DqlUtilsTest extends TestCase {
  public void testEscapeString_null() {
    try {
      DqlUtils.escapeString(null);
      fail("Expected a NullPointerException");
    } catch (NullPointerException expected) {
    }
  }

  public void testEscapeString_empty() {
    assertEquals("", DqlUtils.escapeString(""));
  }

  public void testEscapeString_unescapedString() {
    String value = "hello world";
    assertEquals(value, DqlUtils.escapeString(value));
  }

  public void testEscapeString_unescapedPattern() {
    String value = "\\ % _ \\\\ \\% \\_";
    assertEquals(value, DqlUtils.escapeString(value));
  }

  public void testEscapeString_quoted() {
    String value = "' \\ % _ \\' \\\\ \\% \\_";
    assertEquals(value.replace("'", "''"), DqlUtils.escapeString(value));
  }

  public void testEscapePattern_null() {
    try {
      DqlUtils.escapePattern(null, '\\');
      fail("Expected a NullPointerException");
    } catch (NullPointerException expected) {
    }
  }

  public void testEscapePattern_empty() {
    assertEquals("", DqlUtils.escapePattern("", '\\'));
  }

  public void testEscapePattern_unescapedString() {
    String value = "hello world";
    assertEquals(value, DqlUtils.escapePattern(value, '\\'));
  }

  public void testEscapePattern_escapedPattern() {
    String value = "\\ % _ \\\\ \\% \\_";
    String escaped = "\\\\ \\% \\_ \\\\\\\\ \\\\\\% \\\\\\_";
    assertEquals(escaped, DqlUtils.escapePattern(value, '\\'));
  }

  public void testEscapePattern_quoted() {
    String value = "' \\ % _ \\' \\\\ \\% \\_";
    String escaped = "'' \\\\ \\% \\_ \\\\'' \\\\\\\\ \\\\\\% \\\\\\_";
    assertEquals(escaped, DqlUtils.escapePattern(value, '\\'));
  }

  public void testEscapePattern_quotedSlash() {
    String value = "' \\ % _ \\' \\\\ \\% \\_";
    String escaped = "'' /\\ /% /_ /\\'' /\\/\\ /\\/% /\\/_";
    assertEquals(escaped, DqlUtils.escapePattern(value, '/'));
  }
}