CSAW 2019 - beleaf
by CSAW
Tree sounds are best listened to by https://binary.ninja/demo or ghidra.
Attachments: beleaf
Solution
This challenge was my introduction into reverse engineering. Utilizing Ghidra, I was able to decompile the binary and view the main function:
This function takes in an input with a length greater than 33 bytes (0x21), then iterates through the input. With each iteration, the current index position character is passed into the transformFunc function:
This function takes in a single character and returns the index with which it lies within the &lookup table. Here’s a sample of what our &lookup table looks like:
Lets go back to our main function:
Once the function is “transformed” (the index of that character is found), that returned value is compared with our desired output table. Here is a sample of that table:
This table has values that are offset to every 8 bytes. If the transformedValue and the ExpectedOutput index value do not match up, the challenge will fail. So we need values at: 01, 09, 11, 27, 02, 00, 12, 03, 08, 12, 09, 12, 11, 01, 03, 13, 04, 03, 05, 15, 2e, 0a, 12, 03, 01, 2e, 16, 2e, 12, 06
Lets go back to the transformedFunc:
Let’s plug in a value and walk through this:
1
2
3
4
5
input = f
transformFunc(char f){
long i;
i = 0
while((i != -1 && ((int)f != *(int*)(&lookup +i * 4)))
So, (int)f is converting our char to ASCII (102) The reference to &lookup is referring to the first index in our table:
so this value (&lookup + i * 4) is equivalent to: 0x301020 + 0 * 4 => 0x301020 OR 0x77 (119) Let’s clean it up
1
2
3
while((i != -1 && (102 != 119)){
if (102 < 119){
i = i * 2 + 1
i now equals 1, new iteration
1
while((i != -1 && (119 != (0x301020 + 1 * 4))){
(0x301020 + 1 * 4) => 0x301024 OR 0x66 (102)
1
2
3
4
5
6
while((i != -1 && (102 != 102)){
if (102 < 119){
i = i * 2 + 1;
...
...
return i;
The condition passes as we have found the index with which our value of “f” passes. This index (i) is 1 and that index is returned to the main function
1
if (1 != 01 + 0 * 8)
Here we have returned the value of 1, which, when compared with our desiredOutput, happens to match the index of our current desiredOutput table
We can follow the same logic with all of the other values inside of our lookup table. Once done, we should receive the flag:
1
flag{we_beleaf_in_your_re_future}
This was my first reverse engineering challenge that I was able to fully grasp. Hopefully this helps you understand these types of problems.