Malicious looking mirrors resembling trademarked websites? Phishing?



  • 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?



  • 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.



Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2