- Special thanks to Nachash for this lesson.
Tor is the world's largest anonymity service. Relied on by many, the onion has developed into a staple of tech-security culture. With the immense popularity of Tor, several rumors have circulated regarding its security and effectiveness. This article serves to answer said speculations, and provide further insight into the workings of the Tor service.
How It Works
One takes a big chance using tor. Privacy isn't assured in any way; anonymity however is, given that one changes their habits.
Tor originally stood for "The Onion Router". How Tor essentially works is traffic gets wrapped in multiple layers of encryption, passes from the initial box to the first node in the chain where traffic gets decrypted once, and passed to the next node. It then gets decrypted again and passed to the exit node from where decryption occurs the last time, and routes traffic in the clear.
Tor bridges are basically unofficial entry points into the tor network which are utilized by users in locations such as China in order to access Tor because a vast majority of the official nodes are banned. Such was the case during the Middle East protests, in which online activists were creating exit bridges with haste.
The onion structure undoubtedly has issues. The main issue with Tor is that exit node operators can sniff the traffic that passes through. Some operators choose to do so, and for this reason, it should be assumed that Tor traffic is being monitored, and therefore, always use some form of end to end encryption such as SSHing into a box over Tor.
Another precaution Tor users can take to help protect themselves to a certain extent is to exclude known incompetent nodes, such as those found here. For Linux users, add that line to the /etc/tor/torrc file and restart Tor.
The easiest way to install Tor is the Tor Browser Bundle which can be found on the Tor website. The Tor Browser Bundle does not require installation and comes bundled with a preconfigured Firefox installation and Vidalia, for simple configuration of Tor. Tor can also be installed using your distribution's package manager, which does not usually come with Vidalia or a preconfigured browser. Most mainstream browsers have options for configuring a SOCKS proxy, Tor's default proxy is 127.0.0.1:9050. Programs that do not have proxy options can be used through Tor with proxychains:
|localhost:~ $ proxychains irssi|
Proxychains adds a library to LD Preload, which essentially wraps all DNS and connect calls to proxified ones.
Tor hidden services are services that can be routed through Tor to hide their real location. Common hidden services include web servers and IRC servers. Hidden services use .onion as a pseudo-tld, such as chib43thr24e32ve.onion. The text string before ".onion" is actually a key fingerprint, which ensures the service cannot be found, and it has the expected private key. This allows a service to be accessed through Tor without giving out its IP address (or any other information about the system it is hosted on). When connecting to clearnet websites, the connection is first routed through an entry node, then a second node, finally to the exit node and to the clearnet. Hidden services on the other hand, are routed through a number of Tor nodes, then to a rendezvous point, through more Tor nodes and finally to the hidden service. While hidden services tend to be very slow, they are completely anonymous and offer end-to-end encryption (regardless of protocol).
One of the theoretical pitfalls of hidden services is a correlation attack. If someone controls enough nodes, they can send enough traffic to the hidden service to find its location. The best way to help prevent this is to make the hidden service a Tor node as well. At that point, it passes non-hidden service Tor traffic and keeps anonymity static.
A hidden service can be configured in the torrc with the following lines:
HiddenServiceDir /var/lib/tor/hidden_service/ HiddenServicePort 80 127.0.0.1:80
The HiddenServiceDir directive tells Tor where to store the hidden service private key and hostname, if these do not exist, they will be generated on startup. The HiddenServicePort configures what port to forward.
|localhost:~ $ cat ~/.ssh/config
Compression yes # this compresses the SSH traffic to make it less slow over torProxyCommand connect -5 -R remote -S localhost:9050 %h %p
After this has been added to the SSH configuration, a user can simply ssh myserver to be routed through Tor to the hidden service (or clearnet server). This can also be done with proxychains, but the ProxyCommand directive is a permament solution.
Socat is a netcat replacement that, among many other things, can create a local forward to a server through Tor. This can be used in conjunction with SSH, irssi, or any other networked application. The simplest usage is:
$ socat TCP-Listen:1234,bind=localhost,fork SOCKS4A:127.0.0.1:chib43thr24e32ve.onion:6667,socksport=9050
This would forward all connections to 127.0.0.1:1234 to chib43thr24e32ve.onion:6667.
For the extra-paranoid, Tor can be configured as a transparent proxy for all traffic to or from the local machine. In order to do this, add this script (originally found here) to your startup, be sure to edit the TOR_UID variable (look for the tor user in /etc/passwd):
#!/bin/sh # destinations you don't want routed through Tor NON_TOR="192.168.1.0/24 192.168.0.0/24" # the UID Tor runs as TOR_UID="43" # Tor's TransPort TRANS_PORT="9040" iptables -F iptables -t nat -F iptables -t nat -A OUTPUT -m owner --uid-owner $TOR_UID -j RETURN iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 5353 for NET in $NON_TOR 127.0.0.0/9 127.128.0.0/10; do iptables -t nat -A OUTPUT -d $NET -j RETURN done iptables -t nat -A OUTPUT -p tcp --syn -j REDIRECT --to-ports $TRANS_PORT iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT for NET in $NON_TOR 127.0.0.0/8; do iptables -A OUTPUT -d $NET -j ACCEPT done iptables -A OUTPUT -m owner --uid-owner $TOR_UID -j ACCEPT iptables -A OUTPUT -j REJECT
Finally, add the following lines to the torrc:
VirtualAddrNetwork 10.192.0.0/10 AutomapHostsOnResolve 1 TransPort 9040 DNSPort 5353
Transparent Proxy Hidden Services Only
Alternatively, one can soley proxy hidden service traffic instead of all traffic. Instead of the above iptables rules, use these ones:
TRANS_PORT="9040" DNS_PORT="5353" iptables -t nat -A OUTPUT -p tcp -d 10.192.0.0/10 -j REDIRECT --to-ports $TRANS_PORT iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports $DNS_PORT
Note: these iptables rules will force all DNS queries through tor, but other non-hidden service traffic will be routed normally. The torrc should contain the same lines as the regular transparent proxy:
VirtualAddrNetwork 10.192.0.0/10 AutomapHostsOnResolve 1 TransPort 9040 DNSPort 5353
The torrc is the Tor configuration file, commonly found in /etc/tor/torrc on linux distributions but can also be specified with the -f argument. By default, the Tor SOCKS proxy listens on localhost at port 9050. This can be changed with the "SocksPort" and "SocksBindAddress" directives. There are several other options that allow a user to ban malicious nodes, whitelist Tor nodes, set an outgoing proxy for Tor, or activate the Tor control port, among other things. The Linux man pages have a very extensive list of torrc options.
libtor is a library for interacting with Tor in Python. With it, a user can spawn new Tor instances on arbitrary ports, start up new hidden services, create new Tor sockets (blocking and asynchronous), and several other useful operations.
Special thanks to jtripper for her contributions to this article.
libtor can be downloaded from here. Once downloaded, extract the package and then run:
|localhost:~ $ sudo python setup.py install|
libtor provides three classes: Tor, SocksSocket, and AsyncSocksSocket. Using the set_socks_proxy function, a default SOCKS proxy for usage with SocksSocket and AsyncSocksSocket can be configured:
import libtor libtor.set_socks_proxy("127.0.0.1", 9050)
|This function is called by the Tor class automatically.|
The Tor class is initialized with a "tor instance number", which is just an index specifying what port to start the Tor instance on. The Tor directory will be created in the working directory at ".tor[instance_number]." This class provides the following methods:
|create_tor()||check (default=1, verify that Tor started with errors)||Writes out a new torrc and spaws a Tor process.|
|kill_tor()||none||Kill a running Tor process.|
|restart_tor()||none||Restart a Tor process.|
|cleanup()||none||Delete the Tor directory.|
|read_from_tor_proc()||none||Read the Tor process' output.|
|torctl()|| command (default="", command to send)
password (default="", Torctl password)
|Send a command to the Tor control port.|
|newnym()||none||Send a newnym to the Tor process to get a new identity.|
|hidden_service()|| listen_port (port to listen on)
forward_port (default=listen_port, port to forward to)
|Create a new hidden service on a given port.|
|append_to_torrrc()||line (line to append to torrc)||Append a line to the torrc for this Tor instance.|
|verify_tor()||none||Verify that the Tor process is working (returns true or false).|
import libtor t = libtor.Tor(0) t.hidden_service(80) t.create_tor() print "Tor process started." if t.verify_tor(): print "Connection to Tor verified." tor.kill_tor() tor.cleanup()
The SocksSocket class inherits from the standard Python socket class and can be used in the same way, the only difference is that it accepts a tor_host and tor_port argument. These default to the socks settings set by the Tor class.
import libtor t = libtor.Tor(0) t.create_tor() sock = libtor.SocksSocket() # or libtor.SocksSocket(tor_host="127.0.0.1", tor_port=9052) sock.connect(("google.com", 80)) sock.send("GET / HTTP/1.1\r\n\r\n") print sock.recv(1024) sock.close() t.kill_tor()
The AsyncSocksSocket class also inherits from socket.socket. The provided interface is similar to a standard interface and can be used with select. Any packets sent before the SOCKS negotiation is complete will be queued and sent upon completion.
import libtor import select t = libtor.Tor(0) t.create_tor() sockets = [ libtor.AsyncSocksSocket() ] sockets.connect(("google.com", 80)) while len(sockets) > 0: readable, writable, exceptional = select.select(sockets, , ) for s in readable: try: data = s.recv(1024) except socket.error: sockets.remove(s) break print data s.send("GET / HTTP/1.1\r\n\r\n") t.kill_tor()
Visit the Anonymity Portal for complete coverage.