Modbus Banner Grabbing - Metasploit


This page contains detailed information about how to use the auxiliary/scanner/scada/modbus_banner_grabbing metasploit module. For list of all metasploit modules, visit the Metasploit Module Library.

Module Overview


Name: Modbus Banner Grabbing
Module: auxiliary/scanner/scada/modbus_banner_grabbing
Source code: modules/auxiliary/scanner/scada/modbus_banner_grabbing.rb
Disclosure date: -
Last modification time: 2021-08-27 17:15:33 +0000
Supported architecture(s): -
Supported platform(s): -
Target service / protocol: -
Target network port(s): 502
List of CVEs: -

This module grabs the banner of any device running the Modbus protocol by sending a request with Modbus Function Code 43 (Read Device Identification). Modbus is a data communications protocol originally published by Modicon (now Schneider Electric) in 1979 for use with its programmable logic controllers (PLCs).

Module Ranking and Traits


Module Ranking:

  • normal: The exploit is otherwise reliable, but depends on a specific version and can't (or doesn't) reliably autodetect. More information about ranking can be found here.

Basic Usage


This module is a scanner module, and is capable of testing against multiple hosts.

msf > use auxiliary/scanner/scada/modbus_banner_grabbing
msf auxiliary(modbus_banner_grabbing) > show options
    ... show and set options ...
msf auxiliary(modbus_banner_grabbing) > set RHOSTS ip-range
msf auxiliary(modbus_banner_grabbing) > exploit

Other examples of setting the RHOSTS option:

Example 1:

msf auxiliary(modbus_banner_grabbing) > set RHOSTS 192.168.1.3-192.168.1.200 

Example 2:

msf auxiliary(modbus_banner_grabbing) > set RHOSTS 192.168.1.1/24

Example 3:

msf auxiliary(modbus_banner_grabbing) > set RHOSTS file:/tmp/ip_list.txt

Required Options


  • RHOSTS: The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'

Knowledge Base


Vulnerable Application


This module will perform banner grabbing on devices that use the Modbus protocol by sending a payload with the function code 43 to read the target device's identification information. For more technical information, you can refer to this link: https://en.wikipedia.org/wiki/Modbus#Available_function/command_codes.

By default the service is running on port 502, so any device with this port open could be a potential target.

Verification Steps


  1. Do: use auxiliary/scanner/scada/modbus_banner_grabbing
  2. Do: set RHOST <IP> where IP is the IP address of the target.
  3. Do: run

The response from the target device may contain several objects. Some of these objects can be seen below:

vendor name, product code, revision number (in *major version*.*minor version* format), vendor url, product name, model name

If the target was unable to process the Modbus message, a Modbus exception message will be returned from the target, which will then be output to the screen.

Successful results from the scan will be stored as a note in the framework. You can access these notes by typing note in the console.

msf5 auxiliary(scanner/scada/modbus_banner_grabbing) > notes

Notes
=====

 Time                     Host            Service  Port  Protocol  Type                Data
 ----                     ----            -------  ----  --------  ----                ----
 2020-07-06 13:25:50 UTC  192.168.1.1     modbus   502   tcp       modbus.vendorname   "Schneider Electric"
 2020-07-06 13:25:50 UTC  192.168.1.1     modbus   502   tcp       modbus.productcode  "BMX NOE 0100"
 2020-07-06 13:25:50 UTC  192.168.1.1     modbus   502   tcp       modbus.revision     "V3.10"

Options


There are no non-default options for this module.

Scenarios


The following scenarios describe some of the responses you may receive from the target:

Schneider Electric BMX NOE 0100 - Successful Response

msf6 > use auxiliary/scanner/scada/modbus_banner_grabbing
msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > set RHOSTS 192.168.1.1
RHOSTS => 192.168.1.1
msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > run

[*] 192.168.1.1:502    - Number of Objects: 3
[+] 192.168.1.1:502    - VendorName: Schneider Electric
[+] 192.168.1.1:502    - ProductCode: BMX NOE 0100
[+] 192.168.1.1:502    - Revision: V3.10
[*] 192.168.1.1:502    - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Schneider Electric BMX NOE 0100 - No Reply

The target never replied to the attacker's request.

msf6 > use auxiliary/scanner/scada/modbus_banner_grabbing
msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > set RHOSTS 192.168.1.2
RHOSTS => 192.168.1.2
msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > run

