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:
parent
0763719f27
commit
06ee114731
29
upnphttp.c
29
upnphttp.c
@ -699,7 +699,7 @@ ProcessHTTPPOST_upnphttp(struct upnphttp * h)
|
|||||||
static int
|
static int
|
||||||
check_event(struct upnphttp *h)
|
check_event(struct upnphttp *h)
|
||||||
{
|
{
|
||||||
enum event_type type;
|
enum event_type type = E_INVALID;
|
||||||
|
|
||||||
if (h->req_Callback)
|
if (h->req_Callback)
|
||||||
{
|
{
|
||||||
@ -707,7 +707,6 @@ check_event(struct upnphttp *h)
|
|||||||
{
|
{
|
||||||
BuildResp2_upnphttp(h, 400, "Bad Request",
|
BuildResp2_upnphttp(h, 400, "Bad Request",
|
||||||
"<html><body>Bad request</body></html>", 37);
|
"<html><body>Bad request</body></html>", 37);
|
||||||
type = E_INVALID;
|
|
||||||
}
|
}
|
||||||
else if (strncmp(h->req_Callback, "http://", 7) != 0 ||
|
else if (strncmp(h->req_Callback, "http://", 7) != 0 ||
|
||||||
strncmp(h->req_NT, "upnp:event", h->req_NTLen) != 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,
|
* If CALLBACK header is missing or does not contain a valid HTTP URL,
|
||||||
* the publisher must respond with HTTP error 412 Precondition Failed*/
|
* the publisher must respond with HTTP error 412 Precondition Failed*/
|
||||||
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
|
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
|
||||||
type = E_INVALID;
|
|
||||||
}
|
}
|
||||||
else
|
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)
|
else if (h->req_SID)
|
||||||
{
|
{
|
||||||
@ -728,7 +747,6 @@ check_event(struct upnphttp *h)
|
|||||||
{
|
{
|
||||||
BuildResp2_upnphttp(h, 400, "Bad Request",
|
BuildResp2_upnphttp(h, 400, "Bad Request",
|
||||||
"<html><body>Bad request</body></html>", 37);
|
"<html><body>Bad request</body></html>", 37);
|
||||||
type = E_INVALID;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
type = E_RENEW;
|
type = E_RENEW;
|
||||||
@ -736,7 +754,6 @@ check_event(struct upnphttp *h)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
|
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
|
||||||
type = E_INVALID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user