Red Alert ICS CTF - DEF CON 31

OPC-UA Write Up - Red Alert ICS CTF


The Red Alert ICS CTF is an annual CTF held by NSHC Security at DEF CON. During DEF CON 31, our team won the CTF, earning a DEF CON Black Badge. 

The CTF had a challenge titled OPC-UA. The challenge prompt was as follows:

A PLC that sends strange signals from the airport has been spotted.
Analyzing the signals from the PLC seems to give you a clue on how to control the airport.
Analyze the signals from the PLC to get the 35x35 QR code.

IP : 4840

The challenge requires the player to learn about the OPC UA protocol; track, locate and utilize a library in their programming language of choice to interact with this protocol; collect 35 object values within the OPC UA service every second, at least 70 times, to gather enough data to generate the QR code; and track, locate and utilize a library in their programming language of choice to generate a QR code image given this data.

The following was used to solve this challenge:



OPC Unified Architecture (OPC UA) is a protocol developed by the Open Platform Communications (OPC) Foundation for use in programmable logic controllers (PLCs) commonly found in industrial control systems. The protocol is open, allowing for wider adoption by PLC manufacturers, and provides newer features such as X.509 client certificate authentication, in-transit encryption, data subscription and method calls.


Initial Look

I connected to the service using FreeOpcUa Client (with a packet capture running, of course).  


This screen shows us a few things. First, anonymous, unauthenticated sign in is allowed. Second, two custom objects exist: Runaway Approach Light Control and Approach Light. The Server object is standard in PLCs that use the OPC UA protocol.

Runaway Approach Light Control is a red herring. Approach Light, however, looked interesting:

hint the lines are pixels see if theyre in packet capture.png

We can see line_xx objects, where xx is a two-digit number from 0 to 34 (35 in total). Each value is either a 1 or a 0 and changes approximately once a second. There is also a ts object, which dumps a timestamp in the ISO 8601 format. State of Approach Light turned out to be a red herring.

When initially solving the challenge, the line "analyze the signals from the PLC to get the 35x35 QR code" was missing from the challenge prompt. As a result, I spent many hours attempting to see if there was a flag hidden in a configuration within the Server object, or within the defined Types. Several hours were spent identifying OPC UA enumeration tools to see if FreeOpcUa Client missed something within the service. As such, I chased rabbit holes all of Friday, and I submitted zero flags. On the second day, the CTF organizers explicitly stated that we needed to derive a 35x35 QR code, and the challenge became far more straightforward. 

Simulation, Research and Development


The Red Alert ICS CTF at DEF CON 31 was open for a limited time over three days, per the image above. With this limited time, we almost certainly would be unable to complete enough challenges to beat out the competition and win first place; however, if enough information was collected on the challenges, some of them could be done offline. Our team prioritized challenges that could only be done during competition hours, leaving the rest for the time-to-grind-this-out-and-sleep-at-3AM hours. Ultimately, this strategy was crucial to winning the CTF and the DEF CON 31 Black Badge that year.

During the competition hours Friday, I primarily focused on other challenges. I did end up finding the opcua-asyncio Python library, which I deemed too complicated to work with, and the OPC UA Simulation Server, which I deemed irrelevant. I still had no idea how to convert seemingly-random 1s and 0s into a QR code, nor how to use the FreeOpcUa Client to effectively collect this data. I put the OPC-UA challenge into the back of my mind, instead targeting other, easier challenges.

That evening, in the middle of dinner, it hit me. The simulation server can be used to recreate the PLC and develop code. The 1's and 0's could be black and white pixels, though I had no idea how to turn that into an image. The timestamp object—maybe a red herring, at the time I was unsure.

I hurried over to Caesar's Forum at approximately 2230H and into the "chill room", where a DJ played the exact type of cyberpunk music needed to quickly put together a botch-job of a script. It sounded like something out of a Mr. Robot hacking scene, except instead of writing a zero-day for FBI standard-issue smartphones, I was busy Frankensteining example code into something that could solve this challenge. 

Overnight, I wrote a script that uses the OPC UA subscription service to collect data using the opcua-asyncio library. The library didn't have the best documentation and was not straight-forward to use. In fact, the README code sample contains a syntax error; a more obscure page contains working example code.

The example code came with some limitations. First, it didn't have a programmatic way to determine the full URL to the OPC UA service; it was something that had to hardcoded. I am certain there is a way to determine this dynamically, but I didn't want to read pages upon pages of documentation. Instead, I relied on the packet capture from the initial interaction to determine the URL: