Introducing PCVARK and their malicious ad blockers

It isn’t news that the overwhelming majority of ad blockers in Chrome Web Store is either outright malicious or waiting to accumulate users before turning malicious. So it wasn’t a surprise that the very first ad blocker I chose semi-randomly (Adblock Web with 700,000 users) turned out malicious. Starting from it, I found another malicious extension (Ad-Blocker, 700,000 users) and two more that have been removed from Chrome Web Store a year ago (BitSafe Adblocker and Adblocker Unlimited).

Chrome Web Store extension listing, in the middle is the entry titled “Adblock Web - Adblocker for Chrome” with the description text “Get rid of any intrusive ads easily and make your web cleaner!”

All these ad blockers and probably some more were developed by the company PCVARK. According to Malwarebytes Labs, this company specializes in developing “potentially unwanted programs.” In other words: they show users warnings about alleged compromise, only to push them into installing their software. Once installed, this software will attempt to scare the user into installing more crappy applications and into paying money for fixing the supposed issue.

While PCVARK originally specialized in Mac software, they apparently also discovered pushing malicious ad blockers to Chrome Web Store as a valuable business opportunity. This was encouraged by Google’s lax moderation policies as well an almost complete lack of policy enforcement. While Google eventually managed to remove some extensions, at least two remain despite being obviously related to the removed ones.

How malicious extensions hide running arbitrary code

Two days ago I wrote about the malicious extensions I discovered in Chrome Web Store. At some point this article got noticed by Avast. Once their team confirmed my findings, Google finally reacted and started removing these extensions. Out of the 34 extensions I reported, only 8 extensions remain. These eight were all part of an update where I added 16 extensions to my list, an update that came too late for Avast to notice.

Note: Even for the removed extensions, it isn’t “mission accomplished” yet. Yes, the extensions can no longer be installed. However, the existing installations remain. From what I can tell, Google didn’t blocklist these extensions yet.

Avast ran their own search, and they found a bunch of extensions that I didn’t see. So how come they missed eight extensions? The reason seems to be: these are considerably different. They migrated to Manifest V3, so they had to find new ways of running arbitrary code that wouldn’t attract unnecessary attention.

Update (2023-06-03): These extensions have been removed from the Chrome Web Store as well.

More malicious extensions in Chrome Web Store

Two weeks ago I wrote about the PDF Toolbox extension containing obfuscated malicious code. Despite reporting the issue to Google via two different channels, the extension remains online. It even gained a considerable number of users after I published my article.

A reader tipped me off however that the Zoom Plus extension also makes a request to serasearchtop[.]com. I checked it out and found two other versions of the same malicious code. And I found more extensions in Chrome Web Store which are using it.

So now we are at 18 malicious extensions with a combined user count of 55 million. The most popular of these extensions are Autoskip for Youtube, Crystal Ad block and Brisk VPN: nine, six and five million users respectively.

Update (2023-06-01): With an increased sample I was able to find some more extensions. Also, Lukas Andersson did some research into manipulated extension ratings in Chrome Web Store and pointed out that other extensions exhibited similar patterns in their review. With his help I was able to identify yet another variant of this malicious code and a bunch more malicious extensions. So now we are at 34 malicious extensions and 87 million users.

Update (2023-06-01): Good news: Google started removing these extensions. By the time I published my previous update, a bunch of the extensions mentioned there were already gone. Right now, only nine extensions from this list remain in Chrome Web Store, and these will hopefully also be dealt with soon.

Update (2023-06-02): Google removed one more extension, so only eight extensions remain now. These eight extensions are considerably different from the rest, so I published a follow-up blog post discussing the technical aspects here.

Malicious code in PDF Toolbox extension

The PDF Toolbox extension for Google Chrome has more than 2 million users and an average rating of 4,2 in the Chrome Web Store. So I was rather surprised to discover obfuscated code in it that has apparently gone unnoticed for at least a year.

The code has been made to look like a legitimate extension API wrapper, merely with some convoluted logic on top. It takes a closer look to recognize unexpected functionality here, and quite some more effort to understand what it is doing.

This code allows serasearchtop[.]com website to inject arbitrary JavaScript code into all websites you visit. While it is impossible for me to tell what this is being used for, the most likely use is injecting ads. More nefarious uses are also possible however.

Update (2023-05-31): As I describe in a follow-up article, this extension isn’t alone. So far I found 18 malicious browser extensions using similar code with a combined user count of 55 million. It’s also clear now that these extensions are at the very least being used to redirect search pages.

Online Security extension: Destroying privacy for no good reason

These days it’s typical for antivirus vendors to provide you with a browser extension which is meant to improve your online security. I’ll say up front: I don’t consider any such browser extensions recommendable. At best, they are worthless. At worst, they introduce massive security issues.

As an example I took a brief look at the Online Security extension by ReasonLabs. No, there is no actual reason beyond its 7 million users. I think that this extension is a fairly typical representative of its craft.

A pop-up titled “Online Security for Google Chrome” and subtitled “Protects your browsing and personal information by blocking harmful content and real-time detection of data breaches.” A big orange button below says “Scan now.”

