Recommended Ways to Setup Security Labs? (Pentesting Lab, Malware Lab)

You may have already read this, but just in case, note that there is a section of the Firewall docs that explains how to enable networking between two qubes:

If useful, you can find a concrete example of that setup in action in the SecureDrop docs:

https://docs.securedrop.org/en/stable/development/qubes_staging.html#inter-vm-networking

2 Likes

On the topic of working with Kali, please note that a template is available for both R4.0 and R4.1:

2 Likes

Thanks for the update to the topic, I do appreciate it. I saw that 4.1 had a Kali Template out, however I did not see one for 4.0 so I do appreciate this. I’ll give this a try when I get back on my local machine over the weekend.

Malware typically tends to want to talk to the internet. As well as updating Kali or doing custom VM builds within the Vulnerable side. I can always disconnect them from the network by removing the firewall from using the netvm easily if I want more forced isolation.

Again not dabbled too much into this, I’ve had a lab machine built on Debian for the longest time and it’s just worked for my needs, but I’d like to rid myself of having two machines.

Yes, but you dont need to let it.
The principle of internet-inna-box is that it can be completely isolated, and
you can provide whatever services are required.
Since you monitor all traffic at sys-firewall you can spin up upstream
servers or honeypots as required. (Have these templates and qubes
prepared beforehand).

2 Likes

For doing wifi pentesting you should have another sys-net with a dedicated wifi card. This talk has some hints on how to do that:

Since you asked what the Qubes community thinks, I’ll offer my opinion: You’re trying to use a tool for a different purpose than the one for which it was designed, so don’t be surprised if it’s difficult and you run into problems. Qubes OS is designed to be defensive. It’s designed to protect a single general purpose desktop computer user through strong compartmentalization. It’s not designed to be a pen-testing or malware lab. Can you do it anyway? Sure, just don’t blame the hammer for not being a screwdriver.

On the other hand, if @unman says that Qubes is great for this sort of work, then take his word over mine. He knows much more about this than I do.

2 Likes

I wanted the Qubes Communities opinion so I do appreciate you taking the time to respond. Thank you very much. I like Qubes, I use it as my daily driver. However I have a debian lab that I also mentioned above.

So my current layout of hardware 2x Qubes Machines(Daily Drivers) and 2x Lab Machines(Desktop and a Laptop) I did HTB for awhile but have just moved to VulnHub due to some issues with HTB (Mostly restarts of machines causing issues) which was my biggest concern as it’s a fun hobby.

So I’m just looking to cut those machines down to the 2. I’m not looking to pentest a company network, or to do anything interacting outside the lab within Qubes. I understand it’s not designed for that purpose. But building an internal lab I do feel Qubes is adequate for. Again, I’ve never used Qubes beyond a daily use and some minor tinkering(ie hardening Debian, with Kickstart and a few emulators and developer aspects) so just wanted some more user input. Again thank you very much for taking the time to reply.

1 Like

Any luck on your try?
I want exactly the same for vulnhub machines.

I’m not sure what “exactly the same” means.
You can create a simple lab very easily - all you have to do is enable
networking between qubes in the netvm to which they are attached.
This is covered in detail in the docs

If you want to create a full internet-inna-box, again this is relatively
simple. The netvm will not be connected to upstream netvm, so the whole
system will be offline.
Create qubes to provide the network services that you need -
DNS, web server, sshd, and so forth. (You can attach these to a netvm,
upstream from the netvm to which your qubes are attached, but in this
case you will have to adjust routing and remove NAT: it’s simpler if
you use a single master netvm.)
Enable networking between all these qubes.
You will want to run a packet analyser on the (or both) netvm.

If you have all the service qubes ready, you can spin them up as needed,
and replay traffic to aid analysis.
Almost all the work will be in adjusting the firewall on the netvm to
route (and NAT) traffic as needed. That’s quite straight forward.

Are we talking about a setup like this?

pentester -----------------------|
                                 |
empire ------------------------| |
                              sys-bridge --- sys-firewall --- sys-net --- uplink
vuln_tux1 --------------------|||||      \ or
                               ||||       --- sys-whonix --- sys-firewall --- asf
vuln_tux2 ---------------------||||       \ or
                                |||        --- (none)
vuln_win1 ----------------------|||
                                 ||
vuln_win2 -----------------------||
                                  |
domain_controller ----------------|

You need to change /rw/config/qubes-firewall-user-script in sys-bridge to allow forwarding traffic from anywhere to anywhere:

#!/bin/sh

# This script is called at AppVM boot if this AppVM has the qubes-firewall
# service enabled. It is executed after the empty chains for the Qubes firewall
# are created, but before rules for attached qubes are processed and inserted.
#
# It is a good place for custom rules and actions that should occur when the
# firewall service is started.
# 
# Executable scripts located in /rw/config/qubes-firewall.d are executed
# immediately before this qubes-firewall-user-script.

