Team82 Logo Claroty

Team82 Research

OPC UA Deep Dive Series (Part 6): A One-of-a-Kind OPC UA Exploit Framework

Sharon Brizinov,
Uri Katz
/ August 9th, 2023
OPC UA Deep Dive Series: A One-of-a-Kind OPC UA Exploit Framework

This is Part six of Team82's OPC UA Deep Dive Series, a comprehensive guide to the security of the OPC UA network protocol for unified OT communication. In this entry, we will unveil a unique exploit framework that was crucial to our OPC UA research journey. As of today, the framework will be freely and publicly available on our Git Hub repository.

Introduction

Team82’s extensive Deep Dive Series on OPC UA has arrived at the point where we discuss the tools we’ve developed to examine this critical OT protocol, as well as the vulnerabilities uncovered throughout this lengthy research project. 

The centerpiece tool of our research is an advanced OPC UA Exploit Framework we built and used to execute many unique attacks against OPC UA implementations. It’s been immensely useful in finding close to 50 vulnerabilities in products using the protocol from OPC-UA client to servers to protocol gateways. Today, we are announcing it during a presentation at the Black Hat Briefings in Las Vegas, and are making it publicly available on our GitHub repository. We invite fellow researchers and vendors to use this framework to test their code bases and the security of your respective products.

Download our Exploit Framework Here

Many leading vendors in the OPC UA community have already had limited access to our framework. We created a coalition of vendor representatives on a private Slack channel to share best practices around improving the security of the protocol stack and how it is implemented. These vendors have also used the framework to test their products, and numerous vulnerabilities have been uncovered and addressed since this effort started. 

Researchers and vendors will find this one-of-a-kind framework useful because each of the attack techniques exploits specific functions within the OPC UA protocol implementation. Users can send attacks that contain malformed or malicious packets to subsets of OPC UA, for example, that could trigger vulnerabilities when parsed. While not all vendor implementations were vulnerable during our research, we did find exploits impacting OPC UA servers, for example, that were prone to specific classes of vulnerabilities. 

We collected these methods and used the framework to test them on a wide range of servers; this is a unique capability that allowed us to trigger certain bugs or flaws in more than one server implementation. 

Team82 has used iterations of this framework for some time, including our successful participation at the annual Pwn2Own Miami ICS hacking event run during the annual S4 Conference in Miami.

We hope that researchers and vendors take advantage of the free availability of the framework to test all the concepts we developed on their products. Our GitHub also includes a detailed explainer on how to use the tool. 

In this blog, we’re going to explain how the framework is structured and reveal some of the unique attack capabilities available in the framework, and the currently supported OPC UA servers. 

Team82 Exploit Framework Overview

We divided the framework into four categories of payloads: Sanity, Attacks, Corpus, Server.

  • Sanity: Sanity payloads include Reading Nodes, specific NodeID information given a namespace and NodeID, etc.

  • Attacks: Unique OPC UA-specific attacks that can cause a denial of service, leak sensitive information, or even execute code remotely.

  • Corpus: Reproducing payloads from corpus; useful for fuzzing iterations and reproducers.

  • Server: Simple server implementations (currently one example with cross-site scripting (XSS) payloads).

How to Use the Tool

Basic Usage: python main.py SERVER_TYPE IP_ADDR PORT ENDPOINT_ADDRESS FUNC_TYPE [DIR] Examples:

Sanity: python main.py prosys 1.2.3.4 53530 /OPCUA/SimulationServer sanity

Attack (DoS): python main.py prosys 1.2.3.4 53530 /OPCUA/SimulationServer thread_pool_wait_starvation

python main.py prosys 1.2.3.4 53530 /OPCUA/SimulationServer opcua_file FILE_PATH NUM_REQUESTS

python main.py prosys 1.2.3.4 53530 /OPCUA/SimulationServer opcua_dir PATH_TO_DIR_WITH_CORPUS

python main.py prosys 1.2.3.4 53530 /OPCUA/SimulationServer boofuzz_db BOOFUZZ_DB_FILEPATH

python main.py prosys 1.2.3.4 53530 /OPCUA/SimulationServer threads_run FUNC_NAME COUNT

Server Types: softing, unified, prosys, kepware, triangle, dotnetstd, open62541, ignition, rust, node-opcua, opcua-python, milo

Function types: threads_run, sanity , sanity_read_nodes , sanity_translate_browse_path , sanity_read_diag_info , sanity_get_node_id_info , opcua_dir , opcua_file , boofuzz_db , attack_file_nodejs_opcua_v8_oom , attack_file_ASNeG_OpcUaStack_unhandled_exception , chunk_flood , open_multiple_secure_channels , close_session_with_old_timestamp , complex_nested_message , translate_browse_path_call_stack_overflow , thread_pool_wait_starvation , unlimited_persistent_subscriptions , function_call_null_deref , malformed_utf8 , race_change_and_browse_address_space , certificate_inf_chain_loop , unlimited_condition_refresh

Sanity Payloads

Sanity Name

Description

Function Keyword

Reference

Diagnostic Info

Diagnostic summary information for the server

sanity_read_diag_info

Server Diagnostics Summary Data

Get Node ID Info

Node ID is an identifier for a node in an OPC server’s address space.

sanity_get_node_id_info

NodeID

Read Nodes

Read service is used to read attributes’ Nodes

sanity_read_nodes

Read Service

Translate Browse Path

Translates browse paths to NodeIds. Each browse path is constructed of a starting Node and a RelativePath

sanity_translate_browse_path

Translate Browse Path Service

Sanity Payloads

Sanity Name

Description

Function Keyword

Reference

Diagnostic Info

Diagnostic summary information for the server

sanity_read_diag_info

Server Diagnostics Summary Data

Get Node ID Info

