Skip to content
Permalink
Browse files

Limit CGI command line arguments

Limit the decoded form of individual command line arguments. This is to
work various issues passing command line arguments from Java to the OS
on Windows.
This restriction may be overridden by the new initialisation parameter
cmdLineArgumentsDecoded.
This is the fix for CVE-2019-0232.
  • Loading branch information...
markt-asf committed Apr 3, 2019
1 parent 1c1d49e commit 5bc4e6d7b1c22dc1bf99f475b7e70594ebdd83b9
@@ -335,6 +335,20 @@
<!-- If not set, then webAppRootDir is used. -->
<!-- Recommended value: WEB-INF/cgi -->
<!-- -->
<!-- cmdLineArgumentsDecoded -->
<!-- Only used when enableCmdLineArguments is -->
<!-- true. The pattern that individual decoded -->
<!-- command line arguments must match else the -->
<!-- request will be rejected. This is to -->
<!-- work-around various issues when Java passes -->
<!-- the arguments to the OS. See the CGI How-To -->
<!-- for more details. The default varies by -->
<!-- platform. -->
<!-- Windows: [[a-zA-Z0-9\Q-_.\\/:\E]+] -->
<!-- Others: [.*] -->
<!-- Note that internally the CGI Servlet treats -->
<!-- [.*] as a special case to improve performance -->
<!-- -->
<!-- cmdLineArgumentsEncoded -->
<!-- Only used when enableCmdLineArguments is -->
<!-- true. The pattern that individual encoded -->
@@ -52,6 +52,7 @@
import org.apache.catalina.util.IOTools;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.compat.JrePlatform;
import org.apache.tomcat.util.res.StringManager;


@@ -245,10 +246,21 @@
private static final long serialVersionUID = 1L;

private static final Set<String> DEFAULT_SUPER_METHODS = new HashSet<>();
private static final Pattern DEFAULT_CMD_LINE_ARGUMENTS_DECODED_PATTERN;
private static final String ALLOW_ANY_PATTERN = ".*";

static {
DEFAULT_SUPER_METHODS.add("HEAD");
DEFAULT_SUPER_METHODS.add("OPTIONS");
DEFAULT_SUPER_METHODS.add("TRACE");

if (JrePlatform.IS_WINDOWS) {
DEFAULT_CMD_LINE_ARGUMENTS_DECODED_PATTERN = Pattern.compile("[a-zA-Z0-9\\Q-_.\\/:\\E]+");
} else {
// No restrictions
DEFAULT_CMD_LINE_ARGUMENTS_DECODED_PATTERN = null;
}

}


@@ -314,6 +326,14 @@
private Pattern cmdLineArgumentsEncodedPattern =
Pattern.compile("[a-zA-Z0-9\\Q%;/?:@&,$-_.!~*'()\\E]+");

/**
* Limits the decoded form of individual command line arguments. Default
* varies by platform.
*/
private Pattern cmdLineArgumentsDecodedPattern = DEFAULT_CMD_LINE_ARGUMENTS_DECODED_PATTERN;



