
Python 스크립트로 GeoServer WFS 엔드포인트를 인벤토리화하고 PostGIS/GeoTools의 시간 기반 SQL 인젝션 취약점을 검증하며, 승인된 테스트를 위한 전용 PoC 모드를 제공합니다.
이 저장소는 GeoServer WFS 엔드포인트를 조사하기 위한 두 개의 Python 스크립트를 포함합니다.
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
스크린 통과는 아직 긍정적 결과가 아닙니다. 두 번째로 더 긴 측정도 통과해야만 매개변수 블록이 출력됩니다.
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 요소를 추출하고 ID 또는 숫자 유사 이름을 가진 문자열/JSON 필드를 선택합니다.
후보는 호출 방식에 따라 검사됩니다:
--sleep 없음: 샘플 값이 구문적으로 유효한 JSON이어야 합니다.--sleep N 포함: 제어 요청과 시간 기반 검사 요청이 측정됩니다. JSON 값 검사는 건너뜁니다.결과가 즉시 출력되고 플러시됩니다.
그 후에만 실행 중인 GetCapabilities 응답에서 다음 typeName이 읽힙니다.
따라서 첫 번째 결과가 나타나기 전에 큰 GetCapabilities 응답을 완전히 처리할 필요가 없습니다.
--sleep 없이 자동 모드는 기본적으로 ID 또는 숫자 유사 이름을 가진 문자열/JSON 필드를 고려합니다.
반면 --sleep 사용 시 --candidate-scope auto는 모든 단순 비지오메트리 필드를 사용합니다. XSD 유형과 ID 이름 패턴은 더 이상 타이밍 검사를 차단하지 않습니다. 이는 숫자, 날짜/부울 또는 공급업체별 XSD 유형에서 오탐(false negative)을 방지합니다.
인식된 이름 패턴은 다음과 같습니다:
id
*_id
*_fid
nr_*
*_nr
*nummer*
fid
uuid
guid
key
objectid
시간 기반 검사에서 필드 이름은 추가로 [A-Za-z_][A-Za-z0-9_]* 형식의 단순 식별자여야 합니다.
--sleep 없이 관찰된 값이 구문적으로 JSON으로 해석될 수 있는지 확인합니다. 따라서 예를 들어 문자열 "383205"도 내용이 유효한 JSON 숫자이므로 후보로 간주됩니다. 이 검사는 휴리스틱이며 취약점 증명이 아닙니다.
--sleep 1 사용 시 시간 측정만 결정합니다. 후보는 검사 요청이 제어 요청보다 요청된 sleep 시간의 최소 70%를 추가로 필요로 하는 경우 기본적으로 양성으로 간주됩니다. --timing-result-type auto는 먼저 resultType=hits를 확인하고 음성 결과가 나오면 resultType=results를 확인합니다.
잠정적으로 양성인 측정값은 반드시 더 긴 sleep 시간으로 확인됩니다. 명시적 --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
네임스페이스로 제한:
python3 wfs_inventory.py \
--url https://HOST \
--mode layers \
--namespace fink
python3 wfs_inventory.py \
--url https://HOST \
--mode fields \
--layer namespace:layer
각 필드는 이름, XSD 유형, nillable, id_candidate 및 usable_property가 포함된 JSON 객체로 출력됩니다.
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
모든 속성 내보내기:
python3 wfs_inventory.py \
--url https://HOST \
--mode values \
--layer namespace:layer \
--all-properties \
--max-features 100
--unique를 사용하면 선택된 필드 값의 동일한 조합이 한 번만 출력됩니다.
wfs_inventory.py 매개변수| 매개변수 | 기본값 | 설명 |
|---|---|---|
--url URL | 필수 | 호스트, GeoServer 기본 또는 전체 WFS 엔드포인트 |
--mode auto|layers|fields|values | auto | 실행할 운영 모드 |
--layer NAMESPACE:LAYER | – | 자동 모드를 하나의 피처 타입으로 제한; fields 및 values에 필수 |
--namespace PREFIX | – | 이 네임스페이스 접두사의 레이어만 고려 |
--capabilities-file FILE | – | 다운로드 대신 로컬 GetCapabilities 응답 사용 |
--field NAME | 반복 가능 | values 모드에서 내보낼 속성 |
--all-properties | 꺼짐 | values 모드에서 모든 속성 내보내기 |
--unique | 꺼짐 | 중복 필드 값 조합 억제 |
--page-size N | 500 | GetFeature 페이지당 피처 수; 범위 1~5000 |
--sample-size N | 5 | JSON 구문 검사를 위한 레이어당 샘플 값 수; 범위 1~100 |
--sleep SECONDS | 0 | 시간 기반 검증 활성화; 0 또는 1~10초 허용 |
--candidate-scope auto|id|all | auto | 후보 선택; auto는 sleep 없이 ID 필드를, sleep 사용 시 모든 비지오메트리 필드를 사용 |
--timing-result-type auto|hits|results | auto | 타이밍 검사의 쿼리 경로; auto는 hits를 시도한 후 results를 시도 |
--sleep-threshold RATIO | 0.7 | 필요한 sleep 시간 비율; 범위 0.5~1.0 |
--confirm-sleep SECONDS | 0/자동 | 확인 sleep; 0은 첫 번째 sleep 시간의 최소 3배 사용, 범위 1~10 |
--start-layer-index N |
geoserver_sqli_working.py는 인벤토리 기능을 직접 호출할 수 있습니다. --valid-fields가 지정되면 인벤토리만 실행되고 프로그램이 종료됩니다.
python3 geoserver_sqli_working.py \
--target https://HOST \
--valid-fields 4 \
--sleep 1 \
--valid-diagnose output.txt
내부적으로 다음 매개변수가 wfs_inventory.py에 전달됩니다:
--target -> --url
--valid-fields -> --valid-fields
--valid-diagnose -> --valid-diagnose
--sleep -> --sleep
--candidate-scope -> --candidate-scope
--timing-result-type -> --timing-result-type
--sleep-threshold -> --sleep-threshold
--confirm-sleep -> --confirm-sleep
명시적 --sleep 없이 인벤토리 모드에서 시간 기반 검사는 비활성화된 상태로 유지됩니다.
명시적으로 인가된 테스트 시스템에만 해당:
python3 geoserver_sqli_working.py \
--target https://HOST/geoserver/wfs \
--typename namespace:layer \
--field_name FIELD \
--sleep 5
PoC 모드에서는 대상 경로가 자동으로 정규화되지 않습니다. 여기서는 전체 WFS 엔드포인트를 지정해야 합니다.
이 모드는 먼저 기준선/sleep 테스트를 수행하고, 기존 시간 기반 오라클 변형을 테스트한 다음, 성공적인 확인 시 기본적으로 서버/데이터베이스 메타데이터를 읽습니다. --query로 대신 사용자 정의 스칼라 쿼리를 지정할 수 있습니다.
PoC 모드는 현재 내부적으로 TLS 인증서 검사를 비활성화합니다. 순수 인벤토리의 경우 TLS가 기본적으로 검사되는
wfs_inventory.py를 사용하는 것이 좋습니다.
geoserver_sqli_working.py 매개변수| 매개변수 | 기본값 | 설명 |
|---|---|---|
--target URL | 필수 | 대상 호스트 또는 WFS 엔드포인트; PoC 모드에서는 전체 WFS 경로 사용 |
--typename NAME | fink_bku:fink_meta_mitte_suedwest | PoC 모드의 피처 타입 |
--field_name NAME | PoC 모드에서 필수 | jsonArrayContains용 단순 XSD 필드 이름 |
--field-name NAME | 별칭 | --field_name의 별칭 |
--valid-fields N | – | 인벤토리 모드 활성화 및 N개의 유효한 레이어 후 중지 |
--valid-diagnose FILE | – | 상세 인벤토리 보고서를 FILE에 쓰기; --valid-fields 필요 |
--sleep SECONDS | PoC: 5, 인벤토리: 꺼짐 | 각 모드의 sleep 기간 |
--candidate-scope auto|id|all | auto | 인벤토리 모드의 후보 선택 |
--timing-result-type auto|hits|results | auto | 인벤토리 모드의 타이밍 쿼리 경로 |
--sleep-threshold RATIO | 0.7 | 인벤토리 모드의 타이밍 임계값 |
--confirm-sleep SECONDS | 자동 | 인벤토리 모드의 확인 sleep |
--query SQL | – | PoC 모드의 사용자 정의 스칼라 쿼리 |
--debug | 꺼짐 | PoC 모드에서 조건, 실행 시간 및 결정 표시 |
자동 모드는 텍스트 블록 대신 JSON Lines를 생성할 수 있습니다:
python3 wfs_inventory.py \
--url https://HOST \
--valid-fields 10 \
--report-format jsonl \
--output report.jsonl
--diagnose 사용 시 각 레코드에는 URL, 후보 메타데이터, 검사 값 및 필드별 GetFeature URL이 추가로 포함됩니다.
프록시 사용:
python3 wfs_inventory.py \
--url https://HOST \
--proxy http://127.0.0.1:8080 \
--valid-fields 4
자체 프록시 CA 신뢰:
python3 wfs_inventory.py \
--url https://HOST \
--proxy http://127.0.0.1:8080 \
--proxy-ca proxy-ca.pem \
--valid-fields 4
인가된 테스트 시스템에 대한 TLS 검사 비활성화:
python3 wfs_inventory.py \
--url https://HOST \
--insecure \
--valid-fields 4
--proxy-ca와 --insecure는 함께 사용할 수 없습니다.
큰 GetCapabilities 응답의 경우 다음 옵션이 도움이 됩니다:
python3 wfs_inventory.py \
--url https://HOST \
--valid-fields 4 \
--max-layers 100 \
--sample-size 1 \
--timeout 10 \
--retries 0 \
--delay 0
참고 사항:
GetCapabilities는 한 번만 요청된 후 스트리밍됩니다.--valid-fields 4는 4개의 유효한 레이어 후에만 스캔을 종료합니다. 더 적은 결과가 존재하면 검색은 끝까지 또는 --max-layers까지 실행됩니다.--sample-size 1은 JSON 휴리스틱의 비용을 줄입니다.--timing-result-type auto에서는 음성 hits 결과 후 추가로 두 개의 results 요청이 실행됩니다.--candidate-scope id는 타이밍 요청 수를 줄이지만 다른 이름의 취약한 필드를 놓칠 수 있습니다.--namespace 및 --start-layer-index는 검색 공간을 추가로 제한할 수 있습니다.The read operation timed out--timeout을 늘립니다.--retries 0을 설정합니다.--max-layers 및 --namespace를 사용합니다.--sample-size 1을 사용합니다.--sleep 없이 후보는 --candidate-scope에 따라 XSD/이름 검사와 JSON 구문 검사를 통과해야 합니다.--sleep 사용 시 시간적으로 확인된 후보만 매개변수 블록으로 출력됩니다; 음성 측정값은 stderr에 [sleep-check]로 표시됩니다.--max-layers를 설정합니다.Cannot do natural order without a primary key첫 번째 GetFeature 페이지의 경우 스크립트는 startIndex=0을 보내지 않습니다. 일부 GeoServer/JDBC 레이어는 기본 키 없이도 자연 정렬을 강제하기 때문입니다. 추가 페이지를 내보낼 때 이러한 레이어는 여전히 기본 키 또는 서버 측 지원 정렬이 필요할 수 있습니다.
schema does not define ...Type스크립트는 일반적인 <LayerName>Type과 전역 XSD 레이어 요소에서 참조되거나 익명인 다른 complexType을 모두 고려합니다. 오류가 지속되면 해당 DescribeFeatureType 응답을 --diagnose로 확인해야 합니다.
전체 OWS 오류 메시지가 stderr에 출력됩니다. 일반적인 원인은 지원되지 않는 속성, 서버 측 페이징 설정 또는 레이어별 데이터 소스 구성입니다.
python3 wfs_inventory.py --help
python3 geoserver_sqli_working.py --help
0 |
| 처음 N개의 스트리밍된 레이어 건너뛰기 |
--max-layers N | 0 | 최대 N개 레이어 처리; 0은 무제한 |
--valid-fields N | 0 | N개의 유효한 레이어 블록 후 중지; 0은 무제한 |
--valid N | 별칭 | --valid-fields의 하위 호환 별칭 |
--max-features N | 0 | values 모드에서 N개 피처 후 중지; 0은 무제한 |
--format jsonl|csv|text | jsonl | values 모드의 출력 형식 |
--output FILE | stdout | 보고서 또는 값을 파일에 쓰기 |
--report-format blocks|jsonl | blocks | 자동 보고서 형식 |
--diagnose | 꺼짐 | URL, 유형, 선택 플래그 및 검사 통계 추가 |
--valid-diagnose FILE | – | 진단 활성화 및 FILE에 직접 쓰기 |
--delay SECONDS | 0.1 | 결과/검사 단계 사이의 일시 중지 |
--timeout SECONDS | 30 | HTTP 요청당 타임아웃 |
--retries N | 2 | 타임아웃 또는 네트워크 오류 후 재시도; 범위 0~10 |
--proxy URL | – | HTTP(S) 프록시, 예: http://127.0.0.1:8080 |
--proxy-ca FILE | – | 프록시 인증서를 신뢰하기 위한 PEM CA 인증서 |
--insecure | 꺼짐 | TLS 인증서 검사 비활성화 |
--authorization TEXT | I_AM_AUTHORIZED | 보안 확인; 정확히 I_AM_AUTHORIZED여야 함 |