Implement jvazquez-r7 comments
parent
a0add34a7d
commit
04f2632972
|
@ -8,47 +8,42 @@ require 'msf/core'
|
||||||
class Metasploit3 < Msf::Auxiliary
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
include Msf::Exploit::Remote::Tcp
|
include Msf::Exploit::Remote::Tcp
|
||||||
include Rex::Socket::Tcp
|
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => 'Modbus client, reloaded.',
|
'Name' => 'Modbus Client Utility',
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module allows reading and writing data to a PLC using the Modbus protocol.
|
This module allows reading and writing data to a PLC using the Modbus protocol.
|
||||||
|
|
||||||
This module is based on the 'modiconstop.rb' Basecamp module from
|
This module is based on the 'modiconstop.rb' Basecamp module from
|
||||||
DigitalBond, as well as the mbtget perl script.
|
DigitalBond, as well as the mbtget perl script.
|
||||||
},
|
},
|
||||||
'Author' =>
|
'Author' =>
|
||||||
[
|
[
|
||||||
'EsMnemon <esm [at] mnemonic.no>', # original write-only module
|
'EsMnemon <esm[at]mnemonic.no>', # original write-only module
|
||||||
'Arnaud SOULLIE <arnaud.soullie[at]solucom.fr>', # new code that allows read/write
|
'Arnaud SOULLIE <arnaud.soullie[at]solucom.fr>' # new code that allows read/write
|
||||||
],
|
],
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
|
'Actions' => [AuxiliaryAction.new('READ_COIL', {}),
|
||||||
|
AuxiliaryAction.new('WRITE_COIL', {}),
|
||||||
|
AuxiliaryAction.new('READ_REGISTER', {}),
|
||||||
|
AuxiliaryAction.new('WRITE_REGISTER', {})
|
||||||
|
]
|
||||||
))
|
))
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
OptEnum.new("MODE", [true, 'Command', "READ_REGISTER",
|
|
||||||
[
|
|
||||||
"READ_REGISTER",
|
|
||||||
"READ_COIL",
|
|
||||||
"WRITE_REGISTER",
|
|
||||||
"WRITE_COIL"
|
|
||||||
]
|
|
||||||
]),
|
|
||||||
Opt::RPORT(502),
|
Opt::RPORT(502),
|
||||||
OptInt.new('DATA', [false, "Data to write (WRITE_COIL and WRITE_REGISTER modes only)", 0xBEEF]),
|
OptInt.new('DATA', [false, "Data to write (WRITE_COIL and WRITE_REGISTER modes only)"]),
|
||||||
OptInt.new('DATA_ADDRESS', [true, "Modbus data address", 0]),
|
OptInt.new('DATA_ADDRESS', [true, "Modbus data address"]),
|
||||||
OptInt.new('UNIT_NUMBER', [false, "Modbus unit number", 1]),
|
OptInt.new('UNIT_NUMBER', [false, "Modbus unit number", 1]),
|
||||||
], self.class)
|
], self.class)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# a wrapper just to be sure we increment the counter
|
# a wrapper just to be sure we increment the counter
|
||||||
def sendframe(payload)
|
def send_frame(payload)
|
||||||
sock.put(payload)
|
sock.put(payload)
|
||||||
@modbuscounter += 1
|
@modbus_counter += 1
|
||||||
r = sock.recv(65535, 0.1)
|
r = sock.get
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -59,13 +54,13 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
payload += [datastore['DATA_ADDRESS']].pack("n")
|
payload += [datastore['DATA_ADDRESS']].pack("n")
|
||||||
payload += [1].pack("n")
|
payload += [1].pack("n")
|
||||||
|
|
||||||
packetdata = ""
|
packet_data = ""
|
||||||
packetdata += [@modbuscounter].pack("n")
|
packet_data += [@modbus_counter].pack("n")
|
||||||
packetdata += "\x00\x00\x00" #dunno what these are
|
packet_data += "\x00\x00\x00" #dunno what these are
|
||||||
packetdata += [payload.size].pack("c") # size byte
|
packet_data += [payload.size].pack("c") # size byte
|
||||||
packetdata += payload
|
packet_data += payload
|
||||||
|
|
||||||
return packetdata
|
return packet_data
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_write_coil_payload(data)
|
def make_write_coil_payload(data)
|
||||||
|
@ -76,13 +71,13 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
payload += [data].pack("c")
|
payload += [data].pack("c")
|
||||||
payload += "\x00"
|
payload += "\x00"
|
||||||
|
|
||||||
packetdata = ""
|
packet_data = ""
|
||||||
packetdata += [@modbuscounter].pack("n")
|
packet_data += [@modbus_counter].pack("n")
|
||||||
packetdata += "\x00\x00\x00" #dunno what these are
|
packet_data += "\x00\x00\x00" #dunno what these are
|
||||||
packetdata += [payload.size].pack("c") # size byte
|
packet_data += [payload.size].pack("c") # size byte
|
||||||
packetdata += payload
|
packet_data += payload
|
||||||
|
|
||||||
return packetdata
|
return packet_data
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_write_register_payload(data)
|
def make_write_register_payload(data)
|
||||||
|
@ -92,27 +87,27 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
payload += [datastore['DATA_ADDRESS']].pack("n")
|
payload += [datastore['DATA_ADDRESS']].pack("n")
|
||||||
payload += [data].pack("n")
|
payload += [data].pack("n")
|
||||||
|
|
||||||
packetdata = ""
|
packet_data = ""
|
||||||
packetdata += [@modbuscounter].pack("n")
|
packet_data += [@modbus_counter].pack("n")
|
||||||
packetdata += "\x00\x00\x00" #dunno what these are
|
packet_data += "\x00\x00\x00" #dunno what these are
|
||||||
packetdata += [payload.size].pack("c") # size byte
|
packet_data += [payload.size].pack("c") # size byte
|
||||||
packetdata += payload
|
packet_data += payload
|
||||||
|
|
||||||
return packetdata
|
return packet_data
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
@modbuscounter = 0x0000 # used for modbus frames
|
@modbus_counter = 0x0000 # used for modbus frames
|
||||||
connect
|
connect
|
||||||
case datastore['MODE']
|
case datastore['ACTION']
|
||||||
when "READ_COIL"
|
when "READ_COIL"
|
||||||
@function_code = 1
|
@function_code = 1
|
||||||
response = sendframe(make_read_payload)
|
response = send_frame(make_read_payload)
|
||||||
print_good("Coil value at address #{datastore['DATA_ADDRESS']} : " + response.reverse.unpack("c").to_s.gsub('[', '').gsub(']', ''))
|
print_good("Coil value at address #{datastore['DATA_ADDRESS']} : " + response.reverse.unpack("c").to_s.gsub('[', '').gsub(']', ''))
|
||||||
|
|
||||||
when "READ_REGISTER"
|
when "READ_REGISTER"
|
||||||
@function_code = 3
|
@function_code = 3
|
||||||
response = sendframe(make_read_payload)
|
response = send_frame(make_read_payload)
|
||||||
value = response.split[0][9..10].to_s.unpack("n").to_s.gsub('[', '').gsub(']','')
|
value = response.split[0][9..10].to_s.unpack("n").to_s.gsub('[', '').gsub(']','')
|
||||||
print_good("Register value at address #{datastore['DATA_ADDRESS']} : " + value)
|
print_good("Register value at address #{datastore['DATA_ADDRESS']} : " + value)
|
||||||
|
|
||||||
|
@ -126,7 +121,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
print_error("Data value must be 0 or 1 in WRITE_COIL mode")
|
print_error("Data value must be 0 or 1 in WRITE_COIL mode")
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
response = sendframe(make_write_coil_payload(data))
|
response = send_frame(make_write_coil_payload(data))
|
||||||
print_good("Value #{datastore['DATA']} successfully written at coil address #{datastore['DATA_ADDRESS']}")
|
print_good("Value #{datastore['DATA']} successfully written at coil address #{datastore['DATA_ADDRESS']}")
|
||||||
|
|
||||||
when "WRITE_REGISTER"
|
when "WRITE_REGISTER"
|
||||||
|
@ -135,11 +130,11 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
print_error("Data to write must be an integer between 0 and 65535 in WRITE_REGISTER mode")
|
print_error("Data to write must be an integer between 0 and 65535 in WRITE_REGISTER mode")
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
response = sendframe(make_write_register_payload(datastore['DATA']))
|
response = send_frame(make_write_register_payload(datastore['DATA']))
|
||||||
print_good("Value #{datastore['DATA']} successfully written at registry address #{datastore['DATA_ADDRESS']}")
|
print_good("Value #{datastore['DATA']} successfully written at registry address #{datastore['DATA_ADDRESS']}")
|
||||||
|
|
||||||
else
|
else
|
||||||
print_error("Invalid MODE")
|
print_error("Invalid ACTION")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue