返回文章列表

Ethernet/IP物件模型於Koyo CLICK PLC的控制實踐

本文深入探討 Ethernet/IP 的物件模型,闡述其 class/instance/attribute 結構在工業控制中的核心作用。文章以 Python 工具 cpppo 為例,展示如何在虛擬環境中對 PLC 標籤進行屬性讀寫,並將此技術應用於 Koyo CLICK PLC 的實際操作。內容涵蓋從 CLICK 編程軟體中獲取 Explicit 訊息的位址參數,到利用 Ethernet/IP 指令直接監控與控制 PLC 的輸入輸出點。最終透過 Wireshark 封包分析,驗證了底層通訊的正確性,提供一套完整的理論與實踐結合的控制方法。

工業控制系統 網路安全

在現代工業自動化環境中,Ethernet/IP 以其豐富的物件導向特性,提供了遠比傳統輪詢協議更為精細的控制能力。理解其核心的物件模型,特別是 class、instance 與 attribute 的組合,是實現高階整合與客製化通訊的基礎。本文將跳脫標準的掃描器與適配器配置框架,聚焦於非連接式顯式訊息(Unconnected Explicit Messaging)的應用。透過直接對 PLC 內部物件屬性進行讀寫操作,不僅能繞過傳統的梯形圖邏輯限制,實現更靈活的遠端控制與數據監控,同時也揭示了潛在的攻擊向量。此方法論的掌握,對於系統開發者、整合商以及網路安全研究人員,皆具有高度的實務價值。

Ethernet/IP物件模型互動與Koyo CLICK實戰

玄貓認為,深入理解Ethernet/IP的物件模型,並能靈活運用其class/instance/attribute結構進行數據操作,是掌握工業控制系統的關鍵能力。本節將引導您透過cpppo工具,在虛擬環境中進行Ethernet/IP的屬性讀寫,並將這些知識應用於Koyo CLICK PLC的實際操作與監控。

Ethernet/IP物件模型語法:

Ethernet/IP的物件模型可以傳遞大量資訊,玄貓強烈建議您閱讀相關標準並自行研究協議。對於我們的目的,我們只需要了解以下語法: class/instance/attribute 這就是系統中定義一個**標籤(tag)**的方式。

實務案例:虛擬PLC的屬性讀寫:

1. 建立帶有標籤的Ethernet/IP伺服器:

在您的PLC虛擬機終端機中,輸入以下命令:

python3 -m cpppo.server.enip -v -a 0.0.0.0 'Compressor_StationA@8/1/1'

這條命令指示系統建立一個名為Compressor_StationA的標籤,其物件的類別ID0x08(這是離散輸入點的公開宣告類別ID),實例ID1屬性ID1。如果一切順利,您將看到伺服器成功啟動並顯示該標籤。

2. 讀取單一屬性值:

現在回到您的SCADA虛擬機,輸入以下命令:

python3 -m cpppo.server.enip.get_attribute '@8/1/1' -S -a 192.168.1.10

使用-S(簡潔模式)和-a(位址),此命令請求位於8/1/1的屬性。執行此命令後,您應該會獲得回應,指示該屬性值為0

3. 寫入屬性值:

我們現在將寫入這個標籤。使用以下命令將屬性值設定為1

python3 -m cpppo.server.enip.get_attribute '@8/1/1=(INT)1' '@8/1/1' -S -a 192.168.1.10

比較這兩個語句,您會發現我們只是添加了一個新參數,指示系統將物件@8/1/1設定為整數1。如所示,您現在應該會看到兩個輸出,分別表示設定屬性(Set Attribute Service, SAS)和獲取屬性(Get Attribute Service, GAS)。第一個命令將屬性設定為True,第二個命令返回1的值。

4. 使用別名進行讀寫:

最後,由於我們為物件指定了標籤名稱Compressor_StationA,我們可以使用該名稱來獲取和更新值,因為它已在系統中建立別名。例如,執行以下命令:

python3 -m cpppo.server.enip.client --print Compressor_StationA Compressor_StationA -a 192.168.1.10

您將看到輸出,顯示標籤別名的Get/Set屬性操作。這展示了在遠端控制器中切換值的簡便性,只需要精確的物件映射class/instance/attribute

Koyo CLICK PLC的Ethernet/IP通訊:

現在,我們可以在實驗室中的Koyo CLICK PLC上測試相同的命令方式。

