If we try to run this, we would eventually get the flag, but it's really slow, so let's try to not do that.
If we take a look at the a() function, we can see that it
Has a loop that goes from 1 to n (for i in range)
Defines b to be 0
Checks if i is a multiple of n
If so, add i to b
If b is equal to n, return True
We can see (and also guessing by the title) that this will only return true on perfect numbers. Knowing this, I just looked up a list of perfect numbers, and then just XORed each number with the corresponding perfect number.
Script below.
Then we just wrap the output with flag and submit it
So, from the title, we guess it's using OFB encryption.
For those of you that don't know, OFB encryption works like this: Firstly, like any AES mode, there is a key, and then with OFB, you also have an IV. Then:
Encrypt the IV using the key
Sets the new IV to the encrypted IV
Xor the plaintext block with the encrypted IV, and then this is the output
This repeats for each block.
After reading the script, we can work out that:
It takes the flag.txt, and reads this
Pads this data using pkcs7 padding
Splits the data into blocks of 16 bytes
Randomly shuffles these blocks
Encrypts the blocks with the OFB we mentioned above.
Since the IV and key stay constant, we can connect and receive as many data samples as we want, and since there are 3 blocks, there are only 6 possible permutations for the blocks to be in. (doesn't really matter but whatever)
Looking even closer at the script, we see this line:
This means that the length of the flag must be 33, as we have already established that there are three blocks. This also means, because of the way the data is padded, that one of the blocks must be "}\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f"
(we know the last char is "}")
Now, we can simply attempt to XOR each block with this string to get the key for that block, and then XOR that with the other blocks to get the flag. I made this table for convenience.
We then XOR f24f00b65180b6161b2b9da92d2e42ae with 7d0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f to get 8f400fb95e8fb919142492a622214da1, which is what XOR key was used to encrypt the first block.
Then, we simply XOR this key with each of the other blocks to get the rest of the flag.
So the encryption takes some data, then base64 encodes it and encrypts it by XORing each byte with the byte after it, wrapping the last byte around to the start. The result is then hexlified. So, we can simply bruteforce the first byte in order to bruteforce what the decryption is. This gives us the base64 of the flag, which can be base64 decoded to get: