keygenme-py | CyLab Security Academy (PicoCTF)
keygenme-py is a Medium level ctf challenge in the reverse engineering domain. A python script with no instructions in present in this challenge. A file named keygenme-trial.py is provided.
Upon downloading the file, I tried running it. It welcomes user to something called Arcane Calculator. The username is set to BENNETT. It provides with 4 options to choose from. I went through the code side-by-side while running the program in the terminal.
Choosing option a simply navigates to estimate_burn() function which doesn't seem to contain any correlation with our flag but rather seems like some sort of star distance calculator.
Choosing option b will output nothing. As mentioned option b is locked. Hence, this option isn't something we need to look into either.
Now for option c, it asks for license key. Finally something closer to a flag. We will now look into the functions option c navigates to. It navigates to enter_license() function. The functions asks user for license key and used .strip() to get rid of any white spaces. A global variable bUsername_trial is initialized at the beginning of the program as b"BENNETT" is present inside the function. This is basically converting the string BENNETT to corresponding ASCII characters in sequence for each letters which can be accessed like list. Then, again another function check_key(user_key, bUsername_trial) function is called.
At the beginning of the program 3 variables are declared storing parts of the flag. The beginning and the ending part of the flag are clearly visible, but the middle part with dynamic in its username has exactly 8 x. And looking subsequently at the program, we need to figure those 8 unknown x. A variable summing up these 3 parts of the flag named key_full_template_trial is also declared here.
In the check_key function, user entered license key is compared with the content of bUsername_trial variable. When the length of license key is equal to content ofkey_full_template_trial variable, we verify if the input license key is equal to the first part of the flag initialized, then for the dynamic part a hashlib.sha256() (which creares a secure, fixed-sized 256-bit (32-byte) digital fingerprint from any input) and hexdigest() (which returns the final output of a cryptographic hash function as a human-readable string of hexadecimal digits) are used. The bUsername_trial which contains the ASCII value of the username BENNETT is acted upon by hashlib.sha256 and hexdigest(). On performing hashlib.sha256(b"BENNETT").hexdigest() the following output is obtained:
ba6c084a4d888e1f7c3b0fc71d61c4625708bd915b5e0e60eb73e1667251b567
Now the 8 x are compared with the various index values inside this hexadecimal string.
x -> [4] -> 0
x -> [5] -> 8
x -> [3] -> c
x -> [6] -> 4
x -> [2] -> 6
x -> [7] -> a
x -> [1] -> a
x -> [8] -> 4
Hence, the middle part of the flag is decoded in this way. Now simply combine the flag variables and replace the x with these values. Entering the whole complete flag will output the following:
This means, the flag we obtained is correct.
