一步一步回顾分析攻防演习中的 WebLogic T3 反序列化 0day 漏洞

本文深入分析了WebLogic T3反序列化0day漏洞,涉及Jdk7u21的PoC,重点讨论了如何利用MarshalledObject绕过黑名单。通过构造恶意类,利用反序列化执行恶意代码,实验复现了漏洞利用过程,并探讨了补丁的修复策略。
摘要由CSDN通过智能技术生成

 聚焦源代码安全,网罗国内外最新资讯!

本文内容共分六部分:

一、前言

二、Jdk7u21 的 PoC 分析

1、第一部分利用链分析

2、第二部分利用链分析

三、MarshalledObject分析

四、PoC 构造

五、实验复现

六、补丁分析

一、前言

本次攻防演习期间,有人发现 Weblogic T3反序列化0day漏洞。攻击者可在原Jdk7u21 POC 基础上,加上 java.rmi.MarshalledObject 绕过黑名单,达到入侵目的,具体如下。

二、Jdk7u21的PoC分析

gadget 如下:

HashSet.readObject()
 HashMap.put()
  HashMap.hash()
   *.hashCode() (计算第一个对象hash值)
HashSet.readObject()
 HashMap.put()
  HashMap.hash()
   *.hashcode()
    AnnotationInvocationHandler.invoke()
     AnnotationInvocationHandler.hashCodeImpl()
 HashMap.put()
  AnnotationInvocationHandler.invoke()
   AnnotationInvocationHandler.equalsImpl()
    TemplatesImpl.getOutputProperties()
     TemplatesImpl.getTransletInstance()
      TemplatesImpl.defineTransletClasses()
       TemplatesImpl$TransletClassLoader
     TemplatesImpl.getTransletInstance()
      Class.newInstance()
       Runtime.exec()


1、分析第一部分利用链

Jdk7u21的第一部分利用链如下。

HashSet.readObject()
 HashMap.put()
  HashMap.hash()
   *.hashCode()(计算第一个对象hash值)
HashSet.readObject()
 HashMap.put()
  HashMap.hash()
   *.hashcode()
    AnnotationInvocationHandler.invoke()
     AnnotationInvocationHandler.hashCodeImpl()
 HashMap.put()
  AnnotationInvocationHandler.invoke()
   AnnotationInvocationHandler.equalsImpl()

在对 LinkedHashSet 反序列化过程中,会进入 HashSet.readObject() 函数,关键代码块如下。

/ Read in all elements in the proper order.
for (int i=0; i<size; i++) {
    E e = (E) s.readObject();
    map.put(e, PRESENT);
}

根据 POC 信息,可知该函数会依次读取 LinkedHashSet 的 templates 和proxy对象,并将它们加入 map中。为什么需要加载两个对象呢?继续进入map.put() 函数,如下。

public V put(K key, V value) {
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key);
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }


    modCount++;
    addEntry(hash, key, value, i);
    return null;
}


该函数会计算存储进map的第一个对象Templates的Hash值,进入hash(key),如下。

final int hash(Object k) {
    int h = 0;
    if (useAltHashing) {
        if (k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }
        h = hashSeed;
    }


    h ^= k.hashCode();


    // This function ensures that hashCodes that differ only by
    // constant multiples at each bit position have a bounded
    // number of collisions (approximately 8 at default load factor).
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}


程序会执行常规hash运算,注意,其中的 k.hashCode() 调用了系统函数;而如果构造动态代理,编写或寻找到合适代理类,则极有可能使多个存储进map的对象的hash值一致。返回至HashMap.put() 函数,继续分析,进入至indexFor(hash, table.length) 函数,如下。

/**
 * Returns index for hash code h.
 */
static int indexFor(int h, int length) {
    return h & (length-1);
}


table对象的原定义代码是table[bucketIndex] = new Entry<>(hash, key, value, e),负责保存 map 中每个对象及 hash 值等信息。此函数没有保存对象信息功能,仅仅负责统计返回当前对象在 table 中的索引值。随后返回至HashMap.put() 函数。

随后,如当前对象不在 table 中,则不进入循环,而是进入 addEntry(hash, key, value, i); 且在此期间进入父类方法,最终当前对象被保存至 table 中,关键代码如下。

void createEntry(int hash, K key, V value, int bucketIndex) {
    HashMap.Entry<K,V> old = table[bucketIndex];
    Entry<K,V> e = new Entry<>(hash, key, value, old);
    table[bucketIndex] = e;
    e.addBefore(header);
    size++;
}


保存完第一个对象后,程序返回到 HashSet.readObject() 方法,并在 map 中添加第二个对象。如第二个对象是代理对象,则其 hash 值可能与前一个对象的hash 值碰撞,从而有利于绕过代码的验证逻辑,便于未来开展入侵测试;如POC中存在第二个代理对象,则会继续进入 map.put()。

进入 hash(key),计算第二个代理对象的hash值,进入 HashMap.hash() 函数。

在 POC 中,第二个代理对象的代理类是 AnnotationInvocationHandler,因此执行 k.hashCode() 时,会首先进入 AnnotationInvocationHandler.invoke() 方法,如下。