[-] 192.168.1.2:502      - MODBUS - No reply
[*] 192.168.1.2:502      - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Schneider Electric BMX NOE 0100 - Network Error

Some network error occurred, such as a connection error, a network timeout, or the connection was refused. Alternatively, the host may be unreachable.

msf6 > use auxiliary/scanner/scada/modbus_banner_grabbing
msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > set RHOSTS 192.168.1.3
RHOSTS => 192.168.1.3
msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > run

[-] 192.168.1.3:502     - MODBUS - Network error during payload: The connection timed out (217.71.253.52:502).
[*] 192.168.1.3:502     - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Schneider Electric BMX NOE 0100 - Modbus Exception Code (i.e. Memory Parity Error)

msf6 > use auxiliary/scanner/scada/modbus_banner_grabbing
msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > set RHOSTS 192.168.1.4
RHOSTS => 192.168.1.4
msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > run

[-] 192.168.1.4:502      - Memory Parity Error: Slave detected a parity error in memory.
[*] 192.168.1.4:502      - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Go back to menu.

Msfconsole Usage


Here is how the scanner/scada/modbus_banner_grabbing auxiliary module looks in the msfconsole:

msf6 > use auxiliary/scanner/scada/modbus_banner_grabbing

msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > show info

       Name: Modbus Banner Grabbing
     Module: auxiliary/scanner/scada/modbus_banner_grabbing
    License: Metasploit Framework License (BSD)
       Rank: Normal

Provided by:
  Juan Escobar <[email protected]>
  Ezequiel Fernandez

Check supported:
  No

Basic options:
  Name     Current Setting  Required  Description
  ----     ---------------  --------  -----------
  RHOSTS                    yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
  RPORT    502              yes       The target port (TCP)
  THREADS  1                yes       The number of concurrent threads (max one per host)
  TIMEOUT  2                yes       Timeout for the network probe

Description:
  This module grabs the banner of any device running the Modbus 
  protocol by sending a request with Modbus Function Code 43 (Read 
  Device Identification). Modbus is a data communications protocol 
  originally published by Modicon (now Schneider Electric) in 1979 for 
  use with its programmable logic controllers (PLCs).

References:
  https://modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf
  https://en.wikipedia.org/wiki/Modbus#Modbus_TCP_frame_format_(primarily_used_on_Ethernet_networks)
  https://github.com/industrialarmy/Hello_Proto

Module Options


This is a complete list of options available in the scanner/scada/modbus_banner_grabbing auxiliary module:

msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > show options

Module options (auxiliary/scanner/scada/modbus_banner_grabbing):

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   RHOSTS                    yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
   RPORT    502              yes       The target port (TCP)
   THREADS  1                yes       The number of concurrent threads (max one per host)
   TIMEOUT  2                yes       Timeout for the network probe

Advanced Options


Here is a complete list of advanced options supported by the scanner/scada/modbus_banner_grabbing auxiliary module:

msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > show advanced

Module advanced options (auxiliary/scanner/scada/modbus_banner_grabbing):

   Name                 Current Setting  Required  Description
   ----                 ---------------  --------  -----------
   CHOST                                 no        The local client address
   CPORT                                 no        The local client port
   ConnectTimeout       10               yes       Maximum number of seconds to establish a TCP connection
   Proxies                               no        A proxy chain of format type:host:port[,type:host:port][...]
   SSL                  false            no        Negotiate SSL/TLS for outgoing connections
   SSLCipher                             no        String for SSL cipher - "DHE-RSA-AES256-SHA" or "ADH"
   SSLVerifyMode        PEER             no        SSL verification method (Accepted: CLIENT_ONCE, FAIL_IF_NO_PEER_CERT, NONE, PEER)
   SSLVersion           Auto             yes       Specify the version of SSL/TLS to be used (Auto, TLS and SSL23 are auto-negotiate) (Accepted: Auto, TLS, SSL23, SSL3, TLS1, TLS1.1, TLS1.2)
   ShowProgress         true             yes       Display progress messages during a scan
   ShowProgressPercent  10               yes       The interval in percent that progress should be shown
   VERBOSE              false            no        Enable detailed status messages
   WORKSPACE                             no        Specify the workspace for this module

Auxiliary Actions


