
Script Python per inventariare gli endpoint WFS di GeoServer e verificare vulnerabilità di SQL injection basate sul tempo in PostGIS/GeoTools, con una modalità PoC dedicata per test autorizzati.
Questo repository contiene due script Python per l'analisi degli endpoint WFS di GeoServer.
wfs_inventory.pyScopo: Inventariare layer, campi XSD e valori WFS, nonché verificare opzionalmente i candidati tramite un controllo basato sul tempo.
Esempi di esecuzione:
python3 wfs_inventory.py --url https://HOST --valid-fields 4
python3 wfs_inventory.py --url https://HOST --valid-fields 4 --sleep 1 --confirm-sleep 5 --candidate-scope auto --timing-result-type auto
python3 wfs_inventory.py --url https://HOST --layer namespace:layer --sleep 1 --confirm-sleep 5 --valid-diagnose output.txt
geoserver_sqli_working.pyScopo: Punto di ingresso combinato per l'inventario e una modalità PoC separata.
Esempi di esecuzione:
python3 geoserver_sqli_working.py --target https://HOST --valid-fields 4 --sleep 1 --confirm-sleep 5
python3 geoserver_sqli_working.py --target https://HOST/geoserver/wfs --typename namespace:layer --field_name FIELD --sleep 5
python3 geoserver_sqli_working.py --target https://HOST/geoserver/wfs --typename namespace:layer --field_name FIELD --sleep 5 --query "SELECT current_database()"
Nota importante: Il controllo basato sul tempo e la modalità PoC devono essere utilizzati solo contro sistemi per i quali esiste un'autorizzazione esplicita al test. La normale modalità di inventario utilizza esclusivamente operazioni WFS regolari.
Rendere opzionalmente eseguibili:
chmod +x wfs_inventory.py geoserver_sqli_working.py
python3 wfs_inventory.py \
--url https://HOST \
--valid-fields 4
Il percorso predefinito /geoserver/wfs viene aggiunto automaticamente. Le seguenti indicazioni sono quindi equivalenti:
https://HOST
https://HOST/geoserver
https://HOST/geoserver/wfs
In caso di installazione diversa, è necessario specificare il percorso WFS completo.
Solo per sistemi esplicitamente autorizzati:
python3 wfs_inventory.py \
--url https://HOST \
--valid-fields 4 \
--sleep 1
Durante il controllo, per ogni candidato appare una misurazione su stderr:
[sleep-check] phase=screen typeName=namespace:layer field_name=FIELD resultType=hits baseline=0.120s test=1.128s delta=1.008s passed=true
[sleep-check] phase=confirm typeName=namespace:layer field_name=FIELD resultType=hits requested=3s baseline=0.118s test=3.125s delta=3.007s vulnerable=true
Un screen superato non è ancora un esito positivo. Solo se anche la seconda misurazione, più lunga, viene superata, viene emesso un blocco di parametri.
python3 wfs_inventory.py \
--url https://HOST \
--valid-fields 4 \
--sleep 1 \
--valid-diagnose output.txt
--valid-diagnose FILE attiva automaticamente la diagnosi dettagliata e la scrive nel file specificato.
La modalità predefinita auto elabora le informazioni WFS in questo ordine:
GetCapabilities viene aperto una volta:
/geoserver/wfs?service=WFS&acceptVersions=2.0.0&request=GetCapabilities
La risposta XML viene trasmessa in streaming. Non appena viene trovato un FeatureType/Name, il successivo typeName è determinato.
Per questo layer viene eseguito immediatamente DescribeFeatureType con version=2.0.0.
Lo script estrae gli elementi XSD e seleziona i campi stringa/JSON con nomi simili a ID o numerici.
Il candidato viene verificato a seconda della chiamata:
--sleep: i valori campione devono essere JSON sintatticamente valido.--sleep N: vengono misurate una richiesta di controllo e una richiesta di verifica basata sul tempo. Il controllo del valore JSON viene saltato.Il risultato viene emesso immediatamente e flushato.
Solo successivamente viene letto il successivo typeName dalla risposta GetCapabilities in corso.
In questo modo non è necessario elaborare completamente una grande risposta GetCapabilities prima che appaia il primo risultato.
Senza --sleep, la modalità automatica considera per impostazione predefinita i campi stringa/JSON con nomi simili a ID o numerici.
Con --sleep, --candidate-scope auto utilizza invece tutti i semplici campi non geometrici. Il tipo XSD e il pattern del nome ID non bloccano più il controllo temporale. Ciò previene falsi negativi per tipi XSD numerici, data/booleani o specifici del produttore.
I pattern di nome riconosciuti includono:
id
*_id
*_fid
nr_*
*_nr
*nummer*
fid
uuid
guid
key
objectid
Nel controllo basato sul tempo, il nome del campo deve inoltre essere un semplice identificatore nel formato [A-Za-z_][A-Za-z0-9_]*.
Senza --sleep, viene verificato se i valori osservati possono essere interpretati sintatticamente come JSON. Pertanto, ad esempio, anche la stringa "383205" è considerata un candidato, perché il suo contenuto rappresenta un numero JSON valido. Questo controllo è un'euristica e non una prova di vulnerabilità.
Con --sleep 1, decide esclusivamente la misurazione del tempo. Un candidato è considerato positivo per impostazione predefinita se la richiesta di verifica richiede almeno il 70 percento in più del tempo di sleep richiesto rispetto alla richiesta di controllo. --timing-result-type auto verifica prima resultType=hits e, in caso di risultato negativo, successivamente resultType=results.
Le misurazioni provvisoriamente positive vengono obbligatoriamente confermate con un tempo di sleep più lungo. Senza un --confirm-sleep esplicito, lo script utilizza max(3, --sleep * 3), limitato a 10 secondi. In questo modo un singolo picco di latenza con --sleep 1 non porta più a vulnerable=true.
L'output standard contiene un blocco per ogni layer valido:
typeName=namespace:layer
field_name1=FIELD_A
parameter_string1=https://HOST/geoserver/wfs --typename namespace:layer --field_name FIELD_A
field_name2=FIELD_B
parameter_string2=https://HOST/geoserver/wfs --typename namespace:layer --field_name FIELD_B
parameter_stringN contiene l'endpoint WFS normalizzato e i valori appropriati per --typename e --field_name.
--valid-fields N conta i blocchi di layer, non i singoli campi. Se esistono meno di N layer validi, il catalogo rimanente viene ulteriormente esaminato. Con --max-layers è possibile limitare il tempo di esecuzione massimo.
Le opzioni --diagnose o --valid-diagnose FILE aggiungono tra l'altro:
GetCapabilities utilizzata,DescribeFeatureType,GetFeature generata eEsempio:
python3 wfs_inventory.py \
--url https://HOST \
--valid-fields 10 \
--valid-diagnose diagnose.txt
python3 wfs_inventory.py \
--url https://HOST \
--mode layers
Limitare a un namespace:
python3 wfs_inventory.py \
--url https://HOST \
--mode layers \
--namespace fink
python3 wfs_inventory.py \
--url https://HOST \
--mode fields \
--layer namespace:layer
Ogni campo viene emesso come oggetto JSON con nome, tipo XSD, nillable, id_candidate e usable_property.