Wednesday, August 24, 2022

Can't locate strict.pm

     Back with another interesting Perl endeavor today. I've been working on a triple DES decryptor and ran across a module, Mcrypt, that supported triple DES through mcrypt. (Please understand that 3DES is broken and shouldn't be used for ANYTHING). Sadly this module isn't currently in Devuan's repos. Never the less I installed all the necessary dependencies (libltdl-dev libmcrypt-dev) to get cpan on my system and then ran cpanm Mcrypt. No issues so far then I try to run some previously working Perl code.

┌─[aut0exec@Devuan]─[~/Projects/Perl]
└──╼ $./Do_Stuff.pl 
Can't locate strict.pm:   /usr/local/share/perl/5.32.1/strict.pm: Permission denied at ./Do_Stuff.pl line 24.

    That was a new one for me. So I jumped into the terminal and took a look in the directory it was complaining about to see if strict.pm was there. While the /usr/local part was already odd to me, I checked things out anyways. To my surprise there wasn't anything in that directory let alone strict.pm. At this point I took to Google and was greeted with the normal lack of useful results but some indications that there might be something wrong with the @INC list of paths for Perl. Reading through Perl's documentation, it was described that one can list out the configured paths in @INC.

┌─[aut0exec@Devuan]─[~/Projects/Perl]
└──╼ $perl -V
Can't locate Config.pm:   /usr/local/share/perl/5.32.1/Config.pm: Permission denied.
BEGIN failed--compilation aborted.

    Umm... What? What in the world did Cpan do!? I kid, this turned out to be a user error but at the time I was frantically searching for a way to fix this system as NONE of my Perl code was working all of a sudden.... except for the root user! So the plot thickens. At this point that glaring Permission denied message started to kick my sysadmin troubleshooting gears in a different direction. perl -V as root shows the following paths as the included paths for Perl to search for modules.

  @INC:
    /etc/perl
    /usr/local/lib/x86_64-linux-gnu/perl/5.32.1
    /usr/local/share/perl/5.32.1
    /usr/lib/x86_64-linux-gnu/perl5/5.32
    /usr/share/perl5
    /usr/lib/x86_64-linux-gnu/perl-base
    /usr/lib/x86_64-linux-gnu/perl/5.32
    /usr/share/perl/5.32
    /usr/local/lib/site_perl

    Interesting so it fails on the third entry for normal users? Wonder what the permissions are!?

┌─[aut0exec@Devuan]─[~/Projects/Perl]
└──╼ $ls -l /usr/local/share/perl/
total 4
drwxr-x--- 7 root root 4096 Aug 24 09:02 5.32.1

    Well well well! That would explain both behaviors I was seeing and since this is folder that is supposed to be accessible to all users of the system, I went ahead and allowed for world to have the ability to read/execute into this directory with chmod o+rx /usr/local/share/perl/5.32.1. Then running perl -V again I was pleasantly surprised to see the expected Perl config output! Now to confirm that my other Perl code was working properly again.

┌─[aut0exec@Devuan]─[~/Projects/Perl]
└──╼ $./Do_Stuff.pl 
[INFO] Doing all the things...

    Whoo! That's what I wanted to see! Turns out that my root user's umask value of 0027 came back to bite me. Since I hadn't installed anything with cpan before, the folder at /usr/local/share/perl/5.32.1 didn't exist so it was created. The umask value however would remove all permissions for the world group upon folder creation though! Seems odd that folder permissions would completely tank the perl interpreter from running but I'm sure there's a good reason from the devs for this behavior. None-the-less, hope this helps anyone else who runs across similar behavior to possibly correct their system.

Thursday, August 18, 2022

Installing BloodHound on Parrot OS 5.1

        Today while working on an assessment, I decided to spin up BloodHound on my Parrot OS 5.1 instance. To my demise, BloodHound wasn't already installed. Normally this is quickly solved with a simple apt install bloodhound neo4j but today that wouldn't be the case! Upon trying to startup neo4j, it immediately started throwing errors and a quick Google search showed that I wasn't the only one with the issue but no one had posted any solutions yet. Hopefully this guide will be useful to others.

    First install bloodhound and neo4j.

