observe that open(argv[1]) is called before chroot => use the second argument to open the real root directory, resulting in a fd outside the jail; in the shellcode, call openat with this fd to read the flag
like level 3, we can obtain a fd outside the jail, then use linkat syscall to make a hard link inside the jail so that subsequent syscalls can open and print the flag
the goal is to leave the CWD outside the jail so that it can be used to open the real flag file; to implement this, we can create a new directory inside the current jail and chroot the jail root to the new directory without cd, resulting in the CWD outside the moved jail
only openat() is allowed => require a fd outside the jail the challenge no more creates fd using argv[1] => do this manually by redirecting stderr to the root directory
in the challenge source code, observe that 32-bit mode syscalls are enabled and there is no chroot; given that all available syscall numbers are 3, 4, 5, and 6, we could use 32-bit versions of open(), read(), and write() to print the flag
prepare shellcode(index, value) such that the process sleeps iff flag[index] == value, then set a threshold time for the running process to tell if sleep() has been triggered or not, finally iterate all possible indices and values to test out the flag
defcrack(flag_array, n): for index inrange(n*8, n*8 + 8): for value inrange(256): if verify(index, value): flag_array[index] = value break
flag_array = multiprocessing.Array('d', [0]*64) workers = [multiprocessing.Process(target=crack, args=(flag_array, n)) for n inrange(8)] for worker in workers: worker.start()
print(bytes(flag_array))
Level 12
in this level only read() syscall is allowed; we can prepare shellcode(index, value) so that an extra read() is triggered iff flag[index] == value, that is, the process is blocked for reading iff flag[index] == value, then we can observe its runtime behavior to tell if the extra read() hsa been triggered
in this challenge a parent process would pass the provided shellcode to a sanboxed child process which executes the shellcode and can pass commands for the parent to execute, all syscalls except read, write, and exit are disabled in the child process, we can simply pass command to read the flag into a buffer and then print the buffer
p = process("/challenge/babyjail_level13") p.send(shellcode) p.interactive()
Level 14
this challenge creates a namespace sandbox but forgets to umount the original root so that we can directly read the flag in it
1
echo /old/flag
Level 15
since we can modify the host filesystem in the sandbox, adding the sid bit to cat
1 2 3
chmod u+s /bin/cat exit cat /flag
Level 16
this challenge allows us to access /proc directory in the sandbox, we can find the mount namespace of the host in /proc by file /proc/*/ns/mnt and then enter the host mnt namespace in a forked shell by nsenter --mount=/proc/1/ns/mnt /bin/bash and finally cat /flag
Level 17
this challenge allows us to pass any path except the flag to the sandboxed process from outside and run provided shellcode in the sandboxed process, we can pass the root directory and use openat and sendfile to leak the flag