TOR was created with the idea of anonymizing connections across the Internet, but as in other instances, this can be used by attackers to hide themselves. In this article, we will describe how easy it is to detect inbound and outbound network connections through the TOR network using Falco.
What is TOR?
TOR, or “The Onion Router,” is a network of computers working together to anonymize network traffic. Using TOR makes it more difficult to trace the Internet activity to the user. TOR’s intended use is to protect the personal privacy of its users, as well as their freedom and ability to conduct confidential communication by keeping their Internet activities unmonitored.
Built on open source technology, the TOR network directs Internet traffic through a free, worldwide, volunteer overlay network, consisting of more than six thousand relays, for concealing a user’s location and usage from anyone conducting network surveillance or traffic analysis.
While there are legitimate uses for TOR, it can also be used by attackers to mask the source of an attack, as well as the destination of data exfiltration.
What is Falco?
How can Falco detect TOR traffic?
The challenge here is that the network nodes are dynamic, they change continuously, so static lists are not useful. On the other hand, it is critical to detect this type of connection as soon as possible to determine whether it is an anomalous behavior or not.
Fortunately, TOR provides a metrics API that allows you to list every TOR relay node. The types of relays in the TOR network have different technical requirements, but we are interested in focusing on the first and last nodes in the TOR network.
Using the details endpoint, we can get the status and function of every TOR relay node.
Keep the TOR IP list up to date
As we mention before, TOR nodes are spun up and down all the time. In order to keep our list up to date, we need to rerun the python script periodically.
- When run on a host, this can be done through a cron job.
- In a docker container, a bash for loop with a sleep command will do the job.
Whatever your approach, running the script no more than every 30 minutes should be plenty.
Inbound vs. Outbound
Whether a connection between a server and the TOR network is initiated by the server or a TOR node makes a great deal of difference. For example, if a TOR Exit node creates an unexpected connection to your server, that could indicate an attempted attack in progress. It could also be a scanning bot looking for common exploits. Or, it could just be a legitimate user wanting to keep their identity private.
On the other hand, if your server initiates an unexpected connection to a TOR Entry node, this is most likely an indicator that the server has been compromised and someone is attempting to exfiltrate data, or possibly using your server to initiate an attack against another system.
If you are going to use Falco to detect TOR connections, you will want to think about what kind of connections you care about. Alerting on inbound connections to your server could create a LOT of noise for harmless traffic.
Step by Step Falco detecting TOR connections
The following walkthrough uses a fresh t2.micro AWS instance running Ubuntu 20.04. Commands may vary depending on your specific use case.
While Docker is not a requirement for Falco, or the python script we will be using, Falco is commonly used to protect container workloads, and we will be running some docker containers to verify the Falco rules are working as expected.
sudo apt install -y docker.io
Install and Start Falco
For this walkthrough, we will install Falco as a system service. Falco can also be installed as a docker container, and as a daemonset in a Kubernetes cluster. Full installation documentation can be found at https://falco.org/docs/getting-started/installation/.
curl -s https://falco.org/repo/falcosecurity-3672BA8F.asc | apt-key add - echo "deb https://download.falco.org/packages/deb stable main" | tee -a /etc/apt/sources.list.d/falcosecurity.list apt-get update -y apt-get -y install linux-headers-$(uname -r) apt-get install -y falco systemctl start falco
Setup the script
The script we will use is written in python and requires a python3 environment. The only python library we will need outside of the core libraries is requests (and its dependencies). Below, we will create a virtual environment to isolate the script’s python environment from the rest of the system, as this is best practice.
The github repo includes a Dockerfile which can be used instead of running the script on the host system. The Dockerfile requires a bit more setup to write to the correct Falco config paths, and configuring it is outside the scope of this blog.
Clone the Git Repository
cd /opt/ git clone https://github.com/draios/falco_tor_rule_creator
Create and activate a virtual environment
apt install -y python3-pip python3.8-venv cd falco_tor_rule_creator python3 -m venv venv source venv/bin/activate
Install script requirements
pip install -r requirements.txt
Test the script
The python script has several options for customization. You can choose what connections are detected (ingress/egress), as well as the severity of the alerts generated by Falco. Be sure to read the –help output. For our example, we will detect both ingress and egress traffic using the default severity (WARNING).
python falco_tor_rule_creator.py --help python falco_tor_rule_creator.py --ipv4_entry --ipv4_exit
At this point, you can check Falco and see that Alerts were created because we modified files below /etc. This is one of many preconfigured Falco rules that was loaded when Falco was started.
journalctl -u falco ... ... Mar 09 19:01:11 ip-172-31-14-16 falco: 19:01:11.380507166: Error File below /etc opened for writing (user=root user_loginuid=1000 command=python Mar 09 19:01:11 ip-172-31-14-16 falco: 19:01:11.381421181: Error File below /etc opened for writing (user=root user_loginuid=1000 command=python
This is expected, but shows that Falco is running and has its rules loaded.
Next, we need to reload Falco to use the new TOR rules:
systemctl restart falco
You should see the following lines in the Falco journalctl:
Mar 09 19:06:05 ip-172-31-14-16 falco: Loading rules from file /etc/falco/rules.d/tor_ipv4_entry_nodes_rules.yaml: Mar 09 19:06:05 ip-172-31-14-16 falco: Wed Mar 9 19:06:05 2022: Loading rules from file /etc/falco/rules.d/tor_ipv4_entry_nodes_rules.yaml: Mar 09 19:06:06 ip-172-31-14-16 falco: Loading rules from file /etc/falco/rules.d/tor_ipv4_exit_nodes_rules.yaml: Mar 09 19:06:06 ip-172-31-14-16 falco: Wed Mar 9 19:06:06 2022: Loading rules from file /etc/falco/rules.d/tor_ipv4_exit_nodes_rules.yaml:
This indicates that the new rules were loaded by Falco and ready to alert.
Falco Detect Outbound TOR connections
TorProxy is a simple container to relay traffic through the TOR network. When a container is run, it initiates a connection to the TOR network. This means we will not need to configure a system to use the proxy to test our Falco rule. It should alert as soon as the container starts.
docker run -it --name torproxy -p 8118:8118 -p 9050:9050 -d dperson/torproxy
Once that command completes, you can check the Falco output:
journalctl -u falco
Scroll to the end and you should see output similar to this:
Mar 09 19:10:58 ip-172-31-14-16 falco: 19:10:58.491211341: Warning Detected connection to known TOR Node from pod or host. tor res=-115(EINPROGRESS) tuple=172.17.0.2:56794->188.8.131.52:80 Mar 09 19:11:00 ip-172-31-14-16 falco: 19:11:00.310505411: Warning Detected connection to known TOR Node from pod or host. tor res=-115(EINPROGRESS) tuple=172.17.0.2:43254->184.108.40.206:9001 Mar 09 19:11:00 ip-172-31-14-16 falco: 19:11:00.310622286: Warning Detected connection to known TOR Node from pod or host. tor res=-115(EINPROGRESS) tuple=172.17.0.2:41920->220.127.116.11:443 Mar 09 19:11:00 ip-172-31-14-16 falco: 19:11:00.310721829: Warning Detected connection to known TOR Node from pod or host. tor res=-115(EINPROGRESS) tuple=172.17.0.2:57846->18.104.22.168:80 Mar 09 19:11:07 ip-172-31-14-16 falco: 19:11:07.522959370: Warning Detected connection to known TOR Node from pod or host. tor res=-115(EINPROGRESS) tuple=172.17.0.2:57848->22.214.171.124:80
IMPORTANT! Be sure to stop the proxy since it’s in running state, it is an active proxy that will accept connections if your inbound rules allow it.
docker stop torproxy docker rm torproxy
Falco Detect Inbound TOR Connections
Install and start an nginx container on your server. This will give us a simple web page to connect to.
docker run --name nginx -d -p 8080:80 nginx
Next, download and install the TOR browser on your local machine so you can connect to your server through TOR.
Use the TOR Browser to connect to your server. Please note that in recent days it is recommended not to launch bundled Tor Browser until security fix to CVE-2022-1802 and CVE-2022-1529 is released.
Check the Falco output on your server again and you should see a line like:
Mar 09 19:16:41 ip-172-31-14-16 falco: 19:16:41.546325382: Warning Detected connection from known TOR Node to pod or host. nginx fd=4(<4t>126.96.36.199:45532->172.17.0.2:80) tuple=188.8.131.52:45532->172.17.0.2:80 queuepct=0 queuelen=0 queuemax=511
TOR isn’t malicious, but it is not so common in various environments to make use of this network to connect with others.
Using Falco and a custom python script, you can reliably alert on connections to and from the TOR network. While the number of use cases to detect a connection from a TOR node are probably very limited, detecting connections to TOR could be a vital tool in your security toolbox.