┌─[user@Parrot]─[~]
└──╼ $ sudo apt install bloodhound neo4j -y

    Attempting to start neo4j is where the first issues began. Initially trying to start the service resulted in normal output but the service would never start listening on port 7474. So I reverted to watching the console output. Immediately a number of errors where thrown. The first error was neo4j complaining about the limit on open files. That's an easy fix with ulimit -n 40000 but ultimately it wasn't the reason for neo4j not starting. Turns out that Parrot OS comes with both OpenJDK 11 and OpenJDK 17 installed with OpenJDK 17 set to the default. Dual Java JDK's was causing an odd error while launching neo4j.

WARNING! You are using an unsupported Java runtime. 
* Please use Oracle(R) Java(TM) 11, OpenJDK(TM) 11 to run Neo4j.
* Please see https://neo4j.com/docs/ for Neo4j installation instructions.
Directories in use:
  home:         /usr/share/neo4j
  config:       /usr/share/neo4j/conf
  logs:         /usr/share/neo4j/logs
  plugins:      /usr/share/neo4j/plugins
  import:       /usr/share/neo4j/import
  data:         /usr/share/neo4j/data
  certificates: /usr/share/neo4j/certificates
  run:          /usr/share/neo4j/run
Starting Neo4j.
WARNING: Max 1024 open files allowed, minimum of 40000 recommended. See the Neo4j manual.
OpenJDK 64-Bit Server VM warning: Option UseBiasedLocking was deprecated in version 15.0 and will likely be removed in a future release.
2022-08-18 17:26:03.926+0000 INFO  Starting...
2022-08-18 17:26:07.804+0000 INFO  ======== Neo4j 4.2.1 ========
WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.
2022-08-18 17:26:14.767+0000 ERROR Failed to start Neo4j on dbms.connector.http.listen_address, a socket address. If missing port or hostname it is acquired from dbms.default_listen_address.
java.lang.RuntimeException: Error starting Neo4j database server
<...Trimmed for Brevity...>
2022-08-18 17:26:14.772+0000 INFO  Neo4j Server shutdown initiated by request
2022-08-18 17:26:14.772+0000 INFO  Stopped.

    The above error is not exactly clear as to what the issue might be. After some research it was an easy fix. 

    First determine which java versions are installed/available:

┌─[user@Parrot]─[~]
└──╼ $ sudo update-alternatives --config java
There are 2 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                         Priority   Status
------------------------------------------------------------
* 0            /usr/lib/jvm/java-17-openjdk-amd64/bin/java   1711      auto mode
  1            /usr/lib/jvm/java-11-openjdk-amd64/bin/java   1111      manual mode
  2            /usr/lib/jvm/java-17-openjdk-amd64/bin/java   1711      manual mode

Press <enter> to keep the current choice[*], or type selection number:

    Neo4j requires OpenJDK 11 but as seen above Parrot is defaulting to OpenJDK 17. While we could update the system to use OpenJDK 11 by default, there is likely a reason the Parrot Devs chose OpenJDK 17. So we can temporarily start neo4j using OpenJDK 11 by prepending the binary path to OpenJDK 11's binary folder.

┌─[user@Parrot]─[~]
└──╼ $ PATH="/usr/lib/jvm/java-11-openjdk-amd64/bin:$PATH"
┌─[user@Parrot]─[~]
└──╼ $ ulimit -n 40000
┌─[user@Parrot]─[~]
└──╼ $ sudo env "PATH=$PATH" neo4j console
Directories in use:
  home:         /usr/share/neo4j
  config:       /usr/share/neo4j/conf
  logs:         /usr/share/neo4j/logs
  plugins:      /usr/share/neo4j/plugins
  import:       /usr/share/neo4j/import
  data:         /usr/share/neo4j/data
  certificates: /usr/share/neo4j/certificates
  run:          /usr/share/neo4j/run
Starting Neo4j.
2022-08-18 17:40:56.101+0000 INFO  Starting...
2022-08-18 17:41:01.485+0000 INFO  ======== Neo4j 4.2.1 ========
2022-08-18 17:41:05.507+0000 INFO  Initializing system graph model for component 'security-users' with version -1 and status UNINITIALIZED
2022-08-18 17:41:05.520+0000 INFO  Setting up initial user from defaults: neo4j
2022-08-18 17:41:05.521+0000 INFO  Creating new user 'neo4j' (passwordChangeRequired=true, suspended=false)
2022-08-18 17:41:05.539+0000 INFO  Setting version for 'security-users' to 2
2022-08-18 17:41:05.548+0000 INFO  After initialization of system graph model component 'security-users' have version 2 and status CURRENT
2022-08-18 17:41:05.561+0000 INFO  Performing postInitialization step for component 'security-users' with version 2 and status CURRENT
2022-08-18 17:41:06.442+0000 INFO  Bolt enabled on localhost:7687.
2022-08-18 17:41:09.023+0000 INFO  Remote interface available at http://localhost:7474
2022-08-18 17:41:09.024+0000 INFO  Started.

    Success! What is really interesting about this fix is that once this has been run once and succeeds, neo4j appears to run just fine with OpenJDK 17 afterwards. Now probably not recommended since neo4j specifically requests OpenJDK 11 but it was still interesting to notice! After running the previous commands neo4j and BloodHound can subsequently be launched as follows.

