💾 Archived View for thrig.me › blog › 2023 › 04 › 02 › wacky-unix-paths.gmi captured on 2024-07-09 at 01:00:28. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-11-14)
-=-=-=-=-=-=-
/bin//sh is a legal path.
$ which /bin//sh /bin//sh $ /bin//sh -c 'echo hi' hi
/bin//sh is typically used for not so legal purposes. /bin//sh unlike the normal form /bin/sh fits neatly into a 64-bit box, and one may not want any NUL characters in that box...because reasons.
/ b i n / / s h 00101111 01100010 01101001 01101110 00101111 00101111 01110011 01101000 / b i n / s h \0 00101111 01100010 01101001 01101110 00101111 01110011 01101000 00000000
So if you see /bin//sh it may not necessarily be a typo. It may also be up to no good. "shellcode" might be something to read up on.
This is an extremely important distinction for rsync, in that rsync does different things depending on whether a trailing / is present.
A trailing slash on the source changes this behavior to avoid creating an additional directory level at the destination. You can think of a trailing / on a source as meaning "copy the contents of this directory" as opposed to "copy the directory by name", but in both cases the attributes of the containing directory are transferred to the containing directory on the destination.
-- rsync version 3.2.5 protocol version 31
A good way to learn this difference is to practice with some small test directories to see what goes where. This is probably better than learning on a production system with production data. Also, always be sure to check your chdir(2) calls for errors. That is,
cd -- "$somehwere" ; something-that-assumes-somewhere
is very bad, and must be changed to
cd -- "$somehwere" && something-that-assumes-somewhere
I learned that one in production. The cleanup was not pretty, and took some time. rsync was involved.
$ pwd; (cd /etc && pwd); pwd /tmp /etc /tmp
Likewise for path merging a trailing slash or not yields a different result:
$ perl -MURI -E 'say URI->new_abs(qw[ passwd file:///etc/ ])' file:///etc/passwd $ perl -MURI -E 'say URI->new_abs(qw[ passwd file:///etc ])' file:///passwd
Your software may need to be aware of this difference.
Very silly things are supported;
$ cd ////////////////////////etc//////////////////////// $ pwd /etc
one may want to normalize paths somehow, and probably to match how realpath(3) does it. Or if you can just use it. Be aware that resolving a path and resolving symlinks may be two different things.
$ cd ../../../../../../../../../../etc $ pwd /etc $ exec zsh % p=../../../../../../etc ; print -l $p $p:a ../../../../../../etc /etc % cd /tmp % mkdir -p a/b/c % ln -s a/b/c % p=c ; print -l $p $p:a $p:A c /tmp/c /tmp/a/b/c
Leading ../ are legal, though an attacker may try to get to the passwd file or similar by backtracking out of a tree of unknown depth. chroot(8) or not granting permission to read from most files (to say less of write permissions) are typical steps here.
Software depots may make heavy use of symlinks including ../ runs to fit everything together.
A path might be changed underneath you. There are various system calls that operate on a descriptor rather than a path.
tags #unix