Page 1 of 1

Security: media is publicly available, bypassing login

PostPosted: Thu Jan 21, 2016 3:55 pm
by dest41
I don't think this "feature" is desired: knowing the url of any Subsonic server, it is possible to download media from it with the following URL scheme:
http://server:port/stream?id=N
where N is the number of the song in the library. To dump a library, simply iterate over N.

Anybody can reproduce this behavior? If confirmed, a token should be provided with the request to authenticate the requester.

Re: Security: media is publicly available, bypassing login

PostPosted: Thu Jan 21, 2016 10:08 pm
by frnx
I can definitely reproduce this. I'm disabling external access until we know more, but did you send an email to Sindre about this? He may want to know about it rather sooner than later.

EDIT: Also, using an ID that does not exist when the Subsonic server was just restarted results in downloading (very slowly) a file full of ones (0xFF everywhere), then any subsequent accesses to the main page gives :

Code: Select all
Exception    java.lang.NullPointerException
Message    null
Java version    Oracle Corporation 1.8.0_72
Operating system    Linux 4.3.3-3-ARCH
Server    jetty-6.1.x
Memory    Used 43 of 112 MB
Stack trace    java.lang.NullPointerException
   at net.sourceforge.subsonic.service.SecurityService.getMusicFolderForFile(SecurityService.java:240)
   at net.sourceforge.subsonic.service.SecurityService.isInMusicFolder(SecurityService.java:235)
   at net.sourceforge.subsonic.service.SecurityService.isReadAllowed(SecurityService.java:203)
   at net.sourceforge.subsonic.service.MediaFileService.getMediaFile(MediaFileService.java:99)
   at net.sourceforge.subsonic.service.MediaFileService.getMediaFile(MediaFileService.java:81)
   at net.sourceforge.subsonic.controller.NowPlayingController.handleRequestInternal(NowPlayingController.java:54)
   at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
   at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
   at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
   at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
   at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
   at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
   at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
   at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
   at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
   at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
   at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:265)
   at org.acegisecurity.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:107)
   at org.acegisecurity.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:72)
   at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
   at org.acegisecurity.ui.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:166)
   at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
   at org.acegisecurity.providers.anonymous.AnonymousProcessingFilter.doFilter(AnonymousProcessingFilter.java:125)
   at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
   at org.acegisecurity.ui.rememberme.RememberMeProcessingFilter.doFilter(RememberMeProcessingFilter.java:135)
   at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
   at org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:81)
   at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
   at org.acegisecurity.ui.basicauth.BasicProcessingFilter.doFilter(BasicProcessingFilter.java:173)
   at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
   at org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:271)
   at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
   at org.acegisecurity.ui.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
   at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
   at org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:249)
   at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
   at org.acegisecurity.util.FilterChainProxy.doFilter(FilterChainProxy.java:149)
   at org.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:98)
   at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
   at net.sourceforge.subsonic.filter.RequestEncodingFilter.doFilter(RequestEncodingFilter.java:43)
   at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
   at net.sourceforge.subsonic.filter.ParameterDecodingFilter.doFilter(ParameterDecodingFilter.java:54)
   at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
   at net.sourceforge.subsonic.filter.BootstrapVerificationFilter.doFilter(BootstrapVerificationFilter.java:59)
   at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
   at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
   at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
   at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
   at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
   at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
   at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
   at org.mortbay.jetty.Server.handle(Server.java:313)
   at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
   at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:830)
   at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:514)
   at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
   at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
   at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:396)
   at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)

Re: Security: media is publicly available, bypassing login

PostPosted: Thu Jan 21, 2016 10:22 pm
by daneren2005
There was another thread about it here somewhere so sindre probably already knows about it. I believe it's for the external playlist feature. But you are right it definitely should be authenticated with a token instead of just left wide open like that.

Re: Security: media is publicly available, bypassing login

PostPosted: Thu Jan 21, 2016 10:30 pm
by frnx
Ah, it makes sense then, but it's definitely not ideal. It should at least be possible to disable the external playlist feature (I for one have never used it).

Re: Security: media is publicly available, bypassing login

PostPosted: Fri Jan 22, 2016 10:36 am
by dest41
Just to be sure, I just sent a mail to Sindre Mehus.

Re: Security: media is publicly available, bypassing login

PostPosted: Fri Jan 22, 2016 8:02 pm
by frnx
Thanks! The same thing appears to happen on coverArt.view. I'm going to look at all the routes and see if I can make a list.

Re: Security: media is publicly available, bypassing login

PostPosted: Sat Jan 23, 2016 12:52 pm
by sindre_mehus
Thanks for bringing this up.

The stream and coverart endpoints are intentionally unauthenticated to make it work with external players (e.g., Sonos and Chromecast), but I will find a way to make it more secure.

Thanks
Sindre

Re: Security: media is publicly available, bypassing login

PostPosted: Sun Jan 24, 2016 3:39 pm
by frnx
Thanks for the quick reply, and the quick commits! Using the file hash seems enough to prevent library iteration, I think that's all we needed. :)

Re: Security: media is publicly available, bypassing login

PostPosted: Tue Feb 23, 2016 9:01 pm
by manwithaplan
Sindre or others,

I need to understand this better - couple questions:

1. Does this impact Subsonic 5.2.1?
2. Are we saying that even if you don't allow downloads as a user privilege for any of your users, that this vulnerability allows people to download every single song or album in your database?
3. Is there some workaround I can make in 5.2.1 to mitigate this access? (I have no problem doing custom file changes, but am not willing to upgrade off of 5.2.1 anytime soon).

Thanks all!