public Object invoke(Object var1, Method var2, Object[] var3) {
    String var4 = var2.getName();
    Class[] var5 = var2.getParameterTypes();
    if (var4.equals("equals") && var5.length == 1 && var5[0] == Object.class) {
        return this.equalsImpl(var3[0]);
    } else {
        assert var5.length == 0;


        if (var4.equals("toString")) {
            return this.toStringImpl();
        } else if (var4.equals("hashCode")) {
            return this.hashCodeImpl();
        } else if (var4.equals("annotationType")) {
            return this.type;
        } else {
            Object var6 = this.memberValues.get(var4);
            if (var6 == null) {
                throw new IncompleteAnnotationException(this.type, var4);
            } else if (var6 instanceof ExceptionProxy) {
                throw ((ExceptionProxy)var6).generateException();
            } else {
                if (var6.getClass().isArray() && Array.getLength(var6) != 0) {
                    var6 = this.cloneArray(var6);
                }


                return var6;
            }
        }
    }
}


根据方法名进入this.hashCodeImpl();,相关的代码块如下。

private int hashCodeImpl() {
    int var1 = 0;


    Entry var3;
    for(Iterator var2 = this.memberValues.entrySet().iterator(); var2.hasNext(); var1 += 127 * ((String)var3.getKey()).hashCode() ^ memberValueHashCode(var3.getValue())) {
        var3 = (Entry)var2.next();
    }


    return var1;
}
private static int memberValueHashCode(Object var0) {
    Class var1 = var0.getClass();
    if (!var1.isArray()) {
        return var0.hashCode();
    } else if (var1 == byte[].class) {
        return Arrays.hashCode((byte[])((byte[])var0));
    } else if (var1 == char[].class) {
        return Arrays.hashCode((char[])((char[])var0));
    } else if (var1 == double[].class) {
        return Arrays.hashCode((double[])((double[])var0));
    } else if (var1 == float[].class) {
        return Arrays.hashCode((float[])((float[])var0));
    } else if (var1 == int[].class) {
        return Arrays.hashCode((int[])((int[])var0));
    } else if (var1 == long[].class) {
        return Arrays.hashCode((long[])((long[])var0));
    } else if (var1 == short[].class) {
        return Arrays.hashCode((short[])((short[])var0));
    } else {
        return var1 == boolean[].class ? Arrays.hashCode((boolean[])((boolean[])var0)) : Arrays.hashCode((Object[])((Object[])var0));
    }
}


var3信息来自AnnotationInvocationHandler的memberValues成员变量:如var3 中只有一条map信息,且该map的key为"f5a5a608"而value是加入map的第一个对象,则经调试分析发现,此时会发生两个对象hash值碰撞的情况。返回至 HashMap.put() 继续分析。

在循环代码块中,存在关键比较逻辑,如下。

if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
    V oldValue = e.value;
    e.value = value;
    e.recordAccess(this);
    return oldValue;
}


该逻辑首先会比较两个对象的hash值是否相等:根据 PoC 可知两值相等,并且会执行至 key.equals(k)。k是第一个对象,key是第二个代理对象,则会执行代理类invoke()方法。POC中的代理类是AnnotationInvocationHandler,则进入AnnotationInvocationHandler.invoke(),随后再进入this.equalsImpl(var3[0]),如下。

private Boolean equalsImpl(Object var1) {
    if (var1 == this) {
        return true;
    } else if (!this.type.isInstance(var1)) {
        return false;
    } else {
        Method[] var2 = this.getMemberMethods();
        int var3 = var2.length;


        for(int var4 = 0; var4 < var3; ++var4) {
            Method var5 = var2[var4];
            String var6 = var5.getName();
            Object var7 = this.memberValues.get(var6);
            Object var8 = null;
            AnnotationInvocationHandler var9 = this.asOneOfUs(var1);
            if (var9 != null) {
                var8 = var9.memberValues.get(var6);
            } else {
                try {
                    var8 = var5.invoke(var1);
                } catch (InvocationTargetException var11) {
                    return false;
                } catch (IllegalAccessException var12) {
                    throw new AssertionError(var12);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
WebLogic T3/IIOP反序列化工具是一种用于利用WebLogic T3协议和IIOP协议进行反序列化攻击的工具。在WebLogic ServerT3协议是用于客户端和服务器之间进行通信的协议,而IIOP协议是一种用于分布式对象通信的协议。 这个工具可以被黑客用来利用WebLogic Server的安全漏洞,通过发送恶意的序列化数据包来实现远程代码执行。这种攻击利用了Java反序列化漏洞,是一种非常危险的攻击方式,可能导致服务器被完全控制。 WebLogic T3/IIOP反序列化工具一般包括两个主要组件:Payload生成器和Payload发送器。Payload生成器用于创建恶意的序列化数据包,而Payload发送器则负责将生成的数据包发送到目标服务器。 为了保护WebLogic Server免受此类攻击,建议采取以下措施: 1. 及时更新WebLogic Server到最新版本,修复已知的安全漏洞。 2. 规范代码开发和部署,避免使用不受信任的第三方库或组件。 3. 配置严格的访问控制策略,限制访问WebLogic Server的IP地址和端口。 4. 限制用户权限,避免赋予不必要的权限。 5. 监控WebLogic Server日志,及时检测异常活动和攻击。 6. 避免在生产环境使用默认的管理员凭据,使用强密码,并定期更换密码。 总之,WebLogic T3/IIOP反序列化工具是一种非常危险的工具,可以被黑客用来攻击WebLogic Server。为了保护服务器安全,建议采取一系列措施来防止此类攻击的发生。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值