Three Dots Directory Traversal with Mv

Three dots directory traversal with mv

There may be no directory with the name ... in the current directory, but you're creating a file with that name. (Because it starts with a ., it's hidden).

You can see such hidden files if using the -a argument to ls:

$ ls -a
. ..
$ touch file; mv file ...; ls -a
. .. ...

How can I put files into subdirectories based on the name of the file using bash?

You can do it simpler because mkdir -p path/to/yours works just with one invocation. You do not have to recursively create subdirectories one by one.

Would you please try:

cd /directory/with/files        # cd to directory where files are located

for file in *; do
[[ -f $file ]] || continue # skip non-file entries (just in case)
dir=${file%_*}
base=${file##*_}

dir=${dir//_/\/} # replace "_"s with "/"s
mkdir -p "$dir"
mv -- "$file" "$dir/$base"
done

[Strict Version]
The script below performs the validation of the filenames (with a help of jhnc).

for file in *; do
[[ -f $file ]] || continue # skip non-file entries (just in case)
dir=${file%_*}
base=${file##*_}

dir=${dir//_//} # replace "_"s with "/"s

# validate filenames
case "/$dir/" in
*/../* | */./* | //*) # $dir contains extra dot(s)
echo "skipping invalid filename: $file"
continue
;;
esac
if [[ -z $base ]]; then # the filename ends with "_"
echo "skipping invalid filename: $file"
continue
fi

mkdir -p "$dir"
mv -- "$file" "$dir/$base"
done

Result:

/directory/
└── with
└── files
└── 2020
├── Documents
│   ├── Bills
│   │   └── Water Bill.pdf
│   ├── Receipts
│   │   └── Store Name
│   │   └── Groceries.pdf
│   └── Taxes
│   └── W2.pdf
└── Pictures
└── Family Trip
└── California
└── Disney Land
└── Family Pic.jpg

Dot-dot removed from URL by Firefox

".." means a relative path and used for moving up in the hierarchy. So ".." is not a valid name for a folder therefore you cannot use it in the middle of URL. It just makes no sense.

So to answer your question: ".." is allowed in url but only in the beginning.

Directory traversal with chdir() instead of with absolute paths

I don't think you should expect a substantial time performance difference between the absolute path version and the chdir() version. Rather, the pros and cons of both versions are as follows:

  • The full pathname version might not be able to traverse very deep directory structures because the length of the full pathname eventually exceeds PATH_MAX. The chdir() version does not have this problem.
  • The chdir() version manipulates the pwd, which is generally considered bad practice if you can avoid it: it's not thread-safe, and the end user might expect it to be left alone. For example filenames given on the command line and used by a different part of the program might be relative to what the user thought the pwd was, which breaks when you change it.
  • The chdir() version might go out of control when backing up to a higher directory (chdir("..")) if special care is not taken and the directory structure changes while it is being traversed. Then again the full pathname version might break in a different way under these circumstances...

The openat() family of functions available on modern POSIX systems offer the best of both worlds. If these functions are available, openat() together with fdopendir(), fstatat(), etc... make for a really nice implementation of directory walking.

Is directory traversal via request.url possible?

I was gonna say that you can be sure that it's not possible, then I tried and I have to say that no, it doesn't seem like the http module removes '/../'. The redirection you saw is done in the browser. So whether it's a security risk or not depends on how your static handler is implemented.

Proof of concept:

// Server
var http = require('http');

http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(req.url);
}).listen(1337);

Curl it:

curl  --path-as-is "http://localhost:1337/static/../app.js"
# /static/../app.js

So if you use a homebuilt static handler that just uses path.resolve() you're screwed. Hopefully popular ones like express.static have thought about this, but i haven't tried it.

Update

Express indeed responds with a 404 "Error: Forbidden".

How to deal with Path Traversal?

An easy way would be to validate the fileName through a regex that detects any ../ segments and returns an error if any are present.

if (fileName.match(/\.\.\//g) !== null) {
// return an api error
}

You could have quite a tight validation rule that prevents any forward slashes in fileName at all, making it only possible to point to a file directly in your desired directory.



Related Topics



Leave a reply



Submit