Wednesday, November 30, 2016

F**kadblock! How publishers are defeating ad blockers & how ad blockers are fighting back.

A couple of weeks ago, we looked into how PornHub was getting around ad blockers using WebSockets. We thought it would be cool to take a closer look at how publishers like BusinessInsider and Forbes are detecting ad blockers and preventing users from viewing their content.

BUSINESSINSIDER

When visiting a BusinessInsider article while using an ad blocker like AdBlock Plus, after idling on the page for about 10 seconds, a modal blocks you from reading the article:

HOW IS IT DONE?

BusinessInsider uses piano.io’s VX product (“The evolution of the paywall”) for detecting ad blockers.
Piano.io, helpfully has some documentation on how to detect ad blockersusing their or your own solution. Piano’s solution relies on the open-source library FuckAdblock. They use a safe for work alternate version called BlockAdblock, — “FuckAdBlock same project but with a more convenient name.”
FuckAdblock functions by injecting a dummy div into the webpage that contains css classes and styles that are common to advertisements. Then it performs a variety of checks to see if the div has been hidden from view. If it has, the user has an adblocker enabled.
BusinessInsider’s onpage JavaScript additionally checks to see if the FuckAdBlock js file failed to load, in which case it also detects the user as having an adblocker.

BUSINESSINSIDER WORKAROUND

uBlock Origin works around this detection in a clever way. Chrome extensions have the ability to intercept and modify HTTP requests via the webRequest API. uBlock intercepts the request for FuckAdBlock’s JavaScript and responds with an HTTP 307, the code for a temporary redirect. The URL it redirects to is actually a blob of base64-encoded alternate JavaScript. This JavaScript is then loaded instead of FuckAdblock.
Here is a demo in BugReplay that demonstrates how uBlock’s workaround works. I’ve selected the HTTP redirect that is described above, containing the base64 encoded JavaScript. Clicking the download icon next to the ‘Location’ header will display a plaintext version of the code that is loaded instead of FuckAdblock.
uBlock’s alternate JavaScript creates a dummy version of the FuckAdBlock class that doesn’t actually do anything. This way, if any JavaScript external to this file were to check on the status of FuckAdBlock, it would appear as if it loaded successfully. By watching the video above you can see that the ad blocker detection never pops up a modal nagging the user when using uBlock.
FuckAdBlock has a pretty clever response to uBlock’s hack. They recommend utilizing the integrity attribute for the script tag that loads FuckAdBlock, which causes the browser to fail to load the 307’d version due to it’s hash not matching the integrity check, triggering the onerror for the script which triggers the adblock detector. For now Business Insider doesn’t have that implemented.

FORBES

When visiting Forbes with AdBlock or Adblock Plus enabled, users are presented with this:
Clicking continue when Adblock or Adblock Plus is enabled just brings you back to the same page. Linking a social account does let you past this adblock wall without disabling your ad blocker, but that’s in exchange for your personal info.

HOW IS IT DONE?

Like BusinessInsider, Forbes relies on a third party company to provide ad blocker detection. LiftDNA provides this functionality for Forbes. Unlike Piano, LiftDNA looks to have built their own solution for detecting ad blockers.
After spending some time puzzling over Forbes’ minified / obfuscated JavaScript , I came across a Github Gist that really helped a lot. The basic functionality of how LiftDNA’s ad blocker check works is very similar to FuckAdblock.
Inside Forbes’ page html is a base64 encoded string that, in its decoded form, contains CSS class names of easily identifiable ads. When ad blockers see dom elements with these class names they immediately hide them.
Forbes’ check is a bit trickier than BusinessInsider, since it creates a div element with between 5 and 10 randomly picked class names from a large list, and then checks to see if it is set to display: none. This way it’s harder to create workarounds since you don’t know which class and styles it will choose in a given run. If the code detects that the div is hidden, the user is using an ad blocker. If not, it sets a cookie and allow the user through when they click continue. The following is the function that accomplishes this:
checkBlockedClasses: function() {
for (var a, b = Math.random(), c = $(“.ads-container>div”), d = c.length, e = Math.floor(b * d), f = “${classes!}” !== fbs_settings.classes ? JSON.parse(base64.decode(fbs_settings.classes)) : [“dynamic-ads”], g = [], h = this, i = 0; i < 5 || Math.random() < .7 && i < 10; i++) g.push(f[Math.floor(Math.random() * f.length)]);
this.rand_classes = g, a = $(’<div class=“’ + g.join(” “) + ’”>’).append(’<div style=“height: 1px;”>’), $(c[e]).before(a), window.navigator.userAgent.indexOf(“Firefox”) > -1 ? setTimeout(function() {
a.height() || (h.triggered_by_classes = !0, h.triggerAdBlockState(!0)), a.remove()
}, 100) : (“none” === a.css(“display”) && (this.triggered_by_classes = !0, this.triggerAdBlockState(!0)), a.remove())

FORBES WORKAROUNDS

Forbes Gist method
The Forbes gist that I linked earlier which explains how Forbes’ ad blocker detection works also provides a workaround. It involves allowing through all of the ad-spam classes that Forbes is using, so long as the domain is forbes.com.
The only issue here is having to keep up with Forbes’ CSS name list, since the pool they can draw names from is huge.
At the time of this blog post, the workaround code is on version 17. Also, when I checked the list of class names currently being used by Forbes, it differs from the list in the gist.
uBlock Origin workaround
Forbes was able to block Adblock/Adblock Plus, but uBlock origin was able to successfully fool Forbes into thinking I had disabled my ad blocker. How are they getting around the check?
After going through the uBlock source, I tracked down their workaround.
Basically, if the url looks like the Forbes ad welcome page, it sets the cookie ‘welcomeAd’ to true, and if uBlock can determine the article url from a cookie, it automatically redirects to it.
The Anti-Adblock Killer extension functions similarly, except it sets an additional cookie to better mimic what Forbes’ JavaScript is doing.
Demo
The request shown is the HTTP request for the Forbes article. As you can see, it immediately redirects with a 302 to Forbes’ adblock page. Clicking continue just redirects you back there. If you look at the HTTP request’s cookies you won’t see welcomeAd or dailyWelcomeCookie, both of which get set by extensions that try to subvert Forbes’ adblock.
In this next example, before visiting the page I used a cookie editing extension to add the following cookie values for forbes.com:
welcomeAd=true
dailyWelcomeCookie=true
These are the cookies that Forbes would set upon successfully watching their ad.
As you can see in the linked BugReplay report, instead of 302-ing to the adblock page, it loads the article. If you look at the request cookies, you can see both of the above cookie names and values listed. This fools Forbes into taking you to the requested article.
The Future
As ad blockers continue to grow in popularity and publishers continue to rely on advertising dollars, the war of ads, ad blockers, and ad block blockers will continue.
Looking at uBlock Origin’s resources.txt file, you can see just how many custom JavaScript snippets are there neutralizing various web sites’ strategies to bypass ad blockers. It’s an intensive, manual process collecting, implementing and testing all those strategies, and it’s an unpaid job.
Ad blockers have traditionally only had to worry about removing ads while keeping a website functional- and that was difficult enough. Software that actively tries to detect them and disable the hosting website constitutes a new front in the advertising and privacy war, one that Ad Blockers currently seem to be losing.