CVE-2014-4172: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection') (CWE-74)
value: A URL parameter injection vulnerability was found in the back-channel ticket validation step of the CAS protocol in Jasig Java CAS Client before 3.3.2, .NET CAS Client before 1.0.2, and phpCAS before 1.3.3 that allow remote attackers to inject arbitrary web script or HTML via the (1) service parameter to validation/AbstractUrlBasedTicketValidator.java or (2) pgtUrl parameter to validation/Cas20ServiceTicketValidator.java.
CWE description: The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.
CVSS v3 base score: 9.8
Published: 2020-01-24T19:15Z
Repository: https://github.com/Jasig/java-cas-client
Language: Java
Files changed: cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java, cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java, cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidatorTests.java
Commit date: 2014-06-24 18:44:45 -0400
Commit message: CASC-228 URL Encode Paramaters Passed to Server via Validate

Problem: We currently don't pass encoded values to the server, possibly resolving in parsing/extraction errors.
Solution: URL Encode all values instead of just the service url.

QA Notes: Added unit test.

Diff: diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java
index 3ea31bd..fab0581 100644
--- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java
@@ -108,11 +108,11 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
     protected final String constructValidationUrl(final String ticket, final String serviceUrl) {
         final Map<String, String> urlParameters = new HashMap<String, String>();
 
         logger.debug("Placing URL parameters in map.");
         urlParameters.put("ticket", ticket);
-        urlParameters.put("service", encodeUrl(serviceUrl));
+        urlParameters.put("service", serviceUrl);
 
         if (this.renew) {
             urlParameters.put("renew", "true");
         }
 
@@ -142,11 +142,12 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
 
             if (value != null) {
                 buffer.append(i++ == 0 ? "?" : "&");
                 buffer.append(key);
                 buffer.append("=");
-                buffer.append(value);
+                final String encodedValue = encodeUrl(value);
+                buffer.append(encodedValue);
             }
         }
 
         return buffer.toString();
 
diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java
index 4380348..9ecc5b8 100644
--- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java
@@ -68,11 +68,11 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick
      * Adds the pgtUrl to the list of parameters to pass to the CAS server.
      *
      * @param urlParameters the Map containing the existing parameters to send to the server.
      */
     protected final void populateUrlAttributeMap(final Map<String, String> urlParameters) {
-        urlParameters.put("pgtUrl", encodeUrl(this.proxyCallbackUrl));
+        urlParameters.put("pgtUrl", this.proxyCallbackUrl);
     }
 
     protected String getUrlSuffix() {
         return "serviceValidate";
     }
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidatorTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidatorTests.java
index 7d07288..280e0eb 100644
--- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidatorTests.java
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidatorTests.java
@@ -16,12 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
 package org.jasig.cas.client.validation;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
 import java.io.UnsupportedEncodingException;
 import org.jasig.cas.client.PublicTestHttpServer;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -78,6 +77,17 @@ public final class Cas10TicketValidatorTests extends AbstractTicketValidatorTest
             fail("ValidationException expected.");
         } catch (final TicketValidationException e) {
             // expected
         }
     }
+
+    @Test
+    public void urlEncodedValues() {
+        final String ticket = "ST-1-owKEOtYJjg77iHcCQpkl-cas01.example.org%26%73%65%72%76%69%63%65%3d%68%74%74%70%25%33%41%25%32%46%25%32%46%31%32%37%2e%30%2e%30%2e%31%25%32%46%62%6f%72%69%6e%67%25%32%46%23";
+        final String service = "foobar";
+        final String url = this.ticketValidator.constructValidationUrl(ticket, service);
+
+        final String encodedValue = this.ticketValidator.encodeUrl(ticket);
+        assertTrue(url.contains(encodedValue));
+        assertFalse(url.contains(ticket));
+    }
 }

Vulnerable code:         urlParameters.put("service", encodeUrl(serviceUrl));
                buffer.append(value);
        urlParameters.put("pgtUrl", encodeUrl(this.proxyCallbackUrl));
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
Fixed code:         urlParameters.put("service", serviceUrl);
                final String encodedValue = encodeUrl(value);
                buffer.append(encodedValue);
        urlParameters.put("pgtUrl", this.proxyCallbackUrl);
import static org.junit.Assert.*;

    @Test
    public void urlEncodedValues() {
        final String ticket = "ST-1-owKEOtYJjg77iHcCQpkl-cas01.example.org%26%73%65%72%76%69%63%65%3d%68%74%74%70%25%33%41%25%32%46%25%32%46%31%32%37%2e%30%2e%30%2e%31%25%32%46%62%6f%72%69%6e%67%25%32%46%23";
        final String service = "foobar";
        final String url = this.ticketValidator.constructValidationUrl(ticket, service);

        final String encodedValue = this.ticketValidator.encodeUrl(ticket);
        assertTrue(url.contains(encodedValue));
        assertFalse(url.contains(ticket));
    }