June 18, 2025

SSH Sniffer on Ubuntu

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.

Leave a Reply

Your email address will not be published. Required fields are marked *