┌─[user@Parrot]─[~]
└──╼ $ PATH="/usr/lib/jvm/java-11-openjdk-amd64/bin:$PATH";ulimit -n 40000; sudo "PATH=$PATH" neo4j start
Directories in use:
  home:         /usr/share/neo4j
  config:       /usr/share/neo4j/conf
  logs:         /usr/share/neo4j/logs
  plugins:      /usr/share/neo4j/plugins
  import:       /usr/share/neo4j/import
  data:         /usr/share/neo4j/data
  certificates: /usr/share/neo4j/certificates
  run:          /usr/share/neo4j/run
Starting Neo4j.
Started neo4j (pid 3215). It is available at http://localhost:7474/
There may be a short delay until the server is ready.
See /usr/share/neo4j/logs/neo4j.log for current status.
┌─[user@Parrot]─[~]
└──╼ $ bloodhound &

    It is unlikely that anyone would want to have to type all of that out each time so it is possible to modify the wrapper script for neo4j to contain these fixes. The file is located at /usr/bin/neo4j and the should look as such (simply add the bold lines).

#!/bin/sh

#ARCH=$(dpkg --print-architecture)
#export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-$ARCH/jre/
PATH="/usr/lib/jvm/java-11-openjdk-amd64/bin:$PATH"
ulimit -n 40000

cd /usr/share/neo4j
exec ./bin/neo4j "$@"

    Now simply start neo4j and BloodHound. 

┌─[user@Parrot]─[~]
└──╼ $ sudo neo4j start
Directories in use:
  home:         /usr/share/neo4j
  config:       /usr/share/neo4j/conf
  logs:         /usr/share/neo4j/logs
  plugins:      /usr/share/neo4j/plugins
  import:       /usr/share/neo4j/import
  data:         /usr/share/neo4j/data
  certificates: /usr/share/neo4j/certificates
  run:          /usr/share/neo4j/run
Starting Neo4j.
Started neo4j (pid 3824). It is available at http://localhost:7474/
There may be a short delay until the server is ready.
See /usr/share/neo4j/logs/neo4j.log for current status.
┌─[user@Parrot]─[~]
└──╼ $ bloodhound &

    I hope this helps other get BloodHound up and running on their Parrot OS systems as well. Happy Hacking!

Thursday, August 11, 2022

Perl Weekly Challenge - 177 Task 2

    This challenge built on a previous week's challenge where individuals needed to locate all the prime numbers up to a certain number. Since that had already been accomplished, it was a lot easier to get started on this challenge!

    First, what's a Palindromic Prime Cyclops number? Well, it's a prime palindrome (number that is the same when read forwards and backawards). For example the number 11 is a prime palindrome. Now what makes this challenge interesting is that the prime palindrome now needs to have a 0 in the middle of the number; in other words the cyclops 'eye' is the zero. While 11 is a prime palindrome, it's not cyclopic, technically no two digit number could fit the bill! This leads to the first possible number that can be a prime cyclopic palindrome being 101, since 101 backwards is..... 101! Note how there is the 'cyclops eye' (zero) in the middle. Shockingly the next value that meets the requirements is the number 16061!

    The challenge luckily only wanted the first 20 prime cyclopic palindromes and provided the list to confirm that user's code produced the correct results. Here is the list:

101, 16061, 31013, 35053, 38083, 73037, 74047, 91019, 94049, 1120211, 1150511, 1160611, 1180811, 1190911, 1250521, 1280821, 1360631, 1390931, 1490941, 1520251

    Let's get started! The first step, I chose to start by filtering out any number that wasn't a palindrome. I specifically started at 3 due to also needing to find prime numbers for later use in the program. I could have and probably should have just pre-made an array of all the primes up to 100 to save some program execution time.