This is a list of all auxiliary actions that the scanner/scada/modbus_banner_grabbing module can do:

msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > show actions

Auxiliary actions:

   Name  Description
   ----  -----------

Evasion Options


Here is the full list of possible evasion options supported by the scanner/scada/modbus_banner_grabbing auxiliary module in order to evade defenses (e.g. Antivirus, EDR, Firewall, NIDS etc.):

msf6 auxiliary(scanner/scada/modbus_banner_grabbing) > show evasion

Module evasion options:

   Name                Current Setting  Required  Description
   ----                ---------------  --------  -----------
   TCP::max_send_size  0                no        Maxiumum tcp segment size.  (0 = disable)
   TCP::send_delay     0                no        Delays inserted before every send.  (0 = disable)

Go back to menu.

Error Messages


This module may fail with the following error messages:

Check for the possible causes from the code snippets below found in the module source code. This can often times help in identifying the root cause of the problem.

Illegal Function: The function code received in the query is not recognized or allowed by the slave.


Here is a relevant code snippet related to the "Illegal Function: The function code received in the query is not recognized or allowed by the slave." error message:

43:	
44:	  # Main Modbus exception codes
45:	  def handle_exception_codes(code)
46:	    case code
47:	    when "\xab\x01"
48:	      print_error('Illegal Function: The function code received in the query is not recognized or allowed by the slave.')
49:	    when "\xab\x02"
50:	      print_error('Illegal Data Address: Data address of some or all the required entities are not allowed or do not exist in slave.')
51:	    when "\xab\x03"
52:	      print_error('Illegal Data Value: Value is not accepted by slave.')
53:	    when "\xab\x04"

Illegal Data Address: Data address of some or all the required entities are not allowed or do not exist in slave.


Here is a relevant code snippet related to the "Illegal Data Address: Data address of some or all the required entities are not allowed or do not exist in slave." error message:

45:	  def handle_exception_codes(code)
46:	    case code
47:	    when "\xab\x01"
48:	      print_error('Illegal Function: The function code received in the query is not recognized or allowed by the slave.')
49:	    when "\xab\x02"
50:	      print_error('Illegal Data Address: Data address of some or all the required entities are not allowed or do not exist in slave.')
51:	    when "\xab\x03"
52:	      print_error('Illegal Data Value: Value is not accepted by slave.')
53:	    when "\xab\x04"
54:	      print_error('Slave Device Failure: Unrecoverable error occurred while slave was attempting to perform requested action.')
55:	    when "\xab\x05"

Illegal Data Value: Value is not accepted by slave.


Here is a relevant code snippet related to the "Illegal Data Value: Value is not accepted by slave." error message:

47:	    when "\xab\x01"
48:	      print_error('Illegal Function: The function code received in the query is not recognized or allowed by the slave.')
49:	    when "\xab\x02"
50:	      print_error('Illegal Data Address: Data address of some or all the required entities are not allowed or do not exist in slave.')
51:	    when "\xab\x03"
52:	      print_error('Illegal Data Value: Value is not accepted by slave.')
53:	    when "\xab\x04"
54:	      print_error('Slave Device Failure: Unrecoverable error occurred while slave was attempting to perform requested action.')
55:	    when "\xab\x05"
56:	      print_error('Acknowledge: Slave has accepted the request and is processing it, but requires a long period of time to process it.')
57:	    when "\xab\x06"

Slave Device Failure: Unrecoverable error occurred while slave was attempting to perform requested action.


Here is a relevant code snippet related to the "Slave Device Failure: Unrecoverable error occurred while slave was attempting to perform requested action." error message:

49:	    when "\xab\x02"
50:	      print_error('Illegal Data Address: Data address of some or all the required entities are not allowed or do not exist in slave.')
51:	    when "\xab\x03"
52:	      print_error('Illegal Data Value: Value is not accepted by slave.')
53:	    when "\xab\x04"
54:	      print_error('Slave Device Failure: Unrecoverable error occurred while slave was attempting to perform requested action.')
55:	    when "\xab\x05"
56:	      print_error('Acknowledge: Slave has accepted the request and is processing it, but requires a long period of time to process it.')
57:	    when "\xab\x06"
58:	      print_error('Slave Device Busy: Slave is engaged in processing a long-duration program command.')
59:	    when "\xab\x07"

