Restricted shells escaping techniques – 2

OSCP Study materialLinux privilege escalation

In this blog, we will use programming techniques to bypass restricted shells

Programming languages are great resources for running different commands and other applications to avoid shell restrictions. Examples go on and on endlessly due to the nature of programming languages being very complete and full of features. Remember that generally programming function calls use special characters like commas, parentheses, semicolons, etc, so if the restricted shell in place is not blocking their use, the techniques below will probably work. Let’s analyze some very well known examples:

1.awk Command

The awk is an interpreted programming language designed for text processing. It is a standard feature of most Unix-like operating systems, that’s why we can generally find them allowed in shells.

It has a lot of functions like print()sprintf(), and others. Among the most interesting one is system(). The system() function allows us to use /bin/sh to execute a command in the system by using a very simple command line:

$ awk 'BEGIN {system("/bin/sh")}'

Notice that even if we are not allowed to directly run another shell (/bin/sh) inside lshell, we could easily escape its restrictions by using awk to open a shell for us:


2. Expect

Expect is yet another example of language. It’s more of a program that “talks” to other interactive programs according to a script. This means we can basically create a script inside expect for it to be run. Also, expect has a very interesting function called spawn(). Using spawn() it is possible to drive an interactive shell using its interactive job control features. A spawned shell thinks it is running interactively and handles job control as usual.

Let’s execute a simple command in expect instructing it to spawn a /bin/sh shell for us :


Notice that we were not allowed in lshell to directly execute /bin/sh, nevertheless, we successfully bypassed that restriction by instructing expect to interactively run /bin/sh.

The same could be accomplished with a more simple command such as:



Python is again another very good language to work with. Very flexible and reliable. It has a lot of functions we can use to execute commands in shell, such as system()pty(), and many others. Let’s explore a simple example:


We managed to execute the function print() to echo the string “testing”, so it shouldn’t be difficult to execute any other command like ls or even a shell. For the first example, we are importing the OS module, responsible for OS interaction, and finally using system() function to run a forbidden command, cp, just as a proof of concept:

python os

Notice that we successfully run cp command, so it wouldn’t be difficult to run a shell. Let’s do it:


And there we have it. The same example could be applied in a number of different ways, using different functions, like spawn() function in pty module, as can be seen below:


The techniques you can use will only depend on the functions you have at your disposal.

If we want the shell to be available remotely we can use a reverse shell technique instructing python to open a socket to our attacker machine, like this:


Checking our attacker machine which is already listening on port 5000:



The same can be accomplished in ruby. Let’s do a simple example using irb (Interactive Ruby Shell) from where we can directly invoke a shell or any other command:


Notice that we successfully again obtained a /bin/sh inside irb.

Another way to accomplish the same thing as a reverse shell is by instructing ruby to open a TCPSocket to our attacker machine, and redirecting the interactive shell, like this:



Again another simple example. Let’s use Perl with system() method to execute a forbidden command, cp, using /bin/sh as our interpreter:\


We managed to execute the command, now shouldn’t be difficult to execute a shell:


And again we did it! Another way to accomplish the same thing is by using the exec() the method, like this:


We can get a reverse shell by instructing perl to open a socket to our attacker machine, like this:


Checking our attacker machine which is listening on port 5000:

nc 500


PHP Language has a lot of options to execute commands in a shell, among them the already famous system() and exec(). You can either do it interactively inside php console, or directly in the command line as we did before in ruby, python and Perl.

Here is an example of PHP being used interactively:


Here we managed to run a forbidden command cp. Let’s use now the exec() function to try to execute an interactive shell:


And there we have it. We really don’t need the interactive mode to get a shell in the box. We can simply execute php scripts on the command line and make our victim to send us its reverse shell, like this:


Checking our attacker machine which was already listening port 5000:


Special case

[email protected]:~$ ls 
-rbash: /usr/bin/python: restricted: cannot specify `/' in command names [email protected]:~$  

[email protected]:~$ whoami
-rbash: /usr/bin/python: restricted: cannot specify `/' in command names 
[email protected]:~$ BASH_CMDS[a]=/bin/sh;a  
$ /bin/bash bash: groups: command not found 
[email protected]:~$ export PATH=$PATH:/bin/ 
[email protected]:~$ export PATH=$PATH:/usr/bin 
[email protected]:~/usr$ whoami hacker 
[email protected]:~/usr$ /bin/rbash  --version 
/bin/rbash  --version GNU bash, version 4.2.10(1)-release (i686-pc-linux-gnu) Copyright (C) 2011 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.

Advanced Techniques

Now let’s move into some dirty advance techniques.

1)From ssh

ssh [email protected] – t “/bin/sh” or “/bin/bash”

ssh [email protected] -t “bash –noprofile”

ssh [email protected] -t “() { :; }; /bin/bash” (shellshock)

ssh -o ProxyCommand=”sh -c /tmp/” (SUID)

2)From git

git help status > you can run it then !/bin/bash

7)From zip

zip /tmp/ /tmp/test -T –unzip-command=”sh -c /bin/bash”

3)From pico

pico -s “/bin/bash” then you can write /bin/bash and then CTRL + T

4)From tar

tar cf /dev/null testfile –checkpoint=1 –checkpointaction=exec=/bin/bash

Best Practices & Conclusion

As we saw, there is always a way to bypass restricted shell restrictions and bend the server to our will. We have covered just simple and well-known examples, but the possibilities are endless.

There are always new applications, features and new ways to find escape techniques in them, therefore it is almost impossible to restrict a shell in a way that it could be considered bulletproof, however, some best practices should be in place to have at least a minimum security level, they are:

  1. Prefer to work with “Allowed commands” instead of “Disallowed commands”. The number of commands with escapes you don’t know is far superior to the ones you do.

2. Keep “Allowed Commands” list to a minimum necessary.

3. Inspect your allowed commands for escaping features on a regular basis, either by studying the manual or search in the security community.

4. Check allowed commands that could interact with Linux system variables and restrict their access.

5.Scripts that invoke other scripts can be a security risk specially when they are running with other user’s privileges and software that allow escape or third party command execution. Try to avoid this.

6. If any command allowed has escapes or command execution features, avoid using it. If not possible try to enforce restrictions to block certain functions or use restricted versions. Some commands have restricted versions with no command execution support.

7. If providing Linux editors is inevitable, use restricted versions, such as:

  • vim = rvim (Restricted Vim)
  • ed = red (Restricted ED)
  • nano = rnano (Restricted Nano)

8. A nice hint for restricted software would be to provide them as a symbolic link. For all purposes, your user might think it’s using vim, for example, while it’s just a symbolic link to rvim.

9.If providing pagers is necessary to avoid less and more, and use pages that don’t provide command execution escape like most.

10. When using any software that has built-in third party editors support that relies on $EDITOR and $VISUAL Linux variables, make these variables read-only to avoid users changing it’s content to the software containing escapes.

11. Try to avoid allowing programming languages. If not possible ensure that configuration is hardened and dangerous functions such as pty()system()exec(), etc, are blocked. Some programming languages are easy to harden simply defining functions that are disabled, others are trickier and sometimes the only way to do it is either uninstalling certain functions or not providing the language itself.

For practical hands-on practice visit this link

References : –

Thanks for visiting this blog. Join Certcube Labs for IT security Training & Certifications.

Leave a Reply

Your email address will not be published.