This is part 1 in the series of “Beyond the good ol' LaunchAgents”, where I try to collect various persistence techniques for macOS. For more background check the introduction.
Shell startup files are executed when our shell environment like
bash is starting up. macOS defaults to
/bin/zsh these days, and whenever we open
Terminal or SSH into the device, this is the shell environment we are placed into.
sh are still available, however they have to be specifically started.
When we start
zsh it checks number of files, and if there is an environment variable or command inside, it will be set or executed. Probably the most common is
.zshrc, which is used to set the shell environment and execute commands. It can be found in the user’s home directory.
bash has a similar one, called
The man page of zsh, which we can read with
man zsh has a long description of the startup files.
STARTUP/SHUTDOWN FILES Commands are first read from /etc/zshenv; this cannot be overridden. Subsequent behaviour is modified by the RCS and GLOBAL_RCS options; the former affects all startup files, while the second only affects global startup files (those shown here with an path starting with a /). If one of the options is unset at any point, any subsequent startup file(s) of the corresponding type will not be read. It is also possible for a file in $ZDOT- DIR to re-enable GLOBAL_RCS. Both RCS and GLOBAL_RCS are set by default. Commands are then read from $ZDOTDIR/.zshenv. If the shell is a login shell, commands are read from /etc/zprofile and then $ZDOTDIR/.zprofile. Then, if the shell is interactive, commands are read from /etc/zshrc and then $ZDOTDIR/.zshrc. Finally, if the shell is a login shell, /etc/zlogin and $ZDOTDIR/.zlogin are read. When a login shell exits, the files $ZDOTDIR/.zlogout and then /etc/zlogout are read. This happens with either an explicit exit via the exit or logout commands, or an implicit exit by reading end-of-file from the terminal. However, if the shell terminates due to exec'ing another process, the logout files are not read. These are also affected by the RCS and GLOBAL_RCS options. Note also that the RCS option affects the saving of his- tory files, i.e. if RCS is unset when the shell exits, no history file will be saved. If ZDOTDIR is unset, HOME is used instead. Files listed above as being in /etc may be in another directory, depending on the installation. As /etc/zshenv is run for all instances of zsh, it is important that it be kept as small as possible. In particular, it is a good idea to put code that does not need to be run for every single shell behind a test of the form `if [[ -o rcs ]]; then ...' so that it will not be executed when zsh is invoked with the `-f' option. Any of these files may be pre-compiled with the zcompile builtin command (see zshbuiltins(1)). If a compiled file exists (named for the original file plus the .zwc extension) and it is newer than the original file, the compiled file will be used instead.
As we can see, beyond
.zshrc we have many other files, like
.zshenv and a few others. Normally these files don’t exists on macOS.
Similar startup files exists for
sh. The latter supports far less such files, checking the man page it’s very short.
The benefit of these scripts, especially
.zshrc which is used as the default shell environment, is that when Terminal is started, and it starts the shell, it will inherit Terminal’s privacy permissions.
Many power users will have “Full Disk Access” rights granted to Terminal (as shown above) and as such, it will be able to access many privacy sensitive locations. So if we place any script inside these files, it will have powerful rights. For example:
curl google.com cp -R ~/Library/Messages /tmp/
This script will do a network connection and copy
It will result in accessing messages as shown above.
Beyond that Terminal runs outside the sandbox, thus if we can place anything inside these script files, we can escape the sandbox.
Another related command to watch for, is
chsh, which can change the shell environment for a user.
chsh -s /bin/bash
As defenders it’s a good practice to monitor for the occurrence of these files, and if they exists, then analyze their content.