Tor has a neat feature called Onion Services (A) that allow you to host and access a TCP port with anonymity, the only thing being required is access to the Tor network.
This is a handy feature for many reasons. It allows people to access facebook (facebookcorewwwi.onion) in countries where it is blocked, it allows people to leak documents to the press in a safer way (nyttips4bmquxfzw.onion)
One of the bigger things to note is that it’s only requirement to both host and access onion services is a connection to the Tor network. This means you can host things behind NAT or other firewalls when you normally could not, making it handy for remote access.
Because this makes Tor a nice NAT/firewall evader it would be nice if a Tor client was not needed to access a onion service. For HTTP/HTTPS services there are already services that do this, tor2web
being one of them (amusingly facebook detects this and advices users not to log in via a proxy)
However tor2web has the downside in that it will only work for HTTP/HTTPS, even though onion services can be wrapped with any TCP port service!
To get around this, we can use IPv6 and its very large amount of IP addresses that are standard with a IPv6 deployment.
A Tor onion address is a 8 byte base32 encoded string (80 bits). Conveniently the minimum routable IPv6 block size is a /48 (80 bits of address space) meaning we can have a 1-1 mapping of .onion
addresses to IPv6 addresses in a /48!
In this case you can fit it into a IP address that looks like this:
2a07:1500:fed5:2804:40b9:ca13:a24b:5ac8
First we need to write a DNS server that can take these onion addresses and serve back these IPv6 addresses.
I wrote a small DNS server (100 lines) to automatically translate these DNS entries to their IPv6 addresses using the very useful miekg/dns libary
ben@eshwil:~$ dig -p 553 @127.0.0.1 facebookcorewwwi.tor6.flm.me.uk.
; <<>> DiG 9.10.3-P4-Ubuntu <<>> -p 553 @127.0.0.1 facebookcorewwwi.tor6.flm.me.uk.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10108
;; flags: qr ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;facebookcorewwwi.tor6.flm.me.uk. IN A
;; ANSWER SECTION:
facebookcorewwwi.tor6.flm.me.uk. 2147483646 IN AAAA 2a07:1500:fed5:2804:40b9:ca13:a24b:5ac8
;; Query time: 0 msec
;; SERVER: 127.0.0.1#553(127.0.0.1)
;; WHEN: Tue Apr 03 09:01:57 EDT 2018
;; MSG SIZE rcvd: 119
Now we have the address translation in place, we can build the proxy. This is a slightly abnormal task for a proxy, as it has to listen on all ports on 1,208,925,819,614,629,174,706,176 addresses. This means that we are not able to use conventional ways to accept connections.
iptables
is commonly thought of as only a firewall. However beyond it’s ability to filter is the ability to setup NAT, run bytecode programs and blink LEDs. In our case, we want to send all TCP traffic from a IP range to a single program.
The REDIRECT target is generally used to catch outbound traffic and put it into a proxy (for example, corporate/educational filtering proxies) however you can also use it in the opposite direction and use it for traffic coming inbound to the system.
In our case we have:
ip6tables -t nat -A PREROUTING -d 2a07:1500:fed5::/48 -i eth0 -p tcp -j REDIRECT --to-ports 1337
This takes matches the any TCP connection coming into 2a07:1500:fed5::/48
(even if we are not binding on it) and it redirects it locally to a program listening on port 1337.
Or, better explained:
However there is a catch, when the connection is redirected, the final destination is lost as it has been changed to be the local application. However there is a syscall you can use to request the original address.
From that point onwards it is a case of reversing the dns encoding of the onion address, then proxying the connection to Tor!
After a bit of fiddling, I had a proof of concept that worked! (minus facebook not being able to handle the Host:
header I requested with)
Tor onion services are great because they are live inside a censorship resilient network, however those exact same protections mean that some very unfavorable content can sometimes live inside tor onion services.
To try and avoid any issues such content may cause, I have decided to not accept connections from any port that a browser can make connections on.
You can still use the following ports:
port | original protocol use |
---|---|
1 | tcpmux |
7 | echo |
9 | discard |
11 | systat |
13 | daytime |
15 | netstat |
17 | qotd |
19 | chargen |
20 | ftp data |
21 | ftp access |
22 | ssh |
23 | telnet |
25 | smtp |
37 | time |
42 | name |
43 | nicname |
53 | domain |
77 | priv-rjs |
79 | finger |
87 | ttylink |
95 | supdup |
101 | hostriame |
102 | iso-tsap |
103 | gppitnp |
104 | acr-nema |
109 | pop2 |
110 | pop3 |
111 | sunrpc |
113 | auth |
115 | sftp |
117 | uucp-path |
119 | nntp |
123 | NTP |
135 | loc-srv /epmap |
139 | netbios |
143 | imap2 |
179 | BGP |
389 | ldap |
465 | smtp+ssl |
512 | print / exec |
513 | login |
514 | shell |
515 | printer |
526 | tempo |
530 | courier |
531 | chat |
532 | netnews |
540 | uucp |
556 | remotefs |
563 | nntp+ssl |
587 | stmp |
601 | n/a |
636 | ldap+ssl |
993 | ldap+ssl |
995 | pop3+ssl |
2049 | nfs |
3659 | apple-sasl |
4045 | lockd |
6000 | X11 |
6665 | IRC |
6666 | IRC |
6667 | IRC |
6668 | IRC |
6669 | IRC |
Example usage
Let’s say you wanted to always have access to a raspberry pi, even if you don’t have ports forwarded.
root@shelf-pi:~# apt install tor
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
libevent-2.0-5 logrotate tor-geoipdb torsocks
Suggested packages:
mixmaster xul-ext-torbutton socat tor-arm polipo privoxy apparmor-utils obfsproxy
The following NEW packages will be installed:
libevent-2.0-5 logrotate tor tor-geoipdb torsocks
0 upgraded, 5 newly installed, 0 to remove and 68 not upgraded.
Need to get 107 kB/2,355 kB of archives.
After this operation, 9,842 kB of additional disk space will be used.
Do you want to continue? [Y/n]
…
# setup a hidden (aka onion) service and point it to SSH
root@shelf-pi:~# echo "HiddenServiceDir /var/lib/tor/ssh_hidden_service/" >> /etc/tor/torrc
root@shelf-pi:~# echo "HiddenServicePort 22 127.0.0.1:22" >> /etc/tor/torrc
# restart tor to apply the change
root@shelf-pi:~# systemctl restart tor
# confirm the service was provisioned, obtain the onion domain
root@shelf-pi:~# ls /var/lib/tor/ssh_hidden_service/
hostname private_key
root@shelf-pi:~# cat /var/lib/tor/ssh_hidden_service/hostname
s7wgpiadcsilb3dd.onion
At this point, You can now SSH from the clear internet to this onion service!
ben@eshwil:~$ ssh root@s7wgpiadcsilb3dd.tor6.flm.me.uk
The authenticity of host 's7wgpiadcsilb3dd.tor6.flm.me.uk (2a07:1500:fed5:97ec:67a0:314:90b0:ec63)' can't be established.
ECDSA key fingerprint is SHA256:sB2143z+Ls85q4QOs6hAPrP0A50WhelrAy2Xo8Th5ig.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 's7wgpiadcsilb3dd.tor6.flm.me.uk,2a07:1500:fed5:97ec:67a0:314:90b0:ec63' (ECDSA) to the list of known hosts.
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Apr 3 20:40:48 2018 from
root@shelf-pi:~#
Or! You can CNAME directly to this domain!
Then use it as a subdomain:
ben@eshwil:~$ ssh root@shelf-pi.benjojo.co.uk
The authenticity of host 'shelf-pi.benjojo.co.uk (2a07:1500:fed5:97ec:67a0:314:90b0:ec63)' can't be established.
ECDSA key fingerprint is SHA256:sB2143z+Ls85q4QOs6hAPrP0A50WhelrAy2Xo8Th5ig.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'shelf-pi.benjojo.co.uk' (ECDSA) to the list of known hosts.
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Apr 3 21:12:44 2018 from localhost
root@shelf-pi:~#
As always, you can find the source code to this here: https://github.com/benjojo/six-onions
If you liked this, I’m currently at the Recurse Center and spending the next 12 weeks working on things like this and writing them up, so follow me on twitter or RSS to know when the next one of these come out!