Skip to content

Commit c5f93c2

Browse files
authored
Read device info (#5)
* add read device info command * update Linux payload with read device info * force pymodbus to be included * update Windows payload * Revert "update Linux payload with read device info" This reverts commit 759aae9. * Revert "update Windows payload" This reverts commit e15ad76.
1 parent 3bb1feb commit c5f93c2

File tree

4 files changed

+88
-6
lines changed

4 files changed

+88
-6
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
3+
- id: 9360ba0d-46a3-47a1-bbe6-e6c875790500
4+
name: Modbus - Read Device Information
5+
description: |
6+
Modbus Function (0x2B, subcode 0x0E): Read Device Information
7+
8+
This function code is used to read the device information
9+
tactic: discovery
10+
technique_id: T0888
11+
technique_name: Remote System Information Discovery
12+
executors:
13+
- platform: linux
14+
name: sh
15+
command: >
16+
./modbus_cli #{modbus.server.ip} --port #{modbus.server.port} read_device_info --level #{modbus.read_device_info.level}
17+
payloads:
18+
- modbus_cli
19+
- platform: windows
20+
name: psh
21+
command: >
22+
.\modbus_cli.exe #{modbus.server.ip} --port #{modbus.server.port} read_device_info --level #{modbus.read_device_info.level}
23+
payloads:
24+
- modbus_cli.exe
25+
- platform: darwin
26+
name: sh
27+
command: >
28+
./modbus_cli_darwin #{modbus.server.ip} --port #{modbus.server.port} read_device_info --level #{modbus.read_device_info.level}
29+
payloads:
30+
- modbus_cli_darwin

src/modbus/actions/spec.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@
1414
# 17 (0x11) Report Slave ID
1515

1616

17+
@ModbusClient.action
18+
def read_device_info(self, level=3, device_id=1):
19+
"""
20+
Protocol Function
21+
43 (0x2B) -- Encapsulated Interface Transport
22+
MEI type: 14 (0x0E) - Read Device Information
23+
"""
24+
self.log.info(
25+
f"Read Device Info -- [Device ID: {device_id}]"
26+
)
27+
result = self.client.read_device_information(read_code=level, object_id=0)
28+
return result
29+
1730
@ModbusClient.action
1831
def read_coils(self, address, count, device_id=1):
1932
"""
@@ -128,4 +141,4 @@ def mask_write_register(self, address, and_mask, or_mask, device_id=1):
128141
f"Mask Write Register (22) -- [Address: {address}, AND_mask: {and_mask}, OR_mask: {or_mask}, Device ID: {device_id}]"
129142
)
130143
req = self.client.mask_write_register(address, and_mask, or_mask, slave=device_id)
131-
return req
144+
return req

src/modbus_cli.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,15 @@ def add_fuzz_args(parser):
103103
help="Seconds to wait between write operations [>= 0.0]",
104104
)
105105

106+
def add_info_args(parser):
107+
parser.add_argument(
108+
"--level",
109+
dest="level",
110+
type=to_16bit_uint,
111+
required=False,
112+
default=3,
113+
help="Level of info to request: 1=Basic, 2=Regular, 3=Extended",
114+
)
106115

107116
def add_write_c_subparser(subparsers):
108117
parser = subparsers.add_parser(
@@ -270,6 +279,14 @@ def add_fuzz_r_subparser(subparsers):
270279
)
271280

272281

282+
def add_read_device_info_subparser(subparsers):
283+
parser = subparsers.add_parser(
284+
"read_device_info",
285+
help="Read device information"
286+
)
287+
add_info_args(parser)
288+
add_device_id_arg(parser)
289+
273290
def create_arg_parser():
274291
parser = argparse.ArgumentParser(
275292
description="Modbus Client Action Library " + modbus.version.get_version()
@@ -300,6 +317,7 @@ def create_arg_parser():
300317
add_write_r_subparser(subparsers)
301318
add_write_multi_r_subparser(subparsers)
302319
add_mask_write_r_subparser(subparsers)
320+
add_read_device_info_subparser(subparsers)
303321

304322
return parser
305323

@@ -424,10 +442,24 @@ def do_action(client, args):
424442
log.error(err)
425443
else:
426444
print(f"{result[0]} successful write operations, {result[1]} errors")
445+
elif args.action.lower() == "read_device_info":
446+
print("[*] Read Device Information")
447+
try:
448+
result = client.read_device_info(
449+
args.level,
450+
args.device_id
451+
)
452+
except ValueError as err:
453+
print(f"Device Info Read failed: {err}")
454+
log.error(err)
455+
else:
456+
print_info_result(result)
427457

428458
else:
429459
print("Action not defined.")
430460

461+
def print_info_result(result):
462+
print(result.information)
431463

432464
def print_read_result(result, start, count, datatype):
433465
binary_types = ["coil", "discrete input"]
@@ -470,4 +502,4 @@ def run():
470502

471503

472504
if __name__ == "__main__":
473-
run()
505+
run()

src/modbus_cli.spec

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
# -*- mode: python ; coding: utf-8 -*-
2+
from PyInstaller.utils.hooks import collect_all
3+
4+
datas = []
5+
binaries = []
6+
hiddenimports = ['pymodbus']
7+
tmp_ret = collect_all('pymodbus')
8+
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
29

310

411
a = Analysis(
512
['modbus_cli.py'],
613
pathex=[],
7-
binaries=[],
8-
datas=[],
9-
hiddenimports=[],
14+
binaries=binaries,
15+
datas=datas,
16+
hiddenimports=hiddenimports,
1017
hookspath=[],
1118
hooksconfig={},
1219
runtime_hooks=[],
@@ -35,4 +42,4 @@ exe = EXE(
3542
target_arch=None,
3643
codesign_identity=None,
3744
entitlements_file=None,
38-
)
45+
)

0 commit comments

Comments
 (0)