BACnet Scanner - Metasploit


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

Module Overview


Name: BACnet Scanner
Module: auxiliary/scanner/scada/bacnet_l3
Source code: modules/auxiliary/scanner/scada/bacnet_l3.rb
Disclosure date: -
Last modification time: 2022-08-01 15:11:57 +0000
Supported architecture(s): -
Supported platform(s): -
Target service / protocol: -
Target network port(s): -
List of CVEs: -

Discover BACnet devices by broadcasting Who-is message, then poll discovered devices for properties including model name, software version, firmware revision and description.

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.

Reliability:

  • unreliable-session: The module isn't expected to get a shell reliably (such as only once).

Stability:

  • crash-safe: Module should not crash the service.

Side Effects:

  • screen-effects: Module may show something on the screen (Example: a window pops up).

Basic Usage


msf > use auxiliary/scanner/scada/bacnet_l3
msf auxiliary(bacnet_l3) > show targets
    ... a list of targets ...
msf auxiliary(bacnet_l3) > set TARGET target-id
msf auxiliary(bacnet_l3) > show options
    ... show and set options ...
msf auxiliary(bacnet_l3) > exploit

Knowledge Base


Vulnerable Application


BACnet is a Data Communication Protocol for Building Automation and Control Networks. Developed under the auspices of the American Society of Heating, Refrigerating and Air-Conditioning Engineers (ASHRAE), BACnet is an American national standard, a European standard, a national standard in more than 30 countries, and an ISO global standard. The protocol is supported and maintained by ASHRAE Standing Standard Project Committee 135

This script polls bacnet devices with a l3 broadcast Who-is message and for each reply communicates further to discover more data and saves the data into metasploit. Each bacnet device responds with this data: - It's IP address, and BACnet/IP address (if the device is nested). - It's device number. - Model name. - Application software version. - Firmware revision. - Device description.

Verification Steps


  1. Start msfconsole.
  2. Do: use auxiliary/scanner/scada/bacnet_l3.
  3. Do: set INTERFACE.
  4. Do: run.
  5. Devices running the BACnet protocol should respond with data.

Options


A user can choose between the interfaces of his host (e.g. eth1, ens192...), the number of Who-is packets to send - for reliability purposes, the time (in seconds) to wait for packets to arrive and the UDP port, the default is 47808.

The user can always check these options via the show options command.

msf auxiliary(profinet_siemens) > show options

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

Name       Current Setting  Required  Description
----       ---------------  --------  -----------
COUNT      1                yes       The number of times to send each packet
INTERFACE  eth1             yes       The interface to scan from
PORT       47808            yes       BACnet/IP UDP port to scan (usually between 47808-47817)
TIMEOUT    1                yes       The socket connect timeout in seconds

Scenarios


The following demonstrates a basic scenario, we "detect" two devices:


msf > use auxiliary/scanner/scada/bacnet_l3
msf auxiliary(auxiliary/scanner/scada/bacnet_l3) > run

[*] Broadcasting Who-is via eth1
[*] found 2 devices
[*] Querying device number 826001 in ip 192.168.13.11
[*] Querying device number 4194303 in ip 192.168.13.12
[*] Done scanning
[+] for asset number 826001:
        model name: iSMA-B-4U4A-H-IP
        firmware revision: 6.2
        application software version: GC5 6.2
        description: BACnet iSMA-B-4U4A-H-IP Module

[+] for asset number 4194303:
        model name: PXG3.L-1
        firmware revision: FW=01.21.30.38;WPC=1.4.131;SVS-300:SBC=13.21;
        application software version:
        description: BacnetRouter

[+] Successfully saved data to local store named bacnet-discovery.xml
[*] Done.
[*] Auxiliary module execution completed

Go back to menu.

Msfconsole Usage


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

msf6 > use auxiliary/scanner/scada/bacnet_l3

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

       Name: BACnet Scanner
     Module: auxiliary/scanner/scada/bacnet_l3
    License: Metasploit Framework License (BSD)
       Rank: Normal

Provided by:
  Paz <Paz @ SCADAfence>

Module side effects:
 screen-effects

Module stability:
 crash-safe

Module reliability:
 unreliable-session

Check supported:
  No

Basic options:
  Name       Current Setting  Required  Description
  ----       ---------------  --------  -----------
  COUNT      1                yes       The number of times to send each packet
  INTERFACE  eth1             yes       The interface to scan from
  PORT       47808            yes       BACnet/IP UDP port to scan (usually between 47808-47817)
  SNAPLEN    65535            yes       The number of bytes to capture
  TIMEOUT    1                yes       The socket connect timeout in seconds

Description:
  Discover BACnet devices by broadcasting Who-is message, then poll 
  discovered devices for properties including model name, software 
  version, firmware revision and description.

