The Hare And The Tortoise
Misc, 350 points.
Challenge
Do you know Jean de La Fontaine? A friend of mine created a program mimicking the hare and the tortoise. He told me that smart tortoises always wins. I want you to be that tortoise. Connect with
ssh [email protected]
. Password :tortoise
Source Codes
Walkthrough
After connecting to the server with SSH, we observe that there is a compiled binary and a flag.txt, plus the source codes of the target binary (linked above). The target binary is a setuid binary. This means we can only read the flag by running the binary.
[email protected]_hare_and_the_tortoise$ ls -l
-r-------- 1 hare hare 77 May 11 09:04 flag.txt
-r--r--r-- 1 root root 2360 May 11 09:04 main.c
-r--r--r-- 1 root root 687 May 11 09:04 semaphores.h
-r-sr-xr-x 1 hare hare 2754 May 11 09:04 the_hare_and_the_tortoise
when we run the program, we get
[email protected]_hare_and_the_tortoise$ ./the_hare_and_the_tortoise flag.txt
The tortoise, progressing slowly... : "s"
The hare says : "Do you ever get anywhere?"
The tortoise, progressing slowly... : "h"
The tortoise, progressing slowly... : "k"
The tortoise, progressing slowly... : "C"
The tortoise, progressing slowly... : "T"
The tortoise, progressing slowly... : "F"
The hare says : "Hurry up tortoise !"
The tortoise, progressing slowly... : "{"
The tortoise, progressing slowly... : "r"
The tortoise, progressing slowly... : "4"
The tortoise, progressing slowly... : "c"
Killed
Inspecting the source code, we find that the hare process, after setting all the semaphores, sets an alarm to be 5 seconds later. When it receives the SIGALRM
, it kills the tortoise process. Intuitively, we want to bypass the timer by trapping the signal. However, this doesn't work because the program overwrites the alarm handler. Due to the nature of a SUID program, we cannot replace libc
with LD_PRELOAD
or hook it up with gdb
. So there is only one way left to intercept the signal: kill the hare process with SIGKILL.
It might seems as if we have to write a program to time everything carefully so that we send SIGKILL
immediately after the "Hurry up tortoise" shows up. However, since we have 5 seconds to do it, we can actually start a different ssh session, run ps aux | grep the_hare_and_the_tortoise
, and send the hare process a SIGKILL
manually. The PID of the hare process is always larger because it is the child process. This sounds like it requires some very quick actions, but with the help of bash's history completion, I got it on the third try.
The tortoise, progressing slowly... : "s"
The hare says : "Do you ever get anywhere?"
The tortoise, progressing slowly... : "h"
The tortoise, progressing slowly... : "k"
The tortoise, progressing slowly... : "C"
The tortoise, progressing slowly... : "T"
The tortoise, progressing slowly... : "F"
The hare says : "Hurry up tortoise !"
The tortoise, progressing slowly... : "{"
The tortoise, progressing slowly... : "r"
The tortoise, progressing slowly... : "4"
The tortoise, progressing slowly... : "c"
The tortoise, progressing slowly... : "3"
The tortoise, progressing slowly... : "5"
The tortoise, progressing slowly... : "_"
The tortoise, progressing slowly... : "4"
The tortoise, progressing slowly... : "r"
The tortoise, progressing slowly... : "3"
The tortoise, progressing slowly... : "_"
The tortoise, progressing slowly... : "3"
The tortoise, progressing slowly... : "a"
The tortoise, progressing slowly... : "s"
The tortoise, progressing slowly... : "i"
The tortoise, progressing slowly... : "3"
The tortoise, progressing slowly... : "r"
The tortoise, progressing slowly... : "_"
The tortoise, progressing slowly... : "w"
The tortoise, progressing slowly... : "h"
The tortoise, progressing slowly... : "3"
The tortoise, progressing slowly... : "n"
The tortoise, progressing slowly... : "_"
The tortoise, progressing slowly... : "y"
The tortoise, progressing slowly... : "0"
The tortoise, progressing slowly... : "u"
The tortoise, progressing slowly... : "_"
The tortoise, progressing slowly... : "4"
The tortoise, progressing slowly... : "r"
The tortoise, progressing slowly... : "3"
The tortoise, progressing slowly... : "_"
The tortoise, progressing slowly... : "a"
The tortoise, progressing slowly... : "l"
The tortoise, progressing slowly... : "0"
The tortoise, progressing slowly... : "n"
The tortoise, progressing slowly... : "e"
The tortoise, progressing slowly... : "_"
The tortoise, progressing slowly... : "6"
The tortoise, progressing slowly... : "a"
The tortoise, progressing slowly... : "2"
The tortoise, progressing slowly... : "6"
The tortoise, progressing slowly... : "a"
The tortoise, progressing slowly... : "2"
The tortoise, progressing slowly... : "6"
The tortoise, progressing slowly... : "c"
The tortoise, progressing slowly... : "5"
The tortoise, progressing slowly... : "7"
The tortoise, progressing slowly... : "f"
The tortoise, progressing slowly... : "0"
The tortoise, progressing slowly... : "0"
The tortoise, progressing slowly... : "1"
The tortoise, progressing slowly... : "2"
The tortoise, progressing slowly... : "e"
The tortoise, progressing slowly... : "d"
The tortoise, progressing slowly... : "6"
The tortoise, progressing slowly... : "6"
The tortoise, progressing slowly... : "a"
The tortoise, progressing slowly... : "b"
The tortoise, progressing slowly... : "8"
The tortoise, progressing slowly... : "c"
The tortoise, progressing slowly... : "2"
The tortoise, progressing slowly... : "0"
The tortoise, progressing slowly... : "e"
The tortoise, progressing slowly... : "5"
The tortoise, progressing slowly... : "3"
The tortoise, progressing slowly... : "8"
The tortoise, progressing slowly... : "a"
The tortoise, progressing slowly... : "0"
The tortoise, progressing slowly... : "4"
The tortoise, progressing slowly... : "}"
The tortoise, progressing slowly... : "}"
Slow but steady wins the race!
After parsing the output, we get the flag.
shkCTF{r4c35_4r3_3asi3r_wh3n_y0u_4r3_al0ne_6a26a26c57f0012ed66ab8c20e538a04}