foreach (3..1600000) { 
	if ($_ == reverse($_))

     The above code is pretty simple. The foreach loop simply iterates through the number range 3-1600000. The if statement takes the number, stored in $_, and checks to see if the number is the same forwards and backwards. If it is, then we continue on to the next piece of the challenge, determine if the number is prime. There's a number of ways to do this step.

# If number ends in these it's not prime
my @nums = split(//, $_);
if ( $nums[-1] =~ /0|2|4|5|6|8/) { next; }

# If the sum of the digits is divisble by 3, it's not prime
my $sum = 0;
$sum += $_ for split(//, $_);;
if ( $sum % 3 == 0) { next; }
    The above code rules out a large selection of numbers that aren't prime which helps to reduce the list of palindromes even further. The next step is checking the cyclopic aspect of the number.

my $dig_length = length($_);
if ( 0 == $nums[int((($dig_length/2)))] and 0 ne $dig_length % 2 and check_cyclops $_ and not $_ =~ /0{2,}/ ) { 		
	print ("$_ is a palindromic prime cyclops number!\n"); 
}
    This code does quite a bit. First it checks that middle digit is 0. Then checks that the length of the digit isn't even; even length means that there wouldn't be a zero as the middle digit. Then there is a subroutine called 'check_cyclops'; this will be discussed in a moment. Finally it checks that there aren't multiple zeros in the number. If all of those checks pass, then the program has found a Prime Cyclopic Palindrome!

    Let's revisit the 'check_cyclops' subroutine now. This sub is responsible for ensuring that any value that has made it through all the checks so far is indeed a prime number. Unfortunately to do this the number has to be checked to make sure that it isn't divisible by any other number except 1 and itself. The previous checks were able to get a large portion of the options but there is still a chance that the number is divisible by another prime. So there was also code in this program that builds an array of all the prime numbers up to 10000 while also checking for palindromes. Here is the code to build the array of primes:

if ( $_ < 10000) {
	# Find primes to be used later to check palindromes
	my $i;
	for ( $i=3; $i < $_; $i++) {
		if ( ($_ % $i) == 0 ) { last; }
	}
	if ( $i eq $_ ) { push (@primes, $_); }
  }

    The loop takes the number picked earlier in the foreach loop and attempts to modulo it to every number smaller than it. If the result is ever 0, then that number isn't prime! If the loop makes it all the way to the same number as the number itself, then it is definitely prime and that number gets added to an array of other prime numbers that will be used later to confirm that any potential cyclops values are indeed prime. Finally, 'check_cyclops' is the sub-routine used to confirm the final palindromes are indeed prime.

sub check_cyclops {
	
	my $check_val = shift;
	
	foreach my $prime ( @primes ) {
		if ( $check_val % $prime == 0 ) { return 0; }
	}
	
	return 1;
}

    Time for the moment of truth. Running the program presents the following list of Prime Cyclopic Palindromes: 

aut0exec@aut0exec:~/Projects/Weekly-Challenges$ time ./TWC-177-c1.pl 
101 is a palindromic prime cyclops number!
16061 is a palindromic prime cyclops number!
31013 is a palindromic prime cyclops number!
35053 is a palindromic prime cyclops number!
38083 is a palindromic prime cyclops number!
73037 is a palindromic prime cyclops number!
74047 is a palindromic prime cyclops number!
91019 is a palindromic prime cyclops number!
94049 is a palindromic prime cyclops number!
1120211 is a palindromic prime cyclops number!
1150511 is a palindromic prime cyclops number!
1160611 is a palindromic prime cyclops number!
1180811 is a palindromic prime cyclops number!
1190911 is a palindromic prime cyclops number!
1250521 is a palindromic prime cyclops number!
1280821 is a palindromic prime cyclops number!
1360631 is a palindromic prime cyclops number!
1390931 is a palindromic prime cyclops number!
1490941 is a palindromic prime cyclops number!
1520251 is a palindromic prime cyclops number!
1550551 is a palindromic prime cyclops number!
1580851 is a palindromic prime cyclops number!

real	0m0.811s
user	0m0.807s
sys	0m0.005s
The complete challenge code can be found on my github page. I'm sure there are some better ways to handle the math aspects of this challenge but this worked and was surprisingly quick. I'm looking forward to how other's solved this problem as well.

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.