1. 獲取Explicit訊息的Class/Instance/Attribute:
  • 導航到CLICK編程軟體的「設定」菜單,並選擇「EtherNet/IP 設定…」。
  • 您將進入之前配置過程中看到的設定畫面。
  • 我們將專注於兩個區域,第一個位於「輸入(到掃描器)」選項卡下。注意標記為(Explicit)Class/Instance/Attribute項目:
  • Class: 4
  • Instance: 101
  • Attribute: 3
  • 接著,轉到「輸出(來自掃描器)」選項卡。您將看到類似的Class/Instance/Attribute
  • Class: 4
  • Instance: 102
  • Attribute: 3 玄貓認為,如果您回想起實例ID的用途,您就會明白為什麼它們會有所不同。
2. 監控PLC數據:

我們現在有足夠的數據來與我們正在運行的PLC程式通訊。為了觀察指令如何與PLC互動,我們希望在Koyo CLICK編程軟體中對「數據視圖」(Data View)面板進行一些調整。

3. 設定數據視圖進行監控:
  • 簡而言之,您需要前往「監控」(Monitor)菜單並選擇「數據視圖」(Data View)選項。

此圖示:Ethernet/IP屬性互動與Koyo CLICK監控流程

@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

actor "攻擊者 (玄貓)" as attacker
rectangle "PLC 虛擬機" as plc_vm {
component "cpppo ENIP 伺服器" as cpppo_server
}
rectangle "SCADA 虛擬機" as scada_vm {
component "cpppo ENIP 客戶端" as cpppo_client
}
rectangle "Koyo CLICK PLC" as koyo_plc {
component "EtherNet/IP 適配器" as enip_adapter
component "CLICK 編程軟體" as click_software
database "PLC 數據記憶體" as plc_memory
}

cpppo_server --> cpppo_server : 建立 'Compressor_StationA@8/1/1' 標籤

attacker --> cpppo_client : 讀取屬性 `python3 -m cpppo.server.enip.get_attribute '@8/1/1' ...`
cpppo_client --> cpppo_server : 請求屬性值
cpppo_server --> cpppo_client : 回應屬性值 (0)
cpppo_client --> attacker : 顯示屬性值

attacker --> cpppo_client : 寫入屬性 `python3 -m cpppo.server.enip.get_attribute '@8/1/1=(INT)1' ...`
cpppo_client --> cpppo_server : 設定屬性值 (1)
cpppo_server --> cpppo_client : 回應設定成功
cpppo_client --> attacker : 顯示設定結果

attacker --> cpppo_client : 使用別名讀取 `python3 -m cpppo.server.enip.client --print Compressor_StationA ...`
cpppo_client --> cpppo_server : 請求別名屬性
cpppo_server --> cpppo_client : 回應別名屬性值 (1)
cpppo_client --> attacker : 顯示別名屬性值

attacker --> click_software : 進入 EtherNet/IP Setup
click_software --> enip_adapter : 獲取 Explicit 訊息 Class/Instance/Attribute (Input: 4/101/3, Output: 4/102/3)

attacker --> click_software : 設定數據視圖 (Data View)
click_software --> plc_memory : 監控 PLC 數據

note left of cpppo_server
Ethernet/IP 物件模型: class/instance/attribute
非連接式顯式訊息
end note

@enduml

看圖說話:

此圖示清晰地展示了Ethernet/IP屬性互動的流程以及Koyo CLICK PLC的監控設定。首先,攻擊者(玄貓)PLC虛擬機上使用cpppo伺服器建立了一個帶有class/instance/attribute結構的標籤。隨後,玄貓在SCADA虛擬機上透過cpppo客戶端,成功執行了對該標籤屬性的讀取和寫入操作,並展示了如何使用別名進行通訊。接著,流程轉向Koyo CLICK PLC的實際應用,玄貓透過CLICK編程軟體獲取了EtherNet/IP適配器中Explicit訊息的Class/Instance/Attribute資訊,這些資訊是與PLC進行精確通訊的基礎。最後,玄貓設定了編程軟體的數據視圖功能,以便實時監控PLC內部數據的變化,從而觀察外部指令對PLC的影響。這個流程綜合了虛擬環境的實作與實體PLC的配置,為深入理解Ethernet/IP在工業控制中的應用提供了全面的視角。

Koyo CLICK PLC數據監控與Ethernet/IP燈光控制