/**
* Sets instance variables.
* <P>
@@ -411,6 +431,14 @@ public void init(ServletConfig config) throws ServletException {
cmdLineArgumentsEncodedPattern =
Pattern.compile(getServletConfig().getInitParameter("cmdLineArgumentsEncoded"));
}

String value = getServletConfig().getInitParameter("cmdLineArgumentsDecoded");
if (ALLOW_ANY_PATTERN.equals(value)) {
// Optimisation for case where anything is allowed
cmdLineArgumentsDecodedPattern = null;
} else if (value != null) {
cmdLineArgumentsDecodedPattern = Pattern.compile(value);
}
}


@@ -792,7 +820,17 @@ protected boolean setupFromRequest(HttpServletRequest req)
}
return false;
}

String decodedArgument = URLDecoder.decode(encodedArgument, parameterEncoding);
if (cmdLineArgumentsDecodedPattern != null &&
!cmdLineArgumentsDecodedPattern.matcher(decodedArgument).matches()) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("cgiServlet.invalidArgumentDecoded",
decodedArgument, cmdLineArgumentsDecodedPattern.toString()));
}
return false;
}

cmdLineParameters.add(decodedArgument);
}
}
@@ -1101,7 +1139,6 @@ protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException {
this.env = envp;

return true;

}

/**
@@ -23,6 +23,7 @@ cgiServlet.expandOk=Expanded script at path [{0}] to [{1}]
cgiServlet.find.found=Found CGI: name [{0}], path [{1}], script name [{2}] and CGI name [{3}]
cgiServlet.find.location=Looking for a file at [{0}]
cgiServlet.find.path=CGI script requested at path [{0}] relative to CGI location [{1}]
cgiServlet.invalidArgumentDecoded=The decoded command line argument [{0}] did not match the configured cmdLineArgumentsDecoded pattern [{1}]
cgiServlet.invalidArgumentEncoded=The encoded command line argument [{0}] did not match the configured cmdLineArgumentsEncoded pattern [{1}]
cgiServlet.runBadHeader=Bad header line [{0}]
cgiServlet.runFail=I/O problems processing CGI
@@ -102,12 +102,22 @@ the web application root directory + File.separator + this prefix.
By default there is no value, which results in the web application root
directory being used as the search path. The recommended value is
<code>WEB-INF/cgi</code></li>
<li><strong>cmdLineArgumentsDecoded</strong> - If command line argumemnts
are enabled (via <strong>enableCmdLineArguments</strong>) and Tomcat is running
on Windows then each individual decoded command line argument must match this
pattern else the request will be rejected. This is to protect against known
issues passing command line arguments from Java to Windows. These issues can
lead to remote code execution. For more information on these issues see
<a href="https://codewhitesec.blogspot.com/2016/02/java-and-command-line-injections-in-windows.html">Markus
Wulftange&apos;s blog</a> and this archived
<a href="https://web.archive.org/web/20161228144344/https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/">blog
by Daniel Colascione</a>.</li>
<li><strong>cmdLineArgumentsEncoded</strong> - If command line argumemnts
are enabled (via <strong>enableCmdLineArguments</strong>) individual encoded
command line argument must match this pattern else the request will be rejected.
The default matches the allowed values defined by RFC3875 and is
<code>[a-zA-Z0-9\Q%;/?:@&amp;,$-_.!~*'()\E]+</code></li>
<li><strong>enableCmdLineArguments</strong> - Are command line parameters
<li><strong>enableCmdLineArguments</strong> - Are command line arguments
generated from the query string as per section 4.4 of 3875 RFC? The default is
<code>true</code>.</li>
<li><strong>environment-variable-</strong> - An environment to be set for the
@@ -103,6 +103,14 @@
3875. This restriction may be relaxed by the use of the new
initialisation parameter <code>cmdLineArgumentsEncoded</code>. (markt)
</add>
<add>
When the CGI Servlet is configured with
<code>enableCmdLineArguments</code> set to true, limit the decoded form
of the individual command line arguments to known safe values when
running on Windows. This restriction may be relaxed by the use of the
new initialisation parameter <code>cmdLineArgumentsDecoded</code>. This
is the fix for CVE-2019-0232. (markt)
</add>
</changelog>
</subsection>
<subsection name="Coyote">
@@ -507,6 +507,14 @@
initialisation parameter should not be set to <code>10</code> or higher on a
production system because the debug page is not secure.</p>

<p>When using the CGI Servlet on Windows with
<code>enableCmdLineArguments</code> enabled, review the setting of
<code>cmdLineArgumentsDecoded</code> carefully and ensure that it is
appropriate for your environment. The default value is secure. Insecure
configurations may expose the server to remote code execution. Further
information on the potential risks and mitigations may be found by
following the links in the <a href="cgi-howto.html">CGI How To</a>.</p>

<p><a href="config/filter.html">FailedRequestFilter</a>
can be configured and used to reject requests that had errors during
request parameter parsing. Without the filter the default behaviour is

0 comments on commit 5bc4e6d

Please sign in to comment.
You can’t perform that action at this time.