World Readable Files
Everyone counts their CVEs but do they check for world-readable passwords?
Imagine finding this sight on prod (easier done than it should be):
$ ./worldreadable.py /tmp | grep '\\.password'
/tmp/secret/oops.password
/tmp/deleteme/key.password
In Linux, everything, well most things, are a file. Some of these are pretty benign (e.g. user lists, os version, installed packages). Many other files can be much more sensitive (e.g. passwords, tokens and data).
Files in Linux tend to be readable by default, unless you explicitly set the permissions. Putting these new files in a directory accessible by anyone will make these files world-readable.
World-readable : readable by any user on the machine, regardless of their groups.
The default file permissions are a result of the umask number. Without going into the details on umask in this post:
umask 022
(common default) creates files readable by everyoneumask 027
(more secure) creates files readable only by yourself (and your group)
It can be set and checked using the umask
utility.
If it is set to 022 (expected), be careful and think before you create anything sensitive.
The umask can be set temporarily for a bash session, just run umask 027
or umask 077
. Do this whenever you’re working with credentials to avoid creating world-readable files. This is a simple and effective habit to start today.
(Side note: User home directories are world-readable in some distributions, Debian being one of them – not the best decision.)
Why does this matter?#
If your machine only has one user, world-readable files aren’t a huge issue. You’re the only user so there isn’t much risk allowing “other” users read access. However, some applications may still use “special” users to sandbox their process – this breaks down some of those protections.
On machines with multiple users, world-readable files are a more obvious issue. If a user writes their session token or password (e.g. keytab) to a world-readable file, any other user on that machine will be able to use those credentials (them or a malicious program they ran).
Quickly scanning for world-readable files#
When working out if a file is world-readable, we obviously need to check the permissions assigned to allow of its parent directories. A file is only world-readable if it is readable and all parent directories are accessible
Note: An “accessible” directory is any directory allowing anyone execute (x) permissions, read (r) access isn’t actually required to read files inside it.
$ tree -pufid /a
[drwxr-xr-x] /a
[-rw-r--r--] /a/password1.txt # (world-readable)
[-rw-r-----] /a/password2.txt # (not world-readable)
[drwxr-x---] /a/b
[drwxr-x--x] /a/b/c
[-rw-r--r--] /a/b/c/password3.txt # (not world-readable)
Thankfully, we can scan for these files pretty quickly using a depth-first search, checking any directory for execute permissions and any files for read permissions.
In Python, it ends up looking like this:
#!/usr/bin/env python3
import os
import stat
import sys
def scan_world_readable_files(path):
''' generate scan of world readable files '''
children = os.listdir(path)
for child in children:
child_path = os.path.join(path, child)
if os.path.islink(child_path):
continue
child_mode = os.stat(child_path).st_mode
if os.path.isdir(child_path) and child_mode & stat.S_IXOTH != 0:
yield from scan_world_readable_files(child_path)
elif os.path.isfile(child_path) and child_mode & stat.S_IROTH != 0:
yield child_path
def main():
if os.geteuid() != 0:
print('WARN: Script should be run as root', file=sys.stderr)
base_paths = sys.argv[1:] or ['.']
for base_path in base_paths:
for path in scan_world_readable_files(base_path):
print(path)
if __name__ == '__main__':
main()
(Side note: This script should be run as root, can you see why?)
Running this on our example above, we get (anything world-readable file called password is a red flag):
$ ./worldreadable.py /a
/a/password1.txt
This runs quickly and I’d be surprised if you don’t find something on a multi-user machines.
Call to action#
Security requirements monitoring tend to focus on well-defined standards SOC2, CIS, CVEs. This does a good job ensuring the tools you use are secure, but it won’t always guarantee you are using them in a secure way. Don’t let dashboards and certifications distract you from the fundamentals.
Scan for world-readable files and scan often, especially on machines with multiple users.
Use umask 027
or umask 077
in any session involving the creation of credentials (better safe than sorry).