HTB Cyber Santa CTF 2021: minimelfistic

The Elves finally understood what went wrong with all their plans. It's a security system, but the alarm rings whenever Santa's house is vulnerable to an attack. Will you manage to deactivate it?

TL;DR

The program does not contain puts function and has insufficient gadgets for us to use a vanilla write function. Using ret2csu technique to control the registers and leak LIBC address, then leverage One Gadget to pop a shell.

Basic File Checks

After running the binary for a seemingly random amount of time, it will ask whether we want to turn off the alarm. Whether you put yes or no, it ignores you.

┌──(kali💀JesusCries)-[~/Desktop]
└─$ ./minimelfistic                      

[*] Santa is not home!

[*] Santa is not home!

[!] Santa returned!

[*] Hello 🎅! Do you want to turn off the 🚨? (y/n)
> y

[!] For your safety, the 🚨 will not be deactivated!

With only NX enabled, it seems like a classic ret2libc attack that leverages ROP chain.

Static Code Analysis

Looking at the decompiled code, we can actually stop the program by entering 9. Even though it is not clear how many characters our input buffer local_48 can hold, the enormous number of bytes 0x7f0 it is taking in just screams for buffer overflow.

From this point onwards, there are no other user-defined functions like win or flag that is worth looking at, other than the banner function. It seems to be just calling write to print out the banner, which appears to be quite an innocent function, but can still perhaps be useful to us later.

Finding Offset

Since there is no apparent function that we should target, other than a classic buffer overflow, I am suspecting this to be a ret2libc attack. As usual, we will start by fuzzing the offset.

Leaking LIBC Address

One thing that stands out is that puts is not used in the program. So we need to find another similar function such as write that is capable of writing to the standard output in order to leak the LIBC address.

In a typical ret2libc attack, puts requires the control of one register rdi for leaking the LIBC address; whereas write requires control of three registers:

  • rdi = File descriptor

  • rsi = Buffer to print

  • rdx = Number of bytes to write

However, it seems that we have no way to control the rdx register.

ret2csu

This is a textbook scenario for the use of the ret2csu technique, also known as the universal gadget, a technique used to populate registers when there is a lack of gadgets. Despite an apparent lack of gadgets, it allows us to populate the RDX and RSI registers, which are important for function parameters such as write().

The rest is basically the same as leaking address using puts. When in doubt, consult the man page to understand what arguments write is taking.

Manual Popping Registers

Recall that the banner function also uses write in it's procedure? This must mean that the RDX register is populated with the length of the banner message using strlen. Even though the value of RDX is not exactly 8 bytes, it does not really matter to us, because as long as it is >= 8 bytes, we will be able to get the full address of got.write regardless.

We can use this to compensate for the lack of pop rdx gadgets, and now we have control over 3 of the required registers for write. In other words, we can now craft the ROP chain manually without using ret2csu.

Calling the banner function will take care of RDI and RDX on our behalf, so we just need to focus on getting got.write into RSI. Based on the available options of gadgets, we are forced to pop rsi and pop r15 at the same time, so we have to fill back r15 with any dummy value.

One Gadget

After calculating the base address of LIBC, there is another fancy way to pop a system shell - via One Gadget. A one_gadget is simply an execve("/bin/sh") command that is present in gLIBC. However, there are certain constraints that must be met in order for it to work.

The process of validating these constraints through debugging can be very tedious, and in fact, your LIBC version may not even have a working one_gadget. As such, a general rule of thumb is to play around with all the available one_gadgets to see if any one of them works for your scenario.

Flag: HTB{S4nt4_15_n0w_r34dy_t0_g1v3_s0m3_g1ft5}

Last updated