Skip to content

Commit

Permalink
Merge pull request #5198 from Pandrex247/FISH-1274-Comm
Browse files Browse the repository at this point in the history
FISH-1274 Vulnerability in Metro's WSDL Code Importing/Parsing - Remote Code Execution
  • Loading branch information
Pandrex247 authored Apr 21, 2021
2 parents f3d70f8 + 9b2eb11 commit 19cec93
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2018-2020] [Payara Foundation and/or its affiliates]
// Portions Copyright 2018-2021 Payara Foundation and/or its affiliates
/*
* WebServiceTesterServlet.java
*
Expand Down Expand Up @@ -101,6 +101,13 @@ public static void invoke(HttpServletRequest request, HttpServletResponse respon
WebServiceTesterServlet servlet = new WebServiceTesterServlet(endpoint);

response.setCharacterEncoding("UTF-8");

// Validate Host Header to help prevent Host Header Attacks
if (!servlet.isValidHostHeader(request)) {
throw new ServletException("Host Header does not appear to be valid - it does not appear to be a " +
"valid IPv6 literal, IPv4 dotted-decimal, or DNS name.");
}

if (request.getMethod().equalsIgnoreCase("GET")) {
servlet.doGet(request, response);
} else {
Expand Down Expand Up @@ -646,4 +653,64 @@ private void deleteDir(File path) {
private String encodeHTML(String html) {
return html.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
}

/**
* Method to test that the Host Header is valid and doesn't have any illegal characters, to help prevent Host Header
* Attacks.
*
* @param request The {@link HttpServletRequest} from the
* {@link WebServiceTesterServlet#invoke(HttpServletRequest, HttpServletResponse, WebServiceEndpoint)} method
* @return True if the Host Header is valid, false if it isn't
*/
private boolean isValidHostHeader(HttpServletRequest request) {
// Get the Host Header
String serverName = request.getServerName();

// Decode the Host Header
String decodedServerName = null;
try {
decodedServerName = URLDecoder.decode(serverName, "UTF-8");
} catch (UnsupportedEncodingException unsupportedEncodingException) {
logger.log(Level.WARNING, "Could not decode URL during validation, assuming Host Header is invalid.",
unsupportedEncodingException);
return false;
}

// Shouldn't Happen™, but just in case
if (decodedServerName == null) {
logger.log(Level.WARNING, "Host Header decoded to null during validation, assuming Host Header is invalid.");
return false;
}

// Check IPv6 literal: []
if (decodedServerName.startsWith("[") && decodedServerName.endsWith("]")) {
return true;
}

// Check IPv4 dotted-decimal: xxx.xxx.xxx.xxx
if (checkValidIpv4DottedDecimal(decodedServerName)) {
return true;
}

// Check DNS name is valid - ASCII alphanumerics and "-" only, no segment longer than 63 characters,
// sections separated with ".", possibly ending with "."
if (checkValidDnsName(decodedServerName)) {
return true;
}

// No match implies invalid host header / server name
return false;
}

// Split off for unit testing
protected static boolean checkValidIpv4DottedDecimal(String decodedServerName) {
return decodedServerName.matches(
"^((0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)\\.){3}(0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)$");
}

