The are more than one way to solve this challenge, and me being me I chose the hard way. After
finally solving this challenge it was time to read other peoples writeups, as usual. I will
share the easy way at the end, but I think you could learn a thing or two from the way I
solved it. To start I decided to directly go and reverse the binary since Behemoth doesn’t
offer any source code. I’m using radare2 to reverse the binary. Here is the main function.
From the above we can see that it initializes a variable on the stack string at ebp-0x24 with a string
"touch <pid>" where <pid> is the process id of the program. There is also another
variable path at ebp-0x10 which points into the string variable and contains the
process id of the program as a string.
After that it calls lstat on a file named as the process id of program. lstat is just like
the stat function except it is used for symbolic links. The stat family of functions are used to get information
about a file. The conditional after the call to lstat is still a mystery I have no idea
why it is anding the returned value with 0xf000 and comparing it with 0x8000. Regardless
if the condition fails it deletes the file using unlink and creates a new one using
system("touch <pid>").
After all this it sleeps for about 2000 seconds that’s about 33 minutes. Then it loads
the address of string into eax and moves 0x20746163 to it, which is equivalent to "cat ".
If you remember earlier string contained "touch <pid>" Which means after this instruction
string will become cat h <pid>.
I had to do some dynamic analysis to figure out the last part. And in the end it executes
with system("cat h <pid>"). I set two break points one after the value is loaded and one
when calling the sleep function. When I reached the first break point I used the
jump address function to avoid waiting for the sleep function. When I examine the string
variable i.e. ebp-0x24 there you have it cat h <pid>
Exploit
The exploit I thought of is simple. Since cat can take multiple files as an argument and
print them all I had to do is create a symlink to the file I want to read and the program
will read for me. The problem is the sleep part which I found no way of evading. After
crating the symlink and waiting for the sleep to finish your flag will be printed for you.
First we have to make a directory where we have a write access to.
behemoth2@behemoth:/tmp/abcd$ mkdir /tmp/abcd
behemoth2@behemoth:/tmp/abcd$ cd /tmp/abcd
And make it readable, writable, and executable by everyone.
behemoth2@behemoth:/tmp/abcd$ chmod 777 .
I tried symlinking /etc/behemoth_pass/behemoth3 to h that didn’t work, so the next thing
I tried was symlinking it to the file which had the process id as it’s name. To get this
you first have to run the program and after it has created the file take a note of it’s
name, delete it, and create a symlink with it’s name to /etc/behemoth/behemoth3.
behemoth2@behemoth:/tmp/abcd$ /behemoth/behemoth2
In another terminal or ssh session, I’m using tmux, when you do ls you should see the file
behemoth2@behemoth:/tmp/abcd$ ls
24513
behemoth2@behemoth:/tmp/abcd$ ln -s /etc/behemoth_pass/behemoth3 24513
And after a while, 33.334 minutes to be exact, you should see your password to behemoth3.
behemoth2@behemoth:/tmp/abcd$ /behemoth/behemoth2
# after a long time
nieteidiel
If you noticed earlier the program is using touch to create the file, and it’s using it
in unsafe way by not specifying the full path. This can be exploited by changing the
PATH environment variable to contain our malicious version of touch.