upnphttp: Validate SUBSCRIBE callback URL

The UPnP protocol specification mandates that subscribers can request a
callback to an arbitrary URL. This recently resulted in CVE-2020-12695
(CallStranger) outlining the risk of information disclosure and DoS
attacks.

This commit ensures that the callback URL sent in a SUBSCRIBE request
points to the same IP address that made the request.
This commit is contained in:
Justin Maggard 2020-09-23 18:21:53 -07:00 committed by Justin Maggard
parent 0763719f27
commit 06ee114731

View File

@ -699,7 +699,7 @@ ProcessHTTPPOST_upnphttp(struct upnphttp * h)
static int
check_event(struct upnphttp *h)
{
enum event_type type;
enum event_type type = E_INVALID;
if (h->req_Callback)
{
@ -707,7 +707,6 @@ check_event(struct upnphttp *h)
{
BuildResp2_upnphttp(h, 400, "Bad Request",
"<html><body>Bad request</body></html>", 37);
type = E_INVALID;
}
else if (strncmp(h->req_Callback, "http://", 7) != 0 ||
strncmp(h->req_NT, "upnp:event", h->req_NTLen) != 0)
@ -716,10 +715,30 @@ check_event(struct upnphttp *h)
* If CALLBACK header is missing or does not contain a valid HTTP URL,
* the publisher must respond with HTTP error 412 Precondition Failed*/
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
type = E_INVALID;
}
else
type = E_SUBSCRIBE;
{
/* Make sure callback URL points to the originating IP */
struct in_addr addr;
char addrstr[16];
int i = 0;
const char *p = h->req_Callback + 7;
while (!strchr("/:>", *p) && i < sizeof(addrstr) - 1 &&
p < (h->req_Callback + h->req_CallbackLen))
{
addrstr[i++] = *(p++);
}
addrstr[i] = '\0';
if (inet_pton(AF_INET, addrstr, &addr) <= 0 ||
memcmp(&addr, &h->clientaddr, sizeof(struct in_addr)))
{
DPRINTF(E_ERROR, L_HTTP, "Bad callback IP (%s)\n", addrstr);
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
}
else
type = E_SUBSCRIBE;
}
}
else if (h->req_SID)
{
@ -728,7 +747,6 @@ check_event(struct upnphttp *h)
{
BuildResp2_upnphttp(h, 400, "Bad Request",
"<html><body>Bad request</body></html>", 37);
type = E_INVALID;
}
else
type = E_RENEW;
@ -736,7 +754,6 @@ check_event(struct upnphttp *h)
else
{
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
type = E_INVALID;
}
return type;