top of page

HackTM 2020 Qualifiers - HackDex

Updated: Sep 22, 2022

The challenge starts by having 2 files:

– hackdex, ELF file.

– hacktm.hdex, text file.


Description


Considering your possible trip to Timisoara in May, we thought it is not a bad idea to support you with a simple English to Romanian dictionary program. Today we’re releasing a preview version for you to test. Please keep in mind that it’s still in development


Overview

The hackdex file is an executable file which is essentially a EN-RO dictionary. When we run the file we get:

Welcome to HackDex. Your EN-RO dictionary for HackTM CTF!


    Options:
    1. Translation console
    *. Exit
hackdex>   

When pressing ‘1’ we can type words followed by ENTER and we get their translation in Romanian:

hackdex(1)> a
a -> un, o; un/o oarecare; o singura; pe; perfect; un singur
hackdex(1)> 

As for the hacktm.hdex, this file is the dictionary used by the hackdex ELF to translate to English words into a Romanian:

Some of the hacktm.hdex’s content

a<br>un, o; un/o oarecare; o singura; pe; perfect; un singur
aardvark<br>porcul termitelor (orycteropus sp.)
aaron<br>aaron; prelat, inalta fata bisericeasca
aba<br>aba;dimie
abac<br>grafic; filet conic pentru tevi standardizat in S.U.A.; abaca
abaca<br>canepa de manila; abaca
aback<br>inapoi; in urma
abacus<br>numaratoare; abaca; abac
abaddon<br>gheena, iad
abaft<br>in urma; in spatele; la; spre pupa
abandon<br>parasire; abandon; a abandona; a parasi; a renunta la; a inceta sa
abandoned<br>parasit; dezmatat; desfrinat
abandonment<br>parasire; abandon
abase<br>a retrograda; a degrada
abasement<br>retrogradare; degradare
abash<br>a umili; a face de rusine; a descumpani
abashed<br>rusinat; jenat
abashment<br>umilinta; stinghereala; jena; rusine
abask<br>la soare
abate<br>a toci,; a slabi; a abroga; a anula; a atenua (o durere etc.); a face bont; a pune capat la; a reduce (preturile); a se atenua; a se domoli; a se potoli
abatement<br>slabire; reducere (a unui impozit); abrogare; anulare; atenuare

Reversing


When starting to reverse the challenge we noticed it was written in rust which made it more challenging as we were less familiar with it.

After reversing the main function we noticed there is a variable called “_ZN3dex11PRO_VERSION17h62387400d9c485dbE” which indicate us there was a PRO_VERSION for this program and with some added functionality. After cross-referencing this variable we saw this value is checked against the 0x1337 value:


This check is happening in the “extra” function which is called whenever the user is pressing “9” instead of “1” mentioned above:



The translate function is the function where the program does its dictionary logic.

As we can see in the above picture, whenever the user is pressing “9” it is essentially changing the application from being dictionary to whatever the extra function does.


So what causes the PRO_VERSION to be 0x1337?


The code simply check the amount of time passes between some assignments and put that value in the PRO_VERSION variable. So after patching the variable with the correct value and pressing “9”, we get to the “extra” function.

So after a while of reversing the function we got to the following conclusions:

  • This function has 6 stages, and each of these stages is:

    • Initalizing a new boggle board.

    • Calling the get_valid_words function.

    • Receiving from the user a word.

    • Validating the word received is in the hashtable returned by the get_valid_words function.

    • In case of success continue to next step.


  • At the end of these stages the function concatenates all words received together.

  • Calculate the SHA256 hash of the complete string and compare it to hardcoded hash in the binary.

  • In case the hash is matching we uses the concatenated words as to key to decipher chacha encrypted cipher which presumably is the flag.

There was a problem which the binary did not had the logic of the get_valid_words function implemented which caused us a lot of headache understanding that the binary was not supposed to work at all in the first place, as we thought we simply did not understand the rust compiled assembly correctly.

Another obstacle was to understand the building of the boggle words from the binary because they were mostly using the xmm instruction-set.

After understanding the binary is not fully implemented and not supposed to work, we patched the checks that were standing in our way and got to the point where we were able to insert words and continue to the hash logic.


The solution

So after we extracted the Boggle boards created in each step, we wrote a script that automatically find all the possible words that fits into a given board.

[s@workstation Hackdex]$ python2 sol_1.py 
Z E L 
A N N 
R I G 

'get_words' 0.00 sec
T K L 
B U I 
N R F 

'get_words' 0.00 sec
F R I 
P E N 
U A D 

'get_words' 0.00 sec
E M Z 
B N A 
X E H 
W T V 

'get_words' 0.00 sec
E V O 
R U X 
C O M 
G N I 

'get_words' 0.00 sec
P L Z 
A S I 
S O N 

'get_words' 0.00 sec

One important note here is that in order to find the relevant words that fits into the boards, we used the dictionary we got from the CTF (hacktm.hdex) as our words list.

After receiving the words we created a script that will iterate through all the possibilities and check the hash of the concatenated words and match it against the hash in the binary.

wannabe = "F550BAA8068D9C17669E140626A9D7BF13EF0A66662AEB5910FC406BE196A287".lower()
num_of_iterations = 1

for i in range(6):
    num_of_iterations = num_of_iterations * len(words[i])

current_iteration = 0
for a in words[0]:
    for b in words[1]:
        for c in words[2]:
            for d in words[3]:
                for e in words[4]:
                    for f in words[5]:
                        current_iteration += 1
                        if current_iteration % 1000000 == 0:
                            print("{}/{}".format(current_iteration, num_of_iterations))
                        full = "{}{}{}{}{}{}".format(a,b,c,d,e,f)
                        try:
                            hashed = sha256(full.encode()).hexdigest()

                            if hashed == wannabe:
                                print(full)
                                exit(1)

                        except Exception as e:
                            pass

When we found a match we used that combination as the key in the chacha cipher and found the flag!

0 comments

Recent Posts

See All

Comentarios


bottom of page