loader
Foto

Modbus/TCP használata a virtuális PLC-n

Az ipari protokollokat bemutató sorozatunk első részében elkészítettük azt a virtuális PLC-t, amelynek segítségével "igazi" PLC-t tudunk modellezni, legalábbis a kommunikációs protokollok szintjén. A sorozatunk mostani részében a Modbus/TCP használata, tesztelése kerül bemutatásra.

Felhívjuk az Olvasók figyelmét arra, hogy ez a cikk azért született meg, hogy felhívjuk a figyelmet a titkosított protokollok alkalmazására. Nem célunk, és határozottan elzárkózunk attól, hogy segítsünk bárkinek számítógépes bűncselekmények elkövetésében.

Az OT protokollok olyan kommunikációs protokollok, amelyeket ipari hálózatokon történő vezérlőüzenetek, adatok cseréjére terveztek. A Modicon által a programozható logikai vezérlőkhöz (PLC-khez) kifejlesztett Modbus protokoll kliens/szerver kommunikációt biztosít a különböző típusú buszokon vagy hálózatokon csatlakoztatott eszközök között.

Ahhoz, hogy a virtuális PLC-nken Modbus szerver legyen, el kellett végezni a korábbi cikkben ismertetett telepítési folyamatot. Ez még önmagában nem elég, szükség van egy olyan szerver programra is, amely a különböző kéréseket kiszolgálja. Az Interneten több ilyen alkalmazás is található, az általunk használt (minimálisan módosított) program itt érhető el:

https://github.com/riptideio/pyModbus

 

A cikk írásakor a következő program került alkalmazásra. Kiegészítésre került a logolással, ezért a különböző műveletek láthatók a virtuális PLC-t megvalósító Ubuntu operációs rendszer terminálablakában.

#!/usr/bin/env python
'''
Asynchronous Modbus Server Built in Python using the pyModbus module
'''
# Import the libraries we need
from pymodbus.server.asynchronous import StartTcpServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext

import logging

# Create a datastore and populate it with test data
store = ModbusSlaveContext(
    di = ModbusSequentialDataBlock(0, [17]*100), # Discrete Inputs initializer
    co = ModbusSequentialDataBlock(0, [17]*100), # Coils initializer
    hr = ModbusSequentialDataBlock(0, [17]*100), # Holding Register initializer
    ir = ModbusSequentialDataBlock(0, [17]*100)) # Input Registers initializer
context = ModbusServerContext(slaves=store, single=True)

# Populate the Modbus server information fields, these get returned as
# response to identity queries

identity = ModbusDeviceIdentification()
identity.VendorName = 'Webelektronika'
identity.ProductCode = 'online'
identity.VendorUrl = 'https://github.com/riptideio/pyModbus'
identity.ProductName = 'Modbus Server'
identity.ModelName = 'PyModbus'
identity.MajorMinorRevision = '1.0'