// Split off for unit testing
protected static boolean checkValidDnsName(String decodedServerName) {
// NOTE: HttpServletRequest.getServerName strips the port so no need to check
return decodedServerName.matches("((?!-)[\\w-]{1,63}(?<!-)(\\.|$))+");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2021 Payara Foundation and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://github.com/payara/Payara/blob/master/LICENSE.txt
* See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* The Payara Foundation designates this particular file as subject to the "Classpath"
* exception as provided by the Payara Foundation in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.webservices.monitoring;

import org.junit.Assert;
import org.junit.Test;

public class WebServiceTesterServletTest {

@Test
public void testIpv4Regex() {
// Loopback should work
Assert.assertTrue(WebServiceTesterServlet.checkValidIpv4DottedDecimal("127.0.0.1"));

// Typical default should work
Assert.assertTrue(WebServiceTesterServlet.checkValidIpv4DottedDecimal("192.168.1.1"));

// Empty string should fail
Assert.assertFalse(WebServiceTesterServlet.checkValidIpv4DottedDecimal(""));

// DNS name should fail
Assert.assertFalse(WebServiceTesterServlet.checkValidIpv4DottedDecimal("payara.fish"));

// All 0's allowed
Assert.assertTrue(WebServiceTesterServlet.checkValidIpv4DottedDecimal("0.0.0.0"));

// No 0 prefixes
Assert.assertFalse(WebServiceTesterServlet.checkValidIpv4DottedDecimal("012.168.35.64"));

// 0 suffixes allowed
Assert.assertTrue(WebServiceTesterServlet.checkValidIpv4DottedDecimal("102.120.35.240"));

// Numbers greater than 255 not allowed
Assert.assertFalse(WebServiceTesterServlet.checkValidIpv4DottedDecimal("192.168.43.256"));
Assert.assertFalse(WebServiceTesterServlet.checkValidIpv4DottedDecimal("192.168.43.1234"));

// Must be 4 segments
Assert.assertFalse(WebServiceTesterServlet.checkValidIpv4DottedDecimal("192"));
Assert.assertFalse(WebServiceTesterServlet.checkValidIpv4DottedDecimal("192.168"));
Assert.assertFalse(WebServiceTesterServlet.checkValidIpv4DottedDecimal("192.168.43"));
}

@Test
public void testDnsNameRegex() {
// Standalone name allowed e.g. "localhost"
Assert.assertTrue(WebServiceTesterServlet.checkValidDnsName("payara"));

// "." allowed to denote segments
Assert.assertTrue(WebServiceTesterServlet.checkValidDnsName("payara.fish"));

// "-" is allowed
Assert.assertTrue(WebServiceTesterServlet.checkValidDnsName("payara-jaxws"));

// "-" is allowed, and "." allowed to denote segments
Assert.assertTrue(WebServiceTesterServlet.checkValidDnsName("payara-jaxws.fish"));

// Letters and numbers allowed
Assert.assertTrue(WebServiceTesterServlet.checkValidDnsName("payara2021"));

// Multiple segments allowed, and letters & numbers allowed
Assert.assertTrue(WebServiceTesterServlet.checkValidDnsName("payara.2021.swims"));

// "-" is allowed, "." allowed to denote segments, and so is a trailing "."
Assert.assertTrue(WebServiceTesterServlet.checkValidDnsName("payara-jaxws.fish."));

// Double trailing "." not allowed
Assert.assertFalse(WebServiceTesterServlet.checkValidDnsName("payara-jaxws.fish.."));
// No non-ASCII alphanumerics allowed
Assert.assertFalse(WebServiceTesterServlet.checkValidDnsName("faß.de"));
// No symbol other than "-" or "." allowed
Assert.assertFalse(WebServiceTesterServlet.checkValidDnsName("malicious/payload.wsdl"));
Assert.assertFalse(WebServiceTesterServlet.checkValidDnsName("malicious/payload.wsdl#"));
}

}
3 changes: 1 addition & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@
<hibernate.validator-cdi.version>6.1.5.Final</hibernate.validator-cdi.version>
<jakarta.el.version>3.0.3.payara-p4</jakarta.el.version>
<jakarta.el-api.version>3.0.3.payara-p4</jakarta.el-api.version>
<jaxb-api.version>2.3.2</jaxb-api.version>
<javax.cache-api.version>1.1.1</javax.cache-api.version>
<mail.version>1.6.4.payara-p1</mail.version>
<jakarta.annotation-api.version>1.3.5</jakarta.annotation-api.version>
Expand Down Expand Up @@ -188,7 +187,7 @@
<com.ibm.jbatch.spi.version>1.0.3</com.ibm.jbatch.spi.version>
<jaxws-api.version>2.3.2</jaxws-api.version>
<jakarta.jws-api.version>1.1.1</jakarta.jws-api.version>
<webservices.version>2.4.3.payara-p3</webservices.version>
<webservices.version>2.4.3.payara-p4</webservices.version>
<woodstox.version>5.1.0</woodstox.version>
<stax2-api.version>4.2.1</stax2-api.version>
<jakarta.xml.registry-api.version>1.0.10</jakarta.xml.registry-api.version>
Expand Down

0 comments on commit 19cec93

Please sign in to comment.