Ultimate Encryptor

In this challenge, we have an encrypted flag in a file and the binary used to encrypt it. So I used GHidra to decompile and analyze the Assembly and C. After reading the program, I understood the following 3 functions on the program:

  • read_file(): get the content of a file and return it as a string

  • UltimateEncryption(): encrypt the message and return the text

  • main():

    1. call read_file() passing the first parameter(file with message in clean text);

    2. Pass the content of the file to UltimateEncryption()

    3. Finally, the program salve the content encrypted in a second file passed as a second parameter to binary

After some debugging, renaming variables, and commenting on the main lines I got this code.

char* UltimateEncryption(char* msg) {
  char tmp, zeroChar;
  int index4, index3, index2, index, keyLen;

  size_t msgLen = strlen(msg);
  keyLen = (int)msgLen;

  // Step 0
  if ((msgLen & 1) != 0) { // Check if is Odd or Even with Bitwise Operators
    zeroChar = '0';
    strncat(msg, (char*)&zeroChar, 2);
    keyLen = keyLen + 1;
  }
  printf("%s\n", msg); // print to debug

  // Step 1
  for (index = 0; index < keyLen; index = index + 1) {
    msg[index] = msg[(index + 1) % keyLen] ^ msg[index];
  }
  printf("%s\n", msg); // print to debug

  // Step 2
  for (index2 = 0; index2 < keyLen; index2 = index2 + 1) {
    msg[index2] = msg[index2] ^ 0x2b;
  }
  printf("%s\n", msg); // print to debug

  // Step 3
  for (index3 = 0; index3 < keyLen; index3 = index3 + 1) {
    msg[index3] = msg[index3] + '\x0f';
  }
  printf("%s\n", msg); // print to debug
  
  // Step 4
  for (index4 = 0; index4 < keyLen; index4 = index4 + 2) {
    tmp = msg[index4];
    msg[index4] = msg[(long)index4 + 1];
    msg[(long)index4 + 1] = tmp;
  }
  printf("%s\n", msg); // print to debug
  
  return msg;
}

To put my code to work I got the main() and read_file() raw functions from Ghidra and paste them in my encrypt.c file with the function below. To understand how the encryption was working I commented the "for" statements one a one to understand how each step works. And I had these conclusions:

  • Step 0: if the string was odd, appended '0' at the end;

  • Step 1: switch letter positions two by two. So replace the first letter with a second, the third with the fourth, and so on;

  • Step 2: XOR each byte with 0x2b ("+" in ASCII)

  • Step 3: Skip in 15 the letter using ASCII table

  • Step 4: XOR each letter with the next (and use the last with the first)

After testing all statements, I implemented a decode to each and tested all steps encrypting and decrypting one a one. Finally, I got this solution:

decrypt.py
key = list(open('out.txt', 'rb').read().strip())
plain_size = len(key)

// Step 4
i4 = 0
while i4 < plain_size:
    c = key[i4]
    key[i4] = key[i4 + 1]
    key[i4 + 1] = c
    i4 += 2

// Step 3
for i3 in range(plain_size):
    key[i3] = key[i3] - 0x0f

// Step 2
for i2 in range(plain_size):
    key[i2] = key[i2] ^ 0x2b

// Step 1
index = plain_size-1
while index >=  0:
    key[index] = key[(index + 1) % plain_size] ^ key[index]
    index -= 1

print(''.join(map(chr,key)))

Last updated