Edward received a lockbox with a message
Hello, Ed. I hope you received the box. I set the key to be sent after one year. However, you may attempt to break into it before receiving the key.
This challenge is built in Python.
On executing the given file in a terminal, it will be prompted to enter a key.
We can see that it returns some output while giving an input. This means that the input is being validated based on certain conditions within the code.
We can use reverse engineering tools such as Ghidra, objdump, etc to reverse the executables and to find out the functioning of the code.
On checking the reverse-engineered code, we can arrive at the conclusion that:
As the first step, the code validates the length of the key entered with the code given below:
From the code, we can conclude that the required key length is 32 and if we do not meet it, it will return a false statement.
Here, the key is divided into 4 blocks of equal length, and 8 characters long.
(Analyzing the code)
We can break the functioning of the above-given code into 4 pieces for simplification:
The Unicode code
of each character from block1 is subtracted from 0x92 (which is equal to 146 in decimal).
Then the string ‘domectf’ is attached to each character.
And then, every 8th character of the resultant block1 is taken and combined to form a string and is matched with =N"Y<8:F
Then it will return a false statement if both the strings aren’t a match.
Now we have got a string to compare with the proceeding blocks.
In the given code, the program is retrieving the first block of the key from =N"Y < 8:F
. This is by taking the decimal value of each character in the string and then comparing and subtracting it from 146.
With this, the first block, Dp9VZXL, can be found.
Certain operations are done on block2 prior to the next check.
By analyzing the above-mentioned code, we can understand its functioning as that an array (keys = [102, -247, 54, -231, -35, -8, -88, -168]) is given and it checks whether the sum of twice the ASCII value of each character in block2 and the element in the array with the same index returns the ASCII value of the next character in block2. And this loop will execute until it reaches the last character within the block.
The code finds block2 of our key and hence, we can conclude that block2 is 1tElEKVT
.
Here, the third block of the key is converted into another array by subtracting 0x20 (which is equal to 32 in decimal) from the ASCII value of each character. This returns a string.
Hence, finding block3 is a lot simpler than you thought. That is by adding 32 to each ASCII value and then converting it back to a character from its Unicode codes.
Finding this block might look like a harder one. But in fact, it is a lot easier if you recall base conversion methodology.
The final block of code looks like:
The functioning of code is:
A large number is given and on each iteration, the value obtained by multiplying the index of the value of each 512 to the power of 0x96 minus the Unicode value of each character in the block, is subtracted from the large number.
TRUE expression is returned if the code becomes zero.
i.e:
Here it is kept on adding 512 to the power of the value of 0x96 (150) minus the value of character is multiplied with the index value of character for every iteration. The resultant value is the large number code.
Simply let us understand this with an example of conversion of (153)16 to base 10 using the equation:
3 * (160) + 5 * (161) + 1 * (162)
From this, we can conclude that the large number code is a decimal number, which is obtained by converting a number with base 512 and 0, 1, 2, 3, 4, 5, 6, 7 as individual digits in it.
And 150 – x0, 150 – x1, ……, 150 – x7 will be the position of these digits, and the remaining digits are 0s.
The large number code is:
code = 193467235523314909552858807952825905707585690687056221482407486215822962362081901228539668218909561858261716398442106581207560945004074744751468435208638309807448792333157151318042827086034349204606797072878208156712781015117915286904063496924417175941657872595681280
And with the code given below,
We can write the large number code as
code = 512 **(150 – 0) * 0 + 512 **(150 – 1) * 0+ …......+ 512 **(150 – x2) * 2 + 512 **(150 – x3) * 3 + 512 **(150 – x4) * 4 + 512 **(150 – x5) * 5 +512 **(150 – x6) * 6 + 512 **(150 – x7) * 7 + …+ 512 ** (150-150) *0
And the output of all the digits together will give the base 512 to the version of our large number code, which looks like
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 1, 0, 0, 0, 3, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
And in considering the character value of the positions of numbers from 1 to 7, it will return the string SvWfQ4X.
Since there is more number of 0s, its position is unknown. Hence, we need to brute-force the character at position 0 from the list of combinations of a-z, A-Z, and 0-9.
The FLAG domectf{UDp9VZXL1tElEKVT8IAP1OdarSvWfQ4X}
can be obtained by combining all the blocks we have derived.