Module Options


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

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

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

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   COUNT      1                yes       The number of times to send each packet
   INTERFACE  eth1             yes       The interface to scan from
   PORT       47808            yes       BACnet/IP UDP port to scan (usually between 47808-47817)
   SNAPLEN    65535            yes       The number of bytes to capture
   TIMEOUT    1                yes       The socket connect timeout in seconds

Advanced Options


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

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

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

   Name                Current Setting  Required  Description
   ----                ---------------  --------  -----------
   GATEWAY_PROBE_HOST  8.8.8.8          yes       Send a TTL=1 random UDP datagram to this host to discover the default gateway's MAC
   GATEWAY_PROBE_PORT                   no        The port on GATEWAY_PROBE_HOST to send a random UDP probe to (random if 0 or unset)
   SECRET              1297303073       yes       A 32-bit cookie for probe requests.
   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/bacnet_l3 module can do:

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

Auxiliary actions:

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

Evasion Options


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

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

Module evasion options:

   Name  Current Setting  Required  Description
   ----  ---------------  --------  -----------

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.

Interface <INTERFACE> is down


Here is a relevant code snippet related to the "Interface <INTERFACE> is down" error message:

133:	  def broadcast_who_is
134:	    begin
135:	      broadcast_addr = get_ipv4_broadcast(datastore['INTERFACE'])
136:	      interface_addr = get_ipv4_addr(datastore['INTERFACE'])
137:	    rescue StandardError
138:	      raise StandardError, "Interface #{datastore['INTERFACE']} is down"
139:	    end
140:	    cap = []
141:	
142:	    # Create a socket for broadcast response and a socket for unicast response.
143:	    lsocket = Rex::Socket::Udp.create({

Couldn't collect data for asset number <INSTANCE_NUMBER>.


Here is a relevant code snippet related to the "Couldn't collect data for asset number <INSTANCE_NUMBER>." error message:

272:	
273:	        device['instance-number'] = instance_number.to_s
274:	        devices_by_ip[ip] = [] unless devices_by_ip[ip]
275:	        devices_by_ip[ip].append(device)
276:	      rescue StandardError
277:	        print_bad("Couldn't collect data for asset number #{instance_number}.")
278:	      end
279:	    end
280:	    devices_by_ip
281:	  end
282:	

TIMEOUT


Here is a relevant code snippet related to the "TIMEOUT" error message:

367:	    devices
368:	  end
369:	
370:	  def run
371:	    # Validate user input
372:	    raise Msf::OptionValidateError, ['TIMEOUT'] if datastore['TIMEOUT'].negative?
373:	    raise Msf::OptionValidateError, ['COUNT'] if datastore['COUNT'] < 1
374:	    raise Msf::OptionValidateError, ['INTERFACE'] if datastore['INTERFACE'].empty?
375:	
376:	    begin
377:	      # Broadcast who-is and create request-property messages for detected devices.

COUNT


Here is a relevant code snippet related to the "COUNT" error message:

368:	  end
369:	
370:	  def run
371:	    # Validate user input
372:	    raise Msf::OptionValidateError, ['TIMEOUT'] if datastore['TIMEOUT'].negative?
373:	    raise Msf::OptionValidateError, ['COUNT'] if datastore['COUNT'] < 1
374:	    raise Msf::OptionValidateError, ['INTERFACE'] if datastore['INTERFACE'].empty?
375:	
376:	    begin
377:	      # Broadcast who-is and create request-property messages for detected devices.
378:	      print_status "Broadcasting Who-is via #{datastore['INTERFACE']}"

INTERFACE


Here is a relevant code snippet related to the "INTERFACE" error message:

369:	
370:	  def run
371:	    # Validate user input
372:	    raise Msf::OptionValidateError, ['TIMEOUT'] if datastore['TIMEOUT'].negative?
373:	    raise Msf::OptionValidateError, ['COUNT'] if datastore['COUNT'] < 1
374:	    raise Msf::OptionValidateError, ['INTERFACE'] if datastore['INTERFACE'].empty?
375:	
376:	    begin
377:	      # Broadcast who-is and create request-property messages for detected devices.
378:	      print_status "Broadcasting Who-is via #{datastore['INTERFACE']}"
379:	      capture = broadcast_who_is

No devices found. Exiting.


Here is a relevant code snippet related to the "No devices found. Exiting." error message:

387:	        devices_by_ip = get_properties_from_devices(messages)
388:	        print_status 'Done collecting data'
389:	        sleep(DEFAULT_SLEEP)
390:	        output_results(devices_by_ip)
391:	      else
392:	        fail_with(Failure::NotFound, 'No devices found. Exiting.')
393:	      end
394:	    rescue StandardError => e
395:	      fail_with(Failure::Unknown, e.message)
396:	      return
397:	    end

Go back to menu.


Go back to menu.

See Also


Check also the following modules related to this module:

Authors


  • Paz @ SCADAfence

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.