Creating A VirtualBox Ubuntu VM And Using iptables To Only Allow Outgoing Requests

Useful notes on how to create iptables rules in an Ubuntu VM

Ankur Agarwal
6 min readMay 26, 2020

The main reason for creating a VM was to be able to perform a GET request against the sinkhole URL that was highlighted in an article by Wired magazine on Marcus Hutchins. I’m pretty sure i could have safely done it via my laptop without the VM, but it also sounded like a fun little afternoon project to work with iptables.

NOTE: I’m not a professional white hacker/pen tester, the following are just notes that I’ve taken while creating a VM to perform outgoing HTTP requests and to disallow all connections coming in. I’m not sure I’ve taken all the necessary precautions, so please use the following information as one of many guides before attempting any real threat modelling/pen testing.

Creating the VM

I already had a VM on my machine so I cloned that and started working on it. Here are some steps I found that will help if you’ve never created a VM in VirtualBox before:

Install Useful Tools

You will need to resync the time if the guest VM’s time is incorrect. This can be done using ntpdate, which can be installed using the following:

sudo apt install ntpdate# To resync the time
ntpdate -s ntp.ubuntu.com

The desktop version of Ubuntu doesn’t come with cURL installed, which is a simple tool to perform HTTP requests with. Install it with the following command:

sudo apt install curl# curl google
curl https://google.com

Changing the Default Editor

I prefer using vi over nano, so I changed the default editor with the following command:

sudo update-alternatives –config editor

When working with crontab (more information below), like me, you may accidentally select the wrong editor when given the choice. You can change it with:

select-editor

To Reset All iptables Rules With Crontab

This is only useful if you’re performing actions over SSH, and you don’t want to be locked out of your VM when creating iptables rules. If using VirtualBox this is less of a risk since you can directly interact with the VM, even if all the network traffic is dropped. I still found it to be a good exercise, mainly to remind myself on how to create a crontab job:

  1. Create a reset.sh file somewhere (I chose to use /etc/iptables/)
  2. you may need to use which iptables to find where iptables is installed since crontab jobs require the full path to the binary it will run. In my VM it was installed in /sbin/iptables.
  3. Add the following into the script file. This will reset all the iptables rules:
#!/bin/bash#ipv4
/sbin/iptables -P INPUT ACCEPT
/sbin/iptables -P FORWARD ACCEPT
/sbin/iptables -P OUTPUT ACCEPT
/sbin/iptables -t nat -F
/sbin/iptables -t mangle -F
/sbin/iptables -F
/sbin/iptables -X
#ipv6
/sbin/ip6tables -P INPUT ACCEPT
/sbin/ip6tables -P FORWARD ACCEPT
/sbin/ip6tables -P OUTPUT ACCEPT
/sbin/ip6tables -t nat -F
/sbin/ip6tables -t mangle -F
/sbin/ip6tables -F
/sbin/ip6tables -X

4. Use chown and chmod to change the ownership of the file to root and to allow it to only be executable by root.

sudo chown root:root /etc/iptables/reset.sh
sudo chmod 700 /etc/iptables/reset.sh

5. To edit the root’s crontab and view the results use the following:

sudo crontab -e
sudo crontab -l

6. The following will execute the reset.sh file every minute and redirects stderr to stdout, and stdout to a reset.log file. This can be placed at the end of the crontab file when you use the above command to edit crontab jobs:

* * * * * /etc/iptables/reset.sh > /etc/iptables/reset.log 2>&1

For more information on crontab jobs, check out this link:

Setting Up iptable Rules

Now the fun part. This took me sometime to get my head around. I’m still not 100% sure on all the options and best practices so for more details you will need to do some more of your own research.

Allow Loopback Connections

Internally loopback is used by various tools, and therefore you should allow traffic to the loopback interface with:

sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT

Allow DNS Lookups

We may still want to be able to use the DNS to lookup ips of websites/servers, so you can allow traffic to DNS servers with the following:

sudo iptables -A INPUT -i enp0s3 -p udp --sport 53 -m state --state ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -o enp0s3 -p udp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -i enp0s3 -p tcp --sport 53 -m state --state ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -o enp0s3 -p tcp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT

Allow NTP

HTTP requests using TLS will not work if the VM’s time is out of sync. We can fix the time using ntpdate, which requires traffic to be allowed through the firewall:

sudo iptables -A INPUT -i enp0s3 -p udp --sport 123 -m state --state ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -i enp0s3 -p udp --dport 123 -m state --state NEW,ESTABLISHED -j ACCEPT

Allow Outgoing Connections to 80 and 443

The following allows us to actually perform requests against websites:

sudo iptables -A INPUT -i enp0s3 -p tcp -m multiport --sports 80,443 -m state --state ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -o enp0s3 -p tcp -m multiport --dports 80,443 -m state --state NEW,ESTABLISHED -j ACCEPT

Allow ICMP (Ping)

We may want to allow outgoing ping requests, which can be done with:

sudo iptables -A OUTPUT -i enp0s3 -p icmp -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -o enp0s3 -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT

Drop All Other Connections

Now we can drop all other traffic incoming and outgoing from our VM:

sudo iptables -A OUTPUT -j DROP
sudo iptables -A INPUT -j DROP
sudo iptables -A FORWARD -j DROP

Persisting the Rules

Let’s persist the rules to disk so that we can easily load them during boot:

sudo iptables-save > /etc/iptables/rules.v4

Restoring the Rules

This is the command to restore the rules from a persisted file:

sudo iptables-restore < /etc/iptables/rules.v4

Testing the Rules

Use the following to ensure that the correct ports are open:

# Testing DNS lookups still work
dig google.com
# OR
nslookup google.com
# Test we can perform HTTP and HTTPS requests
curl google.com
curl https://google.com
# Test ping
ping google.com
# Alter the time and use the following to resync the time
ntpdate -s ntp.ubuntu.com
# Ensure all incoming ports are closed (from the guest or host)
nmap <ip address of guest vm>

Enabling the Rules on Boot

The final step is to ensure that the rules are applied when the VM boots up. I’ve employed the use of systemd to help with this.

  1. Create a service file with:
sudo vi /etc/systemd/system/restore-iptables-rules.service 

2. Place the following in the service file:

[Unit]
Description = Apply iptables rules
After=network.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c '/sbin/iptables-restore < /etc/iptables/rules.v4'

[Install]
WantedBy=multi-user.target

3. Enable the service:

sudo systemctl enable restore-iptables-rules.service

4. Start the service:

sudo systemctl start restore-iptables-rules.service

5. Reboot the VM and check that the iptables rules were applied with:

sudo iptables -L

Closing Remarks

I hope this was useful for someone. This was definitely a fun little afternoon project, and I feel pretty safe. Please leave a comment if I’ve missed any steps on building a secure VM.

References

--

--