Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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 10, 2019
1 parent 1c1d49e commit 5bc4e6d
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 2 deletions.
14 changes: 14 additions & 0 deletions conf/web.xml
Expand Up @@ -335,6 +335,20 @@
<!-- If not set, then webAppRootDir is used. --> <!-- If not set, then webAppRootDir is used. -->
<!-- Recommended value: WEB-INF/cgi --> <!-- 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 --> <!-- cmdLineArgumentsEncoded -->
<!-- Only used when enableCmdLineArguments is --> <!-- Only used when enableCmdLineArguments is -->
<!-- true. The pattern that individual encoded --> <!-- true. The pattern that individual encoded -->
Expand Down
39 changes: 38 additions & 1 deletion java/org/apache/catalina/servlets/CGIServlet.java
Expand Up @@ -52,6 +52,7 @@
import org.apache.catalina.util.IOTools; import org.apache.catalina.util.IOTools;
import org.apache.juli.logging.Log; import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory; import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.compat.JrePlatform;
import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.util.res.StringManager;




Expand Down Expand Up @@ -245,10 +246,21 @@ public final class CGIServlet extends HttpServlet {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;


private static final Set<String> DEFAULT_SUPER_METHODS = new HashSet<>(); 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 { static {
DEFAULT_SUPER_METHODS.add("HEAD"); DEFAULT_SUPER_METHODS.add("HEAD");
DEFAULT_SUPER_METHODS.add("OPTIONS"); DEFAULT_SUPER_METHODS.add("OPTIONS");
DEFAULT_SUPER_METHODS.add("TRACE"); 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;
}

} }




Expand Down Expand Up @@ -314,6 +326,14 @@ public final class CGIServlet extends HttpServlet {
private Pattern cmdLineArgumentsEncodedPattern = private Pattern cmdLineArgumentsEncodedPattern =
Pattern.compile("[a-zA-Z0-9\\Q%;/?:@&,$-_.!~*'()\\E]+"); 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. * Sets instance variables.
* <P> * <P>
Expand Down Expand Up @@ -411,6 +431,14 @@ public void init(ServletConfig config) throws ServletException {
cmdLineArgumentsEncodedPattern = cmdLineArgumentsEncodedPattern =
Pattern.compile(getServletConfig().getInitParameter("cmdLineArgumentsEncoded")); 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);
}
} }




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

String decodedArgument = URLDecoder.decode(encodedArgument, parameterEncoding); 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); cmdLineParameters.add(decodedArgument);
} }
} }
Expand Down Expand Up @@ -1101,7 +1139,6 @@ protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException {
this.env = envp; this.env = envp;


return true; return true;

} }


/** /**
Expand Down
1 change: 1 addition & 0 deletions java/org/apache/catalina/servlets/LocalStrings.properties
Expand Up @@ -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.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.location=Looking for a file at [{0}]
cgiServlet.find.path=CGI script requested at path [{0}] relative to CGI location [{1}] 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.invalidArgumentEncoded=The encoded command line argument [{0}] did not match the configured cmdLineArgumentsEncoded pattern [{1}]
cgiServlet.runBadHeader=Bad header line [{0}] cgiServlet.runBadHeader=Bad header line [{0}]
cgiServlet.runFail=I/O problems processing CGI cgiServlet.runFail=I/O problems processing CGI
Expand Down
12 changes: 11 additions & 1 deletion webapps/docs/cgi-howto.xml
Expand Up @@ -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 By default there is no value, which results in the web application root
directory being used as the search path. The recommended value is directory being used as the search path. The recommended value is
<code>WEB-INF/cgi</code></li> <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 <li><strong>cmdLineArgumentsEncoded</strong> - If command line argumemnts
are enabled (via <strong>enableCmdLineArguments</strong>) individual encoded are enabled (via <strong>enableCmdLineArguments</strong>) individual encoded
command line argument must match this pattern else the request will be rejected. command line argument must match this pattern else the request will be rejected.
The default matches the allowed values defined by RFC3875 and is The default matches the allowed values defined by RFC3875 and is
<code>[a-zA-Z0-9\Q%;/?:@&amp;,$-_.!~*'()\E]+</code></li> <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 generated from the query string as per section 4.4 of 3875 RFC? The default is
<code>true</code>.</li> <code>true</code>.</li>
<li><strong>environment-variable-</strong> - An environment to be set for the <li><strong>environment-variable-</strong> - An environment to be set for the
Expand Down
8 changes: 8 additions & 0 deletions webapps/docs/changelog.xml
Expand Up @@ -103,6 +103,14 @@
3875. This restriction may be relaxed by the use of the new 3875. This restriction may be relaxed by the use of the new
initialisation parameter <code>cmdLineArgumentsEncoded</code>. (markt) initialisation parameter <code>cmdLineArgumentsEncoded</code>. (markt)
</add> </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> </changelog>
</subsection> </subsection>
<subsection name="Coyote"> <subsection name="Coyote">
Expand Down
8 changes: 8 additions & 0 deletions webapps/docs/security-howto.xml
Expand Up @@ -507,6 +507,14 @@
initialisation parameter should not be set to <code>10</code> or higher on a initialisation parameter should not be set to <code>10</code> or higher on a
production system because the debug page is not secure.</p> 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> <p><a href="config/filter.html">FailedRequestFilter</a>
can be configured and used to reject requests that had errors during can be configured and used to reject requests that had errors during
request parameter parsing. Without the filter the default behaviour is request parameter parsing. Without the filter the default behaviour is
Expand Down

0 comments on commit 5bc4e6d

Please sign in to comment.