
Self-contained SSH honeypot per catturare le interazioni degli attaccanti e trasformarle in intelligence di sicurezza strutturata.
SSHintel è un honeypot SSH leggero realizzato con Python e Paramiko. Simula una shell Linux fittizia per registrare tentativi di accesso non autorizzati, catturare credenziali e analizzare il comportamento degli attaccanti in un ambiente controllato.
ls, cd, pwd, , , , , , , , , , , , , , , , ecc.)catechogrepfindtreeheadtailwcstatpsdffreeenvidwhoami--tarpit opzionale per rallentare gli attaccanti con output ritardatoSSHintel non è una shell Bash/Linux completa. Simula un sottoinsieme credibile di comandi comuni per raccogliere telemetria sugli attaccanti. I comandi vengono gestiti da un registro leggero; aggiungere un comando significa aggiungere una piccola funzione handler.
pip install -r requirements.txt
Nota: La chiave host SSH viene generata automaticamente al primo avvio. Nessuna generazione manuale della chiave necessaria.
Esegui l'honeypot con una porta, un nome utente e una password specifici:
python3 run.py serve --port 2222 --username user1 --password pass123
La porta predefinita è
2222e l'host è0.0.0.0.
L'honeypot genera automaticamente una chiave host SSH in static/server.key al primo avvio se non esiste già. Nessuna generazione manuale della chiave necessaria.
Per abilitare la modalità tarpit:
python3 run.py serve --port 2222 --username user1 --password pass123 --tarpit
Per disabilitare la telemetria SQLite (solo JSONL):
python3 run.py serve --port 2222 --username user1 --password pass123 --no-db
SSHintel protegge dall'esaurimento delle risorse dovuto a molte connessioni simultanee o connessioni mantenute attive indefinitamente. Questi parametri sono configurabili tramite CLI:
| Flag | Predefinito | Scopo |
|---|---|---|
--max-connections | 50 | Numero massimo di connessioni attive simultanee; le connessioni extra vengono rifiutate e registrate come evento connection_rejected |
--auth-timeout | 60 (s) | Tempo consentito per completare l'handshake/autenticazione SSH; i client bloccati vengono disconnessi |
--session-idle-timeout | 300 (s) | Timeout di inattività per una shell autenticata; una sessione inattiva viene terminata, ma un attaccante che digita attivamente non viene mai interrotto |
Esempio:
python3 run.py serve --port 2222 --username user1 --password pass123 \
--max-connections 25 --auth-timeout 30 --session-idle-timeout 300
Quando ci sono troppe connessioni aperte, la connessione extra viene chiusa immediatamente e un evento di sicurezza connection_rejected (con reason: connection_limit) viene scritto nel log JSONL. Un'autenticazione bloccata viene registrata come disconnessione con reason: auth_timeout; una shell inattiva termina con reason: idle_timeout.
La modalità tarpit invia intenzionalmente l'output lentamente per mantenere impegnato un attaccante, quindi il ciclo del banner tarpit non è soggetto al timeout di inattività — ma le sessioni tarpit contano ai fini del limite di connessioni.
SSHintel include una dashboard web locale che visualizza la telemetria di sicurezza memorizzata in SQLite.
python3 run.py dashboard
Poi apri http://localhost:5000 nel tuo browser.
La dashboard legge dal database SQLite in
data/sshintel.dbper impostazione predefinita. Avvia prima l'honeypot così la telemetria viene catturata, poi avvia la dashboard per vederla popolarsi.
Clicca su un ID sessione (o naviga su /session/<session_id>) per aprire la vista di investigazione sessione, che ricostruisce cronologicamente un singolo attacco:
$ comando di tutto ciò che l'attaccante ha digitato, con le directory di lavoro# Terminale 1: avvia l'honeypot
python3 run.py serve --port 2222 --username user1 --password pass123
# Terminale 2: avvia la dashboard
python3 run.py dashboard
# Terminale 3: simula un attaccante
ssh user1@localhost -p 2222
# (esegui alcuni comandi, poi esci)
Poi apri http://localhost:5000 per ispezionare l'attività catturata.
La dashboard supporta la telemetria live — interroga l'honeypot ogni 2 secondi e si aggiorna automaticamente. Nuove sessioni, comandi ed eventi appaiono in tempo reale senza ricaricare la pagina. Un indicatore live (● Live) mostra lo stato della connessione.
Apri un secondo terminale e prova a connetterti:
ssh user1@localhost -p 2222
Se le credenziali corrispondono, verrai inserito nella shell emulata.
Per rimuovere impronte SSH obsolete:
notepad "%USERPROFILE%\.ssh\known_hosts"
Elimina la riga pertinente che contiene
localhosto l'IP dell'honeypot.
creds_loggerfunnel_loggerlog_files/events.jsonl come JSON Lines (JSONL) — un oggetto JSON valido per rigaOgni evento JSONL include un timestamp UTC ISO-8601, un event_type, un session_id univoco e l'source_ip. Connessioni, tentativi/risultati di autenticazione, esecuzione di comandi, attivazione tarpit e disconnessioni vengono tutti registrati come eventi strutturati.
Ogni connessione SSH in entrata viene tracciata come una sessione indipendente con il proprio session_id. Una sessione registra l'IP sorgente, gli orari di connessione/disconnessione, l'esito dell'autenticazione e la durata della connessione, e ogni evento generato all'interno di quella connessione porta lo stesso session_id (così tentativi di autenticazione, comandi e disconnessioni possono essere ricondotti a una singola connessione). Le sessioni sono isolate per connessione — nessuno stato viene condiviso tra client simultanei.
Ogni sessione riceve anche il proprio filesystem fittizio isolato in memoria — il filesystem simulato viene creato nuovo per ogni connessione e ripulito quando la connessione termina. File, directory e directory di lavoro creati o modificati da un attaccante non sono mai visibili a un altro attaccante connesso nello stesso momento. L'intero filesystem è simulato nella memoria Python e non tocca mai il filesystem reale dell'host.
Valori correnti di event_type: connect, auth_attempt, auth_success, auth_failure, command, disconnect, connection_rejected, tarpit.
SSHintel/
├── honeypot/ # Logica principale dell'honeypot
│ ├── __init__.py
│ ├── main.py # Ciclo di accettazione + limitazione connessioni
│ ├── handlers.py # Configurazione trasporto SSH + shell emulata
│ ├── server.py # Interfaccia server Paramiko (autenticazione)
│ ├── session.py # Tracciamento sessione per connessione
│ ├── fs.py # Filesystem fittizio in memoria (isolato per sessione)
│ ├── shell.py # Shell fittizia: registro comandi + dispatcher
│ ├── limits.py # Limitazione connessioni simultanee thread-safe
│ ├── logger.py # Registrazione eventi JSONL + bridge SQLite
│ └── telemetry_store.py # Archivio telemetria SQLite + livello query
│
├── dashboard/ # Dashboard web locale
│ ├── app.py # Applicazione Flask + rotte API
│ ├── templates/
│ │ ├── index.html # Template principale della dashboard
│ │ └── session.html # Template investigazione sessione
│ └── static/
│ ├── style.css # Stili della dashboard
│ ├── dashboard.js # JS principale della dashboard (aggiornamenti live)
│ └── session.js # JS investigazione sessione
│
├── log_files/ # Log di runtime (ignorati da git)
│ ├── creds_audits.log # Tentativi di credenziali
│ ├── cmd_audits.log # Traccia di audit dei comandi
│ └── events.jsonl # Eventi di sicurezza JSONL strutturati
│
├── data/ # Database SQLite (ignorato da git)
│ └── sshintel.db
│
├── static/ # Chiave host SSH (generata automaticamente)
│ └── server.key
│
├── .github/workflows/ # Configurazione CI
│ └── tests.yml
│
├── Dockerfile
├── README.md
├── requirements.txt # Dipendenze runtime (paramiko, flask)
├── requirements-dev.txt # Dipendenze test (pytest, pytest-cov)
└── run.py # Punto di ingresso CLI
Se preferisci eseguire l'honeypot in un ambiente containerizzato, puoi usare il Dockerfile incluso.
docker build -t sshintel .
Questo crea un'immagine Docker denominata
sshintel.
docker run -p 2222:2222 sshintel
Questo:
static/server.key (se non esiste già)2222 con credenziali predefinite:username: user1, password: pass123Apri un secondo terminale e connettiti via SSH:
ssh user1@localhost -p 2222
Verrai inserito nella shell simulata se le credenziali corrispondono.
Per fermare il container:
docker ps # Trova l'ID del container
docker stop <container_id>
Per rimuovere l'immagine:
docker rmi sshintel
Puoi anche esportare l'immagine usando
docker save -o sshintel.tar sshintele caricarla successivamente condocker load -i sshintel.tar.
Questo progetto è concesso in licenza sotto la Licenza MIT.