How to Build a Passive SSH Sniffer on Ubuntu Using a Bridged Network Adapter
If you’re trying to identify rogue SSH traffic on your home or office network, one effective approach is to build a passive sniffer using a Linux PC. In this guide, we’ll walk through the steps to set up an Ubuntu-based device with dual network adapters to sniff outbound SSH connections silently.
1. Hardware and Network Layout
- One Ubuntu PC with two Ethernet interfaces (e.g., eth0 and eth1)
- An Ethernet cable between your modem/router and this PC
- A second cable from the PC to your internal router or switch
The PC will act as a transparent bridge that allows traffic to flow while capturing packets silently.
2. Set Up a Network Bridge on Ubuntu
ip link show
sudo nano /etc/netplan/99-bridge.yaml
network:
version: 2
renderer: networkd
ethernets:
eth0: {}
eth1: {}
bridges:
br0:
interfaces: [eth0, eth1]
dhcp4: true
sudo netplan apply
3. (Optional) Clone MAC Address
sudo ip link set dev eth0 down
sudo ip link set dev eth0 address AA:BB:CC:DD:EE:FF
sudo ip link set dev eth0 up
# Or persist in Netplan:
macaddress: AA:BB:CC:DD:EE:FF
4. Write a TCPDump Logging Script
sudo nano /usr/local/bin/capture_ssh.sh
#!/bin/bash
LOGDIR="/var/log/tcpdump"
mkdir -p "$LOGDIR"
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
LOGFILE="$LOGDIR/ssh_traffic_$TIMESTAMP.txt"
/usr/bin/tcpdump -i br0 port 22 -nn -l >> "$LOGFILE" 2>&1
sudo chmod +x /usr/local/bin/capture_ssh.sh
5. Create a Systemd Service to Run on Boot
sudo nano /etc/systemd/system/tcpdump-capture.service
[Unit]
Description=Capture SSH Traffic via TCPDump
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
Group=root
ExecStartPre=/bin/sleep 10
ExecStart=/usr/local/bin/capture_ssh.sh
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable tcpdump-capture.service
sudo systemctl start tcpdump-capture.service
6. Monitor Logs
sudo tail -f /var/log/tcpdump/ssh_traffic_*.txt
ssh test@portquiz.net -p 22
7. Email Logs Hourly Using Python and Cron
nano /usr/local/bin/email_tcpdump_logs.py
import smtplib, ssl, os, zipfile
from datetime import datetime
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
LOG_DIR = "/var/log/tcpdump"
TIMESTAMP = datetime.now().strftime('%Y%m%d_%H%M%S')
ZIP_FILE = f"/tmp/tcpdump_logs_{TIMESTAMP}.zip"
GMAIL_USER = "your_email@gmail.com"
GMAIL_PASSWORD = "your_app_password"
TO_EMAIL = "your_email@gmail.com"
def zip_logs():
with zipfile.ZipFile(ZIP_FILE, 'w', zipfile.ZIP_DEFLATED) as zipf:
for root, _, files in os.walk(LOG_DIR):
for file in files:
filepath = os.path.join(root, file)
arcname = os.path.relpath(filepath, LOG_DIR)
zipf.write(filepath, arcname)
def send_email():
msg = MIMEMultipart()
msg['From'] = GMAIL_USER
msg['To'] = TO_EMAIL
msg['Subject'] = f"TCPDump Logs Archive - {TIMESTAMP}"
with open(ZIP_FILE, "rb") as file:
part = MIMEBase('application', 'zip')
part.set_payload(file.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', f'attachment; filename=\"{os.path.basename(ZIP_FILE)}\"')
msg.attach(part)
context = ssl.create_default_context()
with smtplib.SMTP_SSL('smtp.gmail.com', 465, context=context) as server:
server.login(GMAIL_USER, GMAIL_PASSWORD)
server.sendmail(GMAIL_USER, TO_EMAIL, msg.as_string())
if __name__ == "__main__":
zip_logs()
send_email()
os.remove(ZIP_FILE)
chmod +x /usr/local/bin/email_tcpdump_logs.py
crontab -e
0 * * * * /usr/bin/python3 /usr/local/bin/email_tcpdump_logs.py
✅ Done!
You've now built a passive SSH sniffer that runs silently on your network, logs traffic in real-time, and emails you compressed reports every hour. This is great for identifying rogue IoT devices or backdoors calling home.