Pwning your antivirus, part 2: even your Mac isn't SAFE

TL;DR F-Secure has patched multiple vulnerabilities in their SAFE for Mac antivirus product. The official advisory can be found here. As usual, this post focuses on the technical details from a bug hunter's perspective.

Poking around antivirus products is fun, mainly because they seem to be so terribly broken. So continuing with the theme from my last blog post, this time I looked at F-Secure SAFE for Mac, the consumer antivirus product from Finnish F-Secure, specifically the Browsing Protection component. As you can tell from the timeline at the end of this post, I actually started with this before I looked at Avast!, but this time no one else had beaten me to it, meaning getting everything fixed took a little bit longer.

Yeah, sure, the title might be exaggerating a bit. I just can't resist a good pun. If your auto-updates are working (mine actually weren't on one machine, or they might have been just a bit slow to propagate), you're totally safe. Even if you haven't got the update, none of the issues were all that bad in the end. The number of them and a few interesting features made it enough to warrant a blog post, though.

And yeah, "multiple issues" is always good.

Issue #1: Trivially triggering banking protection on non-banking websites.

The Browsing and Banking Protection features in F-Secure SAFE for Mac are implemented as a browser extension that interfaces with the native app using both nativeMessaging and a custom HTTP server running on localhost. I was looking specifically at the Chrome extension.

The extension listens to traffic using Chrome's webRequest APIs and reacts to different URLs based on a classification from F-Secure. In the case of Banking Protection, the software attempts to recognize online banks, then triggering a notification to tell the user they're on a trusted website and can safely go on with their business.

The thing is, when you're doing something like that, you want to make sure you're actually parsing URLs correctly. It can be surprisingly difficult sometimes.

So what about a URL like this one:


That's obviously pointing to example.com, only it has some cruft in the beginning. Well, op.fi is a Finnish bank, and %2f is the URL encoding for /. F-Secure SAFE was parsing the URL like so:

So op.fi is now the domain part and /@example.com/ the path. A tiny little mistake, but it meant Banking Protection would be triggered when visiting the link that's actually pointing to example.com.

Issue #2: Trivially bypassing Browsing Protection.

Browsing Protection in F-Secure SAFE works basically the same way as Banking Protection, only the other way around. The extension looks at the URL you're trying to browse to, then compares it to a blacklist, and blocks access if the URL is known to be malicious or otherwise not cool.

The idea is the same as in triggering the banking notification, and so shouldn't need much explanation:


kalantzis.net is a malware domain picked at random from Malware Domain List, and would normally trigger Browsing Protection. With x%2f@ at the beginning of the URL, however, the URL would be parsed incorrectly by F-Secure SAFE, and the Browsing Protection completely bypassed. The x part in the beginning didn't even have to be a real domain, just a single alphanumeric character would do.

Issue #3: Clickjacking.

Okay, this is a boring one. The Browsing Protection block page, served from the localhost HTTP server, had a button on it to allow whitelisting a blocked page. But it didn't implement any clickjacking protections, no X-Frame-Options, no framebusters. It would have been possible to embed the block page in a frame and trick someone into whitelisting pages.

Issue #4: UI spoofing in the whitelisting confirmation dialog.

When whitelisting a page by clicking the button on the Browsing Protection block page, F-Secure SAFE would display a native dialog window with an F-Secure logo and a confirmation message asking whether you're really sure. As part of that confirmation message, the URL about to be whitelisted would be displayed. The issue was with the software making no effort to encode whitespace character in the URL or to differentiate the URL from the static message. So take for example the following URL:

Triggering a whitelisting dialog for that URL, for example through clickjacking, would result in the following message being displayed in the native popup:
____________________________________________________________________ | | | Do you want to allow access to the following web address? | | (F) | | https://f-secure.com | | | | Trust me. It's totally legit. | | | | Allow Don't allow | |____________________________________________________________________|
The actual domain, kalantzis.net, would be pushed beyond the bottom edge of the dialog, with no way for the user to see it.

Issue #5: Bad practices, unsafe use of DOM APIs, almost useless authentication mechanism.

Finally, there was some terribly fragile code and bad practices in use throughout the software. There were no direct vulnerabilities caused by these as such, but apparently they still played a major part when determining the size of the bounty.

The bad practices included things like abundant use of innerHTML in JavaScript code, and some input sanitization that was just a bit iffy, but most worrying was probably the way the extension authenticated itself to the localhost HTTP server. There was a token named cookie (but not an actual HTTP cookie), obtained via nativeMessaging, what was passed to the HTTP server to authenticate requests. Only the length of the "cookie" was 8 hexadecimal digits. That's the same as 4 bytes, or a single 32-bit integer. Not a terribly difficult secret to guess.


The Browsing Protection bypass and Banking Protection spoof were fixed with a small change to the URL parsing. To protect agains clickjacking, some frame busting code was added. The UI spoof was fixed by disallowing unusual characters in the displayed URL, and the bad practices and miscellaneous issues were addressed as well, including the the short authentication token, whose length was increased significantly.

F-Secure decided to pay me a bounty of 1000 EUR, citing especially my pointing out the quality issues and fragile API as a factor that increased the bounty.



2016-01-12>Initial report
2016-01-14<Reply from F-Secure; investigating
2016-01-20<New release planned, ETA 6 weeks
2016-03-21>Request for a status update
2016-04-04<Fixes in testing, release within 2 weeks
2016-04-08<Fixes released on 2016-04-07; Decision to pay a bounty of 1000 EUR
2016-04-19>Verified the fix, asked about going public
2016-04-19<Advisory planned for 2016-04-26, ok to publish details once it's out
2016-04-21<Advisory pushed forward to 2016-05-03 due to "circumstances"
2016-05-03<Advisory published as FSC-2016-1

No comments:

Post a Comment