Limit CGI command line arguments · apache/tomcat@4b244d8 · GitHub
Skip to content

Commit

Permalink
Limit CGI command line arguments
Browse files Browse the repository at this point in the history
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 55f4eba commit 4b244d8
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
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,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 -->
Expand Down
39 changes: 38 additions & 1 deletion java/org/apache/catalina/servlets/CGIServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;


Expand Down Expand Up @@ -245,10 +246,21 @@ public final class CGIServlet extends HttpServlet {
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;
}

}


Expand Down Expand Up @@ -314,6 +326,14 @@ public final class CGIServlet extends HttpServlet {
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>
Expand Down Expand Up @@ -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);
}
}


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

return true;

}

/**
Expand Down
1 change: 1 addition & 0 deletions java/org/apache/catalina/servlets/LocalStrings.properties
Original file line number Diff line number Diff line change
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.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
Expand Down
12 changes: 11 additions & 1 deletion webapps/docs/cgi-howto.xml
Original file line number Diff line number Diff line change
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
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>false</code>.</li>
<li><strong>environment-variable-</strong> - An environment to be set for the
Expand Down
8 changes: 8 additions & 0 deletions webapps/docs/changelog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,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">
Expand Down
8 changes: 8 additions & 0 deletions webapps/docs/security-howto.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

3 comments on commit 4b244d8

@toratokuro
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the regular expression for cmdLineArgumentsDecoded is [[a-zA-Z0-9\Q-.\/:\E]+] in the web.xml comment (line 358), it's [a-zA-Z0-9\Q-.\/:\E]+ in the CGIServlet.java (line 258).
Which is correct?
(Please allow me if I'm asking a silly question. I'm not so familiar with the issue but need to clarify for some reason.)

@markt-asf
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is [a-zA-Z0-9\Q-.\/:\E]+.
The outer [...] in web.xml are the standard delimiters used in that file for parameter values. Unfortunately that does create a potential ambiguity in this case.

@toratokuro
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much!
It helped a lot!

Please sign in to comment.