Lucene search

K
huntrHaxatronF55315E9-9F6D-4DBB-8C40-BAE50C1AE92B
HistoryJan 26, 2022 - 5:17 a.m.

Path Traversal in gruntjs/grunt

2022-01-2605:17:28
haxatron
www.huntr.dev
27
gruntjs
javascript
symlink traversal

EPSS

0.001

Percentile

21.9%

Description

Grunt is a JavaScript task runner, a tool used to automatically perform frequent tasks such as minification, compilation, unit testing, and linting. In GruntJS, file.copy operations in GruntJS are not protected against symlink traversal for both source and destination directories.

Scenario 1 - Restricted File Read

If a local attacker has write access to the source directory of file.copy, they can create a symlink to a restricted file. When the source directory is then copied from, either by the root user or a GruntJS task / cronjob running as root, the symlink is resolved and the contents of the restricted file will be copied to the destination directory with default umask permissions rw-r–r–, the directory will also be copied with permissions drwxr-xr-x. allowing them to read the restricted file.

Proof of Concept

1: As a lower-privileged user:

mkdir src
ln -s /etc/shadow src/shadow

2: As root execute the following PoC

grunt = require('grunt')
grunt.file.copy("src", "dest")

3: The lower privileged user can read the contents of the /etc/shadow file in the dest directory

cat dest/shadow

Scenario 2 - Restricted File Write

If an attacker has write access to both the source directory and the destination directory (if it has already been created) of file.copy, they can create a symlink to a restricted file in the destination directory and a file of the same name in the source directory. When the destination directory is then copied to, either by the root user or a cronjob running as root, the symlink is resolved to a restricted file and the file of the same name in source is copied to the resolved file path of the symlink in destination

Proof of Concept

1: As a lower-privileged user:

mkdir src
mkdir dest
ln -s /etc/shadow2 dest/shadow2
echo "<overwrite shadow file here>" > src/shadow2

2: As root execute the following PoC

grunt = require('grunt')
grunt.file.copy("src", "dest")

3: The /etc/shadow2 file is overwritten

<overwrite shadow file here>

Comparison with cp command

The standard cp command on all Linux systems copies the symlink object in directories instead of resolving it.

Impact

If a local attacker has write access to the source directory and read access to the directory containing the destination directory, they are able to abuse the file.copy operation to expose restricted files such as /etc/shadow which contains all the hashed passwords of users on the Linux system, they can they escalate their privileges by cracking the password or even SSH private keys. If an attacker has write access to the source and destination directories, they are able to abuse the file.copy operation to overwrite restricted files such as /etc/shadow with their own shadow file and replace the root password with their own or even sign their own pair of SSH keys and replace the SSH public key with their own, guaranteeing them to escalate their privileges.

Recommended Fix

For directories, the file.copy should copy the symlink object rather than resolve it just like the standard cp command on Linux systems. Additionally, if a file in a destination directory is a symlink, then it should not be overwritten so as to prevent unintended consequences.

EPSS

0.001

Percentile

21.9%