TL;DR: Most Online Security functionality is already provided by the browser, and there is little indication that it can improve on that. It does implement its functionality in a maximally privacy-unfriendly way however, sharing your browsing history and installed extensions with the vendor. There is also plenty of sloppy programming, some of which might potentially cause issues.

A way forward for PfP: Pain-free Passwords

A month ago I announced the end of PfP: Pain-free Passwords. But I’m allowed to change my mind, right? Yes, PfP will be developed further after all. However, it’s so different that I’m publishing it as a new browser extension, not an update to the existing extension.

Rather than using its own data format, PfP 3.x reads and writes KeePass database files. In order for the extension to access these files, users have to install a PfP Native Host application. This application provides access to the configured database files only.

Also, PfP 3.x no longer generates passwords on the fly. All passwords are stored inside the database, and generating passwords randomly happens when passwords are added. While this makes recovery more complicated, elsewhere it simplifies things a lot.

Processing a complex syntax with Rust’s declarative macros

I am by no means a Rust expert, and I’m no expert on declarative macros. I was merely solving an issue I had: there was a lot of redundancy in the way my error types were coded. I didn’t want to repeat the same coding patterns all the time, yet the types also seemed too heterogenous for declarative macros. And going with procedural macros wasn’t worth the effort in this case.

After some experimentation I figured out how declarative macros could work in this scenario after all. I doubt that this approach is very original, and maybe I solved something in a sub-optimal way. I couldn’t find any helpful online sources however, which is why I’m documenting this in my own article. Edit: After publishing this article, I found that the pattern used here is called TT munching.

Documenting KeePass KDBX4 file format

I’ve been playing around with KeePass databases. One aspect was rather surprising: given how many open source products use this format, it is remarkably underdocumented. At best, you can find outdated and incomplete descriptions by random people. The KeePass developers themselves never bothered providing complete documentation. All you get is a semi-intelligible list of changes from KDBX 3.1 to KDBX 4 and from KDBX 4 to KDBX 4.1. With the starting point not being documented, these are only moderately useful.

And so it’s not surprising that the implementations I looked at aren’t actually implementing the same file format. They all probably manage to handle common files in the same way, but each of them has subtle differences when handling underdocumented format features.

I’ll try to explain the format and the subtle details here. For that, I looked at the source code of KeePass, KeePassXC, keepass-rs Rust library and the kxdbweb JavaScript library. Let’s hope this documentation helps whoever else needs to work with that file format, and studying source code will no longer be required.

I can only document the latest version of the format (KDBX 4.1), though I’ll try to highlight changes wherever I’m aware of them.

The end of PfP: Pain-free Passwords

Seven years ago I created a password manager. And a few days ago I pushed out the last release for it, notifying users that nothing else will come now. Yes, with the previous release being from 2019, this might have been obvious. Now it’s official however, PfP: Pain-free Passwords is no longer being developed.

Screenshot of a message titled “PfP: Pain-free Passwords is being discontinued.” The text says: “All good things must come to an end. It has been seven years since PfP was first introduced, back then under the name EasyPasswords. It has features that no other password manager can match, and I still like it. Unfortunately, developing a good password manager is lots of effort. I notice that I’ve been neglecting PfP, and this won’t change any more. So I’m now making official what has been somewhat obvious already: PfP is no longer being developed. Does this mean that you can no longer use it? You can. But whatever breaks now stays broken. Sync to Google Drive in particular is already broken and non-trivial to fix unfortunately. What can you use instead? Not LastPass please. Maybe Bitwarden or 1Password. Definitely KeePass or a clone if you don’t mind it being less intuitive. Personally, I’ll be using KeePassXC. How to get your passwords over? On the “All Passwords” page, there is a new button for CSV export. It should be possible to import the resulting file into any password manager. In KeePassXC you’ll need to check “First line has field names,” otherwise the default import settings will do.”

I certainly learned a lot from this adventure, and I really like the product which came out of this. Unfortunately, a password manager is a rather time-consuming hobby, and my focus has been elsewhere for a while already.

This doesn’t mean that PfP is going away. In fact, it will probably work well for quite a while until a browser change or something like that makes it unusable. Sync functionality in particular depends on third parties however, and this one already started falling apart.

Converting incoming emails on the fly with OpenSMTPD filters

This little adventure began with me being annoyed at DMARC aggregate reports. My domain doesn’t have enough email traffic to justify routing DMARC emails to some third-party analytics service, yet I want to take a brief glance at them. And the format of these emails makes that maximally inconvenient: download the attachment, unpack it, look through some (always messy but occasionally not even human-readable) XML code. There had to be a better way.

This could have been a Thunderbird extension, processing the email attachment in order to produce some nicer output. Unfortunately, Thunderbird extensions no longer have this kind of power. So I went for another option: having the email server (OpenSMTPD) convert the email as it comes in.

Since I already had the implementation details of OpenSMTPD filters figured out, this wasn’t as complicated as it sounds. The resulting code is on GitHub but I still want to document the process for future me and anyone else who might have a similar issue.