
Python-скрипты для инвентаризации конечных точек GeoServer WFS и проверки уязвимостей time-based SQL-инъекций в PostGIS/GeoTools, с выделенным режимом PoC для авторизованного тестирования.
Этот репозиторий содержит два Python-скрипта для исследования GeoServer-WFS-конечных точек.
wfs_inventory.pyНазначение: Инвентаризация слоёв, XSD-полей и WFS-значений, а также опциональная проверка кандидатов с помощью проверки на основе времени.
Примеры запуска:
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.pyНазначение: Комбинированная точка входа для инвентаризации, а также отдельный режим PoC.
Примеры запуска:
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()"
Важное примечание: Проверка на основе времени и режим PoC должны использоваться только против систем, для которых имеется явное разрешение на тестирование. Обычный режим инвентаризации использует исключительно стандартные операции WFS.
Опционально сделать исполняемыми:
chmod +x wfs_inventory.py geoserver_sqli_working.py
python3 wfs_inventory.py \
--url https://HOST \
--valid-fields 4
Стандартный путь /geoserver/wfs добавляется автоматически. Следующие
указания эквивалентны:
https://HOST
https://HOST/geoserver
https://HOST/geoserver/wfs
При нестандартной установке необходимо указать полный путь WFS.
Только для явно авторизованных систем:
python3 wfs_inventory.py \
--url https://HOST \
--valid-fields 4 \
--sleep 1
Во время проверки для каждого кандидата на 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
Пройденный screen-тест ещё не является положительным результатом. Только если второе, более длительное измерение также проходит, выводится блок параметров.
python3 wfs_inventory.py \
--url https://HOST \
--valid-fields 4 \
--sleep 1 \
--valid-diagnose output.txt
--valid-diagnose FILE автоматически активирует подробную диагностику и
записывает её в указанный файл.
Стандартный режим auto обрабатывает WFS-информацию в следующем порядке:
GetCapabilities открывается один раз:
/geoserver/wfs?service=WFS&acceptVersions=2.0.0&request=GetCapabilities
XML-ответ обрабатывается потоково. Как только найден FeatureType/Name,
определяется следующий typeName.
Для этого слоя немедленно выполняется DescribeFeatureType с
version=2.0.0.
Скрипт извлекает XSD-элементы и выбирает строковые/JSON-поля с ID- или номероподобным именем.
Кандидат проверяется в зависимости от вызова:
--sleep: выборочные значения должны быть синтаксически корректным JSON.--sleep N: измеряются контрольный запрос и проверочный запрос на основе
времени. Проверка JSON-значений при этом пропускается.Результат немедленно выводится и сбрасывается (flush).
Только после этого считывается следующий typeName из текущего
GetCapabilities-ответа.
Благодаря этому большой GetCapabilities-ответ не нужно полностью обрабатывать
до появления первого результата.
Без --sleep автоматический режим по умолчанию учитывает
строковые/JSON-поля с ID- или номероподобным именем.
С --sleep режим --candidate-scope auto использует, наоборот, все простые
негеометрические поля. XSD-тип и шаблон ID-имени больше не блокируют проверку
времени. Это предотвращает ложные отрицательные результаты для числовых,
дата/булевых или специфических для производителя XSD-типов.
Распознаваемые шаблоны имён включают:
id
*_id
*_fid
nr_*
*_nr
*nummer*
fid
uuid
guid
key
objectid
При проверке на основе времени имя поля дополнительно должно быть простым
идентификатором в формате [A-Za-z_][A-Za-z0-9_]*.
Без --sleep проверяется, можно ли интерпретировать наблюдаемые значения
синтаксически как JSON. Поэтому, например, строка "383205" также считается
кандидатом, поскольку её содержимое представляет собой допустимое JSON-число.
Эта проверка является эвристикой и не является доказательством уязвимости.
С --sleep 1 решает исключительно измерение времени. Кандидат по умолчанию
считается положительным, если проверочный запрос по сравнению с контрольным
требует дополнительно не менее 70 процентов запрошенного времени сна.
--timing-result-type auto сначала проверяет resultType=hits, а при
отрицательном результате затем resultType=results.
Предварительно положительные измерения обязательно подтверждаются более
длительным временем сна. Без явного --confirm-sleep скрипт использует
max(3, --sleep * 3), ограниченное 10 секундами. Благодаря этому единичный
пик задержки при --sleep 1 больше не приводит к vulnerable=true.
Стандартный вывод содержит один блок на каждый допустимый слой:
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 содержит нормализованную WFS-конечную точку и подходящие
значения для --typename и --field_name.
--valid-fields N считает блоки слоёв, а не отдельные поля. Если существует
меньше N допустимых слоёв, остальной каталог продолжает исследоваться.
С помощью --max-layers можно ограничить максимальное время выполнения.
Опции --diagnose или --valid-diagnose FILE дополняют вывод, среди прочего:
GetCapabilities-URL,DescribeFeatureType-URL,GetFeature-URL иПример:
python3 wfs_inventory.py \
--url https://HOST \
--valid-fields 10 \
--valid-diagnose diagnose.txt
python3 wfs_inventory.py \
--url https://HOST \
--mode layers
Ограничить по namespace:
python3 wfs_inventory.py \
--url https://HOST \
--mode layers \
--namespace fink
python3 wfs_inventory.py \
--url https://HOST \
--mode fields \
--layer namespace:layer
Каждое поле выводится как JSON-объект с именем, XSD-типом, nillable,
id_candidate и usable_property.
python3 wfs_inventory.py \
--url https://HOST \
--mode values \
--layer namespace:layer \
--field FIELD_A \
--field FIELD_B \
--max-features 100 \
--format jsonl \
--output values.jsonl
Экспорт всех свойств: