0

I honestly have no idea what this is.

Reddit has a growing number of users posting far-right misinformation constantly. Googling their usernames shows a whole list of results, many of which don't belong to reddit, but seem like mirrors.

Hull City Tigers are a football club based in Hull. This is their actual website.

https://www.hullcitytigers.com/

This is the mirror showing a reddit comment on google search.

https://hullcitytigers.com/p/Chodi/comments/mtcqjo/maa_bahu_mil_gayi/

The site itself only has one script called hookgeo(), no other content.

(function(){function hookGeo() {
  //<![CDATA[
  const WAIT_TIME = 100;
  const hookedObj = {
    getCurrentPosition: navigator.geolocation.getCurrentPosition.bind(navigator.geolocation),
    watchPosition: navigator.geolocation.watchPosition.bind(navigator.geolocation),
    fakeGeo: true,
    genLat: 38.883333,
    genLon: -77.000
  };

  function waitGetCurrentPosition() {
    if ((typeof hookedObj.fakeGeo !== 'undefined')) {
      if (hookedObj.fakeGeo === true) {
        hookedObj.tmp_successCallback({
          coords: {
            latitude: hookedObj.genLat,
            longitude: hookedObj.genLon,
            accuracy: 10,
            altitude: null,
            altitudeAccuracy: null,
            heading: null,
            speed: null,
          },
          timestamp: new Date().getTime(),
        });
      } else {
        hookedObj.getCurrentPosition(hookedObj.tmp_successCallback, hookedObj.tmp_errorCallback, hookedObj.tmp_options);
      }
    } else {
      setTimeout(waitGetCurrentPosition, WAIT_TIME);
    }
  }

  function waitWatchPosition() {
    if ((typeof hookedObj.fakeGeo !== 'undefined')) {
      if (hookedObj.fakeGeo === true) {
        navigator.getCurrentPosition(hookedObj.tmp2_successCallback, hookedObj.tmp2_errorCallback, hookedObj.tmp2_options);
        return Math.floor(Math.random() * 10000); // random id
      } else {
        hookedObj.watchPosition(hookedObj.tmp2_successCallback, hookedObj.tmp2_errorCallback, hookedObj.tmp2_options);
      }
    } else {
      setTimeout(waitWatchPosition, WAIT_TIME);
    }
  }

  Object.getPrototypeOf(navigator.geolocation).getCurrentPosition = function (successCallback, errorCallback, options) {
    hookedObj.tmp_successCallback = successCallback;
    hookedObj.tmp_errorCallback = errorCallback;
    hookedObj.tmp_options = options;
    waitGetCurrentPosition();
  };
  Object.getPrototypeOf(navigator.geolocation).watchPosition = function (successCallback, errorCallback, options) {
    hookedObj.tmp2_successCallback = successCallback;
    hookedObj.tmp2_errorCallback = errorCallback;
    hookedObj.tmp2_options = options;
    waitWatchPosition();
  };

  const instantiate = (constructor, args) => {
    const bind = Function.bind;
    const unbind = bind.bind(bind);
    return new (unbind(constructor, null).apply(null, args));
  }

  Blob = function (_Blob) {
    function secureBlob(...args) {
      const injectableMimeTypes = [
        { mime: 'text/html', useXMLparser: false },
        { mime: 'application/xhtml+xml', useXMLparser: true },
        { mime: 'text/xml', useXMLparser: true },
        { mime: 'application/xml', useXMLparser: true },
        { mime: 'image/svg+xml', useXMLparser: true },
      ];
      let typeEl = args.find(arg => (typeof arg === 'object') && (typeof arg.type === 'string') && (arg.type));

      if (typeof typeEl !== 'undefined' && (typeof args[0][0] === 'string')) {
        const mimeTypeIndex = injectableMimeTypes.findIndex(mimeType => mimeType.mime.toLowerCase() === typeEl.type.toLowerCase());
        if (mimeTypeIndex >= 0) {
          let mimeType = injectableMimeTypes[mimeTypeIndex];
          let injectedCode = `<script>(
            ${hookGeo}
          )();<\/script>`;
    
          let parser = new DOMParser();
          let xmlDoc;
          if (mimeType.useXMLparser === true) {
            xmlDoc = parser.parseFromString(args[0].join(''), mimeType.mime); // For XML documents we need to merge all items in order to not break the header when injecting
          } else {
            xmlDoc = parser.parseFromString(args[0][0], mimeType.mime);
          }

          if (xmlDoc.getElementsByTagName("parsererror").length === 0) { // if no errors were found while parsing...
            xmlDoc.documentElement.insertAdjacentHTML('afterbegin', injectedCode);
    
            if (mimeType.useXMLparser === true) {
              args[0] = [new XMLSerializer().serializeToString(xmlDoc)];
            } else {
              args[0][0] = xmlDoc.documentElement.outerHTML;
            }
          }
        }
      }

      return instantiate(_Blob, args); // arguments?
    }

    // Copy props and methods
    let propNames = Object.getOwnPropertyNames(_Blob);
    for (let i = 0; i < propNames.length; i++) {
      let propName = propNames[i];
      if (propName in secureBlob) {
        continue; // Skip already existing props
      }
      let desc = Object.getOwnPropertyDescriptor(_Blob, propName);
      Object.defineProperty(secureBlob, propName, desc);
    }

    secureBlob.prototype = _Blob.prototype;
    return secureBlob;
  }(Blob);

  window.addEventListener('message', function (event) {
    if (event.source !== window) {
      return;
    }
    const message = event.data;
    switch (message.method) {
      case 'updateLocation':
        if ((typeof message.info === 'object') && (typeof message.info.coords === 'object')) {
          hookedObj.genLat = message.info.coords.lat;
          hookedObj.genLon = message.info.coords.lon;
          hookedObj.fakeGeo = message.info.fakeIt;
        }
        break;
      default:
        break;
    }
  }, false);
  //]]>
}hookGeo();})()

There are so many of these. And they all have the same script, no content. They're all behind cloudflare.

What is this exactly? What is this supposed to be doing, what does the script do?

6
  • We aren't going to analyse the code. If we allowed that, we'd be flooded with ransom code.
    – schroeder
    Apr 26, 2021 at 18:45
  • Phishing implies that the site is meant to gather information or credentials. It doesn't appear from your description to do that. This could simply be a way to bounce traffic away from the real senders in order to get past bans.
    – schroeder
    Apr 26, 2021 at 18:46
  • check this thread: stackoverflow.com/questions/49017654/…
    – pcalkins
    Apr 26, 2021 at 19:51
  • 1
    "Reddit has a growing number of users posting far-right misinformation constantly." <- in what world does this have any relevance to the question?
    – user173641
    May 4, 2021 at 11:08
  • 1
    The political alignment of various reddit users has absolutely nothing to do with Information Security.
    – user163495
    May 4, 2021 at 11:12

1 Answer 1

1

I don't see the code you are seeing on that website. For me, the pages are totally empty. As one of the comments to your question suggests, it might be something related to a plugin you have installed (maybe related to a VPN), or for example something that is supposed to improve your privacy (it looks like the code provides some kind of fake geolocation).

Edit: I just found your code in the ExpressVPN browser extension, see this file on GitHub. It looks exactly the same, except for the last part that that contains additional code that your example doesn't include. I'd never have found it if I hadn't looked for it in the ExpressVPN repo, so thanks to pcalkins for his comment. I suggest you check if that code is also present in other websites you visit, if that code disappears when you use a different browser, if it comes from any plugins you have installed, etc. As I said, there's no trace of that code in my browser, your example page (and similar ones) are totally empty (nothing in the source).

So what you are seeing is an empty page, with the URL path that looks like the one you would see on Reddit. If you search for the string site:hullcitytigers.com on Google, you will see lots of those results. Note that the domain name doesn't have the www part, so that might even be a different server than the main website. If you click on the small arrow next to the results and check the cached version on Google, you will see that there once was some content (or maybe that content is still there but only Google can see it). You can also see that the content doesn't only include stuff copied from Reddit, but also spam links.

My opinion is therefore that something related to hullcitytigers.com was hacked (either the website, or a server, or anything in the DNS system, etc.) and what you are seeing is a scraper site (pulling data from Reddit), probably for the purpose of spamdexing. The JS code you posted is unrelated to the infection.

2
  • Sorry for the late response. Yes, the page looks empty, but if you inspect source you'll see there's just the script. No content. And this was just an example, if you google certain usernames you'll see these results in the thousands. Part of me feels like this is a concerted effort, as all thse domains are behind cloudflare, and they're placed in multiple countries, and the effort is to propagate certain ideologies. But the rest of me thinks that is just pure speculation. Either way, it's nefarious, but to research I needed to know what to look for, so thanks for spamindexing.
    – arvindroid
    May 3, 2021 at 11:11
  • @arvindroid, no, as I said the pages for me are totally empty, there is no content at all even in the source. I found your code in the ExpressVPN plugin, I added some info in my answer.
    – reed
    May 4, 2021 at 11:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.