Node ID is an identifier for a node in an OPC server’s address space.

sanity_get_node_id_info

NodeID

Read Nodes

Read service is used to read attributes’ Nodes

sanity_read_nodes

Read Service

Translate Browse Path

Translates browse paths to NodeIds. Each browse path is constructed of a starting Node and a RelativePath

sanity_translate_browse_path

Translate Browse Path Service

Unique Attack Payloads

Attack Name

Description

Vulnerability Type

Function Keyword

CVE and Reference

Certificate Infinite Chain Loop

Some servers implemented the certificate chain check by themselves and forgot to protect against a chain loop. Example: Cert A is signed by Cert B which is signed by Cert A

Denial of Service

certificate_inf_chain_loop

CVE-2022-37013

Chunk Flooding

Sending large amount of OPC UA MSG chunks without the Final chunk

Denial of Service

chunk_flood

CVE-2022-29864, CVE-2022-21208, CVE-2022-25761, CVE-2022-25304, CVE-2022-24381, CVE-2022-25888

Open Multiple Secure Channels

Flooding the server with many open channel requests leads to a denial of service

Denial of Service

open_multiple_secure_channels

CVE-2023-32787

Close Session With Old Timestamp

Sending bad timestamp in the CLOSE session message leads to an uncaught stacktrace with sensitive information

Information Leakage

close_session_with_old_timestamp

CVE-2023-31048

Complex Nested Message

Sending a complex nested variant leads to a call stack overflow

Denial of Service / Information Leakage

complex_nested_message

CVE-2022-25903, CVE-2021-27432

Translate Browse Path Call Stack Overflow

Triggering a stack overflow exception in a server that doesn't limit TranslateBrowsePath resolving calls

Denial of Service

translate_browse_path_call_stack_overflow

CVE-2022-29866

Thread Pool Wait Starvation

Thread pool deadlock due to concurrent worker starvation

Denial of Service

thread_pool_wait_starvation

CVE-2022-30551

Unlimited Persistent Subscriptions

Flooding the server with many monitored items with “delete” flag set to False leads to uncontrolled memory allocation and eventually to a denial of service

Denial of Service

unlimited_persistent_subscriptions

CVE-2022-25897,CVE-2022-24375,CVE-2022-24298

Function Call Null Dereference

Triggering an application crash after several OPC UA methods have been called and the OPC UA session is closed before the methods have been finished.

Denial of Service

function_call_null_deref

CVE-2022-1748

Malformed UTF8

Triggering an application crash after processing malformed UTF8 strings

Remote Code Execution

malformed_utf8

CVE-2022-2825, CVE-2022-2848

Race Change And Browse Address Space

Adding nodes to the server address space and removing the nodes in a loop while browsing the entire address space.

Denial of Service

race_change_and_browse_address_space

CVE-2023-32172

Unlimited Condition Refresh

Sending many ConditionRefresh method calls leads to uncontrolled memory allocations and eventually to a crash

Denial of Service

unlimited_condition_refresh

CVE-2023-27321


CVE-2023-27334

Corpus Attack Payloads

We've implemented a simple way to fire up an OPC UA corpus at the servers. Our framework will wrap these samples in an OPC UA session so it’s very easy to use. This is very useful to reproduce bugs that were found using fuzzers.

  • opcua_message_boofuzz_db: can be used to shoot an entire boofuzz db at a target

  • opcua_message_file: can be used to shoot an a single file or directory of files with OPC-UA payloads (OPC-UA content itself)

In the repository we also included a lot of corpus we collected from our fuzzing attempts; check:  input_corpus_minimized. They are the result of many hours of fuzzing different targets via various methods and tools.

Rogue Server Implementation (to Attack Clients) Payload

Currently our simple server PoC is a standalone script that is built on top of Python OPC-UA (asyncua). The current example was used in some RCE client exploitation (for example, see here).

Supported OPC-UA Servers

Server Name

Default URI

Default Port

Server Keyword

PTC Kepware KepServerEx

/

49320

kepware

OPC UA .NET Standard Protocol Stack

/Quickstarts/ReferenceServer

62541

dotnetstd

OPC UA Secure Integration Server

/Softing/dataFEED/Server

4897

softing

Prosys OPC UA Simulation Server

/OPCUA/SimulationServer

53530

prosys

Unified Automation UaGateway

/

48050

unified

Inductive Automation Ignition

/

62541

ignition

Triangle Microworks Scada Data Gateway (SDG)

/SDG

4885

triangle

open62541 OPC-UA Protocol Stack

/

4840

open62541

Locka99 OPC-UA Protocol Stack

/

4855

rust

Node OPC-UA Protocol Stack

/

26543

node-opcua

Python OPC-UA Protocol Stack

/freeopcua/server/

4840

opcua-python

Milo OPC-UA Protocol Stack

/milo

62541

milo

Conclusion

We urge vendors and researchers alike to use our OPC UA Exploit Framework to test the security of OPC UA implementations. This is a unique collection of attacks, a one-stop for security testing of this crucial OT protocol stack. We already shared this framework with representatives of some of the leading OT vendors, and close to 50 vulnerabilities surfaced and were addressed. 

We’re hoping to see more of you leverage this tool to test your products and in your research, and coordinate the disclosure of any vulnerabilities you may find with the affected vendor. 

OPC UA Deep Dive Series

A Complete Guide to the OPC UA Attack Surface

Part 1: History of the OPC UA Protocol

Part 2: What is OPC UA?

Part 3: Exploring the OPC UA Protocol

Part 4: Targeting Core OPC UA Components

Part 5: Inside Team82’s Research Methodology

Download our OPC UA Exploit Framework

Stay in the know

Get the Team82 Newsletter

Recent Vulnerability Disclosures

Claroty
LinkedIn Twitter YouTube Facebook