Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
b89729a
Bunch of bugfixes. Tool now actually starts:P
TomTervoortSecura Feb 28, 2024
6d183c8
Many bugfixes.
TomTervoortSecura Feb 28, 2024
6e32757
More bugfixes. Reflect should work until demonstration.
TomTervoortSecura Feb 28, 2024
739642c
Set up test environment.
TomTervoortSecura Feb 28, 2024
0aa291d
Starting to implement HTTPS support.
TomTervoortSecura Mar 11, 2024
2d473df
Reflect/relay against HTTPS transport.
TomTervoortSecura Mar 11, 2024
fbe8cf4
Succesfully tested HTTPS-based reflection attack.
TomTervoortSecura Mar 11, 2024
898bec1
Relay attack is also working now.
TomTervoortSecura Mar 11, 2024
bb9eba4
Got password-based padding oracle to work.
TomTervoortSecura Mar 12, 2024
348c59c
Ready for oracle test.
TomTervoortSecura Mar 13, 2024
15e756f
Added usage instructions for more (not yet implemented) attacks.
TomTervoortSecura Mar 13, 2024
0bdc2bc
Added padding oracle tester.
TomTervoortSecura Mar 15, 2024
501847f
Working on CN path injection attack.
TomTervoortSecura Mar 18, 2024
7cad94c
Finally fixed padding oracle!
TomTervoortSecura Mar 18, 2024
6ff4273
Decrypt command now works and gives nice output.
TomTervoortSecura Mar 18, 2024
ebf2ebc
Sigforge command works now.
TomTervoortSecura Mar 18, 2024
ea5d486
Stable version of tool. Following commands work properly:
TomTervoortSecura Mar 19, 2024
b4c60f9
Fixed sigforge bug.
TomTervoortSecura Mar 19, 2024
5aef940
Fixed OPC handshake crypto. TODO: fix session crypto.
TomTervoortSecura Mar 19, 2024
bf3efae
Working on signature fix.
TomTervoortSecura Mar 19, 2024
1b98612
Fixed OPC handshake with known key. cn-inject works properly now.
TomTervoortSecura Mar 19, 2024
0681578
Implemented OPN bypass as part of reflection attack.
TomTervoortSecura Mar 20, 2024
5f9e652
Prevented padding oracle selector from hanging.
TomTervoortSecura Mar 20, 2024
e658589
Some fixes to accomodate Prosys implementation.
TomTervoortSecura Mar 20, 2024
4d197b2
Few more bugfixes.
TomTervoortSecura Mar 20, 2024
1309de8
More fixes.
TomTervoortSecura Mar 20, 2024
709f959
Almost got padding oracle based auth bypass to work.
TomTervoortSecura Mar 21, 2024
5fadb83
Added support for timing-based padding oracle attack.
TomTervoortSecura Mar 21, 2024
1454e3b
Implemented "check" command to list endpoints and evaluate which atta…
TomTervoortSecura Mar 21, 2024
a75851f
Improved timing checker.
TomTervoortSecura Mar 21, 2024
c764e68
Implemented auth-check.
TomTervoortSecura Mar 21, 2024
9b25b9e
Small auth-check fixes.
TomTervoortSecura Mar 21, 2024
dbebd40
Dirty hack.
TomTervoortSecura Mar 21, 2024
15faa0a
Removed temporary hack.
TomTervoortSecura Mar 21, 2024
0b61646
Fixed timestamp serialization bug.
TomTervoortSecura Mar 22, 2024
7272c7e
Padding oracle bugfix.
TomTervoortSecura Mar 25, 2024
b11206d
Performance enhancements and more configurability of timing attack.
TomTervoortSecura Mar 25, 2024
c183ec2
Forgot to apply this bugfix...
TomTervoortSecura Mar 25, 2024
4efbe8e
Improved error handling.
TomTervoortSecura Mar 25, 2024
8013fe2
Fixed chunking implementation.
TomTervoortSecura Mar 25, 2024
a124136
Fixed discovery URL in get_endpoints.
TomTervoortSecura Mar 26, 2024
04914b7
Made some adjustments to make Ignition attack work.
TomTervoortSecura Mar 26, 2024
f7e22b7
Allow padding oracle attack against endpoints not advertising PKCS1 but
TomTervoortSecura Mar 26, 2024
c9592ec
Fixed some bugs to make it work against Prosys.
TomTervoortSecura Apr 11, 2024
47e02d5
Improved error checking.
TomTervoortSecura Apr 11, 2024
a1c70f4
Added Prosys-specific padding oracle distinguisher.
TomTervoortSecura Apr 15, 2024
35e2d00
Increased default timeout.
TomTervoortSecura Apr 15, 2024
cf59da1
Better error logging when padding oracle fails.
TomTervoortSecura Apr 22, 2024
6d640b4
None downgrade attack.
TomTervoortSecura Apr 23, 2024
e018225
Implementation of range dropping attack.
TomTervoortSecura Apr 23, 2024
6dc9235
Added MitM attacks to CLI interface.
TomTervoortSecura Apr 29, 2024
4587d9a
Got None downgrade working succesfully.
TomTervoortSecura Apr 29, 2024
19eeb18
Small bugfix.
TomTervoortSecura Apr 29, 2024
60217da
First half of bytedrop attack is working now.
TomTervoortSecura Apr 29, 2024
f7e309c
Small bytedrop test.
TomTervoortSecura Apr 29, 2024
12d5348
Fixed anoymous authentication check.
TomTervoortSecura May 17, 2024
85ab7fe
Added support for long RSA keys.
TomTervoortSecura May 17, 2024
fc0b6e4
Added an even shorter expansion to the timing oracle checks.
TomTervoortSecura May 17, 2024
63e1913
Progress bar fix.
TomTervoortSecura May 24, 2024
15da3f2
Added socket keepalive.
TomTervoortSecura Jun 14, 2024
b356cd2
Removed "byte drop" attack.
TomTervoortSecura Jun 19, 2024
a298c7e
Dockerized the tool.
TomTervoortSecura Jun 21, 2024
5199571
Small fixes.
TomTervoortSecura Jul 1, 2024
a083038
Fixed issue with attacking Prosys. More logging.
TomTervoortSecura Jul 2, 2024
44a2991
Padding fix.
TomTervoortSecura Jul 3, 2024
fe752fc
Wrote README.
TomTervoortSecura Jul 23, 2024
fa9cf0b
Added misc attack descriptions to README.
TomTervoortSecura Jul 23, 2024
92d5b50
Initial commit
djrevmoon Jun 25, 2025
f13d830
GitHub merge. Added license file.
TomTervoortSecura Jun 25, 2025
7f09111
Added talk link to README.
TomTervoortSecura Jun 25, 2025
75c1cc3
Bump requests from 2.31.0 to 2.32.4
dependabot[bot] Jun 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM python:3.10

