Typosquatting Malware Found in Composer Repository

Typosquatting Malware in Composer Repository

If you’re familiar with modern PHP development techniques and practices you must certainly know and enjoy the benefits of composer when it comes to bringing in third party libraries.

With PHP being such a popular language on the web and composer so widely used, it is no surprise that attackers are doing their best to jeopardize it and take advantage of vulnerable applications out there.

Not too long ago there was a successful attempt against composer’s core: packagist.org.

And recently another type of attack was detected, in this case the problem was a typosquatting malware that got into the public repository.

This type of attack exploits the fact that people type fast and don’t usually review what the end result looks like or, if they do, they just take a quick look and move on.

For instance, if you wanted to get some content from a remote website from your terminal you could issue a command such as:

curl https://remotesite.com

But what if instead of curl you typed cyrl? Like this:

cyrl https://remotesite.com

In most cases this wouldn’t have any further consequences than getting a message like:

zsh: command not found: cyrl

So you’d realize your mistake, fix the typo and go on your way. But what if there actually was a cyrl command available in your computer? It would simply do whatever it was meant to do… the problem would be that, if it produced a somewhat similar output to what you expect from curl, it’d be very hard for you to notice the fact that you just run something other than the command you meant to run.

Of course, this scenario is utterly extreme, since someone would have to have access to your personal computer and install such a binary… very unlikely.

In this case, the attack vector was a handcrafted package name uploaded into packagist.org (The main repository for composer packages).

Since packagist.org is a public repository, there’s not much control over what gets published, as long as it follows a few simple rules.

What the attacker did was look for a very popular package (Download stats are very easy to come by), create a malicious one with a very similar name and put it up for download right next to the original.

In this case, the fake package was called symfont/process (mimicking  symfony/process).

You can see how the usage of such a similar name allows for many developers to download the malware instead of the actual package they were looking for by simply mistyping (Note how the t is right next to the y on your keyboard).

Once the package is downloaded it will provide its own implementation of Symfony\Process\Process which is not very much like the one designed by the Symfony team.

What this Process class does is send information about the host it’s running on back to a central location, to be used in further attacks.

The attack is completed by opening a webshell on the server infected with the malware which can be used by the attacker to execute random commands on the victim.

Of course the attack can only be successful if:

  1. The victim’s application makes use of the Symfony\Process class
  2. The part of the application that makes use of the  Symfony\Process class is actually executed

It is safe to assume both conditions are met since the fact that the package is present as a project dependency means that there’s a need for it (Or the was a need for it in the past and nobody removed it from the composer.json file yet).

Still, in a case like this, there’s a small window of opportunity to avoid being a victim of such a threat between the time of downloading/installing the malware and actually allowing it to run its malicious code.

For more details you can read the original report by Sean Murphy (The researcher who discovered the problem) here.

According to the report, the attacker has been identified and the threat neutralized (If you search for the package symfont/process on the packagist site there’s no reference to it.

It’s worth mentioning a similar situation presented itself back in 2016 with the Monolog package as commented in this post by Jordi Boggiano.

In this case, the attack attempt was perpetrated via uploading a package named momolog/monolog instead of the popular monolog/monolog (A widely used package for error log handling).

It’s very interesting what Jordi did to encounter this suspicious package. He put together a script that would get the names of the vendors with of the most downloaded packages from packagist.org and compared the names of each to the others using the levenshtein function, which calculates the distance between two strings, effectively giving an idea of the similarity between the two.

For instance, running the following code:

levenshtein(‘monolog’, ‘momolog’);

Will produce a 1 as a result, while this:

levenshtein(‘monolog’, ‘monologer’);

Will produce a 2.

A levenshtein distance of one means that just by replacing one character for another (or adding or removing one) on a string you get the second.

This doesn’t necessarily mean that the similar vendor name is a bad actor, though it should definitely raise a flag.

After getting a short list of potential attackers it’s easy to go through it mannually looking for potential typosquatting attempts. It’s basically trying to spot those names that could be produced by hitting a key that’s right next to the correct one.

Finally it seems like the automation that was proposed by Jordi never got developed or deployed, otherwise, the symfont attack wouldn’t have been possible.

Typosquatting vs. Dependency Confusion

There’s another somewhat similar type of attack known as dependency confusion. In the case of this attack, the target is not the individual developer but the package manager itself.

It’s a common practice for big companies to have their own private packagist where they store libraries that are only meant to be used internally.

Modern package managers have the intelligence to deal with version calculations to determine when a particular library is outdated. They do so by comparing the locally installed version numbers to the published ones.

This attack is performed by uploading to a public repository a package with the exact same name as the private one but with a higher version number.

This way, when someone asks their package manager to install the aforementioned library, they’ll inadvertently be downloading the malicious version.

In the case of composer, or better yet, packagist, there are a few measures in place to avoid becoming victims of such attacks. Among those you’ll find that:

  • Composer package names are of the form vendor/package. The vendor name is reserved for the first entity to upload a package. This means no attacker can hijack your company name and thus publicly upload malicious packages on your behalf… unless they beat you to upload the first package.
  • Up from version 2.0 of Composer, custom repositories take precedence over public ones.

You can read more details about Composer’s Dependency Confusion prevention measures here and, if you want to go deeper into understanding the nature of this threat and how it was discovered here’s the article by Alex Birsan, the researcher who first reported its existence.

Conclusion

While this particular attack is no longer a concern this kind of vulnerability could easily be replicated using another popular package as vector.

So, it’s probably a good idea to look twice at the composer require you’re issuing before hitting enter.

Or better yet, rely on automatic tools such as Mend to help you stay on the safe side.

Mauro Chojrin / About Author

Mauro is a PHP Trainer and Consultant.

He’s been involved in the IT Industry since the year 1997 in a wide array of positions, going from which include technical support, development, team leadership, IT Management and, off course, teaching.

Currently Mauro’s focus is on in-company training and consulting but also maintaining his blog and YouTube channel where he shares his knowledge with the world.

LinkedIn

Leave a Reply

Your email address will not be published. Required fields are marked *