# allow connected qubes to talk to each other
iptables -I FORWARD -j ACCEPT

pentester and empire i.e. need to have their firewalls switched off or at least a

sudo iptables -I INPUT -j ACCEPT

to allow incoming traffic since you want to serve stuff with

sudo python3 -m http.server 80 &

or catch an incoming shell with

sudo rlwrap nc -lvnp 443

You can cut off the vulnerable machines from the internet by disconnecting sys-bridge from it’s uplink or setting up specific and cumbersome iptables rules. sys-bridge needs to have provides_network set to True.

Meanwhile my /rw/config/qubes-firewall-user-script in sys-bridge looks like this:

#!/bin/sh

# This script is called at AppVM boot if this AppVM has the qubes-firewall
# service enabled. It is executed after the empty chains for the Qubes firewall
# are created, but before rules for attached qubes are processed and inserted.
#
# It is a good place for custom rules and actions that should occur when the
# firewall service is started.
#
# Executable scripts located in /rw/config/qubes-firewall.d are executed
# immediately before this qubes-firewall-user-script.

# allow redirects to localhost
sysctl -w net.ipv4.conf.all.route_localnet=1

# nuke all iptables but NAT table
/usr/sbin/iptables -P INPUT ACCEPT
/usr/sbin/iptables -P FORWARD ACCEPT
/usr/sbin/iptables -P OUTPUT ACCEPT
/usr/sbin/iptables -F
/usr/sbin/iptables -X
/usr/sbin/iptables -F -t mangle
/usr/sbin/iptables -X -t mangle

# setup iptables to redirect to DNS requests to localhost
/usr/sbin/iptables -t nat -F PR-QBS
/usr/sbin/iptables -t nat -A PR-QBS -d 10.139.1.1/32 -p udp -m udp --dport 53 -j DNAT --to-destination 127.0.0.1
/usr/sbin/iptables -t nat -A PR-QBS -d 10.139.1.1/32 -p tcp -m tcp --dport 53 -j DNAT --to-destination 127.0.0.1
/usr/sbin/iptables -t nat -A PR-QBS -d 10.139.1.2/32 -p udp -m udp --dport 53 -j DNAT --to-destination 127.0.0.1
/usr/sbin/iptables -t nat -A PR-QBS -d 10.139.1.2/32 -p tcp -m tcp --dport 53 -j DNAT --to-destination 127.0.0.1

# setup iptables to allow network scans
/usr/sbin/iptables -t nat -D POSTROUTING 3
/usr/sbin/iptables -t nat -A POSTROUTING ! -d 10.137.0.0/24 -j MASQUERADE

sys-bridge is based on a kali template and I’m running a dnscrypt-proxy.service in there to enable dns-cloaking for my vulnerable machines.

1 Like

Hint how to set up a dhcp network inside Vulnhub virtual machines without having root access beforehand I’ve been thinking about this for days now but can’t come up with anything, the only thing I’ve found is this thread

Not sure what you want or need to achieve, but if you use Vulnhub VMs as HVMs on Qubes and these machines expect to receive their ip settings and stuff from uplink, you might want to install a dhcp server on the direct uplink machine (in my case sys-bridge). My suggested readings on that topic:

https://wiki.archlinux.org/title/Dnsmasq
https://wiki.archlinux.org/title/Dhcpd

Don’t forget to disarm your iptables.

hi I have a kali linux based appwm and a vulnhub hvm virtual machine I tried to understand in the wiki but didn’t understand how to apply this in the context of qubes and sys-bridge could you write the commands to be entered in sys-bridge ? thanks

Just scroll up.

Sure you have. And since you engage in this kind of activity you won’t need help with iptables or dnsmasq, am I right?

This forum has lately been populated by trolls and sockpuppets which create burner accounts ask or even demand help. That is a highly unsocial behaviour threatening the motivation of all those user honestly trying to help other users.

I’m new to this, I was able to handle the conversion of the vulnhub machine to an HVM vm and then with the help of your iptables instructions, I was able to get the appwm kali to be fully operational along with the jobs from the hackthebox site, thank you for that. but I can’t get my nmap to see my vulnhub vm Nully Cybersecurity: 1 ~ VulnHub I suspect I’m not configuring dnsmasq or dhcpd correctly in sys-bridge I’ve been trying to find the root password for a given vulnhub machine to do the configuration inside but it doesn’t seem to be listed publicly for this machine I’m asking for help configuring dhcpd and dnsmasq if it’s not difficult for you

I apologize if I gave the impression of not being a dishonest user, usually I’m only in forum reading mode, as I don’t have much to share with people, because I’m just learning qubes, I had to create a new account because the first one I created in a disposable dvm virtual machine and forgot to save the login credentials, I’m really sorry if it could somehow harm the forum, now I have a permanent account

