Security researcher hacks Apple, Google, Microsoft, after compromising upstream software packages.
Credit: Tamanna Rumee
A security researcher managed to breach over 35 major companies including Apple, Google and Microsoft in a striking (and strikingly clever) software supply chain attack that puts a stark spotlight on the risks associated with consuming packages from open source repositories without adequately checking for malicious upstream activity.
Security researcher Alex Birsan hit the companies via a "substitution attack" which exploits a design flaw in the way native installation tools and DevOps workflows pull dependencies into a software supply chain (as well as the way in which many developers freely consume snippets of code from public forums without curation.)
Birsan — who has earned over $130,00 in bug bounties for the stunningly effective campaign — published over 200 rogue packages to widely used open-source ecosystems including npm, PyPI, RubyGems. These were designed to have names like those he had identified as being used in private software development programmes that relied on certain open source upstream components. The process was largely automated.
As Sonatype explains: "Let's assume your application uses an internal, privately-created PyPI [a bit of Python script] component called foobar (version 1) as a dependency. Later, should an unrelated component by the same name but higher version number foobar (version 9999) be published to the PyPI downloads public repository, the default configuration of PyPI development environments dictates that the foobar with the higher version be downloaded as a dependency. In this case, that would mean, the attacker's counterfeit foobar package with a higher version number would silently and automatically make its way into your software build."
Despite Birsan marking his packages with a note saying "for security research purposes only" they were rapidly installed into corporate systems, from which he could exfiltrate data via DNS queries that hit an authoritative name server configured to keep a record of every machine where the packages were downloaded.
Private package names are often hidden in JavaScript files.
As first reported by Bleeping Computer, Birsan started by identifying the names of "private" software packages in GitHub repositories, internet forums and — jackpot — most commonly inside JavaScript files themselves.
(As he notes in his own write-up: "Apparently, it is quite common for internal package.json files, which contain the names of a javascript project's dependencies, to become embedded into public script files).
He then exploited the way in which many companies store internal packages on a private feed but allow the retrieval of dependencies from a public feed. (As Microsoft notes in a whitepaper referencing the attack, "this ensures that the latest package releases are automatically adopted. Internal developers publish their packages to this private feed, and consumers check both private and public feeds for the best available versions.")
See also: Hacker breaches water plant via TeamViewer
Having identified these private software packages, he created counterfeit projects using the same names on open-source repositories such as npm, PyPI, and RubyGems, but laced them with superficially malicious code that would phone home using DNS from inside company networks, so he could track the campaign.
(npm is the world's largest software registry; think of it — very crudely — as a sprawling marketplace of JavaScript software laid out on stalls of mixed provenance: visitors can adapt packages of code for your apps, or incorporate packages as they are. Some of that code is well maintained, but some of it riddled with open issues that have been raised on GitHub and only sporadically tweaked by a tiny pool of contributors.)
His success was in his own word "astonishing", with the majority of the 35+ companies successfully penetrated falling into the 1000+ employees category: "One such company is the Canadian e-commerce giant Shopify, whose build system automatically installed a Ruby gem named shopify-cloud only a few hours after I had uploaded it, and then tried to run the code inside it." (After notifying them, the Shopify team had a fix ready within a day).
Birsan notes: "Another $30,000 reward came from Apple, after the code in a Node package which I uploaded to npm in August of 2020 was executed on multiple machines inside its network."
People have seen this coming…
People have seen this kind of attack coming, broadly, for example, in last year's "Vulnerabilities in the Core" open source census from the Linux Foundation and Harvard University, but more specifically vis-a-vis this particular technique of namespace hijacking, by people like Sonatype CTO Brian Fox.
Fox in 2017 noted that the lack of a proper namespacing requirement in open-source ecosystems has the potential to cause dependency hijacking attacks. As he put it at the time: "The fact that so much of the npm ecosystem is effectively not namespaced has actually created potential build time malware injection possibilities."
"If I know of a package in use by a company through log analysis, bug report analysis, etc. I could potentially go register the same name in the default repo with a very high semver [semantic versioning] and know that it's very likely that this would be picked up over the intended, internally developed module because there's no namespace," he said.
(Sonatype says its systems spotted Birsan's malicious packages early and contacted the researcher, who emphasised that it was taking place under bug bounty programmes as part of an ongoing security research campaign and that coordinated disclosure was set to take place in early 2021.)
Talking about the attack on Twitter, Microsoft's Barry Dowans explained one aspect of the attack further, noting: "To give a use case from .NET, we have internal packages for testing infrastructure. Those were on an internal feed, and didn't have reserved names, hence Alex hitting up .net first, because he could squat them on nuget! [The package manager for .NET] Nuget pulls from all feeds in parallel, and if the public ones had a higher version number it would win because we aren't version locking to specific versions, in order to pick up patches."
Read Alex Birsan's full write-up here.
See also: Follow The Stack on LinkedIn here.