Skip to content

Commit aa6ac36

Browse files
committed
Cosmetic changes, mostly
1 parent 66fe8ad commit aa6ac36

File tree

1 file changed

+62
-59
lines changed

1 file changed

+62
-59
lines changed

modules/auxiliary/scanner/scada/modbus_findunitid.rb

Lines changed: 62 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,29 @@
55
# http://metasploit.com/framework/
66
##
77

8-
9-
## MODBUS/TCP scanner to find correct Unit_ID/StationID
10-
118
require 'msf/core'
129

1310
class Metasploit3 < Msf::Auxiliary
1411
include Msf::Exploit::Remote::Tcp
1512
include Msf::Auxiliary::Fuzzer
1613

17-
1814
def initialize(info = {})
1915
super(update_info(info,
20-
'Name' => 'Modbus_findunitID',
16+
'Name' => 'Modbus Unit ID and Station ID Enumerator',
2117
'Description' => %q{
22-
This module sends a command (0x04, read input register) to modbus endpoint.
18+
Modbus is a cleartext protocol used in common SCADA systems, developed
19+
originally as a serial-line (RS232) async protocol, and later transformed
20+
to IP, which is called ModbusTCP. default tcpport is 502.
21+
22+
This module sends a command (0x04, read input register) to the modbus endpoint.
2323
If this command is sent to the correct unit-id, it returns with the same funcion-id.
2424
if not, it should be added 0x80, so that it sys 0x84, and an exception-code follows
25-
which do not interest us. This does not always happen, but at least the first 4 bytes
26-
in the return-packet should be exact the same as what was sent.
27-
You can change port, ip and the scan-range for unit-id.
28-
There is also added a value - BENICE - to make the scanner sleep a second or more
29-
between probes. We have seen installations where scanning too many too fast workes like a DoS.
25+
which do not interest us. This does not always happen, but at least the first 4
26+
bytes in the return-packet should be exact the same as what was sent.
27+
28+
You can change port, ip and the scan-range for unit-id. There is also added a
29+
value - BENICE - to make the scanner sleep a second or more between probes. We
30+
have seen installations where scanning too many too fast workes like a DoS.
3031
},
3132
'References' =>
3233
[
@@ -35,9 +36,9 @@ def initialize(info = {})
3536
],
3637
'Author' => [ 'EsMnemon <esm[at]mnemonic.no>' ],
3738
'License' => MSF_LICENSE,
38-
'DisclosureDate' => 'Oct 28 2012',
39-
'Version' => '$Revision: 0001 $'
39+
'DisclosureDate' => 'Oct 28 2012'
4040
))
41+
4142
register_options(
4243
[
4344
Opt::RPORT(502),
@@ -47,60 +48,62 @@ def initialize(info = {})
4748
OptInt.new('TIMEOUT', [true, 'Timeout for the network probe, 0 means no timeout', 2])
4849
], self.class)
4950
end
51+
5052
def run
51-
start="\x21\x00\x00\x00\x00\x06"
52-
theend="\x04\x00\x01\x00\x00"
53-
noll="\x00"
54-
# between, \01..\0ff (1-255)
55-
unless (1..255).include? datastore['UNIT_ID_FROM']
56-
print_status("unit ID must be between 1 and 254 adjusting UNIT_ID_FROM to 1")
57-
datastore['UNIT_ID_FROM']=1
58-
end
59-
unless (1..255).include? datastore['UNIT_ID_TO']
60-
print_status("unit ID must be between #{datastore['UNIT_ID_FROM']} and 255, adjusting UNIT_ID_TO to #{datastore['UNIT_ID_FROM']} ")
61-
datastore['UNIT_ID_TO']=datastore['UNIT_ID_FROM']
62-
end
63-
if datastore['UNIT_ID_FROM'] > datastore['UNIT_ID_TO'] then
64-
print_status("UNIT_ID_TO is less than UNIT_ID_FROM, setting them equal")
65-
datastore['UNIT_ID_TO']=datastore['UNIT_ID_FROM']
66-
end
53+
start="\x21\x00\x00\x00\x00\x06"
54+
theend="\x04\x00\x01\x00\x00"
55+
noll="\x00"
56+
# between, \01..\0ff (1-255)
57+
unless (1..255).include? datastore['UNIT_ID_FROM']
58+
print_status("unit ID must be between 1 and 254 adjusting UNIT_ID_FROM to 1")
59+
datastore['UNIT_ID_FROM']=1
60+
end
6761