FORMAT = ('%(asctime)-15s %(threadName)-15s' '%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)

# Start the listening server
print ('Starting Modbus server...')
StartTcpServer(context, identity=identity, address=("0.0.0.0", 502))

 

Fontos az, hogy a vizsgálógépünk ugyanabban a hálózatban legyen, mint a virtuális PLC. Nézzük meg a Kali Linux VM IP címét, ehhez adjuk ki a következő parancsot.

ipconfig

Az első ábrán látható a Kali Linux operációs rendszert futtató virtuális gép IP címe, amely a következő: 192.168.1.107

kep
1. ábra   Kali Linux vizsgálógép IP címének a lekérése
 

Nézzük most meg, hogy milyen egyéb gépek, stb találhatók az otthoni, saját (!) hálózaton. Használjuk erre a célra szintén az "nmap"-ot és az ICMP protokollt, ezért alkalmazzuk az "-sP" kapcsolót.

sudo nmap -sP 192.168.1.1/24

Az ICMP protokoll segítségével (pingelés) megkeressük a hálózaton lévő eszközöket, és természetesen a virtuális PLC-t is (2. ábra).

kep
2. ábra   A hálózaton lévő eszközök felderítése
 

A virtuális PLC-nk a 192.168.1.105-ös IP címen található. Megtaláltuk tehát a PLC-t a hálózaton, a következő lépés most az, hogy megnézzük, hogy ezen az IP címen milyen szolgáltatások találhatók (azaz, milyen portok vannak nyitva).

(ahhoz, hogy a Modbus működjön, indítsuk el az Ubuntu virtuális gépen a cikk elején közölt python kódot)

sudo python3 server2.py

Elindult a Modbus szerver az Ubuntu virtuális gépen, ez látható a következő ábrán.

kep
3. ábra   Az Ubuntu operációs rendszeren elindításra kerül a Modbus szerver
 

Most már megnézhetjük a Kali Linux alatt, hogy a virtuális PLC-n milyen szolgáltatások találhatók. Tekintettel arra, hogy a Modbus portja (502, 5020) az "nmap"-nál nem tartozik a default portok közé, célszerű teljes port scan-t végezni, azaz, alkalmaznunk kell a "-p-" kapcsolót.

sudo nmap -p- 192.168.1.105

Látható a 4. ábrán a teljes port scan eredménye, az 502-es porton üzemel az "mbap". 

kep
4. ábra   A virtuális PLC-t megvalósító Ubuntu operációs rendszeren feldeítésre kerül az összes nyitott TCP port
 

Kérjünk most le verziószámokat, ehhez a következő utasítás kiadása szükséges. (Egyébként felesleges most már a teljes port scan alkalmazása, ez feleslegesen növeli a scan futási idejét.)

sudo nmap -sV -p- 192.168.1.105

Az 5. ábrán láthatók a szolgáltatások a hozzájuk tartozó verziószámokkal. Sajnos a Modbusról nem kaptunk érdemi információt.

kep
5. ábra   A virtuális PLC nyitott portokkal, és a portokon lévő szolgáltatások a verziószámaikkal
 

Próbáljunk meg egy másik scanbeállítást. Alkalmazzuk a "-O" és a "-A" kapcsolókat, illetve már csak nyitott portokat használjuk.

sudo nmap -p 21,22,23,80,502 -O -A 192.168.1.105

Sajnos most sem sikerült érdemi információkat szerezni a Modbusról.

kep
6. ábra   Újabb port scan a virtuális PLC nyitott portjain
 

Az "nmap" port scan-nél használhatók különböző script-ek is, amelyek az adott szolgáltatás megismerésénél segíthetnek. Az "nmap" rendelkezik olyan script-tel, amely a Modbus felderítésénél használható. Adjuk ki a következő parancsot.

sudo nmap -p 502 --script modbus-discover 192.168.1.105

Az 502-es TCP porton található Modbus szerverről már több információ áll rendelkezésünkre (7. ábra), látható a "WebElektronika-online-1.0".  (Emlékeztetőül, ezt írtuk be a korábban elindított Python alkalmazásban.)

kep
7. ábra   A Modbus szerver adatainak a lekérdezése
 

A lekérdezés által generált hálózati forgalom megtekinthető a Wireshark grafikus felületén is. Ahhoz, hogy a Modbushoz tartozó hálózati csomagok kerüljenek csak megjelenítésre, alkalmazzuk a "modbus" filtert.

kep
8. ábra   A "modbus-discover" script által generált hálózati forgalom, a forgalomban titkosítás nélkül kiolvashatók az érzékeny adatok
 

Könnyen észrevehető a Modbus/TCP protokoll hibája, ez a kommunikációs megoldás nem rendelkezik titkosítással. Az érzékeny adatok könnyen kiolvashatók a hálózati forgalomból.

Írjuk/olvassuk most a Modbus szerver regisztereit. Ezekre a műveletekre az Interneten több megoldás is található, mi az "mbtget" alkalmazást fogjuk használni. Ezért a Github-ról le kell tölteni az "mbtget"-et, ezért a Kali Linux terminálablakában adjuk ki a következő utasítást.

gti clone https://github.com/sourceperl/mbtget.git

Látható a 9. ábrán, hogy az "mbtget" könyvtár tartalmát lemásoljuk a Kali Linux VM-re.

kep
9. ábra   Az "mbtget" klónozása
 

Most már alkalmazható az "mbtget" script, és először kérjük le a helpet, hogy megismerjük ennek az alkalmazásnak a paraméterezését, 

./mbtget -h

 

A script futtatása után a következő felsorolás lesz a terminál ablakban.

usage : mbtget [-hvdsf] [-2c]
               [-u unit_id] [-a address] [-n number_value]
               [-r[12347]] [-w5 bit_value] [-w6 word_value]
               [-p port] [-t timeout] serveur

command line :
  -h                    : show this help message
  -v                    : show version
  -d                    : set dump mode (show tx/rx frame in hex)
  -s                    : set script mode (csv on stdout)
  -r1                   : read bit(s) (function 1)
  -r2                   : read bit(s) (function 2)
  -r3                   : read word(s) (function 3)
  -r4                   : read word(s) (function 4)
  -w5 bit_value         : write a bit (function 5)
  -w6 word_value        : write a word (function 6)
  -f                    : set floating point value
  -2c                   : set "two's complement" mode for register read
  -hex                  : show value in hex (default is decimal)
  -u unit_id            : set the modbus "unit id"
  -p port_number        : set TCP port (default 502)
  -a modbus_address     : set modbus address (default 0)
  -n value_number       : number of values to read
  -t timeout            : set timeout seconds (default is 5s)

 

Először olvassuk ki a 0. címen lévő memóriarekesz tartalmát, majd írjunk bele ellentétes tartalmat, azután újra olvassuk ki ugyanazt a memóriarekeszt. Ehhez el kell indítani a "mbtget/scripts" könyvátr alatt található "mbtget" script-et a következő paraméterezéssel.

Először kiolvassuk a 0. memóriarekesz tartalmát. (Az eredmény 0 lesz (10. ábra).

./mbtget -r1 -a 0 192.168.1.105

 

Ezután 1-et írunk be a kérdéses memóriarekeszbe.

./mbtget -w5 1 -a 0 192.168.1.105

 

Most újra kiolvassuk ugyanazt a memóriarekeszt. Látható a 10. ábrán, hogy az előbb beírt érték került kiolvasásra.

./mbtget -r1 -a 0 192.168.1.105

Ez az írás/olvasás folyamat látható a 10. ábrán.

kep
10. ábra   Kiolvasásra kerül a 0. cím tartalma, majd ide logikai 1-et írunk, majd újra kiolvassuk az adott memóriaterület értékét
 

Nézzük meg ez a folyamatot a hálózati forgalomban. A Wireshark grafikus megjelenítési felületén látható, hogy mindig egy "query" történt, azután pedig egy "Response". Történik tehát egy kérés (pl.: Read Colls"), majd erre a kérésre érkezik a válasz (11. ábra).

kep
11. ábra   Kérés-válasz a Modbus protokollnál
 

Nézzük meg a Wiresharkban most a memóriarekesz első olvasásánál a "Modbus" csomag tartalmát (12. ábra). Látható a "Bit 0" értéke, amely "0".

kep
12. ábra   Első olvasás, a kiolvasott érték "0"
 

Nézzük most meg a hálózati forgalomban azt az olvasási folyamatot, amely az írás után történt. Látható a hálózati forgalomban, hogy a kérdéses bit értéke már nem "0", hanem "1".

kep
13. ábra   A kiolvasott érték "1", tehát az írás művelete is sikeres volt
 

Könnyen észrevehető tehát az, hogy az ipari környezetben széles körben alkalmazott Modbus protokoll nem rendelkezik semmilyen titkosítással. A kezelése egyszerű, könnyen elsajátítható a használata, de az alkalmazásával nagy árat fizetünk az IT biztonság területén.
Az érzékeny adatok kényelmesen megismerhetők/módosíthatók.

Egy diagnosztikai parancs, amelyet a támadó használhat, a Read Device Identification (eszközazonosítás olvasása), amellyel megpróbál információkat gyűjteni a Modbus eszközről: A 43-as funkciókóddal ellátott MODBUS-kérelem Read Device Identification (Eszközazonosítás olvasása) arra készteti a Modbus kiszolgálót, hogy visszaadja a gyártó nevét, a termék nevét és a verziószámot. A támadó elküldi a 43-as funkciókóddal ellátott Modbus kérelmi csomagot a hálózat összes rendszerének, és olyan információkat gyűjt, amelyek hasznosak lehetnek a későbbi támadások során.

Még egyszer felhívjuk az Olvasók figyelmét arra, hogy ez a cikk azért született meg, hogy rámutassunk a Modbus protokoll használatának a veszélyére, és a védekezés fontosságára. Határozottan elhatárolódunk bármilyen bűncselekmény elkövetésének a segítésében.

Az információs rendszer vagy adat megsértése bűncselekmény (423. §).



Egyéb cikkek

További cikkeink ebben a témakörben

Régebbi cikkeink

Az nmap (grafikus megjelenítésnél a ZenMap) használata az IT biztonság, illetve az üzemeltetés területén dolgozó szakembereknél szinte elkerülhetetlen. Az ingyenes szoftver segítségével tesztelhetők a számítógépeink, a számítógéphálózatunk, vizsgálha. . . .

A Python programozási nyelv nagyon elterjedt a fejlesztők körében. Használják beágyazott rendszereknél, webes alkalmazásoknál, IT biztonság különböző területein, stb. Látható, hogy nagyon széles a felhasználási területe ennek a nyelvnek, ideje volt m. . . .

Elkezdjük most részletesebben megismerni az nmap használatát. Az nmap nagyon fontos eszköz az IT biztonsággal, illetve az üzemeltetéssel foglalkozó szakembereknél. De hogyan működik? Hogyan lehet és érdemes a scannelési tulajdonságokat beállítani? M. . . .