Skip to content

Detecting a New Grafana Exploit in Go

    
Detecting a New Grafana Exploit in Go

A new Grafana vulnerability has been discovered that enables arbitrary file reads off the system. This vulnerability (CVE-2021-43798) and many arbitrary file reads like it are exactly the thing that Contrast’s new Go agent can detect before any exploitation occurs.

The Grafana team acted quickly and responsibly to patch this vulnerability and issue upgrade guidance to their users. In this write-up, we are working to explain how automated security testing and vulnerability scanning tools can detect this same type of vulnerability in custom applications. We would like to compliment the Grafana team on their handling of this issue.

What is Grafana

Grafana is an operational dashboard for rendering large amounts of data quickly, to show the real time and historical information. It is commonly used in system monitoring and Site Reliability Engineering for its ability to show data and allow deeper drill-downs at any level needed by the team. Grafana is a well-known member of the Cloud Native Computing Foundation.

How The Vulnerability Works

The vulnerability impacts Grafana by untrusted data making its way to the File APIs.

1.  Data enters Grafana through the URL, controlled by a remote user. The exploit starts in pkg/macaron/macaron.go, a middleware component for
     request handling. The macaron middleware represents the source where data enters the application from a remote user. It gets here via an API
     endpoint meant to load an asset (image, JS, etc.) for one of Grafana’s many plugins.
     macaron.go

          // ServeHTTP is the HTTP Entry point for a Macaron instance.
          // Useful if you want to control your own HTTP server.
          // Be aware that none of middleware will run without registering any router.
          func (m *Macaron) ServeHTTP(rw http.ResponseWriter, req *http.Request) {       
                  req.URL.Path = strings.TrimPrefix(req.URL.Path, m.urlPrefix)
                  m.Router.ServeHTTP(rw, req)
          }                

2. Grafana looks at the URL (req.URL.Path) to determine which plugin contains the asset as well as which asset is being asked for. The untrusted         remote data is trimmed, concatenated, and reassigned to other values.
    a. Plugins are common in Grafana because they enable it to understand complex data.

3. Later on, this untrusted data reaches the filesystem.Open method, giving the remote user the ability to control which file is accessed.

func (hs *HTTPServer) getPluginAssets(c *models.ReqContext) {

   pluginID := web.Params(c.Req)[":pluginId"]
   plugin, exists := hs.pluginStore.Plugin(c.Req.Context(), pluginID)
   if !exists {
       
c.JsonApiErr(404, "Plugin not found", nil)
       
return
   }

   requestedFile := filepath.Clean(web.Params(c.Req)["*"])
   pluginFilePath := filepath.Join(plugin.PluginDir, requestedFile)

   if !plugin.IncludedInSignature(requestedFile) {
   hs.log.Warn("Access to requested plugin file will be forbidden in upcoming Grafana versions as the file "+
   
"is not included in the plugin signature", "file", requestedFile)
   }

   // It's safe to ignore gosec warning G304 since we already clean the requested file path and subsequently
   // use this with a prefix of the plugin's directory, which is set during plugin loading
   
// nolint:gosec
   
f, err := os.Open(pluginFilePath)

//...

An automatically generated diagram of the application’s data flow shows this vulnerability. This diagram was generated when the Contrast Go agent was placed in the application. The automatic security testing software detected and reported the vulnerability.

One interesting point is that the vulnerability goes through filepath.Clean. This method does not sanitize data for security, rather it simplifies/shortens it to remove things like extra slashes, resolve the parent (../) references, and so on.

HOW CONTRAST SECURITY SHOWS THE VULNERABILITY

Contrast Security's vulnerability testing software shows the vulnerability appears as a Path Traversal flaw, showing a full stack trace for how it traced through the code.

Path Traversal from

 

What the Agent Sees under the hood

The agent works inside the Go application, using insight similar to what an Application Performance Monitoring (APM) or Debugger would see. A rendered version of this understanding as a DOT file. This shows the vulnerable code flow without needing the vulnerability to be exploited. This type of integrated testing can help developers locate similar issues in their own applications without dedicated security expertise.

Agent Sees Under the Hood

Finding Your Own Custom Flaws

The Grafana vulnerability shown here is a complete CVE, with a proof of concept exploit available in the wild. Many organizations that develop custom software do not have the ability to go through the entire CVE process before a patch and must find their own vulnerabilities.

Organizations can find similar OWASP-type vulnerabilities in their own custom code by using the Contrast agent in their Go test environment.

 

Ehden Sinai, Senior Software Engineer, Contrast Security

Ehden Sinai, Senior Software Engineer, Contrast Security

Ehden Sinai is a senior software engineer with Contrast Security and focused on developer tooling and managed runtimes. Ehden’s tooling work has contributed to Contrast Assess achieving the largest language support of any interactive application security testing (IAST) tool. Ehden has spoken at various developer-centric events, including his work on the Contrast Go agent at Baltimore GoLang and his work on the Contrast Node agent at Charm City JS.