COPY . /app/
WORKDIR /app
RUN pip install -r requirements.txt
ENTRYPOINT ["python", "opcattack.py"]
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 Secura

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
187 changes: 187 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# OPC UA attack tool

Python tool to automate the OPC UA attacks described in my talk "[No VPN Needed? Cryptographic Attacks Against the OPC UA Protocol](https://www.blackhat.com/us-25/briefings/schedule/index.html#no-vpn-needed-cryptographic-attacks-against-the-opc-ua-protocol-44760)", and to
evaluate whether an OPC UA endpoint is potentially vulnerable.

## Usage

$ ./opcattack.py -h
usage: opcattack.py [-h] attack ...

Proof of concept tool for attacks against the OPC UA security protocol.

positional arguments:
attack attack to test
check evaluate whether attacks apply to server
reflect authentication bypass via reflection attack
relay authentication bypass via relay attack between two servers
cn-inject path injection via an (untrusted) certificate CN
auth-check tests if server allows unauthenticated access
decrypt sniffed password and/or traffic decryption via padding
oracle
sigforge signature forgery via padding oracle
client-downgrade
password stealing downgrade attack against a client

options:
-h, --help show this help message and exit

Run `opcattack.py <command> -h` to get help for configuration options of a specific attack.

## Installation

Requires Python 3.10 or higher. Install dependencies via `pip install -r requirements.txt`.

Alternatively, you can build a Docker container:

docker build -t opcattack .
docker run -it opcattack <arguments>

When running the `reflect` attack with `--bypass-opn` and `-T` flags, you may want to persist the cache file like this:

docker run -it -v opccache:/var/cache opcattack reflect -c /var/cache/opcfile --bypass-opn -T <interval> -C <count> opc.tcp://<host>:<port>


## Evaluating an endpoint

The first thing you'll want to do is enumerate the endpoints of an OPC UA server by running the following command
against either the server itself or a discovery server:

opcattack.py check opc.tcp://<host>:<port>

Or, if the server supports HTTPS:

opcattack.py check https://<host>:<port>

The output will list endpoint information as well as which attack may be applicable based on the supported security
policies and transport protocols.

If you want to determine whether the server is vulnerable to the timing-based padding oracle variant, you can run
`check -t`, which measures response times for different ciphertext expansion parameters.

## Checking if authentication is required

An OPC UA endpoint may be configured to simply not enforce client or user authentication in the first place. While this
is not the most exciting vulnerability, it is important to check this first to make sure that either authentication
bypass actually, well, bypasses something. You can run `opcattack.py auth-check <endpoint>` to try a simple anonymous
login.

If successful, it will enumerate all readable nodes within the OPC server. It does not test for write access, however.

## Performing an HTTPS reflect/relay attack (attack 1)

If the `check` command reports at least one HTTPS endpoint, a reflection attack may be possible whenever a server
trusts its own certificate. A PoC can be executed as follows:

opcattack.py reflect https://<host>:<port>/

This will carry out all the necessary steps. If succesful, the tool will enumerate all nodes on the server; this
demonstration can be disabled via the `-n` flag.

If client authentication is succesfully bypassed but the server also requires user authentication this is reported by
the tool. If certificate based user authentication is allowed the tool will automatically attempt reusing the
reflected signature to spoof user authentication as well.

HTTPS relay attacks between two different servers can be executed as follows:

