// 1 ZERO-DAY · 1 CVE · 1 EXPLOIT NELLE ULTIME 24H

Architettura di Rilevamento: Dove Guardare e Cosa Vedere

Hai trascorso le ultime quattro pagine a imparare come pensano gli attaccanti — concatenazione di stringhe, stacking UNION, probe blind basati sul tempo, l'automazione implacabile di sqlmap. Ora capovolgi la prospettiva. Sei tu che osservi ShopBox (192.0.2.10) dall'esterno, cercando di individuare quel medesimo lavoro in corso contro di te. La domanda non è se puoi rilevare l'SQL injection. È se puoi rilevare il tuo SQL injection — quello modellato per il tuo schema, i tuoi pattern di query, il tuo livello di rumore.

Questa pagina è un albero decisionale. Parti dalla radice con qualsiasi allarme ti abbia svegliato, segui i rami, e arrivi a un'azione concreta con un esempio concreto di ShopBox. Li ho ordinati per layer di rilevamento, ma la vera abilità è sapere quando un layer fallisce e un altro coglie ciò che ti è sfuggito.


Domanda Radice: Ho un allarme. Di che tipo?

Fonte di Allarme Prima Domanda Se Sì Se No
IDS/IPS di Rete (Suricata, Snort) Il payload è nel body della richiesta HTTP o nell'URL? → Ramo A: Corrispondenza firma su pattern noto → Ramo B: Codificato, frammentato, o in un header? Controlla le keyword HTTP
Web Application Firewall Il WAF l'ha bloccato, o solo loggato? → Ramo C: Bloccato — verifica nessun bypass → Ramo D: Solo loggato — risposta attiva immediata
Log applicativi (Apache/nginx di ShopBox) Il log mostra la query string completa? → Ramo E: Corrispondenza diretta pattern → Ramo F: Parametrizzato o body POST — serve ispezione più profonda
Log di audit del database (MySQL general log, pgAudit su 192.0.2.30) log_statement = all o pgAudit è attivo? → Ramo G: Ricostruzione completa query → Ramo H: Abilitalo ora — stai volando alla cieca

Ramo A: Network IDS — Hit Firma su Pattern Noto

Quando ha successo: Attacchi basati su UNION con keyword evidenti, probe error-based, pattern boolean classici. Le cose dalla Pagina 3 — exploit manuale con stringhe chiare come ' UNION SELECT.

Quando fallisce: Blind time-based (Pagina 4), dove il payload è semplicemente AND SLEEP(5). Nessun errore. Nessun dato extra nella risposta. La risposta HTTP appare identica. Ho visto Suricata 9.0.0-dev navigare oltre una run time-based di sqlmap per sei ore perché le soglie di rilevamento predefinite dello strumento si aspettano anomalie visibili. I pacchetti erano puliti. Il timing era il segnale, e Suricata non lo misura tra sessioni.

Esempio concreto ShopBox — rilevazione UNION:

Ecco una regola Suricata che ha catturato il nostro probe UNION manuale contro la ricerca prodotti:

alert http $EXTERNAL_NET any -> $HOME_NET any ( msg:"SHOPBOX UNION SQLi in search parameter"; flow:established,to_server; http.uri; content:"search="; http.uri; content:"UNION"; fast_pattern; content:"SELECT"; http.uri; content:"FROM"; classtype:web-application-attack; sid:1000001; rev:1;
)

Perché questo conta: fast_pattern dice al multi-pattern matcher di Suricata di dare priorità a "UNION" come ancoraggio. Senza di esso, il motore scansiona prima per il più lungo "search=", sprecando cicli su ogni richiesta legittima. Su un'istanza ShopBox trafficata, quella latenza conta — i pacchetti persi sono attacchi mancati.

Ma quella regola è inutile contro questo payload dalla nostra run blind:

search=test' AND (SELECT * FROM (SELECT(SLEEP(5)))a) AND 'a'='a

Nessun UNION. Nessun SELECT nell'URI che la regex cattura pulitamente. Il SLEEP è sepolto in una subquery. Ho dovuto costruire una seconda regola usando http.user_agent perché l'UA predefinito di sqlmap si annuncia — ma un attaccante reale la cambia in cinque secondi.

Verità segnale-rumore: Sulla rete di training di ShopBox, con studenti che la martellano, quella regola UNION si attiva 200+ volte al giorno da stringhe di ricerca legittime contenenti "UNION" (descrizioni prodotto, contenuto generato dagli utenti). L'ho tarata per richiedere sia UNION che SELECT ... FROM entro 30 byte. I falsi positivi sono scesi a due a settimana. I falsi negativi? Sconosciuti per definizione — è il compromesso.