玄貓認為,透過實時監控PLC數據並利用Ethernet/IP協議直接操作設備,是深入理解工業控制系統互動的進階實踐。本節將引導您在Koyo CLICK編程軟體的數據視圖中添加監控點,並使用cpppo工具透過Ethernet/IP控制燈光,最終透過Wireshark驗證通訊。

數據視圖設定與監控:

1. 添加監控暫存器:
  • 在Koyo CLICK編程軟體的「數據視圖」(Data View)中,選擇一個單元格。
  • 從下拉選單中選擇您希望監控的位址,例如X001X002Y001Y002等。
  • 點擊「確定」後,繼續添加其他位址,直到您的數據視圖與預期相符。
  • 玄貓建議您啟用「覆蓋」(Override)功能,以便手動控制輸入。
2. 初始屬性獲取:

一旦數據視圖中顯示了這些暫存器,並且與設定相符,請回到SCADA虛擬機終端機,輸入以下命令:

python3 -m cpppo.server.enip.get_attribute '@4/101/3' '@4/102/3' -S -a 192.168.1.20

如前所述,此命令使用簡潔模式來獲取這些物件的屬性。如果您的所有輸入和輸出都處於關閉狀態,您應該會收到相應的回應。

3. 理解XD與YD暫存器:

玄貓提醒,在Koyo CLICK PLC的Ethernet/IP設定文檔中,XD暫存器是唯讀的,而YD暫存器是讀寫的。這與控制哲學有關,超出了本書的範圍。您只需要知道,如果您希望直接與燈光互動,可以使用Ethernet/IP繞過PLC的輸入I/O,直接使用YD暫存器啟動線圈。

手動觸發輸入與Ethernet/IP控制:

1. 手動開啟X001和X002:

下一步是從「數據視圖」面板手動開啟X001X002。您會注意到一些二進制數學,這應該會讓您回想起早期的電腦科學知識。例如,0001 + 0010 == 0011,這在十六進制中表示為3。因此,XD0被賦予十六進制值3

2. 再次獲取屬性驗證:

為了確保我們正在查看正確的特性,我們將再次執行Get屬性命令:

python3 -m cpppo.server.enip.get_attribute '@4/101/3' '@4/102/3' -S -a 192.168.1.20

如果一切設定正確,您應該會看到輸入的十六進制值為3

3. 透過Ethernet/IP控制燈光:

既然我們已經確認了正確的位址,就可以開始開啟和關閉燈光了。回想一下,在虛擬PLC中,我們只是將值類型和實際值附加到讀取命令中。在這種情況下,我們將重複@4/102/3物件,並包含類型以及我們希望開啟的燈光組合的十六進制等效值。執行以下命令來開啟所有燈光:

python3 -m cpppo.server.enip.get_attribute '@4/101/3' '@4/102/3=(INT)15' '@4/102/3' -S -a 192.168.1.20

預期結果是所有燈光都將開啟。

4. 驗證輸出狀態:

再次檢查「數據視圖」頁面,確保所有輸出(例如Y001-Y004)都已開啟。

Wireshark驗證Ethernet/IP通訊:

最後,使用Wireshark監聽SPAN介面,記錄Set屬性封包。在Wireshark的「資訊」(Info)欄中,您應該會看到發送的三條指令的以下資訊:

  • 第一個命令是「Get attribute」被偵測到。
  • 接著是「Set attribute single」命令,用於設定屬性。
  • 最後一個命令是再次「Get attribute」,用於獲取Set命令的結果。

如果您曾進行任何研究以發現更多應用類別ID,您會發現0x04類別ID是一個廣泛接受的組件標準(assembly standard)。如果您展開「Assembly: Set Attribute Single」封包並檢查協議的CIP層內部,您會看到數據值為0F00,這在十六進制中表示15

玄貓總結,我們成功地透過Ethernet/IP開啟和關閉了燈光。協議結構乍看之下可能比Modbus複雜和繁瑣,但經過研究和試錯,我們意識到位址的class/instance/attribute結構使其變得相當直接。

此圖示:Koyo CLICK Ethernet/IP控制與監控流程

@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

actor "攻擊者 (玄貓)" as attacker
rectangle "SCADA 虛擬機" as scada_vm {
component "cpppo ENIP 客戶端" as cpppo_client
}
rectangle "Koyo CLICK PLC" as koyo_plc {
component "EtherNet/IP 適配器" as enip_adapter
component "CLICK 編程軟體" as click_software
database "PLC 數據記憶體" as plc_memory
}
cloud "網路" as network {
component "ESXi vSwitch / SPAN 埠" as span_port
}
rectangle "分析工作站" as analysis_ws {
component "Wireshark" as wireshark
}

