Configuring iptables for VPN to pentesting labs

Hello, first time poster here.

My situation is that I am a pentesting student, and I have a Kali app qube (from unman: Index of /Templates_4.1).

I connect via VPN to various lab environments full of lab machines to learn pentesting. Either my own homelab, or places like HackTheBox, TryHackMe, etc.

I experience the common problem where, because of how networking works in Qubes, I do not have the network connectivity I would like between my Kali VM and machines in the lab environment on the VPN. I would like my Kali VM to be able to receive incoming connections from other machines on the VPN/in the lab, for example if I am running a netcat listener trying to catch a reverse shell.

At first I was using a ProxyVM (based on debian-11-minimal with openvpn installed):

sys-net → sys-firewall → ProxyVM (with openvpn) → Kali VM

And that was working for most things, except for incoming connections to my Kali VM from machines on the VPN network (like a reverse shell). Tinkering with the iptables was beyond my ability. The default iptables that appear in my Kali VM, and in my ProxyVM are as follows:

$ sudo iptables -L            
Chain INPUT (policy DROP)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere             state INVALID
DROP       udp  --  anywhere             anywhere             udp dpt:bootpc
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     icmp --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
REJECT     all  --  anywhere             anywhere             reject-with icmp-host-prohibited
DROP       all  --  anywhere             anywhere            

Chain FORWARD (policy DROP)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere             state INVALID
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
QBS-FORWARD  all  --  anywhere             anywhere            
DROP       all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
DROP       all  --  anywhere             anywhere            

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain QBS-FORWARD (1 references)
target     prot opt source               destination

Just to troubleshoot, I tried tinkering with iptables in both my ProxyVM and Kali VM and got nowhere.

Instead I now have openvpn running directly in my Kali VM:

sys-net → sys-firewall → Kali VM (with openvpn running)

and I crudely wiped the iptables in the Kali VM:

iptables -F
iptables -P INPUT ACCEPT
iptables -P INPUT ACCEPT
iptables -P INPUT ACCEPT

Success. That works. But it feels far from ideal.

My ideal would be to use a ProxyVM handling the openvpn connection to whatever lab i’m working in, and I would have some easy way of configuring my iptables/Qubes networking such that the Kali VM is more exposed only to the VPN network as would be appropriate for pentesting - it should receive incoming connections, respond to pings, etc, basically like i am using a regular Kali installation connected to the VPN. This could be persistent and/or general, but I also wouldn’t mind writing a simple bash script to modify iptables on startup, or to open up specific ports on my Kali VM when I need it - however, my knowledge of iptables is really not sufficient to figure this out on my own.

Notably, the VPN set up is such connections from the Kali VM going to IPs outside of the lab network are routed to the regular internet. So I’m also not looking for a solution where there Kali VM is “wide open” on the VPN and completely locked down otherwise.

I am aware of some of the dom0 script out there to automatically forward a port to a specific VM. I don’t think they are applicable in my situation, since they don’t account for a ProxyVM, or that I’m dealing with a VPN network specifically/only where I want to open up ports.

My current solution works, but I think I would greatly benefit from some advice on setting up the iptables in my Kali VM at least, or possibly a way to make it work with a ProxyVM. Searching the forums (and elsewhere) I do know that this is an issue pentesting students come up against regularly, but I havn’t seen a good solution and I think a good solution would benefit people besides me! Also if the best solution is to just tell me to learn iptables, feel free although I would appreciate some guidance/advice/starting points too!

Thanks for reading and any help you have.

1 Like

Welcome.
iptables rules in qubes always give me a headache, with that weird DNS and DHCP setup and considering there’s also nftables and you don’t know which takes priority… so you end up duplicating your efforts in both iptables and nftables just to be sure…
After some searching found some clarification about the whole iptables-nftables business

Still doesn’t answer what happens when you set contradictory rules using both commands.
Also even after trying reading docs multiple times still can’t wrap my head around that PR-QBS DNS propagation business. In general my confusion stems from DHCP server sitting somewhere (as I understand it) in the back of qubes infrastructure and communicating with vms in mysterious (to me) ways (qrexec?), and the whole DNS business communication being facilitated by interacting with something in the back of qubes using qubes specific mechanisms but wrapping them in the standard network protocol clothes, ergo the whole PR-QBS chain in the table…

anyway… for what you want you would need to route from your vpn vm tun interface to your kali
you could try instructions here in the section Port forwarding to a qube from the outside world

for openvpn setup I recommend using qubes-tunnel

I have learned a little bit more about iptables. For example, with a setup like this:

sys-net → sys-firewall → Kali VM (running openvpn to a lab network)

I can add an iptable rule like this:

iptables -I INPUT 1 -j ACCEPT -i tun0

To allow in traffic coming from the VPN (on the tun0 interface). Great! I would still take suggestions on how to tune the iptables in a Kali VM here.

I’m still at a loss getting it to work with a ProxyVM handling the VPN, as in:

sys-net → sys-firewall → ProxyVM (running openvpn to a lab network) → Kali VM

In this case, i’ve tried troubleshooting by flushing all iptables, and setting all chains to ACCEPT in the ProxyVM and KaliVM, still without success. I suspect it may not be a firewall issue then, but something about the routing in the ProxyVM i have to modify… but I’m at a loss here.

Thanks for this suggestion, I had looked at that, but it does not seem applicable here. As I understand it, in my situation, I shouldn’t actually need to muck around in sys-net nor sys-firewall, because the traffic I’m concerned with is going through a VPN. It’s all inside the VPN “tunnel” as it passes through sys-net and sys-firewall, so firewall rules or routing there have no effect. And besides, it is working fine without a ProxyVM.

