Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
أدوات/GitHubGitHub/dylan-chainguard/cve-2026-22732-poc
أدوات دفاعيةتحليل الثغرات الأمنيةالاستغلالالمحاكاة الافتراضية للأمانأمن الويبالتعلم والتعليم
GitHubdylan-chainguard/cve-2026-22732-poc

cve-2026-22732-poc

إثبات مفهوم يوضح CVE-2026-22732، وهو خلل في Spring Security حيث يؤدي setIntHeader("Content-Length") إلى إسقاط جميع ترويسات الأمان، مع إصدارات قابلة للاستغلال ومصححة.

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة
عرض المستودع
منذ 2س 52دلم تتم المراجعة بعد

CVE-2026-22732 — إثبات المفهوم

يقوم Spring Security بإسقاط رؤوس أمان استجابة HTTP بصمت. للعرض / الاستخدام التعليمي فقط؛ شغّله فقط مقابل هذا التطبيق المحلي.

CVECVE-2026-22732 (CWE-425)، نُشر في 2026-03-19
CVSS 3.19.1 حرج — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
التبعية المباشرةspring-boot-starter-web + spring-boot-starter-security 2.7.18
المكوّن المصابspring-security-web / -config / -core 5.7.11 — عابر فقط، لا يُذكر أبدًا في pom.xml
المكوّن المُصلَّحspring-security-web 5.7.14-0.cgr.2، يُوصَل إليه بتغيير <version> واحد — انظر الانتقال
تم التحقق علىTomcat 9.0.118، JDK 17.0.18، macOS arm64

النطاقات المتأثرة: 5.7.0–5.7.21، 5.8.0–5.8.23، 6.3.0–6.3.14، 6.4.0–6.4.14، 6.5.0–6.5.8، 7.0.0–7.0.3. يثبّت Spring Boot 2.7.18 إصدار Spring Security 5.7.11، وهو تمامًا داخل النطاق الأول:

root@kitploit:~
$ mvn dependency:tree -Dincludes=org.springframework.security
+- org.springframework.security:spring-security-config:jar:5.7.11:compile
|  \- org.springframework.security:spring-security-core:jar:5.7.11:compile
\- org.springframework.security:spring-security-web:jar:5.7.11:compile

تشغيله

root@kitploit:~
./run.sh        # terminal 1 — builds and starts on :8080 (pins JDK 17)
./exploit.sh    # terminal 2 — drives every endpoint, diffs the headers

يثبّت run.sh قيمة JAVA_HOME لأن Spring Boot 2.7.x لا يمكنه العمل على JDK 25 الذي يحلّه mvn افتراضيًا على هذا الجهاز. تجاوزه باستخدام JAVA_HOME_17=/path/to/jdk17.

كما يبني باستخدام -s settings-chainguard.xml افتراضيًا، لأن الوالد المُصلَّح غير موجود على Maven Central. اضبط MAVEN_SETTINGS=/path/to/your/settings.xml للإشارة إلى مكان آخر، أو MAVEN_SETTINGS= للبناء من Central فقط — وهو ما يعمل مع 2.7.18 الأصلي فقط.

