A zip archive received from a remote location may contain arbitrary paths which, when translated to an absolute path, may escape the directory where it is extracted. Such paths may include one or more ../ to traverse the directory tree upwards to write to an arbitrary location, such as the root directory (/) or a sensitive path like /usr/local/. A sophisticated attack may also attempt to overwrite an existing file by making the filename identical as that of the target file.
Validate the path of each zip entry before writing them to a file. Several different tactics may be used to prevent the path traversal by one or more of ../ occuring in a zip entry's path.
A naive but effective way to validate the path of a zip entry is to check if its path, converted to string, contains any occurrences of ../. If a path does have one, then it can be suspected that the creator of the zip archive is attempting a path traversal attack.
A more sophisticated way is to use a JavaScript library function that can be used to check if a substring is a prefix of a string. For example, the following XSJS application uses String.indexOf(substring) to check if the name of the directory is indeed the directory resolved by path.join(prefix, suffix). If the absolute path obtained by the join function does not start with the target folder's name, the entryPath contains bits such as ../ that traverses the path.
var zipArchive = new $.util.Zip(requestBody.asArrayBuffer());
var targetFolderName = "unzipped";
for (var entryPath in zipArchive) {
var targetFilePath = require("path").join(targetFolderName, entryPath)
if (targetFilePath.indexOf(targetFolderName) === 0) {
require("fs").createWriteStream(targetFilePath).write(zip[entryPath]);
}
}This XSJS application simply appends the path of each entry to a target directory name and a separator then saves it to a file with the concatenated path, thereby skipping any validation on it.
var zipArchive = new $.util.Zip(requestBody.asArrayBuffer());
var targetFolderName = "unzipped";
for (var entryPath in zipArchive) {
var targetFilePath = targetFolderName + "/" + entryPath;
require("fs").createWriteStream(targetFilePath).write(zip[entryPath]);
}- SAP: Server-Side JavaScript Security Considerations.
- OWASP: Path Traversal.
- SAP XSJS Documentation: $.util.Zip.
- Common Weakness Enumeration: CWE-23.
- Common Weakness Enumeration: CWE-59.