68-
datastore['UNIT_ID_FROM'].upto(datastore['UNIT_ID_TO']) do |counter|
69-
sploit=start
70-
sploit+=[counter].pack("C")
71-
sploit+=theend
72-
select(nil,nil,nil,datastore['BENICE'])
73-
connect()
74-
sock.put(sploit)
75-
#debug: print_status("sent to unit_id #{counter} ")
76-
data = sock.get_once(12, datastore['TIMEOUT'])
77-
if (data.nil?)
78-
data=noll+noll+noll+noll
62+
unless (1..255).include? datastore['UNIT_ID_TO']
63+
print_status("Unit ID must be between #{datastore['UNIT_ID_FROM']} and 255")
64+
print_warning("Adjusting UNIT_ID_TO to #{datastore['UNIT_ID_FROM']} ")
65+
datastore['UNIT_ID_TO'] = datastore['UNIT_ID_FROM']
7966
end
80-
if data[0,4] == "\x21\x00\x00\x00" #return of the same trans-id+proto-id
81-
print_good("Received: correct MODBUS/TCP from stationID #{counter}")
82-
else
83-
print_status("Received: incorrect/none data from stationID #{counter} (probably not in use)")
67+
68+
if datastore['UNIT_ID_FROM'] > datastore['UNIT_ID_TO'] then
69+
print_warning("UNIT_ID_TO is less than UNIT_ID_FROM, setting them equal")
70+
datastore['UNIT_ID_TO'] = datastore['UNIT_ID_FROM']
71+
end
72+
73+
datastore['UNIT_ID_FROM'].upto(datastore['UNIT_ID_TO']) do |counter|
74+
sploit = start
75+
sploit += [counter].pack("C")
76+
sploit += theend
77+
select(nil,nil,nil,datastore['BENICE'])
78+
connect()
79+
sock.put(sploit)
80+
81+
data = sock.get_once(12, datastore['TIMEOUT'])
82+
if (data.nil?)
83+
data=noll+noll+noll+noll
84+
end
85+
86+
if data[0,4] == "\x21\x00\x00\x00" #return of the same trans-id+proto-id
87+
print_good("Received: correct MODBUS/TCP from stationID #{counter}")
88+
else
89+
print_status("Received: incorrect/none data from stationID #{counter} (probably not in use)")
90+
end
91+
92+
disconnect()
8493
end
85-
disconnect()
86-
end
8794
end
8895
end
8996

9097

9198
=begin
92-
93-
Modbus is a cleartext protocol used in common SCADA systems, developed
94-
originally as a serial-line (RS232) async protocol, and later transformed
95-
to IP, which is called ModbusTCP. default tcpport is 502.
96-
97-
This client is developed and tested against a SAIA PCD1.M2 system
98-
http://www.saia-pcd.com/en/products/plc/pcd-overview/Pages/pcd1-m2.aspx
99-
and a modbus/tcp PLC simulator from plcsimulator.org
100-
and the Modbus SLAVE from http://www.modbustools.com/
101-
102-
Mission is to find Unit-ID/stationID of the modbus-endpoint,
103-
RHOST=IP of the modbus-service (PLC)
104-
RPORT=Usually 502
99+
For testing purposes:
105100
101+
This client is developed and tested against a SAIA PCD1.M2 system
102+
http://www.saia-pcd.com/en/products/plc/pcd-overview/Pages/pcd1-m2.aspx
103+
and a modbus/tcp PLC simulator from plcsimulator.org
104+
and the Modbus SLAVE from http://www.modbustools.com/
105+
106+
Mission is to find Unit-ID/stationID of the modbus-endpoint:
107+
RHOST=IP of the modbus-service (PLC)
108+
RPORT=Usually 502
106109
=end

0 commit comments

Comments
 (0)