opcattack.py relay https://<source> https://<destination>


## Performing an RSA padding oracle attack (attack 2)

### Error-based variant

If you just want a proof of concept on whether a padding oracle is possible, the most straightforward way to do this
is via the `sigforge` command, which attempts to use a padding oracle attack to forge an RSA signature over any chosen
message with the server's public key. You can then verify this signature using a tool like OpenSSL, to demonstrate that
the signature indeed matches the given message. Run it as follows:

opcattack.py sigforge opc.tcp://<host>:<port> <hex-encoded message>

All padding oracle commands will first check for a few predefined status codes or messages, and tests their reliability
by submitting many correctly and incorrectly padded encrypted messages. The "quality score" of the padding oracle is
judged based on its false negative rate. If a single false positive is detected, the method is scored a 0.

Not all OPC UA implementations have been tested with this. If an implementation's error messages need to be
distinguished in a way not yet accounted for this tool will not be smart enough to find it.

The tool also allows a decryption attack. While this can be done for any RSA ciphertext produced with the same public
key it is most useful on a passively sniffed secure channel handshake or an encrypted password. See
`opcattack.py decrypt -h` for instructions on how to extract those. You can run this as follows:

opcattack.py decrypt opc.tcp://<host>:<port> <hex-encoded ciphertext>

The tool will print the hex-encoded plaintext, if succesful. If the plaintext looks like an encrypted password this
password will be decoded. If the plaintext looks like an OpenSecureChannel message it will be parsed and printed,
revealing the secret nonce inside.

When the two nonces of the same handshake are decrypted the channel keys can be derived and used to decrypt the rest
of the communication. That is currently not implemented in this tool, however.

### Timing-based variant

If no error-based oracle is found, you can test a timing-based oracle instead. First, run `opcattack.py check -t` to
test response timings. This will produce results such as the following:

[*] Timing experiment results:
[+] Expansion parameter 10:
[+] Average time with correct padding: 0.018887882232666017
[+] Average time with incorrect padding: 0.005357732772827148
[+] Shortest time with correct padding: 0.016694307327270508
[+] Longest time with incorrect padding: 0.022701740264892578
[+] -----------------
[+] Expansion parameter 30:
[+] Average time with correct padding: 0.03950897693634033
[+] Average time with incorrect padding: 0.005196962356567383
[+] Shortest time with correct padding: 0.035872697830200195
[+] Longest time with incorrect padding: 0.011386394500732422
[+] -----------------
[+] Expansion parameter 50:
[+] Average time with correct padding: 0.06519682884216309
[+] Average time with incorrect padding: 0.005134844779968261
[+] Shortest time with correct padding: 0.05526590347290039
[+] Longest time with incorrect padding: 0.009844779968261719
[+] -----------------
[+] Expansion parameter 100:
[+] Average time with correct padding: 0.1187672519683838
[+] Average time with incorrect padding: 0.00522763729095459
[+] Shortest time with correct padding: 0.10398173332214355
[+] Longest time with incorrect padding: 0.013846635818481445
[+] -----------------

When a timing-based padding oracle is present then the time with correct padding should be longer than the time with
incorrect padding. Here, that is obviously the case. For executing the attack, you need to pick an "expansion
parameter" that shows a clear difference between the "shortest time with correct padding" and the
"longest time with incorrect padding". A bigger expansion parameter will generally be more reliable but less
performant.

Finally, you need to pick a threshold which is some value in between the "shortest time with correct padding" and
the "longest time with incorrect padding". This value will be used to judge how to classify a padding oracle query.
When the response is positive, the query will be repeated a few times to reduce the chance of false positives due to
temporary network hiccups.

You can configure these expansion and threshold parameters by adding the flags
`-T <threshold-parameter> -C <expansion-parameter>` to a `sigforge`, `decrypt` or `reflect` command. Once these
parameters are added, timing-based padding oracles will be taken into account with these parameters.

### Combining with a reflection attack

The tool also implements the combination of a reflection and two padding oracle attacks to achieve an authentication
bypass over an `opc.tcp` secure channel. You can run this by adding the `--bypass-opn` flag to the `reflect` command:

opcattack.py reflect https://<host>:<port>/ --bypass-opn

If the padding oracle is timing based you can also add `-T` and `-C` parameters.

The tool will cache the result of the "first half" of the attack (i.e. the signature spoofing phase). If the attack
fails or halts somewhere during the "second half" (the decryption or reflection phases), you can try running the tool
again and the first half will be automatically skipped.

### Miscellaneous attacks

The tool implements two other experimental attacks, but these are not novel protocol flaws:

- `cn-inject`: attempts a path injection attack via the CN of an untrusted certificate. While in theory this would be possible against a naive implementation of the OPC UA [certificate file name conventions](https://reference.opcfoundation.org/GDS/v105/docs/F) I have not actually found an implementation (yet) that is vulnerable to this.
- `client-downgrade`: MitM attack to downgrade encryption of a client connection, attempting to steal the user password. This is already pretty much a known potential flaw, however, and most implementations I found are not affected because they need the user to specify a specific security policy in the client configuration.


Loading