It is difficult to answer a question if the information you provide are somewhat vague, but I will still try.

dom0 has assigned an IP-address and routes for your HVM. But your HVM does not know these parameters as it does not run the startup scripts. If you can’t setup IP and routes manually in the HVM because you don’t have the privileges to do so and if you assume your HVM asks a DHCP-server on it’s uplink, it is probably a reasonable approach to run a DHCP-server in your sys-bridge.

To my knowledge or experience your DHCP-server has to provide the exact same IP and route dom0 assigned for the relevant HVM. Otherwise you won’t have connectivity between sys-bridge and your nully-HVM.

Therefore you might want to do this first:

[user@dom0 ~]$ qvm-prefs nully-HVM | grep '10'
dns                   D  10.139.1.1 10.139.1.2
ip                    D  10.137.0.32
visible_gateway       D  10.137.0.9
visible_ip            D  10.137.0.32

and then hand those preferences over to your DHCP-server.

If you got your dhcpd working, please be so kind to share your solution in this thread as others might profit from that. “it works now, thank you” doesn’t help future visitors of this thread.

You might get an answer from the creator of that vulnhub machine, but you certainly won’t find it here. Or at least I suspect that being unlikely.

2 Likes

Just a quick hack… you would have to setup the following two files in sys-bridge’s /rw/config :

/rw/config/rc.local

#! /bin/sh
# allow redirects to localhost
/usr/sbin/sysctl -w net.ipv4.conf.all.route_localnet=1

# there is no place like 127.0.0.1
echo "nameserver 127.0.0.1" > /etc/resolv.conf
echo "nameserver 127.0.0.1" >> /etc/resolv.conf

# enable hotplugging survival
/usr/bin/qubesdb-write /qubes-primary-dns 127.0.0.1
/usr/bin/qubesdb-write /qubes-secondary-dns 127.0.0.1

# rerun setup of DNAT rules
/usr/lib/qubes/init/network-proxy-setup.sh

# setup and start dnsmasq
/usr/bin/cp /rw/config/dnsmasq.sys-bridge /etc/dnsmasq.d/dnsmasq.sys-bridge
/usr/bin/systemctl start dnsmasq.service

# nuke all but NAT table
/usr/sbin/iptables -P INPUT ACCEPT
/usr/sbin/iptables -P FORWARD ACCEPT
/usr/sbin/iptables -P OUTPUT ACCEPT
/usr/sbin/iptables -F
/usr/sbin/iptables -X
/usr/sbin/iptables -F -t mangle
/usr/sbin/iptables -X -t mangle

# setup iptables to allow network scans
/usr/sbin/iptables -t nat -D POSTROUTING 3
/usr/sbin/iptables -t nat -A POSTROUTING ! -d 10.137.0.0/24 -j MASQUERADE

/rw/config/dnsmasq.sys-bridge

# dns stuff
port=53
domain-needed
bogus-priv
no-resolv

address=/red.lab/10.137.0.a
address=/blue.lab/10.137.0.b
address=/admin.lab/10.137.0.c
address=/empire.lab/10.137.0.d
address=/work.lab/10.137.0.e
address=/offsec.lab/10.137.0.f
address=/router.lab/10.137.0.g

# dhcp stuff
dhcp-range=10.137.0.1,10.137.0.250,255.255.255.255,1m
dhcp-host=red,10.137.0.a
dhcp-host=blue,10.137.0.b
dhcp-host=admin,10.137.0.c
dhcp-host=empire,10.137.0.d
dhcp-host=work,10.137.0.e
dhcp-host=offsec,10.137.0.f
dhcp-host=router,10.137.0.g

#log-queries
#log-dhcp

You need to

  • adapt a, b, c, d, e, f, g and the machine names to your local lab specifics ( qvm-prefs <machine-name> | grep '10')
  • have dnsmasq installed in your sys-bridge’s template, preferably disabled
  • leave the lease time set to one minute for starters.

I didn’t have time to test this, have no idea if it work on Qubes 4.2-rcX as they changed to nftables.

But I think it’s a start.

And I’d be happy to hear if that worked or what tweaks have had to be done to make it work.

1 Like

Hi, thank you very much for taking the time to help, I did everything exactly as written, but it doesn’t work

I used the standard debian-11 template, installed dnsmasq in it, then created sys-bridge, enabled the provides network checkbox, then copied the qubes-firewall-user-script configuration from the post just above, and also ran sudo chmod +x, then did exactly as in the post above and changed the IP and VM names, additionally ran sudo chmod +x, and I ended up with this

# dns stuff
port=53
domain-needed
bogus-priv
no-resolv

