Tuesday, August 2, 2022

VirtualBox Multi-Host VM Communication

    The other day I realized that my main laptop I use to practice different pentesting tactics and techniques upon was starting to get a bit over burdened from the number of virtual machines I was wanting it to support. Seeing that I run Linux as much as humanly possible, a lot of my computers are older and suffer from a lack of resources; primarily RAM and CPU. For example one of my pentesting laptops is a measly dual-core I5 with 16GB of RAM. By all means it's more than enough to run Devuan and a few Linux virtual machines but as it stands, my current PNPT studies have required that I run a Windows Server 2019 domain controller and two Windows 10 enterprise hosts as well as my Parrot OS VM. Ouch... This little laptop runs it but it's definitely not pretty. As usual, this got the gray-matter firing up wondering if there was a way to build a virtual testing environment between multiple laptops.

    Running hypervisors isn't anything new for me. I have plenty of experience with "enterprise" hyperviors like Xen, XenServer, XCP, and KVM (I consider KVM an enterprise hypervisor at least!). These hypervisors make it trivial to spread VMs across a number of hosts and then network them all together seamlessly with fancy switches and vlans but I was looking to have something that's a bit more portable. In other words two laptops and nothing else. While this is probably still possible with all of the previously mentioned hypervisors, I did want to retain the graphical environment that both of my laptops had for 'ease of maintenance'. So virtualbox on top of Devuan it is! 

    Real quickly before we proceed let's get some terminology squared away. This guide will refer to the system running Devuan+VirtualBox as the 'host' and any virtual machine running within VirtualBox upon the host will be referred to as a 'guest'. The following networks will also be in play:

Network Network Interface IP/CIDRHostNetwork Type
Network Avboxnet0192.168.56.0/24HOST AHost-Only Vbox Net
Network Bvboxnet1192.168.60.0/24HOST BHost-Only Vbox Net
Network Cvbox_gre172.16.1.0/30HOST A & BGRE Net Connection
Network Deth0192.168.1.0/24HOST A & BLAN for Both Hosts

    At first I was going to head down the path of a customized Devuan virtual machine to act as a router between the two virtualbox hosts but some more thinking about things, I quickly realized this was probably unessecary and I could leverage the host's networking stack and host-only network adapters within virtualbox to accomplish this task without the need for MORE virtual machines! As we'll see, this was correct, and frankly quite neat! Ultimately this is what the network topology looks like.

    While there's a lot going on in this diagram, it's actually quite simple. Host A and Host B both have their 'eth0' interfaces on the 192.168.1.0 network. Each host has a Host-only virtualbox network; vboxnet0 and vboxnet1 respectively (technically any host-only network can work here, this guide separates them to help lessen confusion). vbox_gre is a Generic Routing Encapsulation (GRE) network that will be created between Host A and Host B to allow the two vboxnets to communicate with one another through the GRE tunnel. Technically the GRE tunnel as well as the guest traffic between the two hosts will traverse the 192.168.1.0/24 network inside GRE packets.

A note before starting configurations: All modifications done here are RUNTIME changes. This means a reboot will cause the changes to be undone! This guide leaves the decision to make these changes permanent to the reader.

    To get started, both hosts need to have the GRE kernel module available. This can be loaded using: modprobe gre. Assuming no errors, each host can now be setup to participate in the GRE tunnel. Before starting that, let's lay out all the IP addresses that will be involved as there are many and it might get confusing.

Host Network Interface IP/CIDRInt Purpose
A eth0192.168.1.19/24Host A LAN Conn.
Beth0192.168.1.108/24Host B LAN Conn.
A vbox_gre172.16.1.1/30GRE Net Interface
B vbox_gre172.16.1.2/30GRE Net Interface
A vboxnet0192.168.56.1/24Host-Only VBox Network
B vboxnet1192.168.60.1/24Host-Only VBox Network
A enp0s3192.168.56.109/24Parrot OS Guest
B Nic 1192.168.60.101/24Windows Server 2019 Guest

root@host-A:~# ip tunnel add vbox_gre mode gre remote 192.168.1.108 local 192.168.1.19 ttl 16
root@host-A:~# ip link set vbox_gre up
root@host-A:~# ip addr add 172.16.1.1/30 dev vbox_gre 

      Now the tunnel configuration commands can be run on host B (NOTE: Watch IP assignments!).

root@host-B:~# ip tunnel add vbox_gre mode gre remote 192.168.1.19 local 192.168.1.108 ttl 16
root@host-B:~# ip link set vbox_gre up
root@host-B:~# ip addr add 172.16.1.2/30 dev vbox_gre 

    At this point the tunnel should be established but it is worth noting on systems utilizing firewalls the tunnel may not become active until both sides of the connection attempt to send traffic. The following iptables rule appears to solve this issue (note the correct host when running the commands):

# Allow GRE protocol from Host B
root@host-A:~# iptables -A INPUT -s 192.168.1.108 -p gre -j ACCEPT

# Allow GRE protocol from Host A
root@host-B:~# iptables -A INPUT -s 192.168.1.19 -p gre -j ACCEPT 

    Just a quick check to see if the two ends of the tunnel can speak to one another.
root@host-A:~# ip -4 -o a sh vbox_gre
7: vbox_gre    inet 172.16.1.1/30 scope global vbox_gre\
root@host-A:~# ping -c 2 172.16.1.2
PING 172.16.1.2 (172.16.1.2) 56(84) bytes of data.
64 bytes from 172.16.1.2: icmp_seq=1 ttl=64 time=1.01 ms
64 bytes from 172.16.1.2: icmp_seq=2 ttl=64 time=1.12 ms

