Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@ykare
Last active December 29, 2016 04:04
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ykare/1fb2d5d11e16cb0003c3 to your computer and use it in GitHub Desktop.
Save ykare/1fb2d5d11e16cb0003c3 to your computer and use it in GitHub Desktop.
Struts1のS2-020(CVE-2014-0094)対策
package example;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.regex.Pattern;
import javax.servlet.GenericServlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* commons-beanutils 1.7以降が必要。それ以前のバージョンを使っている場合は、置き換えること
* Struts1.X バージョンごとの同梱しているcommons-beanutilsバージョン
* Struts1.3.10: 1.8.0
* Struts1.2.9 : 1.6
* Struts1.1 : 1.6
* Struts1.0.2 : 無し。 org.apache.struts.util.BeanUtils.java にパッチをあてる
*
* Servlet2.3以降: <listener> に example.SafeBeanUtils$InitializeListener を登録
* Servlet2.2以前: <servlet> に example.SafeBeanUtils$InitializeServlet を登録
*
* ※正規表現が使えるのはJDK1.4以降、それ以前のJDKだと正規表現をOROなどで書き換える必要がある
*/
public class SafeBeanUtils extends BeanUtilsBean {
private static final Log LOG = LogFactory.getLog(BeanUtilsBean.class);
private static final Pattern CLASS_ACCESS_PATTERN = Pattern.compile(
"(.*\\.|^|.*|\\[('|\"))class(\\.|('|\")]|\\[).*",
Pattern.CASE_INSENSITIVE);
@SuppressWarnings("rawtypes")
@Override
public void populate(Object bean, Map properties)
throws IllegalAccessException, InvocationTargetException {
for (Object obj : properties.keySet()) {
if (obj instanceof String) {
String key = (String) obj;
if (CLASS_ACCESS_PATTERN.matcher(key).matches()) {
LOG.fatal("Attack detected: " + key);
throw new IllegalArgumentException("Attack detected: "
+ key);
}
}
}
super.populate(bean, properties);
}
/**
* for Servlet2.3 API以降 <listener>
* <listener-class>example.SafeBeanUtils$InitializeListener</listener-class>
* </listener>
*/
public static class InitializeListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
BeanUtilsBean.setInstance(new SafeBeanUtils());
}
@Override
public void contextDestroyed(ServletContextEvent event) {
}
}
/**
* for Servlet2.2 API以前 <servlet>
* <servlet-name>InitializeServlet</servlet-name>
* <servlet-class>example.SafeBeanUtils$InitializeServlet</servlet-class>
* <load-on-startup>1</load-on-startup> </servlet>
*/
public static class InitializeServlet extends GenericServlet {
private static final long serialVersionUID = -198262514592399731L;
@Override
public void init() throws ServletException {
BeanUtilsBean.setInstance(new SafeBeanUtils());
}
@Override
public void init(ServletConfig config) throws ServletException {
BeanUtilsBean.setInstance(new SafeBeanUtils());
}
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
throw new UnsupportedOperationException(
"this Servlet initialize use only");
}
}
}
$ diff -u jakarta-struts-1.0.2-src/src/share/org/apache/struts/util/BeanUtils.java src/org/apache/struts/util/BeanUtils.java
--- jakarta-struts-1.0.2-src/src/share/org/apache/struts/util/BeanUtils.java 2002-02-09 23:38:56.000000000 +0900
+++ src/org/apache/struts/util/BeanUtils.java 2014-04-28 23:34:31.430035300 +0900
@@ -77,6 +77,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.regex.Pattern;
/**
@@ -92,6 +93,9 @@
*/
public class BeanUtils {
+ private static final Pattern CLASS_ACCESS_PATTERN = Pattern.compile(
+ "(.*\\.|^|.*|\\[('|\"))class(\\.|('|\")]|\\[).*",
+ Pattern.CASE_INSENSITIVE);
// ------------------------------------------------------ Private Variables
@@ -411,6 +415,12 @@
String name = (String) names.next();
if (name == null)
continue;
+
+ if (CLASS_ACCESS_PATTERN.matcher(name).matches()) {
+ throw new IllegalArgumentException("Attack detected: "
+ + name);
+ }
+
Object value = properties.get(name); // String or String[]
/*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment