PicoCTF: keygenme-py

This challenge gives us a trial version of a software that needs a license key to unlock to the full version. Looking at the code, we see that our flag is the license key.

We can see the flag is defined across 3 variables and one of them is hidden from us with x’s. I also want to take a second to explain what the b is in bUsername_trial = b”GOUGH”. When adding a b in front of a string literal you are specifying it as a byte string. So python will interpret the characters in the string as bytes(the numeric value of these bytes are also ascii numbers). However, it’s important to note that if you print the string directly your program will return b”string”. This does not encode a string as ascii to be printed but rather to be used by another function that requires encoded characters, for example.

Our program is unable run because the string is not encoded, but if we use a byte string.

The program works! This will be important later.

If we continue looking at our code we find the parts where the license key is taken and validated.

Let’s break this down

  • First, we are asked to enter are license key. The license key is stripped of whitespaces then passed to the check_key function along with an additional argument bUsername_trial. This is the version of the username that contains a byte string.
  • Next, in the check_key function, The length of our key is compared to the length of key_full_template_trial. If the lengths aren’t a match the program returns a False value. If they match then the characters in the key are checked. The first loop checks the static part, which we already know because it is defined at the beginning of our script. Once this is validated it is passed on to the next loop
  • This loop validates the dynamic part which is the string we saw in the beginning that was x’ed out “xxxxxxxx”. Since the variable is not defined earlier, in the same way the static part was, this loop essentially recreates it in order to validate. A SHA256 hash of the username value is taken then turned into a hex digest . Specific indexes of this values are taken and when strung together form the dynamic_part. Since we know how this was made we can recreate it ourselves in our own script.

First we import hashlib then define our username with a bytes string because the values need to be encoded in order to take a hash value. Next we run the same hashing and hex commands on our username and store the output in a variable called hash_key. Then I take all the indexes from the script and put them, in the same order, inside of a list. Next, I write a for loop that will iterate through our list of indexes against our hash_key to print the missing piece of the flag. After that I add the static parts we saw defined in our script and enter it as license key within the program.

It worked!