documentation/modules/auxiliary/scanner/scada/opcua_enum.md
This module detects OPC-UA servers that speak the OPC-UA TCP binary transport
(opc.tcp://). OPC-UA (IEC 62541) is the dominant interoperability standard for
industrial automation and is exposed by a wide range of OT software, including
PLCs, SCADA platforms, historians, and gateway products.
The module sends an OPC-UA Hello (HEL) message and inspects the response:
Any response other than ACK or ERR is treated as a non-detection, keeping the fingerprint tight and avoiding false positives from unrelated services.
The IANA-registered port for OPC-UA TCP is 4840, which is the module's
default RPORT. However, several common OT products use non-standard ports:
RPORT 62541.0.0.0.0) in
Config > OPC UA > Server Settings. In practice this means many Ignition
installs do not expose OPC-UA externally unless deliberately configured to.http://<gateway>:8088), go to Config > OPC UA > Server
Settings, and under Bind Addresses remove localhost and add 0.0.0.0
(or the specific interface IP). Save. The server rebinds without a gateway
restart. ss -tlnp | grep 62541
LISTEN 0 4096 *:62541 *:* users:(("java",...))
The official Inductive Automation Ignition Docker image provides the quickest way to stand up a test target. Note that Ignition's OPC-UA server binds to localhost only by default, so one configuration step is required to expose it for scanning — this is itself worth knowing, as it means a default Ignition gateway is not reachable on OPC-UA from other hosts until an administrator changes the bind address.
docker run -d \
--name ignition-opcua-test \
-p 8088:8088 \
-p 62541:62541 \
-e ACCEPT_IGNITION_EULA=Y \
-e GATEWAY_ADMIN_USERNAME=admin \
-e GATEWAY_ADMIN_PASSWORD=password \
-e IGNITION_EDITION=standard \
inductiveautomation/ignition:8.3
(Use the inductiveautomation/ignition:8.1 tag to test against 8.1.x.)
docker logs ignition-opcua-test 2>&1 | grep -i "Gateway started"
http://localhost:8088, sign in with the admin credentials above, and go to
Config > OPC UA > Server Settings. Under Bind Addresses, remove
localhost and add 0.0.0.0, then save. The server rebinds immediately; the
logs will confirm: docker logs ignition-opcua-test 2>&1 | grep -i "binding endpoint" | tail -2
# ... Binding endpoint opc.tcp://... to 0.0.0.0:62541 ...
set RPORT 62541).Any standalone OPC-UA server (open62541, Eclipse Milo, Prosys Simulation Server, etc.) on port 4840 can also be used to exercise the module.
msfconsole.use auxiliary/scanner/scada/opcua_enumset RHOSTS <target>set RPORT 62541.run[+], including the ProtocolVersion
and the server's advertised receive/send buffer sizes.msf6 > use auxiliary/scanner/scada/opcua_enum
msf6 auxiliary(scanner/scada/opcua_enum) > set RHOSTS 10.10.0.3
RHOSTS => 10.10.0.3
msf6 auxiliary(scanner/scada/opcua_enum) > set RPORT 62541
RPORT => 62541
msf6 auxiliary(scanner/scada/opcua_enum) > run
[+] 10.10.0.3:62541 - OPC-UA server detected (ACK) - ProtocolVersion=0 RecvBuf=65535 SendBuf=65535
[*] 10.10.0.3:62541 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
A server that rejects the HEL (for example, due to an invalid endpoint URL) still confirms OPC-UA. The StatusCode and reason are decoded:
msf6 auxiliary(scanner/scada/opcua_enum) > run
[+] 192.0.2.10:4840 - OPC-UA server detected (ERR) - Bad_TcpEndpointUrlInvalid
[*] 192.0.2.10:4840 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/scada/opcua_enum) > set RHOSTS 10.10.0.0/24
RHOSTS => 10.10.0.0/24
msf6 auxiliary(scanner/scada/opcua_enum) > run
[+] 10.10.0.3:4840 - OPC-UA server detected (ACK) - ProtocolVersion=0 RecvBuf=65535 SendBuf=65535
[*] Scanned 256 of 256 hosts (100% complete)
[*] Auxiliary module execution completed
The module reports a service of type opc-ua in the database for each detected
server. Review with:
msf6 > services -S opc-ua