Lucene search

K
huntrKtg9BE837427-415C-4D8C-808B-62CE20AA84F1
HistoryMar 07, 2022 - 1:57 p.m.

Authorization Bypass Through User-Controlled Key

2022-03-0713:57:33
ktg9
www.huntr.dev
12

9.1 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

NONE

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

6.4 Medium

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

NONE

AV:N/AC:L/Au:N/C:P/I:P/A:N

0.003 Low

EPSS

Percentile

68.5%

Description

Hello go restful maintainer team, I would like to report a security concerning your CORS Filter feature.

Go restful allows user to specify a CORS Filter with a configurable AllowedDomains param - which is an array of domains allowed in CORS policy.

However, although there’s is already another param called allowedOriginPatterns used for matching origin using regular expression, all domains in AllowedDomains is also used as regular expression to check for matching origin in this code in file cors_filter.go:

if len(c.allowedOriginPatterns) == 0 {
			// compile allowed domains to allowed origin patterns
			allowedOriginRegexps, err := compileRegexps(c.AllowedDomains)
			if err != nil {
				return false
			}
			c.allowedOriginPatterns = allowedOriginRegexps
		}

		for _, pattern := range c.allowedOriginPatterns {
			if allowed = pattern.MatchString(origin); allowed {
				break
			}
		}

So by this, if the user input example.com to be one of domain in AllowedDomains, all domains starting with example.com would be acceptable.

Proof of Concept

  1. Install go restful and create a file main.go with this content:
package main

import (
	restful "github.com/emicklei/go-restful/v3"
	"io"
	"net/http"
)

func main() {
	container := restful.NewContainer()

	ws := new(restful.WebService)
	ws.Route(ws.GET("hello").To(hello))
	container.Add(ws)
	server := &http.Server{Addr: ":8000", Handler: container}

	//container.Filter(logHeaders)
	cors := restful.CrossOriginResourceSharing{
		ExposeHeaders: []string{"X-My-Header"},
		AllowedDomains: []string{"example.com"},
		CookiesAllowed: true,
		Container: container,
	}
	container.Filter(cors.Filter)
	server.ListenAndServe()
}

func hello(req *restful.Request, resp *restful.Response) {
	io.WriteString(resp, "world")
}

In the above code, example.com is configured as an allowed domain.

  1. Run the above code and access link /hello with Origin Header = example.com.hacker.domain and see that the request gets through
    CORS policy and response looks like this:
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: example.com.hacker.domain
Access-Control-Expose-Headers: X-My-Header
Date: Mon, 07 Mar 2022 13:31:08 GMT
Content-Length: 5
Content-Type: text/plain; charset=utf-8
Connection: close

world

Impact

This vulnerability is capable of breaking CORS policy and thus allowing any page to make requests, retrieve data on behalf of other users.

9.1 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

NONE

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

6.4 Medium

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

NONE

AV:N/AC:L/Au:N/C:P/I:P/A:N

0.003 Low

EPSS

Percentile

68.5%