CTFlearn: Ramada

Ramada is an easy reversing challenge from ctflearn. It is one of those challenges that is both easy and kinda hard at the same time. I got really stuck because the script I wrote to reverse some operations didn’t round the integers correctly, it would have been easy otherwise.

/assets/images/ramada/r1.png

When we run the challenge we see the following:

/assets/images/ramada/Screenshot_from_2021-03-10_20-55-37.png

When we run it again with an argument to match the usage Ramada CTFlearn{kernel} we get:

/assets/images/ramada/Screenshot_from_2021-03-10_20-57-52.png

Open it now with ghidra to analyse the source. Open the main function in the Decompiler:

/assets/images/ramada/Screenshot_from_2021-03-10_21-01-23.png

In the source at line 49 we find the expected length of the flag:

sVar4 = strlen((char *)__s);
...
if (sVar4 == 0x1f) {

Converting sVar4 0x1f to an integer is 31

The CTFlearn{} part of the flag is 31 - 10 = 21

Generate a string of length 21 to test it:

crazyeights@es-base:~$ python3 -c "print('CTFlearn{'+'A'*21+'}')"
CTFlearn{AAAAAAAAAAAAAAAAAAAAA}

When we run it with the correct length flag we get:

/assets/images/ramada/Screenshot_from_2021-03-10_21-18-12.png

In the main function in the decompiler we can see that the function CheckFlag is called:

iVar3 = CheckFlag((char *)aiStack104);

CheckFlag() is called with only the so-called kernel part of the flag as input, meaning it doesn’t include the CTFlearn{} part.

Next we check the contents of the CheckFlag function:

/assets/images/ramada/Screenshot_from_2021-03-10_21-25-02.png

In CheckFlag() function it loops through the user input, iVar2 for each char in the string it is cast to int, and cubes it, and then compared to the corresponding int in the data array. We can assume that the flag is stored in data

Checking out the contents of data:

/assets/images/ramada/Screenshot_from_2021-03-10_21-39-04.png

Since we know that iVar2 * iVar2 * iVar2 is equal to data if the user enters the correct flag. We can write a program that takes each entry in data and reverses the cube operation (cube root) :

import numpy as np

data = [0x13693, 0x6b2c0, 0x11a9f9, 0x157000, 0x1cb91, 0x1bb528, 0x1bb528, 0xded21, 0x144f38, 0xfb89d, 0x169b48, 0xd151f, 0x8b98b, 0x17d140, 0xded21, 0x1338c0, 0x1338c0, 0x11a9f9, 0x1b000, 0x144f38, 0x1734eb]

s = ""
for d in data:
	s+=str(hex(round(np.cbrt(int(d)))))[2:]+" "
	
print(s)

We get the following (with each entry being in hex):

/assets/images/ramada/Screenshot_from_2021-03-10_21-48-08.png

When we get ascii representation instead we get:

/assets/images/ramada/Screenshot_from_2021-03-10_21-57-14.png

The code is as follows:

import numpy as np

data = [0x13693, 0x6b2c0, 0x11a9f9, 0x157000, 0x1cb91, 0x1bb528, 0x1bb528, 0xded21, 0x144f38, 0xfb89d, 0x169b48, 0xd151f, 0x8b98b, 0x17d140, 0xded21, 0x1338c0, 0x1338c0, 0x11a9f9, 0x1b000, 0x144f38, 0x1734eb]

s = ""
for d in data:
	i = round(np.cbrt(d))
	s+=chr(i)
	
print(s)

When we run the ramada program with this string as the flag kernel we get:

/assets/images/ramada/Screenshot_from_2021-03-10_21-59-03.png

We have found the flag 🥳

FIN.