attacker --> click_software : 設定數據視圖 (X001, X002, Y001-Y004)
click_software --> plc_memory : 監控 PLC 數據

attacker --> cpppo_client : 獲取屬性 `python3 -m cpppo.server.enip.get_attribute '@4/101/3' '@4/102/3' ...`
cpppo_client --> enip_adapter : 發送 Get 請求
enip_adapter --> cpppo_client : 回應屬性值 (初始狀態)
cpppo_client --> attacker : 顯示屬性值

attacker --> click_software : 手動開啟 X001, X002 (數據視圖)
click_software --> plc_memory : 更新 XD0 (Hex 3)

attacker --> cpppo_client : 再次獲取屬性 (驗證 X001, X002 狀態)
cpppo_client --> enip_adapter : 發送 Get 請求
enip_adapter --> cpppo_client : 回應屬性值 (Hex 3)
cpppo_client --> attacker : 顯示屬性值

attacker --> cpppo_client : 設定屬性 `python3 -m cpppo.server.enip.get_attribute '@4/101/3' '@4/102/3=(INT)15' ...`
cpppo_client --> enip_adapter : 發送 Set 請求 (Y001-Y004 ON)
enip_adapter --> cpppo_client : 回應 Set 結果
cpppo_client --> attacker : 顯示 Set 結果

enip_adapter --> plc_memory : 更新 YD0 (Hex F)
plc_memory --> click_software : 數據視圖顯示 Y001-Y004 ON

network --> span_port : 流量鏡像
span_port --> wireshark : 捕獲 EtherNet/IP 流量 (Get/Set 封包)
wireshark --> attacker : 顯示封包細節 (服務碼, 數據值 0F00)

note right of enip_adapter
Ethernet/IP Class/Instance/Attribute:
Input: @4/101/3 (XD0)
Output: @4/102/3 (YD0)
end note

@enduml

看圖說話:

此圖示詳盡地展示了透過Ethernet/IP協議控制Koyo CLICK PLC燈光並進行監控的整個流程攻擊者(玄貓)首先在CLICK編程軟體中設定數據視圖以監控PLC的X和Y暫存器。接著,玄貓使用cpppo客戶端SCADA虛擬機發送Ethernet/IP請求,獲取PLC的初始屬性狀態。在手動在數據視圖中開啟X001和X002後,玄貓再次透過cpppo驗證了輸入狀態的變化。最關鍵的步驟是玄貓透過cpppo發送Ethernet/IP Set請求,將輸出暫存器@4/102/3的值設定為15(十六進制F),從而開啟了所有燈光(Y001-Y004)。整個通訊過程被Wireshark透過SPAN埠捕獲,並詳細分析了Get和Set屬性封包的內容,包括服務碼和數據值0F00。此圖不僅展示了如何實際操作工業設備,也強調了利用網路分析工具驗證和理解協議互動的重要性。

縱觀從虛擬環境模擬到實體設備控制的完整實踐路徑,Ethernet/IP的物件模型掌握,展現了一條從抽象理論到具體應用的突破軌跡。相較於傳統工業協議,class/instance/attribute結構初看之下雖顯繁瑣,但一旦跨越此認知門檻,它所賦予的精準控制粒度與靈活性,反而成為實現高階自動化與系統整合的基石。此次實戰的價值不僅在於成功點亮一盞燈,而在於建立了一個完整的「整合性實踐迴圈」:透過cpppo進行指令操作、藉由Data View實現狀態監控、並利用Wireshark完成底層通訊驗證。

玄貓認為,這種融合IT工具鏈(腳本化控制、網路分析)與OT領域知識(PLC暫存器、I/O邏輯)的操作能力,正是未來工業控制與資安專家的核心競爭力所在。它預示著一個新趨勢:單純的協議知識已不足夠,唯有能將其轉化為可驗證、可重現的系統性操作,才能在日益複雜的工業4.0生態中取得主導權。

綜合評估後,這套從理論解析到動手實踐的學習路徑,代表了高效掌握複雜工業協議的最佳模式。對於追求技術深度與實戰能力的專家而言,將這種抽象模型轉譯為具體物理控制的能力,已不僅是技術操作,更是衡量其能否系統性駕馭現代工業自動化系統的關鍵指標。