Silly Gunslinger Joe has learned from his mistakes with his private terminal
and now tries to remember passwords. But he’s gotten more paranoid and chose
to develope an additional method: protect all his private stuff with a secure
locking mechanism that no one would be able to figure out! He’s so confident
with this new method that he even started using it to protect all his precious
gold. So… we better steal all of it!
Author: Sam Thomas / xorpse
After logging in, we see that there are two files in the home directory:
Notice the setuid and setgid bits on gold_stash: when executed, gold_stash
will run as if started by the user gold. Note also that FLAG is only
readable by the user gold.
After transferring gold_stash to a local directory and executing it, we are
presented with a basic login prompt:
Disassembling the main function, gives us the credential input routine:
Followed by an uninteresting section of code for removing trailing newlines
(due to the use of read).
And finally, the authentication check using hardcoded credentials:
So with the user/password combination (Joe/omg_joe_is_so_rich), we try to gain
Success! However, applying the same method on the challenge server yields
What could be wrong? If we debug with gdb on the challenge server we get the
expected result. However, gdb executes gold_stash as the user joes_gold
rather than gold. Ergo, one of strcmp or read must be behaving
differently when executed as the user gold.
A look into the libc.so.6 binary on the system reveals nothing untoward;
another possibilty is that a system call has been hijacked, and an ls of the
kernel modules directory seems to point in that direction (notice the joe
…which contains a module joe.ko. Such module should contain an init
function. In this case, joe_init. In order to hijack a system call, the
system call table must be located:
Once found, it’s stored within sct. read is the first system call, (i.e. at
offset 0 within sct) and is replaced with a function called joe:
The address of the original read function is saved to o_read.
The function joe (from a high-level) works as:
Read buffer using o_read;
Copy buffer from user to kernel using copy_from_user;
If uid == 1001: encode first 18 characters using:
If the original string compared equal to ‘omg_joe_is_so_rich’ or if
the original string had the prefix ‘omg_joe_is_so_rich’ then the encoded
value replaces it (via copy_to_user).
To get the desired string we need to encode ‘omg_joe_is_so_rich’:
Which gives: bcXoc]VkTGrE_oKcXT as the encoded password.