
Rapport détaillé CVE-2021-31856 avec PoC et analyse de code pour une vulnérabilité d'injection SQL dans l'API de fichier de pattern de Meshery, permettant l'extraction de données non authentifiée.
| élément | détails | remarque |
|---|---|---|
| projet | https://github.com/layer5io/meshery | |
| date annoncée | 2021-04-28 | |
| CVE-ID | CVE-2021-31856 | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-31856 |
| EDB-ID | \ | |
| Version vulnérable | v0.5.2 | \ |
| Version corrigée | v0.5.3 | https://github.com/layer5io/meshery/pull/2745 |
| CVSS | 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N | |
| Auteur | https://github.com/ssst0n3 |
La fonction GetMesheryPatterns() dans meshery/models/meshery_pattern_persister.go présente une vulnérabilité d'injection SQL via le paramètre order de la requête /api/experimental/patternfile?order=id%3Bselect(randomblob(1000000000))&page=0&page_size=0.
http://<IP>:9081/api/experimental/patternfile?order=id%3Bselect(randomblob(1000000000))&page=0&page_size=0
Le paramètre order dans la fonction GetMesheryPatterns est une instance de chaîne de caractères. Il est directement ajouté à la requête lors de l'utilisation de Gorm, et l'instruction SQL est exécutée par Find().
https://github.com/layer5io/meshery/blob/v0.5.2/models/meshery_pattern_persister.go#L35
func (mpp *MesheryPatternPersister) GetMesheryPatterns(search, order string, page, pageSize uint64) ([]byte, error) {
if order == "" {
order = "updated_at desc"
}
...
query := mpp.DB.Order(order)
...
Paginate(uint(page), uint(pageSize))(query).Find(&patterns)
...
}
Si le paramètre order provient de l'entrée utilisateur sans aucun filtrage, il existe une vulnérabilité d'injection SQL.
En suivant le processus d'appel, on constate que le paramètre order provient directement de la requête.
https://github.com/layer5io/meshery/blob/v0.5.2/handlers/meshery_pattern_handler.go#L140
func (h *Handler) GetMesheryPatternsHandler(
rw http.ResponseWriter,
r *http.Request,
prefObj *models.Preference,
user *models.User,
provider models.Provider,
) {
q := r.URL.Query()
resp, err := provider.GetMesheryPatterns(r, q.Get("page"), q.Get("page_size"), q.Get("search"), q.Get("order"))
if err != nil {
http.Error(rw, fmt.Sprintf("failed to fetch the patterns: %s", err), http.StatusInternalServerError)
return
}
rw.Header().Set("Content-Type", "application/json")
fmt.Fprint(rw, string(resp))
}
Si l'on débogue, on constate que la requête est :
SELECT * FROM `meshery_patterns` ORDER BY <ORDER>
si on définit order=id;drop table meshery_patterns, l'instruction devient
SELECT * FROM `meshery_patterns` ORDER BY id;drop table meshery_patterns
et la table sera supprimée.
La chaîne complète des appels est :
https://github.com/layer5io/meshery/blob/v0.5.2/router/server.go#L127
gMux.Handle("/api/experimental/patternfile", h.ProviderMiddleware(h.AuthMiddleware(h.SessionInjectorMiddleware(h.PatternFileRequestHandler)))).
Methods("POST", "GET")
https://github.com/layer5io/meshery/blob/v0.5.2/handlers/meshery_pattern_handler.go#L93
func (h *Handler) PatternFileRequestHandler(
...
h.GetMesheryPatternsHandler(rw, r, prefObj, user, provider)
}
https://github.com/layer5io/meshery/blob/v0.5.2/handlers/meshery_pattern_handler.go#L149
func (h *Handler) GetMesheryPatternsHandler(
...
resp, err := provider.GetMesheryPatterns(r, q.Get("page"), q.Get("page_size"), q.Get("search"), q.Get("order"))
..
https://github.com/layer5io/meshery/blob/v0.5.2/models/default_local_provider.go#L439
func (l *DefaultLocalProvider) GetMesheryPatterns(req *http.Request, page, pageSize, search, order string) ([]byte, error) {
...
return l.MesheryPatternPersister.GetMesheryPatterns(search, order, pg, pgs)
}
https://github.com/layer5io/meshery/blob/v0.5.2/models/meshery_pattern_persister.go#L35-L44
func (mpp *MesheryPatternPersister) GetMesheryPatterns(search, order string, page, pageSize uint64) ([]byte, error) {
if order == "" {
order = "updated_at desc"
}
...
query := mpp.DB.Order(order)
...
Paginate(uint(page), uint(pageSize))(query).Find(&patterns)
...
}
Définir une liste blanche pour le paramètre order au lieu d'utiliser des paramètres provenant de l'entrée utilisateur sans aucun filtrage.
https://github.com/layer5io/meshery/pull/2745
Vous pouvez trouver des références dans la documentation de Gorm : https://gorm.io/docs/security.html