--- 172.16.1.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 1.005/1.061/1.117/0.056 ms

###################################################################

root@host-B:~# ip -4 -o a sh vbox_gre
7: vbox_gre    inet 172.16.1.2/30 scope global vbox_gre\
root@host-B:~# ping -c 2 172.16.1.1
PING 172.16.1.1 (172.16.1.1) 56(84) bytes of data.
64 bytes from 172.16.1.1: icmp_seq=1 ttl=64 time=0.532 ms
64 bytes from 172.16.1.1: icmp_seq=2 ttl=64 time=0.617 ms

--- 172.16.1.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1020ms
rtt min/avg/max/mdev = 0.468/0.472/0.477/0.004 ms

    This is looking good! The two VirtualBox hosts can communicate via the GRE tunnel. Now let's setup the hosts so that VM's on the host-only networks can communicate over the GRE tunnel. 

    NOTE: It is worth noting that doing the next steps sort of defeats the purpose of a Host-Only network in VirtualBox. Following these steps will bypass some of the inherent security of a Host-Only network. Do not proceed if you don't understand these implications or if you are questioning whether you want to do this. (Obligatory disclaimer!)

    Alright disclaimer out of the way, lets do this! So now the respective interfaces on each of the hosts need to be allowed to forward traffic and the proper firewall rules added as well. Make sure to replace vbox_gre and vboxnet[01] with the proper interface names from the respective VirtualBox host.

root@host-A:~# iptables -A FORWARD -i vboxnet0 -o vbox_gre -j ACCEPT
root@host-A:~# iptables -A FORWARD -i vbox_gre -o vboxnet0 -j ACCEPT
root@host-A:~# echo 1 > /proc/sys/net/ipv4/conf/vbox_gre/forwarding 
root@host-A:~# echo 1 > /proc/sys/net/ipv4/conf/vboxnet0/forwarding 

###################################################################

root@host-B:~# iptables -A FORWARD -i vboxnet1 -o vbox_gre -j ACCEPT
root@host-B:~# iptables -A FORWARD -i vbox_gre -o vboxnet1 -j ACCEPT
root@host-B:~# echo 1 > /proc/sys/net/ipv4/conf/vbox_gre/forwarding 
root@host-B:~# echo 1 > /proc/sys/net/ipv4/conf/vboxnet1/forwarding

    The final step to all of this is to ensure that each of the guests in the respective Host-Only network is configured to use the Host's vboxnet interface as the gateway. You could use the interface as a default gateway but this opens up a slew of other issues ( You did read the disclaimer above right?). I'll leave it to the reader to decide what is best but for completion of this article, I'll add specific routes.

    The first guest is my Parrot OS virtual machine. It is homed on VirtualBox Host-A and has an IP address of 192.168.56.109. A route to the 192.168.60.0/24 network via the vboxnet0 adapter's IP address (192.168.56.1) is needed.

# Parrot OS Guest on VirtualBox Host A
root@ParrotOS:~# ip route add 192.168.60.0/24 via 192.168.56.1
# Optionally if a desire to ping the GRE Tunnel endpoints, add that network as well
root@ParrotOS:~# ip route add 172.16.1.0/30 via 192.168.56.1

    The same process for the Windows Server 2019 guest home on VirtualBox Host-B is also needed. The Win2019 host has an IP address of 192.168.60.101. A route to the 192.168.56.0/24 network via the vboxnet1 adapter's IP address (192.168.60.1) is needed.

# Windows Server 2019 Guest on VirtualBox Host B
C:\Users\Adminstrator>route add 192.168.56.0 mask 255.255.255.0 192.168.60.1
# Optionally if a desire to ping the GRE Tunnel endpoints, add that network as well
C:\Users\Adminstrator>route add 172.16.1.0 mask 255.255.255.252 192.168.60.1

    Now the moment of truth.... Can the two guests ping each other on different virtualbox hosts over the host-based GRE tunnel!?

Testing from Windows:


   Testing from Parrot OS:


 And just to further prove that there's end to end communication, here's an nmap scan; after-all this is for pentesting purposes!
┌─[root@ParrotOS]─[~]
└──╼ #nmap -sV 192.168.60.101
Starting Nmap 7.92 ( https://nmap.org ) at 2022-08-02 21:26 PDT
Nmap scan report for 192.168.60.101
Host is up (0.0018s latency).
Not shown: 989 filtered tcp ports (no-response)
PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2022-08-03 03:26:07Z)
135/tcp  open  msrpc         Microsoft Windows RPC
139/tcp  open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: greek.local0., Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp  open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: greek.local0., Site: Default-First-Site-Name)
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: greek.local0., Site: Default-First-Site-Name)
3269/tcp open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: greek.local0., Site: Default-First-Site-Name)
Service Info: Host: MEDUSADC; OS: Windows; CPE: cpe:/o:microsoft:windows

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 63.98 seconds

     Ah what a glorious sight! Rest assured that I didn't cheat and run a Windows DC locally on Host-A to make it look like it works! I certainly hope this guide will be of use to others as I can't imagine I'm the only person who's ever wanted this sort of functionality with VirtualBox.

No comments:

Post a Comment

Have a thought or question? Please share!