Acknowledge: Slave has accepted the request and is processing it, but requires a long period of time to process it.


Here is a relevant code snippet related to the "Acknowledge: Slave has accepted the request and is processing it, but requires a long period of time to process it." error message:

51:	    when "\xab\x03"
52:	      print_error('Illegal Data Value: Value is not accepted by slave.')
53:	    when "\xab\x04"
54:	      print_error('Slave Device Failure: Unrecoverable error occurred while slave was attempting to perform requested action.')
55:	    when "\xab\x05"
56:	      print_error('Acknowledge: Slave has accepted the request and is processing it, but requires a long period of time to process it.')
57:	    when "\xab\x06"
58:	      print_error('Slave Device Busy: Slave is engaged in processing a long-duration program command.')
59:	    when "\xab\x07"
60:	      print_error('Negative Acknowledge: Slave cannot perform the programming function recieved in the query.')
61:	    when "\xab\x08"

Slave Device Busy: Slave is engaged in processing a long-duration program command.


Here is a relevant code snippet related to the "Slave Device Busy: Slave is engaged in processing a long-duration program command." error message:

53:	    when "\xab\x04"
54:	      print_error('Slave Device Failure: Unrecoverable error occurred while slave was attempting to perform requested action.')
55:	    when "\xab\x05"
56:	      print_error('Acknowledge: Slave has accepted the request and is processing it, but requires a long period of time to process it.')
57:	    when "\xab\x06"
58:	      print_error('Slave Device Busy: Slave is engaged in processing a long-duration program command.')
59:	    when "\xab\x07"
60:	      print_error('Negative Acknowledge: Slave cannot perform the programming function recieved in the query.')
61:	    when "\xab\x08"
62:	      print_error('Memory Parity Error: Slave detected a parity error in memory.')
63:	    when "\xab\x0a"

Negative Acknowledge: Slave cannot perform the programming function recieved in the query.


Here is a relevant code snippet related to the "Negative Acknowledge: Slave cannot perform the programming function recieved in the query." error message:

55:	    when "\xab\x05"
56:	      print_error('Acknowledge: Slave has accepted the request and is processing it, but requires a long period of time to process it.')
57:	    when "\xab\x06"
58:	      print_error('Slave Device Busy: Slave is engaged in processing a long-duration program command.')
59:	    when "\xab\x07"
60:	      print_error('Negative Acknowledge: Slave cannot perform the programming function recieved in the query.')
61:	    when "\xab\x08"
62:	      print_error('Memory Parity Error: Slave detected a parity error in memory.')
63:	    when "\xab\x0a"
64:	      print_error('Gateway Path Unavailable: The gateway was likely misconfigured or is overloaded as it was unable to internally connect the input and output channels.')
65:	    when "\xab\x0b"

Memory Parity Error: Slave detected a parity error in memory.


Here is a relevant code snippet related to the "Memory Parity Error: Slave detected a parity error in memory." error message:

57:	    when "\xab\x06"
58:	      print_error('Slave Device Busy: Slave is engaged in processing a long-duration program command.')
59:	    when "\xab\x07"
60:	      print_error('Negative Acknowledge: Slave cannot perform the programming function recieved in the query.')
61:	    when "\xab\x08"
62:	      print_error('Memory Parity Error: Slave detected a parity error in memory.')
63:	    when "\xab\x0a"
64:	      print_error('Gateway Path Unavailable: The gateway was likely misconfigured or is overloaded as it was unable to internally connect the input and output channels.')
65:	    when "\xab\x0b"
66:	      print_error("Gateway Target Device Failed to Respond: Gateway could not find the target device on the network or the target device didn't respond.")
67:	    else

Gateway Path Unavailable: The gateway was likely misconfigured or is overloaded as it was unable to internally connect the input and output channels.


Here is a relevant code snippet related to the "Gateway Path Unavailable: The gateway was likely misconfigured or is overloaded as it was unable to internally connect the input and output channels." error message:

59:	    when "\xab\x07"
60:	      print_error('Negative Acknowledge: Slave cannot perform the programming function recieved in the query.')
61:	    when "\xab\x08"
62:	      print_error('Memory Parity Error: Slave detected a parity error in memory.')
63:	    when "\xab\x0a"
64:	      print_error('Gateway Path Unavailable: The gateway was likely misconfigured or is overloaded as it was unable to internally connect the input and output channels.')
65:	    when "\xab\x0b"
66:	      print_error("Gateway Target Device Failed to Respond: Gateway could not find the target device on the network or the target device didn't respond.")
67:	    else
68:	      print_error('MODBUS - received incorrect data.')
69:	    end

