I've talked a bunch about mod_status leaks, mainly because they are so prevalent.

However, today I want to talk to you about a way to detect co-hosting without mod_status. This attack takes more work to pull off than simply requesting /server-status, but it is easily doable for someone who has the time.

Virtual Hosting

Most web servers support the concept of virtual hosting, that is hosting more than one domain on a single server. The web server interpreted the Hostname header to determine which version of a site to serve.

This works well on the clearnet where IP resolutions are common and it is trivial to work out if two sites are co-hosted.

There are multiple ways of setting up virtual hosting such that a different hostname header will not trigger content to be served. For example, using Caddy we can specify that two hidden services are served on separate ports:

[hshostname].onion:2016 {
 root ./site1
 tls off

[hshostname2].onion:2017 {
 root ./site2
 tls off

And in our torrc file we can then setup the hidden services like so:

HiddenServiceDir /var/lib/tor/hidden_service_1/
HiddenServicePort 80 localhost:2016

HiddenServiceDir /var/lib/tor/hidden_service_2/
HiddenServicePort 80 localhost:2017

However configuring servers in such a way requires extra work and diligence which is often not carried out.

Hostname Hacking

Because of the above tendency for misconfigurations, plenty of sites, even those that disable mod_status are vulnerable to hostname hacking.

curl -H "Host: [redacted].onion" --socks5-hostname -s [redacted].onion | sha1sum 
d756.... -

curl -H "Host: localhost" --socks5-hostname -s [redacted].onion | sha1sum
423a.... -

As you can see from above trace, changing the Hostname header completely changes the output of the site (and this output change is consistent).

This technique can be used to test for co-hosting leaks in hidden services .

Depending on the configuration of the server, Hostname can be a different onion site, or a gibberish - generally the first case you can confirm co-hosting directly, and in the latter case you can confirm co-hosting by testing that each hidden service serves the same "default" page when messing with Hostname.

This test will be included in OnionScan in the near future.

I have so far been able to use this attack to confirm co-hosting on a ring that did remove mod_status, but did not obviously remove co-hosting. I suspect a large scan trying a bunch of hostnames per site would be fairly lucrative.

This attack can also be used to test whether a site is hosted on Freedom Hosting II - as a separate test from the known SSH fingerprint attack.

curl --socks5-hostname -s [redacted].onion | grep -Po "<title>(.*)</title>"

curl -H "Host: fhostingesps6bly.onion" --socks5-hostname -s [redacted].onion | grep -Po "<title>(.*)</title>"
<title>Freedom Hosting II</title>

curl -H "Host: localhost" --socks5-hostname -s [redacted].onion | grep -Po "<title>(.*)</title>"
<title>100x Your Coins in 24 Hours - the real underground service</title>


Lesson: Virtual Hosting is a great way to limit infrastructure costs, but be sure you are not shooting yourself in the foot.

If you would like to support further research and development of tools like OnionScan you can become a patron at Patreon