Ramo C/D: Web Application Firewall — Bloccato o Loggato?

Un WAF (Web Application Firewall, un reverse proxy che ispeziona il traffico HTTP prima che raggiunga la tua applicazione) posizionato davanti a ShopBox vede ciò che vede l'IDS, e in più può far rispettare — bloccare, limitare la rate, sfidare. Ma i WAF hanno due modalità di fallimento, e una è peggiore dell'altra.

Azione WAF Cosa Fai Razionale
Bloccato (Ramo C) Verifica che il blocco fosse corretto, poi caccia varianti di bypass Gli attaccanti sondano i WAF come sondano il SQL — aspettati un seguito
Solo loggato (Ramo D) Escalation immediata — perché non ha bloccato? Gap di policy, soglia mancata, o evasione in corso

⚠️ Solo per uso autorizzato e difensivo.

Il caso solo-loggato è dove ho trovato il male più grande. Un WAF configurato in modalità apprendimento, o con una regola impostata su "alert" perché qualche unità aziendale ha urlato per i falsi positivi. Ho una volta ricostruito una violazione di ShopBox fino a un WAF che loggava 1' AND 1=1-- ma non 1' AND 1=1# — la variante commento è scivolata via perché la regola usava una corrispondenza letterale --. L'attaccante ha trovato il varco in venti minuti.

Azione di triage: Se il tuo WAF l'ha loggato, estrai la catena completa di richieste. L'SQL injection è raramente singolo colpo. Cerca:

  • Richieste precedenti: 1', 1'', 1'-- — sequenza di probe
  • Richieste successive: stringhe più lunghe, riferimenti a schema (information_schema, pg_catalog)
  • Cluster temporali: richieste a velocità macchina (default sqlmap: 1 req/sec con --delay=0)

Ramo E/F: Log Applicativi — Cosa Ha Visto il Web Server

I log Apache di ShopBox su 192.0.2.10 registrano il layer HTTP. Se l'applicazione logga la query string completa, puoi fare grep di artefatti. Ma "completo" sta facendo un lavoro pesante qui.

Ramo E — Query string completa visibile:

# Su ShopBox Apache, il formato log tipico include la query string
grep -E "(UNION|SELECT|INSERT|DELETE|DROP|sleep\(|benchmark\()" \ /var/log/apache2/shopbox-access.log | head -20

