Bash under the hood — Command Lookup
When you execute a command in bash, have you ever thought about the process it goes through to do it?. In this post, I'm going to explain the background process that bash use to search the command and how this can affect the security in your system.
Command types
Bash has many types of commands:
- Builtin commands. Are built into a shell because not have alternatives or are some internal-function/keyword like
for
,while
,if
, etc. In this case, bash doesn't require searching an executable of some other file, the only process that makes is an internal call for executing the command. - External commands. Are external commands defined in a binary file or some type of file that can be interpreted. Some examples are
python3
,awk
,sed
, etc. To execute this type of command, bash check an environment variable namedPATH
, this contains a list of paths separated by:
, these are the directories where bash is going to search the executable file that matches with the name of the command. - Alias commands. An alias lets you create a shortcut name for a command, file name, or any shell text. You can use aliases to redefine built-in commands but not to redefine reserved words.
How determinate the command type?
To determinate the type of some command you can use type
. For example, cd
is a built-in command :
Input:
type cd
Output:
cd is a shell bultin
Why cd
need to be a built-in command?. Because the shell process is linked with a special variable named Working Directory, this variable determines the current directory of the process and when you change from one directory to another, the only change that you do is in this variable that is attached to the shell process.
Some other commands don’t require this type of internal change in the shell process, one example is the date
command. Thedate
is implemented as an external command, in others words, is an executable file located in some path in the operating system.
Input:
type date
Output:
date is /usr/bin/date
In this case, /usr/bin/date
is the path where the executable file related to the date
command is located. This path can change depending on the current hierarchy of the file system.
Hashed commands
In some cases, when you use the type
command you can receive a message related to a hash, one example is:
Input:
type python3
Output:
python3 is hashed (/usr/bin/python3)
When you see a “python is hashed” message like the one above, that means that the command has been put into a hash table for quicker lookup.
To display all the commands that are hashed, you can use:
Input:
hash -l
Output:
builtin hash -p /usr/bin/sed sedbuiltin hash -p /usr/local/bin/python3 python3builtin hash -p /usr/bin/awk awk
....
Sometimes, you need to research the path of some command that is in the hash table, in these cases, you can delete the entry of some specific command with the -d
option.
hash -d [COMMAND]
Or you can delete all the entries with:
hash -r
Environment variable PATH
In the past, when we mention the type of commands, we found that the external commands are searched in an environment variable named PATH
, but, what is an environmental variable?.
Environment variables are some dynamic variables, that sometimes is used to change the behavior of some process. In these cases, the PATH
is an environment variable that defines the places where bash is going to search an executable file that matches with a command which could not be identified as built-in.
You can see the content of the environment variable PATH
with:
Input:
echo $PATH
Output:
/bin:/usr/local/games:/usr/games:/snap/bin:/usr/local/go/bin:/home/blue/.bin/:/home/userA/go/bin:/home/userA/.poetry/bin/......
As you can see, this can be a very large string. The way to interpret this string is to split it by the :
character, the tokens created are paths in your system that identified the directories where your system is going to look up for files that match with commands which can not be identified as built-in commands.
Duplicated commands
Some commands are repeated, in other words, is possible to have a command that is a built-in command and external at the same time but in the execution time, only one of them can be executed.
You might notice that some of these built-ins (e.g., echo and kill) also exist as executables. It is even possible to have several versions of the same external command scattered under different directories subscribed to in the PATH
variable. The type
command has an -a
option that displays all locations containing a command, for example:
Input:
type -a kill
Output:
kill is a shell builtinkill is /usr/bin/killkill is /bin/kill
To redefine the built-in commands or external commands, you have many alternatives:
- Create an alias. The alias commands have more priority in the lookup process than the built-in commands and external commands.
Example:
ls='ls --color=auto'
Note. In this case, when we execute the ls command, this is going to expand to the
ls
command with the--color=auto
as if it were a shortcut.
2. Put an executable file with the same name of the command in some directory that is defined in the PATH
variable, and use enable -n command
to disable the built-in command. In the case of overriding an external command, you only need to put the directory before the directory of the original command.
Note. For get a complete list of all the built-ins commands that are enabled or disabled, use
enable -a
.
Security Issues
The misconfiguration of the environment variable PATH
is a very common way to make a Privilege Escalation. If you notice that the relative path ‘.’ is in the environment PATH
variable, that means that the logged user can execute files from the current directory without append ./
, this may result in executing a “suspicious” scripts in your current directory that has the same name as some global command only because the current directory (.) is first declared in the PATH
variable.
Exists many techniques to get root permissions with this method, but all of the relief of generating a fake executable with the same name of some target command, that forces the user to execute your fake command when he intends to execute the original command, this is caused by exploiting some of the over curing techniques mentioned above.
For more detailed examples, check this post that explains in detail many techniques to achieve this.
Thanks for reading!
This is all for this post, I hope the content has been to your liking, see you in the next post.