Having problems with your account or logging in?
A lot of changes are happening in the community right now. Some may affect you. READ MORE HERE

Protect your Struts1 applications

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor
0 49 73.7K

[UPDATE]: Please refer to and install following filter to protect from Classloader maniupulation in Struts1 applications:

https://github.com/rgielen/struts1filter 

Since the last post on how to mitigate the Struts 2 zero day on the wild we have received many queries from customers wondering if their legacy Struts 1 applications were also vulnerable to this same attack.

The Struts security team confirmed that classloader manipulation is also possible in Struts 1 applications even if they don’t use OGNL for parameter binding. They have assigned CVE-2014-0114 to this issue.

Further discussions with Struts security team have confirmed that although classloader manipulation has been verified, remote code execution has not been confirmed yet.

At Micro Focus we don’t wait for an exploited zero day before we take action to protect our customers. Therefore, while the Struts team works on a patch for this issue, we strongly recommend Struts1 developers to take the following actions to mitigate the risk.

Struts1 lacks the Struts2 Interceptor chain so we cannot benefit from the Parameter Interceptor to do the work for us. But we can easily build our own using Servlet Filters for the Struts’s org.apache.struts.action.ActionServlet Servlet.

Struts ActionForm bean population relies on ServletRequest.getParameterNames() to first get a list of all parameters being sent on the query and proceed to set those parameter on the ActionForm bean properties.

The following Filter will create a ServletRequest wrapper that overwrites getParameterNames() method and checks the parameter names against a customizable regular expression. If a parameter name matches this regular expression, it will be removed from the list returned by ServletRequest.getParameterNames().


Figure 1: ParamFilter.java

package com.company.filters;

import java.io.IOException;
import java.util.*;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public final class ParamFilter implements Filter {

    FilterConfig filterConfig = null;

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        String regex = this.filterConfig.getInitParameter("excludeParams");
        chain.doFilter(new ParamFilteredRequest(request, regex), response);
    }

    public void destroy() { }
    
    static class ParamFilteredRequest extends HttpServletRequestWrapper {

        private HttpServletRequest originalRequest;
        private String regex;

        public ParamFilteredRequest(ServletRequest request, String regex) {
            super((HttpServletRequest)request);
            this.originalRequest = (HttpServletRequest) request;
            this.regex = regex;
        }
        public Enumeration getParameterNames() {
            List<String> requestParameterNames = Collections.list((Enumeration<String>) super.getParameterNames());
            List finalParameterNames = new ArrayList();

            for (String parameterName:requestParameterNames) {
                if (!parameterName.matches(regex)) {
                    finalParameterNames.add(parameterName);
                    System.out.println("Param : " + parameterName);
                }
            }
            return Collections.enumeration(finalParameterNames);
        }
    }
}

 

