Blog: OT, ICS, IIoT, SCADA
Pwning a Siemens Scalance ICS switch through ARM reversing
We’ve been working in industrial control systems security for a long time. Several of the team here used to work in OT control rooms or support SCADA environments.
Whilst pen testing a ship control system, we noticed a heavy reliance on Siemens Scalance industrial ethernet switches, so bought a couple for our own research.
After some reverse engineering, we discovered reversible encryption of the admin passwords with a static key, and reversible encryption of user passwords with a different key.
That would give anyone with the static key the ability to compromise the switch.
We disclosed to Siemens, who were awesome & quickly fixed the issue. It transpired that our finding affected their entire Scalance OT switch range!
Here’s how we found the static key: I hope you find the techniques useful
Siemens Scalance x200
This project started with configuration files being provided to me by a colleague who noticed that the passwords looked unusual and didn’t seem to be a one-way hash. There are already exploits available to recover the config file and firmware, meaning that it would be possible for an attacker to gain access to this information:
The passwords were small in size, and variable in length depending on the password size, rounded to 8 characters. This heavily implied the use of a block cipher for encryption.
The 64-bit size of the small passwords being used for testing implied that DES or Blowfish were in use as the encryption algorithm. What was also of note was that the administrator account had two passwords, which was unusual.
Reverse engineering the firmware payload
The firmware file that was provided for testing was identified to be an ARM ELF file with a lot of data but a small amount of code. Running the “binwalk” command on the ELF file found version strings for the “VxWorks” Real Time Operating System and LZMA compressed data, which was extracted in order to identify its purpose.
The LZMA compressed file was likely to be the main firmware payload for the device, and decompression of it showed that it was a binary file with no discernible file signature.
A hexdump of the decompressed binary showed that it was ARM firmware, which can be easily identified manually by the upper nybble of each 32-bit value being an “E”, or by using the “binwalk -A” command on the file.
As the firmware had been identified and was in a readable format, it could be loaded into IDA as an ARM Little-endian binary file.
At this stage, static analysis was being performed on the firmware payload, and no information was known about the internals of the device. Due to this, the entry-point for the firmware (where it is loaded into memory) was not known.
When this occurs, it is possible to use a default address of 0x00000000 as the entry point, as the firmware will still partially disassemble. However, references to functions and data will not be accurate, making only superficial analysis possible.
Finding the entry point would be extremely valuable, as it would make it easier to identify code references and trace functions that are being used.
There are numerous techniques that could be used, such as identifying switch cases in the code with absolute references however there was a shortcut, due to the firmware utilising the VxWorks Real Time Operating System.
The VxWorks symbol table provides function references which match with string references, allowing each function in the firmware to have a name defining its function, and by identifying the “sysInit” function used at the start of firmware, one can find the entry point of the firmware. This was identified to be 0x00001000, the firmware was reloaded with this reference and the disassembly improved.
A small IDC script was created, which allowed each function reference in the table to be deployed to the relevant functions, drastically increasing the speed with which the purpose of each function could be assessed.
RAM could be identified by values being set in the code and also aided IDA with disassembling the remainder of the firmware. It was also helpful in identifying functions with similar memory references.
Finding the password encryption
We could find function references with the word ‘password’ and/or find any function calls which look like encryption, with a focus on either Blowfish or DES encryption.
Then trace the values loaded into the parameters before calling them, for ARM these would be set in registers R0, R1, R2 etc.
Blowfish function calls were identified in the “CliEditPasswordSet” function, proving that reversible encryption was used.
A Blowfish test function was identified using specific constants which could be searched for on the internet, which allowed for identification of the exact Blowfish library used, which could be downloaded from GitHub.
Using this information, one can trace the encryption key used for Blowfish, by identifying the value passed to register R1. This was due to the fact that register R0 would contain the “ctx” variable, R1 would contain the key, and R2 would contain the length of the key.
Analysis of this showed that the encryption key used for the administrator password was “ELS_key” however attempts to decrypt standard user passwords using this string failed.
Further analysis showed a second key was used, but could not be identified statically, as the references to it were not easy to trace.
When Static Analysis Isn’t Feasible
Static analysis is useful when you are dealing with a relatively simple piece of software, or you have a lot of time to trace each function call. In this instance the reason we couldn’t identify the encryption methodology for the user passwords via static analysis was due to the unusual nature with which they were encrypted.
We bought our Scalance switch from eBay and quickly identified JTAG on the board, soldered headers to it and connected it to our Segger J-Link JTAG debugger.
Using the Segger GDB Server, it was possible to add breakpoints and step through each element of the firmware.
From this, the exact variables used by the encryption could be identified by checking the register settings when functions were called.
The following password encryption methodology was identified:
- The administrator password is encrypted with the static key “ELS_key”
- The second administrator password is a static string “ELSDebug” which is encrypted with the plaintext administrator password, which is used to make sure that the administrator password corresponds to the encryption used by the user passwords
- All other user passwords are also encrypted with the plaintext administrator password
I couldn’t work this out via static analysis because the method used is so unusual, and assumptions about the encryption keys being used could not be made.
Due to the reversible nature of the passwords, this was disclosed to Siemens
Siemens Product CERT were really cool and quick to respond to disclosure.
Siemens investigated and determined that the issue affected the entire Scalance switch product line, so they asked for extra time over the usual 90 days. We agreed, as they were communicating well with us and the request was reasonable.
Disclosure was coordinated: https://www.us-cert.gov/ics/advisories/ICSA-19-162-04
New firmware was released: https://support.industry.siemens.com/cs/document/109767965/firmware-update-version-5-2-4-for-scalance-x-200
And Siemens issues a security advisory: https://cert-portal.siemens.com/productcert/pdf/ssa-646841.pdf