[discovery-api] Mitigating real-world device compromise

I want us to work through a real-world UPnP compromise that has
publicized recently. The specific compromise we can focus on was made
against Netgear routers [1].

the tl;dr version of [1] is that, by visiting a specific URL on your
router, you can gain persistent access to it and all its settings
without passing through any authentication process.

We could do some hand-wringing on how this happened in the first place
but it would be more productive to detail how the Network Service
Discovery API is capable of mitigating against such attacks. I will
summarize some initial thoughts here and would welcome other input on
this topic.

Firstly, all existing router-level devices (including the compromised
Netgear devices) would not be exposed to web pages via this API
because they do not provide CORS support. To opt in to web sharing,
UPnP devices need to implement CORS on specific UPnP service
endpoints. It should be obvious that router-level devices and other
sensitive services should not expose CORS HTTP headers and thus should
never be exposed to web pages in the first place.

A secondary attack vector arising here is if a web page gains access
to a service residing on the same device as router functionality (e.g.
I could request and be granted access to media services via CORS on a
device that also implements router services).

An exploit that takes advantage of this could look as follows:

navigator.getNetworkServices('serviceA').then(function(networkServices) {
  var serviceUrl = new URL(networkServices[0].url); //
http://url.spec.whatwg.org/#api
  var exploitUrl = serviceUrl.protocol + '//' + serviceUrl.host;
  exploitUrl += (serviceUrl.port ? ':' + serviceUrl.port : '');
  exploitUrl += '/secondaryService/maliciousMethodCall';

  // Use XHR to interact with exploitUrl...
});

According to the current specification this attack vector would fail
if 'secondaryService' did not implement CORS or did not provide CORS
to the requesting origin. However, to initial a simple GET request to
a particular URL as detailed in this particular exploit, a web page
could simply do the following:

var imgEl = new Image();
imgEl.src = exploitUrl;
document.body.appendChild(imgEl);

That would have the effect of requesting this URL via HTTP GET
regardless of whether that resource is an image or not (which it
clearly isn't and that device, according to [1], is now pwned).

I have briefly mentioned a way we could avoid this exploit where local
network urls will be obfuscated from their original host [2] thereby
avoiding a leak of local network IP addresses and ports.

Let's say in the example above that serviceUrl returned
'app://<uuid>/'. The original service endpoint url for this service
was actually 'http://10.0.2.1:5000/myService' and app://<uuid>/ simply
acts as a proxy to that URL. What this proxy does is make
'http://10.0.2.1:5000/myService' the _root_ path of 'app://<uuid>/'.
Developers cannot call anything above '/myService' in the www
hierarchy and developers cannot infer paths to any other potential
services on the same device from the provided url. The 'app://<uuid>/'
serviceUrl acts as a full HTTP proxy to http://10.0.2.1:5000/myService
and any sub-resources therein (e.g. app://<uuid>/logo.png maps to
http://10.0.2.1:5000/myService/logo.png, etc).

Having such a concept removes the ability for a web developer to infer
other service endpoint URLs from any other shared service endpoint
URLs.

A remaining challenge with that approach is that services, once
connected to web pages via app:// based URLs. may still leak their IP
address in service messaging data calls. E.g. a service providing a
pointer to a media resource may transfer data via XHR to a web page
that looks as follows
'http://10.0.2.1:5000/myService/_media/0123.ogg'. Exposing this URL to
web pages would allow them to infer other well-known services on the
same device by running the exploit code I included above.

A full solution should would obfuscate both the initial service
endpoint url and monitor service messaging itself with a view to
obfuscating in-messaging urls via XHR. For this I propose we add an
additional user agent processing step whenever a web page calls
xhr.response, xhr.responseText or xhr.responseXML on an app:// URL.
Primarily, the additional XHR processing step would be that if the XHR
url requested begins with 'app://' then parse any response body for
matches to the original URL host+port combination and replace with any
matches with an app:// URL based reference to that same resource. The
finer details of this process would be defined fully within the NSD
API spec (I'm just presenting the main proposal for now).

When we are obfuscating local network URLs at both the service sharing
and service communication levels we will be able to fully isolate
network services from each other. Also, the only network services that
can be shared with web pages are CORS-enabled services and sensitive
network resources should not expose such headers (thereby excluding
them from any NSD API sharing). At this point we have successfully
mitigated any exposure to the kind of attack in [1].

Other thoughts and proposals on this would be welcome, specifically
mitigating or avoiding altogether the attack vectors detailed in [1].
Showing we can avoid/mitigate such attacks is an essential step in
demonstrating APIs suitability.

Best regards,

Rich

[1] http://shadow-file.blogspot.com.au/2013/10/complete-persistent-compromise-of.html

[2] http://lists.w3.org/Archives/Public/public-device-apis/2013Oct/0129.html

Received on Thursday, 24 October 2013 01:06:01 UTC