Stopping Supply Chain Attacks With Preflight

CodeCov and Supply Chain Attacks

The above examples of remote CodeCov bash execution may vanish over time. However, other instances of remote shell script execution are prevalent even across projects and repositories on GitHub.

  • Swapping software
    A script that we pull can still feel like it behaves nicely. But then, it would let us install a different software package than what we originally thought it would.
  • Tricking into old updates
    To avoid being detected for giving you a tainted binary? An attacker may simply push an older version of the same software you’re installing, assuming that this older version contains a famous exploit they can use.
  • Tricking into future updates or “update jacking”
    An attacker might want to point the script at their own update package. Which, in terms of server, is well into the future. So rollback attempts would fail. For the same goal, an attacker can replace a specific update in the past, present, or future (as long as they can cause an updater to trigger).

Introducing: Preflight

How Does Preflight Work?

What happens when you execute a “ curl | sh " karate-chop? Here's one breakdown of such a chain in very general terms, highlighting the major links in the chain:

Getting Preflight

First of all, it’s the chicken and the egg. How do you pull a legit preflight binary from us without verifying it with preflight? Having that preflight solves this exact problem?

  • Drop it on your own Artifactory or similar
  • Push it directly into your repos (it should be as small as 4mb and seldom change so Git should work nicely with it)
$ brew tap spectralops/tap && brew install preflight

Flying With Preflight

The curl | sh workflow is packaged as a tool, verified with our own signature that we can create with Preflight. In addition, Preflight can verify any runnable against several of providers such as VirusTotal and others to detect malware automatically

So how does it look in action?

Someone changed the script or binary you’re running. Abort!

$ curl -L https://XXX | preflight run sha256=1ce...2244a6e86 ⌛️ Preflight starting ❌ Preflight failed: Digest does not match. Expected: <...> Actual: <...> Information: It is recommended to inspect the modified file contents.
$ curl -L https://XXX | preflight run sha256=1ce...2244a6e86 ⌛️ Preflight starting using file lookup: malshare.current.sha256.txt ❌ Preflight failed: Digest matches but marked as vulnerable. Digest matches but marked as vulnerable. Information: Vulnerability: Hash was found in a vulnerable digest list More: malshare.current.sha256.txt
$ curl -L https://XXX | preflight run sha256=1ce...2244a6e86 ⌛️ Preflight starting ✅ Preflight verified ... actual script output ...

Codecov Revisited

A perfect example of Preflight in action would be CodeCov.

$ curl -s https://codecov.io/bash | ./preflight create sha256=d6aa3207c4908d123bd8af62ec0538e3f2b9f257c3de62fad4e29cd3b59b41d9
sha256=d6aa3207c4908d123bd8af62ec0538e3f2b9f257c3de62fad4e29cd3b59b41d9
steps: - curl -s https://codecov.io/bash | sh
steps: - curl -s https://codecov.io/bash | ./ci/preflight run sha256=d6aa3207c4908d123bd8af62ec0538e3f2b9f257c3de62fad4e29cd3b59b41d9

Dealing With Change

When updating an old binary or script to a new updated version, there will be at least two (2) valid digests “live”. Just replacing the single digest used will fail for the older runnable which may still be running somewhere.

$ preflight <hash list|https://url/to/hash-list>
curl .. | ./ci/preflight run sha256=d6aa3207c4908d123bd8af62ec0538e3f2b9f257c3de62fad4e29cd3b59b41d9,sha256=<new hash>,...
curl .. | ./ci/preflight run https://dl.example.com/hashes.txt
  • You use a URL when your runnables change often. Remember to follow the chain of trust. This will now mean that:
  • Your hash list URL is now a source of trust
  • Visually: we’re swapping the chain of trust like so curl <foreign trust> | ./ci/preflight <own trust>

Checking Scripts And Binaries

If you want to use Preflight as another tool for improving your Unix pipes chops, you can with the “check” command:

Piping:

$ curl -s https://example.com/some-script | preflight check sha256=d6aa3207c4<...>b4 | sh
  • If a check fails, you’ll get an exit(1), and an error message

Executables:

$ preflight check sha256=d6aa3207c4<...>b4 ./my-script.sh
  • If a check fails, you’ll get an exit(1) and an error message

Creating New Hashes

You can easily create new hashes with preflight. The default is a SHA256 hash, but you could also create a sha256, sha1, and md5 hash.

$ preflight create test.sh sha256=fe6d02cf15642ff8d5f61cad6d636a62fd46a5e5a49c06733fece838f5fa9d85
$ preflight create test.sh --digest md5 md5=cb62874fea06458b2b0cabf2322c9d55

Malware lookup

preflight comes with lookup providers. This is optional and you can enable them by using environment variables:

File Lookup

You can download a daily list of malware signatures from malshare.com or any equivalent service. Here is a direct link to such a list.

env: PF_FILE_LOOKUP: malshare.current.sha256.txt steps: - wget https://www.malshare.com/daily/malshare.current.sha256.txt - curl https://... | preflight <sha>
$ PF_FILE_LOOKUP=malshare.current.sha256.txt preflight run fe6d02cf15642ff8d5f61cad6d636a62fd46a5e5a49c06733fece838f5fa9d85 test.sh ⌛️ Preflight starting using file lookup: malshare.current.sha256.txt ❌ Preflight failed: Digest matches but marked as vulnerable. Information: Vulnerability: Hash was found in a vulnerable digest list More: malshare.current.sha256.txt

VirusTotal Lookup

You can use the virus total community API access to lookup your hashes.

env: PF_VT_TOKEN: {{secrets.PF_VT_TOKEN}} steps: - curl https://... | preflight <sha>
$ PF_VT_TOKEN=xxx preflight check e86d4eb1e888bd625389f2e50644be67a6bdbd77ff3bceaaf182d45860b88d80 kx-leecher.exe ⌛️ Preflight starting using VirusTotal ❌ Preflight failed: Digest matches but marked as vulnerable. Information: Vulnerability: VirusTotal stats - malicious: 40, suspicious 0 More: https://www.virustotal.com/gui/file/e86d4eb1e888bd625389f2e50644be67a6bdbd77ff3bceaaf182d45860b88d80/detection

Summary

While there’s a lot of interest in protecting the use of 3rd party libraries? Frequently — especially in CI systems — we’re actually running 3rd party tools to get a certain job done. This is another chance for attackers to aim at our supply chain. Using Preflight, we can ensure we employ 3rd party tools safely and securely.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store