Perché questo conta: Le corrispondenze sleep( e benchmark( prendono di mira indicatori blind time-based che l'IDS di rete spesso manca. I log applicativi vedono il parametro raw prima che il database lo esegua.

Ramo F — Parametrizzato o body POST oscurato:

I framework moderni loggano la route, non il body. Una POST su /api/search con body JSON {"query": "test' AND SLEEP(5)--"} non lascia traccia nei log Apache predefiniti. Serve logging a livello applicazione — il codice stesso di ShopBox che scrive su /var/log/shopbox/app.log — o sei alla cieca.

In termini semplici: Il web server vede la busta; l'applicazione vede la lettera dentro. Se logghi solo le buste, non puoi leggere la minaccia.


Ramo G: Log di Audit del Database — La Verità Assoluta

È qui che Samuel diventa religioso. IDS di rete e WAF indovinano l'intento. I log del database sanno cosa è stato eseguito.

MySQL su 192.0.2.20: Abilita general_log o usa il plugin di audit. Il general log mostra ogni statement come ricevuto.

PostgreSQL su 192.0.2.30: Due layer. Il log_statement = all standard ti dà le basi — ogni testo di statement. pgAudit estende questo con campi strutturati: classe di statement, tipo di comando, oggetto toccato, parametri bound. Verifica la tua release per le capacità attuali; le configurazioni variano.

# postgresql.conf su 192.0.2.30 — illustrativo, verifica per la tua versione di pgAudit
shared_preload_libraries = 'pgaudit'
pgaudit.log = 'write, ddl' # meno volume di 'all', cattura le cose pericolose

Perché questo conta: pgaudit.log = 'all' su un ShopBox di produzione genererebbe centinaia di GB al giorno — l'ho imparato a mie spese durante una scansione di compliance. Il volume schiaccia il tuo log shipper e il budget del tuo SIEM. Inizia mirato: write (INSERT, UPDATE, DELETE) e ddl (cambi di schema). L'esfiltrazione basata su SELECT non apparirà, ma catturerai la distruzione dati e la creazione di backdoor table.

Formato output pgAudit — taggato con AUDIT: e campi strutturati. Spedisci questo off-host immediatamente; lo storage locale è un bersaglio di cancellazione.

# output illustrativo — verifica sul tuo target
AUDIT: SESSION,1,1,DDL,CREATE TABLE,TABLE,public.backdoor,"CREATE TABLE backdoor (data text)",<not logged>

Realtà segnale-rumore: I log di audit del database sono basso-rumore, alto-segnale per attacchi riusciti. Ma perdono il probe che l'applicazione sanifica via. Servono entrambi: layer di rete per il tentativo, layer database per il successo.


Costruire la Correlazione: Da Singola Query a Pattern di Attacco

Nessun log singolo racconta la storia. L'attacco UNION dalla Pagina 3 che Suricata ha catturato? L'ho trovato perché l'allarme correlava con una entry del general log MySQL che mostrava SELECT ... UNION SELECT password FROM users--. Il blind time-based dalla Pagina 4? Suricata l'ha mancato completamente. L'ho trovato solo perché la run di sei ore di sqlmap ha prodotto un pattern nei log applicativi: parametri search= identici con timing variato al microsecondo, sempre restituendo HTTP 200, nessun body di errore.

Query di correlazione Splunk/ELK — struttura illustrativa, adatta al tuo schema:

# Splunk — illustrativo, verifica i nomi dei campi nel tuo ambiente
index=shopbox (source="suricata" OR source="shopbox-app" OR source="mysql-audit")
| eval attack_phase=case( match(_raw, "UNION|SELECT.*FROM"), "exploitation", match(_raw, "SLEEP\(|BENCHMARK\("), "blind-probe", match(_raw, "information_schema|pg_catalog"), "enumeration", 1=1, "other" )
| stats dc(attack_phase) as phase_count, values(src_ip) as attacker_ips, range(_time) as duration_seconds by session_id
| where phase_count >= 2 AND duration_seconds > 300

Perché questo conta: Questo cerca sessioni che colpiscono più fasi di attacco in oltre cinque minuti — il segno distintivo di exploit manuale o automatizzato, non un probe isolato. Uno scanner potrebbe colpire information_schema poi svanire. sqlmap in esecuzione blind ciclerà attraverso enumerazione, conferma ed estrazione per ore.

In termini semplici: Una query strana è rumore. Lo stesso IP sorgente che colpisce la tua search box con SLEEP(5), poi SLEEP(10), poi una query di schema, poi una UNION — quello è un attacco che si svolge al rallentatore.


Il Flusso di Triage del Risponditore

Quando la correlazione scatta, non ripari. Verifichi, delimiti la portata, contieni, eradichi — e tratto questo come checklist letterale, non suggerimento.

Passo Punto Decisionale Azione ShopBox
Allarme Qualsiasi fonte scatta Apri ticket, timestamp, preserva i log
Verifica È SQLi reale o falso positivo? Ricostruisci la query completa dai log database; replay in lab se necessario
Delimitazione Quali host? Quali dati? Controlla 192.0.2.20 (MySQL) e 192.0.2.30 (PostgreSQL) per SELECT non autorizzati in outfile o COPY TO
Contenimento Possiamo bloccare senza rompere ShopBox? Aggiornamento regola WAF, isolamento segmento di rete, disabilitazione feature di ricerca colpita
Eradicazione Cosa hanno lasciato dietro? Caccia UDF, nuove tabelle, utenti alterati, web shell; confronta schema con known-good

Intuizione guadagnata: Ho visto analisti saltare "verifica" e firewallare un IP che si è rivelato un crawler di motore di ricerca con fuzzing aggressivo dei parametri. Ho visto "delimitazione" mancato perché l'attaccante ha pivotato da MySQL a PostgreSQL dopo il fallimento iniziale — stesso ShopBox, backend diverso, singola svista. Il flusso è sequenziale per un motivo: contieni prima di verificare, e potresti bloccare ricavi legittimi; eradica prima di delimitare la portata, e ti perdi il backdoor che hanno piantato nell'altro database.


Quando Continuare a Leggere

La Pagina 6 copre cosa succede quando questa architettura fallisce — una vera violazione di ShopBox dove abbiamo mancato la finestra di correlazione. La Pagina 7 costruisce le difese che rendono il rilevamento meno critico. Ma non puoi costruire difesa senza sapere dove i tuoi occhi sono deboli. Audita i tuoi layer di rilevamento ora: IDS di rete per l'ovvio, WAF per l'imposto, log applicativi per il contesto, audit database per la verità. Poi lega insieme il tutto, o accetta che vedrai solo gli attacchi che vogliono essere visti.

Lettura consigliata