يقرأ exploit.sh إصدارات spring-security-web وspring-boot الفعلية من target/*.jar، لذا تُبلغ لافتته دائمًا عمّا يعمل فعليًا بدلًا من نص ثابت.

الإعداد

لا يطبّق SecurityConfig أي تخصيص للرؤوس على الإطلاق — الإعدادات الافتراضية لـ Spring Security سارية، وهو بالضبط ما يعتمد عليه تطبيق واعٍ أمنيًا. تُعيد كل نقطة نهاية نفس الجسم الحساس:

root@kitploit:~
{"account":"4111-1111-1111-1111","holder":"D. Havelock","balance":"82914.55"}

الشيء الوحيد الذي يتغيّر هو كيفية كتابة المتحكّم للاستجابة.

النتائج المقاسة

root@kitploit:~
BASELINE  standard Spring MVC return value
  /safe/account                    OK        all 6 headers delivered

CONTROL   getOutputStream(), body > 8 KB buffer
  /vuln/stream/account             OK        all 6 headers delivered

CONTROL   explicit response.flushBuffer()
  /vuln/flush/account              OK        all 6 headers delivered

EXPLOIT   setIntHeader("Content-Length", n)  <-- CVE-2026-22732
  /vuln/content-length/account     BYPASSED  ALL 6 security headers dropped

BY DESIGN application sets its own Expires header (NOT this CVE)
  /vuln/cache/account              PARTIAL   Cache-Control + Pragma dropped

فقط /vuln/content-length/account تتغيّر حالته عند ترقيع CVE، لذا فهو نقطة النهاية الوحيدة التي يستمدّ منها exploit.sh حكمه. والباقي عناصر تحكّم.

الثغرة — setIntHeader("Content-Length", n) → تجاوز كامل

ثلاثة أسطر من كود متحكّم يبدو عاديًا تجرّد كل رأس وعد به Spring Security:

root@kitploit:~
response.setContentType("application/json");
response.setIntHeader("Content-Length", body.length);
response.getOutputStream().write(body);
root@kitploit:~
$ curl -sD - -o /dev/null http://localhost:8080/vuln/content-length/account
HTTP/1.1 200
Content-Type: application/json
Content-Length: 77
Date: Tue, 01 Sep 2026 00:53:18 GMT

لا X-Frame-Options، لا X-Content-Type-Options، لا Cache-Control، لا Pragma، لا Expires، لا X-XSS-Protection. قارن مع /safe/account، الذي يحمل الستة جميعًا. الاستجابة قابلة للتأطير من أي أصل، وقابلة لاستنشاق MIME، وقابلة للتخزين المؤقت — بينما تخدم رقم بطاقة.

الحالة بحكم التصميم — رأس تخزين مؤقت يضبطه التطبيق → كبت التخزين المؤقت

تصحيح: نسخة سابقة من هذا README سمّت هذه "الاستغلال 2" وادّعت أنها الحالة التي توثّقها النشرة. هي ليست جزءًا من CVE-2026-22732 ولا يصلحها أي ترقية. CacheControlHeadersWriter متطابق بايت ببايت في 5.7.11 و5.7.14-0.cgr.2 و6.5.8 (آخر إصدار مصاب) و 6.5.9 (أول إصدار مُصلَّح) — تم التحقق بمقارنة ملفات المصادر jars. يذكر توثيقها Javadoc السلوك صراحةً: "Inserts headers to prevent caching if no cache control headers have been specified."

لا يزال يستحق العرض، لأن التسريب حقيقي والمخاطر المتبقية تنجو من الترقيع. يتوقف CacheControlHeadersWriter إذا كان Cache-Control أو Expires أو Pragma موجودًا بالفعل، لذا فإن ضبط أي واحد من الثلاثة يكبت كل توجيهات no-store الخاصة بـ Spring Security. سطر واحد حسن النية يفعل ذلك:

root@kitploit:~
response.setHeader("Expires", "Thu, 01 Jan 2099 00:00:00 GMT");
root@kitploit:~
/safe/account                  NOT cacheable  (Cache-Control: no-cache, no-store, max-age=0, must-revalidate)
/vuln/cache/account            CACHEABLE      (Cache-Control: absent / Expires: Thu, 01 Jan 2099 00:00:00 GMT)
/vuln/content-length/account   CACHEABLE      (Cache-Control: absent / Expires absent)

يُحتسب Expires كـ"موجود" في الجدول أعلاه، لكن بقيمة صديقة للمهاجم اختارها التطبيق — تم استبدال Expires: 0 الخاص بـ Spring Security، لا مجرد إسقاطه. بيانات حامل البطاقة الآن قابلة للتخزين من كل متصفح ووكيل مشترك على المسار حتى 2099.

على البناء المُرقَّع يتحوّل /vuln/content-length/account إلى NOT cacheable، بينما يبقى /vuln/cache/account تمامًا كما هو أعلاه. فقط كود التطبيق أو وكيل عكسي يصلحه — وهذا هو الشيء المفيد قوله بصوت عالٍ في عرض: ترقية المكتبة تغلق CVE وتترك هذا دون مساس.

نتيجتان سلبيتان، محفوظتان عن قصد

عدة مقالات متداولة على نطاق واسع — بما في ذلك مستودع إعادة إنتاج عام — تُدرج response.getOutputStream() وresponse.flushBuffer() كمحفّزات، موضّحة أن "الاستجابة تُثبَّت قبل أن يتمكن Spring Security من حقن رؤوسه". على Spring Security 5.7.11 هذا خطأ. كلتا نقطتي النهاية تُسلّمان الرؤوس الستة جميعًا.

يُظهر /diag/committed لماذا لا يصمد التفسير. بعد كتابة 12 KB تكون الاستجابة فعلًا مثبَّتة داخل المتحكّم، ومع ذلك تصل الرؤوس:

root@kitploit:~
>>> DIAG response.isCommitted() after 12048 byte write = true
    | wrapper class = org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterResponse

يتجاوز OnCommittedResponseWrapper الدالة flushBuffer() وكتابات تدفق الإخراج، لذا يُخرج رؤوسه قبل تلك التثبيتات. ترتيب التثبيت وحده ليس العلّة؛ مسار Content-Length المُعلَن هو العلّة. نشرة Spring نفسها لا تؤيد أبدًا رواية ترتيب التثبيت.

إبقاء نقطتي النهاية هاتين يجعل PoC قابلًا للتكذيب: يُظهر ما لا يُعاد إنتاجه بوضوح كما يُظهر ما يُعاد إنتاجه، وكلاهما يبقى أخضر عبر الترقيع، وهو ما يجعل نقطة النهاية الوحيدة التي تنقلب ذات معنى.

الانتقال من المصاب → المُرقَّع

سطر واحد في pom.xml، لا شيء آخر. لا تغيير في المصدر، لا تغيير في الخاصية، لا ترقية إصدار رئيسي لـ Spring Boot:

root@kitploit:~
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.7.18</version>            <!-- vulnerable -->
  <version>2.7.18-0.cgr.3</version>    <!-- patched   -->
</parent>

هذا يعيد تثبيت spring-security.version من 5.7.11 إلى 5.7.14-0.cgr.2 (و spring-framework.version من 5.3.31 إلى 5.3.39-0.cgr.4) عبر spring-boot-dependencies الخاص بالوالد. القياس:

النقل العكسي هو الإصلاح الرسمي

بمقارنة ملفات المصادر jars الخاصة بـ spring-security-web، ملف واحد فقط يهم. 5.7.11 → 5.7.14-0.cgr.2 يضيف تجاوزات setHeader / setIntHeader / addIntHeader إلى OnCommittedResponseWrapper، كل منها يوجّه Content-Length عبر setContentLength():

root@kitploit:~
@Override
public void setIntHeader(String name, int value) {
    checkContentLengthHeader(name, value);   // <-- added
    super.setIntHeader(name, value);
}

قبل الإصلاح، فقط addHeader كان يفعل هذا، لذا ترك setIntHeader("Content-Length", n) الطول المتتبَّع للغلاف عند 0، ولم يُطلق onResponseCommitted() أبدًا، ولم يكتب HeaderWriterFilter رؤوسه أبدًا قبل أن يثبّت Tomcat الاستجابة.

تظهر نفس الكتلة حرفيًا عند مقارنة 6.5.8 الرسمي (آخر إصدار مصاب) مع 6.5.9 (أول إصدار مُصلَّح)، لذا هذا هو الإصلاح الرسمي منقولًا عكسيًا، وليس إعادة تنفيذ. يضيف بناء Chainguard حارسين ضد القيم الفارغة لا يملكهما 6.5.9 الرسمي (value != null على تحميل String، و (csq != null) ? csq.length() : 4 في append).

تخفيفات أخرى

Spring Security 5.7.x وصل إلى نهاية العمر الرسمي؛ إصلاحات OSS تصل فقط في 6.4.15 / 6.5.9 / 7.0.4+. إذا لم يكن إصدار 5.7.x المُعاد بناؤه خيارًا:

  1. الترقية بعيدًا عن 5.7.x — ترحيل إلى Spring Boot 3.x.
  2. حل بديل — اضبط HeaderWriterFilter.shouldWriteHeadersEagerly = true عبر ObjectPostProcessor. وفقًا للنشرة، هذا يغيّر السلوك: الرؤوس المكتوبة من التطبيق عندئذ تتجاوز رؤوسًا محددة فقط بدلًا من كبت رؤوس Spring Security. هذا أيضًا يصلح /vuln/cache/account، وهو ما لا تفعله ترقية الإصدار.
  3. الدعم التجاري — نقل عكسي من Tanzu Spring Enterprise لإصدارات 5.7.x/5.8.x.
  4. الدفاع في العمق — اضبط الرؤوس على الوكيل العكسي / الدخول بحيث لا يكون رأس التطبيق المُسقَط هو الضابط الوحيد. هذا هو الخيار الوحيد المذكور الذي يغطي نقطتي النهاية.

لا شيء من هذه مُدمج في هذا المشروع، لذا السلوك المصاب هو الافتراضي والحالة المُرقَّعة يمكن الوصول إليها بتغيير <version> الواحد أعلاه.

ترقيع Tomcat المضمّن دون ترقية Spring Boot

يثبّت Boot 2.7.18 إصدار Tomcat 9.0.83، الذي يضع عليه grype . علامة 34 ثغرة CVE (4 حرجة). كلها مُصلَّحة في 9.0.118 أو أقل، و9.0.118 هو أحدث إصدار 9.0.x — لذا خاصية واحدة تُزيل المجموعة:

root@kitploit:~
<properties>
  <tomcat.version>9.0.118</tomcat.version>
</properties>

يُعلن spring-boot-dependencies كل قطعة tomcat-embed-* عبر تلك الخاصية الواحدة، لذا تجاوزها يعيد تثبيت core وel وwebsocket معًا. تم التحقق:

root@kitploit:~
$ mvn dependency:tree | grep tomcat-embed
tomcat-embed-core:jar:9.0.118:compile
tomcat-embed-el:jar:9.0.118:compile
tomcat-embed-websocket:jar:9.0.118:compile

قيد: ابقَ على خط 9.0.x. نقل Tomcat 10+ واجهة Servlet API إلى jakarta.* بينما يُصرَّف Spring Framework 5.3 مقابل javax.servlet، لذا تفشل ترقية 10.x/11.x في وقت التشغيل بـ NoClassDefFoundError على أنواع servlet.

ترقيع كل شيء آخر، مع البقاء داخل كل خط رئيسي

نفس الآلية مطبَّقة على بقية التبعيات المُدارة في Boot 2.7.18. لا ترقيات إصدار رئيسي، ولا ترقية Spring Boot:

تتفاعل هذه التجاوزات مع الوالد المُرقَّع، لذا اعرف ما تفعله قبل العرض. على 2.7.18-0.cgr.3 يوفّر الوالد بالفعل tomcat.version 9.0.118 وlogback.version 1.2.13 و snakeyaml.version 1.33 — تصبح هذه الصفوف الثلاثة مكرّرة تمامًا ويمكن حذفها دون تغيير أي شيء. صفّا jackson-bom.version وlog4j2.version لا يزالان يقومان بعمل حقيقي: يحتفظ الوالد المُرقَّع بإصدارات Boot الأصلية 2.13.5 / 2.17.2، لذا تفوز التجاوزات وتُحلّ هاتان التبعيتان إلى بنيات رسمية عادية بدلًا من بنيات Chainguard. spring-framework.version مُعلَّق عليه عن قصد، وهو ما يسمح بمرور 5.3.39-0.cgr.4 الخاص بالوالد.

تقدّم grype .

الحالةالنتائجالتفصيل
Boot 2.7.18 الأصلي997C / 39H / 38M / 15L
+ ترقية Tomcat653C / 23H / 29M / 10L

مُزالة بالكامل: Tomcat (34)، Jackson (7)، log4j (1). الإجمالي 99 → 43، الحرجة 39 → 12.

تم التحقق بعد كل ترقية: يُقلع التطبيق على Tomcat/9.0.118، وتُعيد نقاط النهاية الستة جميعًا 200، و تُعاد الثغرة بايت ببايت. لا يزال Spring Boot 2.7.18 وSpring Security لا يزال 5.7.11، لذا CVE-2026-22732 دون مساس — وهذا هو مغزى هذا القسم، وكذلك حدّه الصادق: ترقيع كل شيء حوله لا يفعل شيئًا لثغرة إطار التطبيق. إصلاح تلك يحتاج ترقية الوالد، لا خاصية.

لماذا يتوقف Logback عند 1.2.13

أحدث 1.x هو 1.6.3 — نفس الإصدار الرئيسي، لذا اسميًا داخل النطاق. لا يعمل. استبدل Logback 1.3+ StaticLoggerBinder من SLF4J 1.7 بمزوّد ServiceLoader من SLF4J 2.x، ويستدعي LogbackLoggingSystem في Boot 2.7 الدالة StaticLoggerBinder مباشرة. القياس مع 1.5.38:

root@kitploit:~
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder"
Caused by: java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder
    at org.springframework.boot.logging.logback.LogbackLoggingSystem.getLoggerContext(...:304)

يتطلب الإفلات من هذا SLF4J 2.x (ترقية رئيسية) و نظام تسجيل Boot 3.x. 1.2.13 هو السقف الحقيقي، تاركًا 6 نتائج Logback (2 متوسطة، 4 منخفضة) غير قابلة للإصلاح على هذا الخط.

الـ43 المتبقية

اثنتان من الثلاث ثغرات الحرجة المتبقية تستحقان القراءة بعناية بدلًا من الاعتماد على الدرجة:

  • CVE-2016-1000027 (spring-web، الإصلاح 6.0.0) — إلغاء تسلسل عبر HttpInvokerServiceExporter. لا يستخدم هذا التطبيق HTTP Invoker، لذا فهو غير قابل للوصول هنا.
  • CVE-2024-38821 (spring-security-web، الإصلاح 5.7.13) — تجاوز مصادقة الموارد الثابتة في WebFlux. هذا تطبيق servlet، لذا أيضًا غير قابل للوصول. إنها قابلة للإصلاح داخل الخط الرئيسي (5.7.13/5.7.14 على Central) وتُركت فقط لإبقاء هذا القسم مثبَّتًا عند 5.7.11. يزيلها الوالد المُرقَّع كأثر جانبي، لأن 5.7.14-0.cgr.2 تجاوز إصدار الإصلاح.
  • CVE-2026-22732 — متعمّدة في الحالة المصابة؛ تُزال بترقية الوالد.

البقايا بنيوية: Spring Framework 5.3.x وSpring Security 5.7.x كلاهما منتهي العمر. هذا، وليس Tomcat أو Jackson، هو الحجة الحقيقية للترحيل إلى Boot 3.x.

التخطيط

root@kitploit:~
pom.xml                     parent + 2 starters, nothing else. Flip the <version> to switch state.
run.sh                      build + run on JDK 17, via settings-chainguard.xml
exploit.sh                  header diff, cache impact, clickjacking check, CVE-scoped verdict
settings-chainguard.xml     Chainguard Libraries repo -- required for the patched parent
src/main/java/com/example/poc/
  PocApplication.java       @SpringBootApplication
  SecurityConfig.java       permitAll, zero header customisation
  AccountController.java    baseline, 2 exploits, 2 controls, 1 diagnostic

المصادقة permitAll وCSRF معطّل حتى يعمل curl دون مصادقة — لا هذا ولا ذاك جزء من هذه الثغرة.

المصادر

  • spring.io/security/cve-2026-22732 — النشرة الرسمية
  • GHSA-mf92-479x-3373
  • NVD CVE-2026-22732
  • مقالة Broadcom / Tanzu
  • تحليل HeroDevs
  • semgrep/cve-2026-22732-demo — إعادة الإنتاج التي لم تصمد ادعاءاتها حول stream/flush هنا
  • Red Hat Bugzilla #2449306
تنزيل الأداة
2.7.182.7.18-0.cgr.3
/safe/accountOK 6/6OK 6/6
/vuln/stream/accountOK 6/6OK 6/6
/vuln/flush/accountOK 6/6OK 6/6
/vuln/content-length/accountBYPASSED 0/6OK 6/6
/vuln/cache/accountPARTIAL 4/6PARTIAL 4/6 (by design)
exploit.sh verdictVULNERABLEPATCHED
الخاصيةافتراضي Boot 2.7.18مثبَّت هناسبب السقف
tomcat.version9.0.839.0.118أحدث 9.0.x؛ 10+ هو jakarta.*
spring-framework.version5.3.315.3.39آخر 5.3.x من OSS على Central
jackson-bom.version2.13.52.22.2أحدث 2.x
log4j2.version2.17.22.26.1أحدث 2.x
snakeyaml.version1.301.33آخر 1.x؛ إصلاح CVE المتبقية هو 2.0
logback.version1.2.121.2.13آخر 1.2.x — انظر أدناه
spring-security.version5.7.11تُرك كما هوهو موضوع العرض
+ كل ترقيات داخل الخط الرئيسي
43
3C / 12H / 18M / 10L
المكوّنلماذا لا يمكن إصلاحه داخل الخط الرئيسي
spring-webmvc / -expression / -core / -context (25)5.3.39 هو آخر 5.3.x من OSS؛ 14 من 15 نتيجة webmvc ليس لها إصلاح على الإطلاق، و5.3.42 الذي يذكره grype تجاري فقط
logback-core (6)يحتاج SLF4J 2.x، انظر أعلاه
spring-security-* (8)خط منتهي العمر؛ CVE-2026-22732 متعمّدة
spring-boot / -autoconfigure (3)لا إصلاح منشور لـ 2.7.x
snakeyaml (1)CVE-2022-1471 مُصلَّحة فقط في 2.0