Breaking out of CHROOT Jailed Shell Environment

Learn the basics of how chroot actually works, what is different between process current working directory and root directory and how the limitation in chroot which help you break out to root file system

Breaking out of CHROOT Jailed Shell Environment

Till now you have been struggling for getting the root user on the system via different techniques. What if I told you are already a root user but still can't access some files and don't even have /root directory or other directories like /sys or /proc

Well, don't get deceived by such root environments. These types of environments are called chroot jails. Today I will put some light on breaking out of chrooting jail environment using the second-chroot method

What is chroot anyway?

Have you ever encountered a situation where the system is powered off while updating the kernel version and when you switch on again, the kernel panic happens? To fix this what actually you do is

  1. Boot live Linux OS
  2. Mount the root partition
  3. Chroot to the new partition and fix the issue
  4. Reboot the system and remove Live OS USB  

Chroot is a syscall and command-line utility that changes the root directory for the current running process and its children to create file system level isolation, don't confuse it with the current working directory.

The top of file hierarchy in Linux OS is root (/), you can not go above beyond this. So even if you perform cd .. on the root directory, it will land you in the same directory only. For instance, here I performed cd .. 100 times on root directory

Enough talk, let's see chroot in action

Here, I am creating the chroot directory, copying files necessary for the chroot environment to spawn a shell and continue execution.

# id -ur ; whoami 
# mkdir chroot
# cp -a bin/ usr/ lib/ root/ chroot/
# ls 
bin     chroot  dev     etc     home    lib     media  ... truncated
# chroot chroot/ sh
# id -ur ; whoami 
whoami: unknown uid 0
# ls 
bin   lib   root  usr

Did you notice, whoami command failed with a message "unknown uid 0", this is because the utility command is looking for /etc/passwd file to compare uid = 0 with the name of the user. I did not intentionally copy that directory to show that there is no way for a regular program to break out of the chroot environment and read the real file system.

However, the environment variables are passed from the host to the chrooted environment

# export NAME=tbhaxor
# chroot chroot/ 
# echo $NAME

All the commands will inherit the root directory from chroot and environment variables from the host. If you add or modify any environment variables here, it will not affect the host shell

If you are looking for the real-world use cases of the chroot environment, they are already listed here on its Wikipedia page –

Understanding Process CWD vs ROOT

Linux /proc filesystem manages two paths for the currently running process.

  • cwd – current working directory of the process
  • root – root directory of the process

A root directory is a symlink to the Linux file system where actually the program is running. Usually, it is set to / but for the chrooted environment it is set to the path of the directory passed as the first argument to chroot command. It can not be changed by process directly, but chroot() syscall does this

The current working directory is the symlink to the directory where the process is currently running from its root directory. This can be easily changed by calling cd shell utility or chdir() syscall

Allow me to show this in a chrooted environment practically. To demonstrate I will keep the cat process open on the chrooted environment will look at the /proc file system from the host file system

# ps -eaf
    1 root      0:00 /bin/sh
   14 root      0:00 bash
   22 root      0:00 bash
   58 root      0:00 /bin/sh -i
   60 root      0:00 cat
   62 root      0:00 ps -eaf
# ls -l /proc/60/cwd
lrwxrwxrwx    1 root     root             0 Aug 22 22:12 /proc/60/cwd -> /chroot
# ls -l /proc/60/root
lrwxrwxrwx    1 root     root             0 Aug 22 22:12 /proc/60/root -> /chroot

Now after changing the directory to "/usr/bin" in the chrooted environment and again run the cat program

# ps -eaf
    1 root      0:00 /bin/sh
   14 root      0:00 bash
   22 root      0:00 bash
   58 root      0:00 /bin/sh -i
   66 root      0:00 cat
   67 root      0:00 ps -eaf
# ls -l /proc/66/root
lrwxrwxrwx    1 root     root             0 Aug 22 22:13 /proc/66/root -> /chroot
# ls -l /proc/66/cwd
lrwxrwxrwx    1 root     root             0 Aug 22 22:13 /proc/66/cwd -> /chroot/usr/bin

As you can see, cwd is changed but is appended to the root directory. Apparently, in the host file system, it will start from /, not any other folder like /chroot in this case

Understanding Chroot Limitation

When you perform the first chroot in a directory, it spawns a shell with root user privileges. For the operating system, it will be running the shell in the directory but for chrooted it will be running in the root directory

/ # chroot  chroot/
/ # ls -l
total 16
drwxr-xr-x    2 0        0             4096 Aug  6 21:29 bin
drwxr-xr-x    7 0        0             4096 Aug  6 21:29 lib
dr-xr-xr-x  428 0        0                0 Aug 22 22:38 proc
drwx------    2 0        0             4096 Aug 22 22:38 root
drwxr-xr-x    8 0        0             4096 Aug  6 21:29 usr
/ # ls -l /proc/self/cwd
lrwxrwxrwx    1 0        0                0 Aug 22 22:39 /proc/self/cwd -> /
/ # ls -l /proc/self/root
lrwxrwxrwx    1 0        0                0 Aug 22 22:39 /proc/self/root -> /

In the above example, I have used privileged docker container to bind mount /proc from host to /proc in a chrooted environment which will be /chroot/proc on the host file system

Now here comes the limitation of the chroot. When running with root user, malicious users can perform second-chroot and without letting kernel change the current working directory, This way there will have some reference to the outside of the chrooting environment, performing chdir("..") on outside the second chroot will traverse it to the host file system root directory. Now then you perform chroot(".") it will take the path from cwd instead of root.

So to break out from chroot environment, you need 2 basic requirements

  1. A privileged shell
  2. Any program that let you call 3 syscalls

Let's see this in action. I will run the following script and inspect cwd and root in the process

import os

print("PID", os.getpid())

if not os.path.exists("chroot"):

# almost every exploit will have 1000 iteractions
# since now you know the working, let's use 1

# prevent the python from exiting
input("Press enter to exit")

After running the exploit and reading input function, when you will run another shell and find cwd and root of the python process, you will find the following

/ # ps -eaf
    1 root      0:00 /bin/sh
   51 root      0:00 bash
   75 root      0:00 /bin/sh -i
   78 root      0:00 python
   81 root      0:00 sh
   84 root      0:00 ps -eaf
/ # ls -l /proc/78/cwd
lrwxrwxrwx    1 root     root             0 Aug 22 23:16 /proc/78/cwd -> /
/ # ls -l /proc/78/root
lrwxrwxrwx    1 root     root             0 Aug 22 23:16 /proc/78/root -> /chroot/chroot

To actually breakout, you need to add the following lines of code instead of input() from the above code


For your reference, I have created the following diagram with the flow of execution of the breakout

There are several other techniques explained in the chw00t exploit. This is the most basic one and can be fixed by simply dropping root user privileges after chrooting. Then it will prevent malicious users to perform a second chroot. This is already explained on Wikipedia, under the Limitations section –

Since I have already explained the break out in detail, I recommend you solve the following labs on your own at first

If you face any error or want hints, do contact me