address=/kalitest.lab/10.137.0.21
address=/nully.lab/10.137.0.31

# dhcp stuff
dhcp-range=10.137.0.1,10.137.0.250,255.255.255.255,1m
dhcp-host=kalitest,10.137.0.21
dhcp-host=nully,10.137.0.31

#log-queries
#log-dhcp

but it causes a systemd error with this text

● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server
     Loaded: loaded (/lib/systemd/system/dnsmasq.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Mon 2023-10-16 14:48:31 EDT; 2s ago
    Process: 1466 ExecStartPre=/etc/init.d/dnsmasq checkconfig (code=exited, status=1/FAILURE)
        CPU: 14ms

Oct 16 14:48:31 sys-bridge systemd[1]: Starting dnsmasq - A lightweight DHCP and caching DNS server...
Oct 16 14:48:31 sys-bridge dnsmasq[1474]: inconsistent DHCP range at line 11 of /etc/dnsmasq.d/dnsmasq.sys-bridge
Oct 16 14:48:31 sys-bridge dnsmasq[1474]: FAILED to start up
Oct 16 14:48:31 sys-bridge systemd[1]: dnsmasq.service: Control process exited, code=exited, status=1/FAILURE
Oct 16 14:48:31 sys-bridge systemd[1]: dnsmasq.service: Failed with result 'exit-code'.
Oct 16 14:48:31 sys-bridge systemd[1]: Failed to start dnsmasq - A lightweight DHCP and caching DNS server.

Apparently 255.255.255.255 causes the error, I tried to remove it from the string and then systemd started successfully, so I tried 255.255.255.0 and with it systemd also runs successfully

● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server
     Loaded: loaded (/lib/systemd/system/dnsmasq.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2023-10-16 15:28:18 EDT; 1s ago
    Process: 2815 ExecStartPre=/etc/init.d/dnsmasq checkconfig (code=exited, status=0/SUCCESS)
    Process: 2823 ExecStart=/etc/init.d/dnsmasq systemd-exec (code=exited, status=0/SUCCESS)
    Process: 2831 ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf (code=exited, status=0/SUCCESS)
   Main PID: 2830 (dnsmasq)
      Tasks: 1 (limit: 4620)
     Memory: 1.0M
        CPU: 63ms
     CGroup: /system.slice/dnsmasq.service
             └─2830 /usr/sbin/dnsmasq -x /run/dnsmasq/dnsmasq.pid -u dnsmasq -7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new --local-service --trus>

Oct 16 15:28:18 sys-bridge systemd[1]: Starting dnsmasq - A lightweight DHCP and caching DNS server...
Oct 16 15:28:18 sys-bridge dnsmasq[2830]: started, version 2.85 cachesize 150
Oct 16 15:28:18 sys-bridge dnsmasq[2830]: DNS service limited to local subnets
Oct 16 15:28:18 sys-bridge dnsmasq[2830]: compile time options: IPv6 GNU-getopt DBus no-UBus i18n IDN2 DHCP DHCPv6 no-Lua TFTP conntrack ipset auth >
Oct 16 15:28:18 sys-bridge dnsmasq-dhcp[2830]: DHCP, IP range 10.137.0.1 -- 10.137.0.250, lease time 2m
Oct 16 15:28:18 sys-bridge dnsmasq[2830]: read /etc/hosts - 5 addresses
Oct 16 15:28:18 sys-bridge systemd[1]: Started dnsmasq - A lightweight DHCP and caching DNS server.
lines 1-20/20 (END)

but with none of these options, kalitest does not see nully, here is an example of how ping works

ping 10.137.0.31
PING 10.137.0.31 (10.137.0.31) 56(84) bytes of data.
From 10.137.0.8 icmp_seq=1 Destination Host Unreachable
From 10.137.0.8 icmp_seq=2 Destination Host Unreachable
From 10.137.0.8 icmp_seq=3 Destination Host Unreachable
From 10.137.0.8 icmp_seq=4 Destination Host Unreachable
^C
--- 10.137.0.31 ping statistics ---
6 packets transmitted, 0 received, +4 errors, 100% packet loss, time 5115ms
pipe 4

I also tried this configuration option, but it didn’t work either

# dhcp stuff
dhcp-range=10.137.0.1,10.137.0.250,1m
# subnet mask
dhcp-option=1,255.255.255.255
# gateway
dhcp-option=3,10.137.0.8
# dns
dhcp-option=6,10.139.1.1,10.139.1.2

I’ve also tried using standalone instead of appvm and disabling the networkmanager with sudo systemctl disable --now NetworkManager, but unfortunately none of that helped, kalitest still doesn’t see nully with nmap, ping, and netdiscover

addendum, I tried to enable netvm in sys-bridge and disable it by setting the value of none, but it didn’t help