Gateway Target Device Failed to Respond: Gateway could not find the target device on the network or the target device didn't respond.


Here is a relevant code snippet related to the "Gateway Target Device Failed to Respond: Gateway could not find the target device on the network or the target device didn't respond." error message:

61:	    when "\xab\x08"
62:	      print_error('Memory Parity Error: Slave detected a parity error in memory.')
63:	    when "\xab\x0a"
64:	      print_error('Gateway Path Unavailable: The gateway was likely misconfigured or is overloaded as it was unable to internally connect the input and output channels.')
65:	    when "\xab\x0b"
66:	      print_error("Gateway Target Device Failed to Respond: Gateway could not find the target device on the network or the target device didn't respond.")
67:	    else
68:	      print_error('MODBUS - received incorrect data.')
69:	    end
70:	  end
71:	

MODBUS - received incorrect data.


Here is a relevant code snippet related to the "MODBUS - received incorrect data." error message:

63:	    when "\xab\x0a"
64:	      print_error('Gateway Path Unavailable: The gateway was likely misconfigured or is overloaded as it was unable to internally connect the input and output channels.')
65:	    when "\xab\x0b"
66:	      print_error("Gateway Target Device Failed to Respond: Gateway could not find the target device on the network or the target device didn't respond.")
67:	    else
68:	      print_error('MODBUS - received incorrect data.')
69:	    end
70:	  end
71:	
72:	  def run_host(ip)
73:	    object_name = {

MODBUS - No data was received from the target machine, its possible it may be offline or not responding.


Here is a relevant code snippet related to the "MODBUS - No data was received from the target machine, its possible it may be offline or not responding." error message:

130:	      end
131:	
132:	      num_objects = data[mbtcp['num_objects']['start'], mbtcp['num_objects']['bytes']]
133:	
134:	      if num_objects.nil?
135:	        print_error('MODBUS - No data was received from the target machine, its possible it may be offline or not responding.')
136:	        return
137:	      end
138:	
139:	      num_objects = num_objects.unpack1('C')
140:	      print_status("Number of Objects: #{num_objects}")

MODBUS - Interrupt during payload


Here is a relevant code snippet related to the "MODBUS - Interrupt during payload" error message:

162:	          type: "modbus.#{object['name'].downcase}",
163:	          data: object['str_value']
164:	        )
165:	      end
166:	    rescue ::Interrupt
167:	      print_error('MODBUS - Interrupt during payload')
168:	      raise $ERROR_INFO
169:	    rescue ::Rex::HostUnreachable, ::Rex::ConnectionError, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused => e
170:	      print_error("MODBUS - Network error during payload: #{e}")
171:	      return
172:	    rescue ::EOFError

MODBUS - Network error during payload: <E>


Here is a relevant code snippet related to the "MODBUS - Network error during payload: <E>" error message:

165:	      end
166:	    rescue ::Interrupt
167:	      print_error('MODBUS - Interrupt during payload')
168:	      raise $ERROR_INFO
169:	    rescue ::Rex::HostUnreachable, ::Rex::ConnectionError, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused => e
170:	      print_error("MODBUS - Network error during payload: #{e}")
171:	      return
172:	    rescue ::EOFError
173:	      print_error('MODBUS - No reply')
174:	      return
175:	    end

MODBUS - No reply


Here is a relevant code snippet related to the "MODBUS - No reply" error message:

168:	      raise $ERROR_INFO
169:	    rescue ::Rex::HostUnreachable, ::Rex::ConnectionError, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused => e
170:	      print_error("MODBUS - Network error during payload: #{e}")
171:	      return
172:	    rescue ::EOFError
173:	      print_error('MODBUS - No reply')
174:	      return
175:	    end
176:	  end
177:	
178:	  def cleanup

Go back to menu.


References


See Also


Check also the following modules related to this module:

Authors


  • Juan Escobar <juan[at]null-life.com>
  • Ezequiel Fernandez

Version


This page has been produced using Metasploit Framework version 6.2.23-dev. For more modules, visit the Metasploit Module Library.

Go back to menu.