A Better Approach to Securing Software Supply Chains
/One fast-growing form of cyber attack is to embed malware into trusted software, allowing it to be installed without the knowledge of a user. This malware can be:
· introduced directly into the software delivered by a trusted provider,
· introduced into third-party provided libraries,
· embedded in compromised APIs and services,
· added to open source projects,
· or injected into source code management tools and repositories, compilers, and packaging system tools.
The attack surface is massive and dynamic, and in each instance the end result is the same: a software application or update is directly or indirectly changed without the knowledge and consent of the trusted provider or the user.
Your Software Supply Chain isn’t a Chain
Attempts to identify and assess every embedded component in a software package generally fail. We can periodically survey software providers to see if their policies, procedures and practices meet minimum expectations, but that tells us little about specific software packages and even less about the components they source from others.
Worse, a package may use multiple third-party components, each of which may have multiple embedded components. While commonly referred to as a “software supply chain”, it’s more like a pyramid; the deeper you go, the more suppliers there are and the less visibility you have.
Imagine your software vendor licenses a library from another company, that library makes a service call to a third company, and that service contains open source code. What visibility would you have into the quality of the open source code? Would you even know it exists? Your ability to trust components decreases exponentially with distance (supplier layers).
No Good Baseline
It’s clear that we can’t evaluate the security of each component, especially when we don’t even know what all of the components are. We can assess the finished software package, which is a smaller surface area that doesn’t require being able to pre-identify every part. However, that assessment presumes we know what to look for.
Static scans rely on things such as signatures, so new or custom malware could easily be missed. We can do behavioral “dynamic analysis,” but the behavior baselines are generally built from past behaviors. New software doesn’t have a past history, and updates are generally expected to have new features (meaning new behaviors). In short, we don’t have a good baseline to compare against.
A new approach is clearly needed.
Declared Intent
That new approach is “Declared Intent.” The premise is to evolve and apply the whitelist permission concept used by mobile apps. When you install a mobile app, it asks for permission to access resources such as your camera, microphone, files, or network. You can review the resources and decide if they make sense for the app you are installing. You can also deny access.
We need something like that in data center (and desktop) apps, only better. We need to whitelist more than resources; we need to whitelist risky behaviors with resources.
Imagine if every provider of software components included a file that declared the intended behavior of their code. Want to send data to a server in a foreign country? Declare it. Want to kill running processes that your software didn’t create? Declare it. Want to read files owned by another user? Declare it.
The declarations from each component could be combined and added to the declarations from the developer who created the finished package. Unlike mobile apps, we wouldn’t just declare access to resources, we would declare actions. With resources such as files, the risky behavior might be reading or writing files not owned by this userid and not in a publicly accessible directory (in Linux systems, this could include breaking out of a namespace). A security team could review all declarations and decide if the behaviors are warranted before installing the software or update.
We need to start by defining a behavioral framework and classification system for declarations. One good approach is to inspect “system calls,” since most risky behaviors require acting through the operating system. Of the roughly 400 Linux system calls, there are about 20 actions that are likely to be of interest to a security team. We can layer on “variables” that further describe the specific resource. If a risky behavior is reading a file not owned by this program’s userid, the “variable” might be the filename or path of the file being read.
· Step 1: Static Analysis. Most software providers would bristle at the notion of having to manually classify the behaviors of their code; it runs counter to investments in developer productivity. Automation through static analysis can help. If we know what behaviors to look for, we can scan source code at check-in or build to automatically produce declarations. Ideally, these declarations would be reviewed and tweaked by a developer who has a deep understanding of his/her intent and the “variables” described above.
When presented with a compiled binary component that lacks behavior declarations, we can scan the binary and detect system calls in assembly language. This method is guaranteed to catch every system call, but is less perfect at capturing intent.
For “variables” that aren’t defined in the software, such as those in user-created config files, we can supplement the declarations by asking the user to whitelist certain addresses and file paths.
· Step 2: From SBoM to SBoA. Once behaviors are defined, they need to be stored and shared in a well understood format. Fortunately, people have already been thinking about ways to describe applications and their components through a Software Bill of Materials (SBoM).
Most SBoM work has focused on capturing the versions of components for license compliance checks and vulnerability tracking, but why stop there? We propose extending one or more SBoMs to include the intended behaviors of each component in the package, in effect creating a Software Bill of Activities (SBoA). Leveraging and extending a standard SBoM schema makes the behavior declarations easier to consume and understand by both humans and tools. It also increases the value of an SBoM by adding new use cases.
Leveraging an SBoM means we get the benefit of all of the work that’s gone into deciding how SBoMs should be stored, published, secured, and maintained. SBoAs have these same needs.
· Step 3: Catching Gaps. In an ideal world, every risky behavior in every software package would be pre-declared, stored in an SBoA, and risk-assessed by users. Security professionals don’t believe in ideal worlds. Motivated attackers will seek to obfuscate injected code, add code after the declarations are captured, or manipulate the SBoA. Not all software suppliers will include an SBoA, and some may include versions that are out of date. As a result, we will be left with gaps in declarations.
Systems designers would describe those gaps as the result of having an “open loop system,” relying on the SBoA to be accurate as it gets created and updated. A “closed loop system” would ensure that the final SBoA is correct through a feedback loop.
How? By using the SBoA, which describes intended software behavior, to detect undeclared behaviors. SBoAs are deterministic representations of intent, not best guesses based on previously observed behavior, making them the perfect baseline for runtime, dynamic analysis.
An SBoA could be ingested by a container or VM, loaded by an application firewall, or even translated into operating system “system call filters.” As an application runs, violations could be blocked or generate alerts. If a risky behavior isn’t declared, through simple omission or because of a malicious hack, it will be detected.
This three-step process of capturing intended behaviors, publishing them in a standard format for review, and runtime assessing for undeclared behaviors creates a trustworthy system.
More than the Sum of the Parts
The real value of this approach in securing software supply pyramids is more than the sum of the parts. Static scans to declare behaviors, reviews of expected behaviors in an SBoA, and runtime enforcement of behaviors each have stand-alone merit.
The intersection of all three creates a much more secure application. Risky behaviors are declared, reviewed, and enforced without obvious opportunities for attackers to circumvent the system.
Lou Steinberg is Founder & Managing Partner of CTM Insights, a cybersecurity research lab and early stage incubator. CTM is researching the best ways to implement behavior whitelisting using Declared Intent. We invite those interested to join us.