Figure 2: Web.xml configuration

 

    <filter>
        <filter-name>ParamFilter</filter-name>
        <filter-class>com.company.filters.ParamFilter</filter-class>
        <init-param>
            <param-name>excludeParams</param-name>
            <param-value>(.*\.|^|.*|\[('|"))(c|C)lass(\.|('|")]|\[).*</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>ParamFilter</filter-name>
        <servlet-name>YOUR ACTION SERVLET</servlet-name>
    </filter-mapping>

 

We would like to thank the Struts security team for their prompt response and their validation of the proposed mitigation filter.

Update (01/05/2014):

 

MF Security Research Team has confirmed remote code execution is possible on certain application servers and has notified Struts security team.

Stay Secure!

Tags (4)
49 Comments
Not applicable

In the original Struts 2 vulnerability documentation, the regular expression also check for the following initial strings followed by a dot:

 

  • dojo
  • struts
  • session
  • request
  • application
  • servletRequest
  • servletResponse
  • parameters
  • action
  • method

Why the regexp for Struts 1 presented here does not include them? Are they relevant?

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Arturo,

 

Thanks for your comment. Those keywords are relevant if evaluated in the context of the Struts2 Value Stack via OGNL. Struts1 does not use OGNL and has no access to the anything similar to the Value Stack and so they dont suppose a specific risk.

 

Cheers,

Alvaro

Not applicable

Is it safe to assume that if I am not using ActionForm, but simple using actions alone, then I am not impacted by this vulnerability?

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Kishore,


Thanks for your comment. If there is no ActionForm associated with the action in the action declaration, then Struts will not start the ActionForm binding process and therefore this particular attack vector will not be possible. However we strongly recommend taking all possible mitigation actions to protect your applciations from unknown attack vectors that may be working on the wild.

 

Cheers,

A

Not applicable

Thanks for making this code available. What license  applies to it if any?

Not applicable

Here is an improved version of the filter that compiles the pattern only once: https://gist.github.com/anonymous/0045ef4df99b31b43daa

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Patrick,

 

Thanks for your comment. The fix is not licensed in any way and its completely open source so that any one is free to use it or modify it.
It is provided as-is with no guarantees nor support and designed as a temporal workaround until a patch is made available.


Cheers,

A

Not applicable

Can you tell a sample test URL that we can use to test this logic?

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Thanks for the comment pmulay,

 

Any action associated with an actionForm is vulnerable. URL should look like http://myserver.com/myaction.do

 

Cheers,

A

Not applicable

how do you test if the vulnerability is there and then verify the fix addressed the issue? The main problem I have is I don't know how to test it the vulnerability and thus can't verify if the issue is really addressed after incorporating this fix. Thanks for any help you can provide.

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Jamie,

 

Thanks for your comment, Im sorry I cannot explain how to verify if the issue has been fixed withouth disclosing the exploit details.

 

All I can say is that the filter has been tested in our labs and verified by the Struts security team.

 

Cheers,

A

Not applicable

Thanks for providing the patch!

 

After analysing the regular expression, did you realise that in your regular expression:

 

(.*\.|^|.*|\[('|"))(c|C)lass(\.|('|")]|\[).*

 

the prefix part can be simplified to:

 

(.*)(c|C)lass(\.|('|")]|\[).*

 

Is this still what you intended to do?

 

Regards,

William

 

Not applicable
 

I'm using Struts 1.3.10 with Websphere 8. I tried testing the above fix  in my application by providing urls with parameters like "?class.classLoader.defaultAssertionStatus=true", or "class.classLoader.resource.dircontext.docBase=someText" either case all such parameters are permitted into my application. I see those parameters inside the finalParameters returned by the by getParameters(). Am I testing correctly or am I missing something here? I've placed this ParamFilter as the first filter in the chain in my web.xml file. Thanks in advance.

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Thanks for the comment William,

 

Yes I realized that and I would suggest removing the .* from the first group since otherwise properties ending on "class" wont be accepted. I chose to stick to Struts2 proposed regex and notify them about the extra ".*"

 

Cheers,

A

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Reva,

 

Thanks for your comment. This filter is a temporal fix for this particular vulnerability. Struts 1 uses getParameterNames to loop through parameters that are going to be bound to ActionForm properties. So in order to mitigate this issue, it is enough to prevent dangerous property names from appearing in the return collection of getParameterNames(). Other request methods like getParameters are not intercepted by the filter and so those parameter will still be available for the servlets except that an ActionForm property mapping will be prevented.

 

Cheers,

A

Not applicable

Hi Alvaro,

 

Can you give an example url parameter which will be prevented by this Filter? 

 

Thanks!

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Reva,

 

The one you posted is an example of a bean property that wont be bound to the actionForm, although a request.getParameters() will return it. The filter will prevent request.getParameterNames() but not request.getParameters(), effectively preventing ActionForm property binding but not other legitimate accesses to the request parameter.

 

Cheers,

A

Not applicable

I have been able to replicate the exploit when using a ActionForm directly, but not when using DynaActionForms. We are using DynaActionForms it appears to use form properties from the struts-config instead of the request.getParameterName during the ActionForm binding process. Is this correct?

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi JFreedom,

 

Thanks for your comment. DynaActionForms use request.getParameterNames() in the same way that ActionForms do. But the bind process is slightly different, DynaActionForms contains a HashMap where the property name and value are stored instead of using apache commons BeanUtils to set up the beans properties.

 

Cheers,

A

Not applicable

Thanks so much for addressing this.

 

You responded to a comment that the regex given by Struts 2 is slightly incorrect, but I was unsure how to apply your comments.  You said to remove the .* from the first group, so would this change the regex to

 

(.*\.|^|\[('|"))(c|C)lass(\.|('|")]|\[).*

 

or something else?  I was finding that in our application, with the original regex, we were able to set property names that ended in "class" just fine but were also able to deny setting those that would affect the class object directly, but I'm wondering if I'm missing something.  Can you please clarify?

 

Thanks!

 

Kristina

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Kristina,

 

Thank you for your comment. The original regex suggested by the struts team is effectively equivalent to

.*(c|C)lass(\.|('|")]|\[).*

That regex will match and prevent setting nested properties like:  somethingclass.prop

But it will allow setting a property like: simpleclass  (no nesting)

 

The regex that you suggest:

(.*\.|^|\[('|"))(c|C)lass(\.|('|")]|\[).*


will allow to set nested and simple properties that end in "class" but will prevent the classloader manipulation.

 

Thanks,

A

Not applicable

Hello ,

 

Is this ok if I use below filter mapping in given solution.

 

    <filter-mapping>

     <filter-name>ParamFilter</filter-name>
       <url-pattern>*.do</url-pattern>    
    </filter-mapping>

Not applicable

Hi Alvaro,

 

I understand your comment about not able to detail how to verify the vulnerability. I am wondering if we can discuss this in private. I am working on a product where we need to verify if our product is vulnerable. Not sure if you can reach me via the email address I provided in the form or if possible, I can also be reached at xxx-xxx-xxxx. Thanks in advance.

 

Jamie

 

 

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi ushasingh,

 

That should work if all your actions use the .do suffix

 

Cheers,

A

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Jamie,

 

Im really sorry, but I cannot give any details on the exploit. Please get in contact with the Struts security team to see if they can help you.

 

Cheers,

A

Not applicable

 Hi Team,

       Thank you for your solution.

       But which name I need to configure in servlet-name

<servlet-name>YOUR ACTION SERVLET</servlet-name>
Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi,

 

It depends on how do you name your Struts1 servlet. Look for a servlet definition like:

 

    <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
      ....
  </servlet>

 

The servlet name for this particular example is "action".

 

Thanks,

A

Not applicable

Thanks for the solution.

 

I have a question though.

 

If my request has a parameter name like myclass.name, would it not get filtered out as well? I am not good at regular expressions so not sure this regular expression filters only the malecious input parameters and not valid businessnames like myclass.something?

 

Thanks,

Nilesh

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Nilesh,

 

Thank you for your comment. The original regex suggested by the struts team will match and prevent setting nested properties like:  myclass.something

But it will allow setting a property like: myclass  (no nesting)

 

The following regex will allow to set nested and simple properties that end in "class" but will prevent the classloader manipulation.

(.*\.|^|\[('|"))(c|C)lass(\.|('|")]|\[).*



Thanks,

A

shigee Absent Member.
Absent Member.

Hi,

 

Workarounds of cookie was necessary in Struts2.

In Struts1, is similar Workarounds unnecessary?

 

 

Thanks!

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Shigee,

 

No, this particular bug only affects Action Form bindings

 

Cheers,

A

Not applicable

I've coded this, tested it, and I can see the bit of code that lets parameters through is being used, by examining the log.

 

So negatively, I can see this is working, no problemo.

 

How can I test a positive (ie, that somehing is being trapped by the code)? I dont want to know anything about the exploit, but I need a strategy whereby I can show this code is working.

 

Any ideas? Am I missing something glaringly obvious here? Me missing something obvious is always the default position.

 

Cheers,

 

Tom

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Tom,

 

Thanks for your comment. If the filter works ok and its correctly deployed, it should be preventing access to certain parameters. The parameters that are going to be intercepted are the ones in that match the regular expression. So for example if you have a Action form with a user field of type "User", then trying to set the nested property "user.class" should be trapped by the filter and logged.

 

Cheers,

A

Not applicable
struts.debug=true
1)You *should* see the parameters trapped by your regex with the System.out:
if (!parameterName.matches(regex)) { finalParameterNames.add(parameterName); System.out.println("Param included is : " + parameterName); }
else { System.out.println("Param excluded is : "+parameterName); }
2)Shark your line if you want to see the traffic coming and going

Saludos Cordiales desde EEUU,
Martín

 

Not applicable

Hi Alvaro,

 

Thanks for the post. Its very useful. Also, I'm having some queries. I would like to clear them out. 

 

1. Our application is based upon Spring Framework and is just using the struts tiles framework . So in our case we are having controllers instead of action forms. As we have imported struts 1.3.10 jars, so would like to know if our application comes under the scope of vulnerablility. 

 

2. Also, we are having a custom XSS filter already defined for all the URL's to find below patterns in parameter's.

 

Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
// Remove any lonesome <script ...> tag
Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
// eval(...)
Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
// expression(...)
Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
// javascript:...
Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE),
// vbscript:...
Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE),
// onload(...)=...
Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
//remove <IMG.. > tags
Pattern.compile("<IMG(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)

 

I would like to know if this servers the same purpose as the ParamFilter.

 

3. My last query is will Param Filter or above XSS filter prevent cookie attacks too?

 

Not applicable

Can we define a security policy and secure specific classes? Will this help in solving this?

Not applicable

I was able to recreate the issue (Struts 1.1) with url parameters (class.ClassLoader), which resulted in modifying the classloader settings. But could not see any issue with html elements with name class.ClassLoader. Is it sufficient if I only put parameter blacklisting in the filter?

 

Would like to know why the ParamWrapperFilter reads the input stream and check for blacklist pattern.

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi,

 

Parameter blacklistt should be used to protect query parameters and request body (so it is necessary to read and protect the request input stream)

 

Cheers,

A

Not applicable

Hi

 

I would like to know whether struts team will release the Struts1.3 version with this vulnerability been fixed ?

 

Thanks in advance.

 

Feroz

Not applicable

Hi Support,

 

Any update for the my earlier query ?

 

In addition, Is this vulnerability impacted If my project is using the DynaActionForm ?

 

Please let me know in details.

 

Thks and Rgds

 

Feroz

Not applicable

Hi support ,

 

We are using DynaActionForm in my project.

 

I would like to check with Struts support team to confirm whether the DynaActionForm is really impacted with this vulnerability.

 

Please let us know in details.

 

FYI. I have raised the same type of question last month and the question was not published yet into the portal.

 

Rgds

 

Feroz

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Feroz,

 

DynaActionForms are impacted but Im sorry we cannot disclose details.

 

Cheers,

A

Not applicable

Hi Alvaro,

 

I have applied filter using StrutsFilter1.jar from maven repository and modifying web.xml file by adding this:

<

 

filter>

 

<filter-name>ParamWrapperFilter</filter-name>

 

<filter-class>net.rgielen.struts1.filter.ParamWrapperFilter</filter-class>

</

 

filter>

 

<filter-mapping>

 

<filter-name>ParamWrapperFilter</filter-name>

 

<servlet-name>banking</servlet-name>

</

 

filter-mapping>

 

 

However, when I Analyze project using forify static analyzer it still flags Struts1Classloader issue.

 

Is that supposed to be?

 

Thanks

 

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi nvaslav48,

 

A bug has been filed and issue will be remove in future releases.

 

Thanks,

A

Not applicable

Hi,

 

I would like to know if we have a solution to above discussed problem yet?

 

Thanks,

Sohil

Not applicable

hi,

 

Also I am trying to Test the ParamWrapperFilter which was last updated on Jan 22. I am providing "][]Class][<>" as a value to parameterName, however pattern.matcher(parameterName).matches() line always returns false. Please can somebody explain me what I am doing wrong here.

 

Thanks,

Sohil

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor
Hi Sohil, Please file an issue in the github repo for further discussion. Thanks, A
Not applicable

 

Hi Alvaro,

As per your suggestion, I have posted issue in github repo. Please let me know if there is a fix for Classloader manipulation issue for Struts1.x.

 

https://github.com/rgielen/struts1filter/issues/4

 

Thanks,

Sohil

Micro Focus Frequent Contributor
Micro Focus Frequent Contributor

Hi Sohil,

 

I have just replied to your comment in github: https://github.com/rgielen/struts1filter/issues/4

 

Also, please check for a different workaround that implies patching Struts 1 code or using an unofficial patched build: https://github.com/rgielen/struts1filter/issues/3

 

Workaround: use patched struts distribution instead of this filter.

Patch link: https://github.com/apache/struts1/pull/1/files

Patched struts 1.3.10 is available for example for Fedora 20 in build "struts-1.3.10-10.fc20" in form of RPM: http://koji.fedoraproject.org/koji/buildinfo?buildID=552377

The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.