Thanks for this as well, but also not helpful i believe. I did try the project on which it is based, and those projects seek to lock down the VPN connection to avoid leaks - in my case this is actually undesirable.

In the settings on the ProxyVM you can set it as “provinding network”, if you do that you can in the KaliVM set ProxyVM as the netvm, than KaliVM with use ProxyVM as the gateway.

@renehoj
sorry, perhaps I wasn’t clear enough in my posts. I know how to set up a ProxyVM. my question is about getting that arrangement to allow the type of incoming connections to my Kali VM necessary to pentesting lab work. it requires modifying firewall rules, which is really what I’m looking for advice on!

Look at the documentation
BUT, as you are using VPN you will need to handle inbound traffic at the
VPN level so that it is directed down the tunnel to your sys-net, and
then down to the proxy. You may not be able to do this.

1 Like

Hi!

I know it’s been a long time, I hope my response helps anyway.
I’ve ran into the same issue today when pentesting a network of one of our customers.
My setup is the following:

Pentesting-AppVm (running debian12) → sys-firewall → sys-proton → sys-net

My Pentesting-AppVm runs “openfortivpn” so I can reach the internal network of our customer. So, TLDR, I first go through ProtonVPN and then into a Fortinet VPN.
I was exposing a SMB port to the network, but no server inside the Fortinet VPN could reach it.

My colleague was running a Parallels VM with Kali Linux and, after opening the SMB port, could get connections from servers.

So that got me wondering “why is this happening to me?”.
I checked out the official guides on port exposure, but all refered to connecting one qube to the exposed port of another qube, OR exposing a qube port to the local network (via WiFi or Ethernet).

I ran a Windows StandaloneVM and could receive traffic to my TCP exposed port, so I figured out that my Debian12 Pentesting-AppVM had a network filter dropping incoming connections.

So, the solution…

First I checked iptables, but the problem wasn’t there. Anyway, you should check them out like this:
sudo iptables -L -n -v

Then, if iptables are messing your incoming connections, drop them and enable everything for them (or fine-tune them as you like).
Dropping them:

sudo iptables -F
sudo iptables -t nat -F
sudo iptables -t mangle -F
sudo iptables -X

Enable everything in them:

sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT

Now, if this does not work, this is probably a NFT issue. You can check out your nft rules with this command:
sudo nft list ruleset

And also, you should check your ‘nftables.conf’ file:
cat /etc/nftables.conf

This was the content of my “nftables.conf” (the default):

table inet filter {
	chain input {
		type filter hook input priority filter;
	}

	chain forward {
		type filter hook forward priority filter;
	}

	chain output {
		type filter hook output priority filter;
	}
}

You see the “type filter hook CHAIN_NAME priority filter;” lines? They dont specify “policy accept” or “policy drop”, so, by default, “policy drop” is applied and everything is dropped in them.

I fixed it using sudo nano /etc/nftables.conf and writing this rules:

table inet filter {
	chain input {
		type filter hook input priority filter; policy accept;
	}

	chain forward {
		type filter hook forward priority filter; policy accept;
	}

	chain output {
		type filter hook output priority filter; policy accept;
	}
}

Then, you reload NFT rules with this command so “/etc/nftables.conf” gets applied:
sudo nft -f /etc/nftables.conf

And you can list the new rules like this:
sudo nft list ruleset

Now everything works for me and I can receive SMB connections in the TCP port 445 of this Pentesting-AppVM to do some nice NTLM relays.

I don’t know if this solution poses a security risk, but if I find any, I will reply again to this post with the patch.
Btw, this change is not persistent in my AppVM, so, if I this messes something, I just reboot the AppVM and I’m cool again.

TNT

Oh, sudo systemctl status nftables showed that the service is inactive, so now I don’t really know how this black magic is working xD

Maybe we need an expert here.
At least it works…

The firewall rules with nftables are not loaded using the default nftables systemd unit.

Thanks @solene for pointing it out.

It ended up being easier:
sudo nft add rule qubes custom-input ct state new,established,related counter accept

Run this in your AppVM. Now you will be able to get inbound traffic.
This enables inbound traffic for 0.0.0.0

You can limit the inbound traffic to certain IPs with a command like this:
sudo nft add rule qubes custom-input ip saddr <IP address that will be receiving inbound traffic> ct state new,established,related counter accept

I used the documented way shown here: Firewall — Qubes OS Documentation

The second command (The one in the Qube B thing) is the one used. So this will enable incoming VPN traffic used this way.

TNT

Also, if you want to eliminate the created inbound accept rule…

First, get the handle of your added rule with this command:
sudo nft -a list chain qubes custom-input

The output should be something like this:

table ip qubes {
	chain custom-input { # handle 63
		ct state established,related,new counter packets 196 bytes 651979 accept # handle 80
	}
}

(Scroll to the right to view the full output if it’s not showing completely in this scrollable code box, you need to notice that “# handle 80”)

Now you can delete the added rule with this command:
sudo nft delete rule qubes custom-input handle <rule handle>

The handle of my added rule is “80”. So I run this command:
sudo nft delete rule qubes custom-input handle 80

Now, if I list the rules, this rule won’t show anymore:
sudo nft -a list chain qubes custom-input

table ip qubes {
	chain custom-input { # handle 63
	}
}

This means I cannot receive inbound traffic no more.

Hope this helps.

TNT