Published on

TFCCTF 2023 – Pass

Authors
  • avatar
    Name
    Lumy
    Twitter

Pass (50 points, 239 solves)

Can you get the right password?

Table of Contents

  1. Binary ninja
  2. Conversion to python code
  3. First solution : Bruteforce process
  4. Second solution : Reverse the encrypt function

Binary Ninja

Compiled binary given : pass

See here for full code source given after the CTF : github.com/qLuma/TFC-CTF-2023/blob/main/pass We only have the compiled code of the program. Thus, we will use my favorite tool: Binary ninja

000011a9  uint64_t encrypt(char arg1)

000011c0      uint64_t rax_1
000011c0      if (arg1 == 0x7b || arg1 == 0x7d)
000011c2          char var_c_1 = 0x5a
000011c6          rax_1 = 0x5a
000011c0      if (arg1 != 0x7b && arg1 != 0x7d)
000011da          rax_1 = zx.q((arg1 + 7) ^ 0xb)
000011df      return rax_1


000011e0  void set_flag()

000011fc      __builtin_strncpy(dest: &flag, src: "PziP97vkc5sA6oJM0KwWEnQX2ltd", n: 0x1d)
00001240      __builtin_strncpy(dest: &data_4058:1, src: "OFaH0nAFTuS42myr31GYbJIfBKqV", n: 0x1d)
00001284      __builtin_strncpy(dest: &data_4071:1, src: "SdAFWsLpx8N0v4PzO7aIVQaHrLw9", n: 0x1d)
000012c8      __builtin_strncpy(dest: &data_408a:1, src: "Vq6AW8c1K5ZyFXzMeRAOiJ2nWQSo", n: 0x1d)
0000130c      __builtin_strncpy(dest: &data_40a3:1, src: "XYy2Pj7x96RzkcA3inNqlDOBLfF0", n: 0x1d)
00001350      __builtin_strncpy(dest: &data_40bc:1, src: "KZ4rNFYGTn0Cl5U9aX2WIH1cOsdL", n: 0x1d)
00001394      __builtin_strncpy(dest: &data_40d5:1, src: "yIbm2AZ0k31u7FrxBECKPpMhYG5w", n: 0x1d)
000013d8      __builtin_strncpy(dest: &data_40ee:1, src: "VUyvA5LfgXcW9eDSMTBlsorR2z4Y", n: 0x1d)
0000141c      __builtin_strncpy(dest: &data_4107:1, src: "2laXN3e8<qSCmwK0Do9bJzYvdkE6", n: 0x1d)
00001460      __builtin_strncpy(dest: &data_4120:1, src: "5YgG3dRBhwMvOp2qS08UWQKtL1Py", n: 0x1d)
000014a4      __builtin_strncpy(dest: &data_4139:1, src: "QbphJTXLd2~fktr45ES7OK3x0as9", n: 0x1d)
000014e8      __builtin_strncpy(dest: &data_4152:1, src: "yNqu1XSC9nA`rGpBvQlbDktjI4aZ", n: 0x1d)
0000152c      __builtin_strncpy(dest: &data_416b:1, src: "xLm2KlVYnXw0mpt5aOe8B4grGRjF", n: 0x1d)
00001570      __builtin_strncpy(dest: &data_4184:1, src: "XFe06gaZv3PYdpS4CDquJnmkRhVW", n: 0x1d)
000015b4      __builtin_strncpy(dest: &data_419d:1, src: "1Mn6sKScF3vV7pdzYfTkBRbqGZ9C", n: 0x1d)
000015f8      __builtin_strncpy(dest: &data_41b6:1, src: "bzu2wtPHkXsx1pK14ojTfJYIeRWA", n: 0x1d)
0000163c      __builtin_strncpy(dest: &data_41cf:1, src: "0PpU1TjDKaW85uZ2mlFHYMSEkcQJ", n: 0x1d)
00001680      __builtin_strncpy(dest: &data_41e8:1, src: "BvKo6WIdTnVRewMPk|3pU1SjN6Gl", n: 0x1d)
000016c4      __builtin_strncpy(dest: &data_4201:1, src: "ErN7s0HYlp9tMqAmBh0dXD4VaU6u", n: 0x1d)
00001708      __builtin_strncpy(dest: &data_421a:1, src: "K8NZWU1fnrsQaEc5Bht09eHwxYDK", n: 0x1d)
0000174c      __builtin_strncpy(dest: &data_4233:1, src: "DSpWj0ahd5rtIzyKETxUq9CkXQVm", n: 0x1d)
00001790      __builtin_strncpy(dest: &data_424c:1, src: "C8DAP37Kc1UqOvdb2GT0Yvxuhz5Q", n: 0x1d)
000017d4      __builtin_strncpy(dest: &data_4265:1, src: "1grzfdR4JiVpo83QOEWlL2<BtcD0", n: 0x1d)
00001818      __builtin_strncpy(dest: &data_427e:1, src: "9Xm7Q5RNkljfOZogB8ctIzyrapVh", n: 0x1d)
0000185c      __builtin_strncpy(dest: &data_4297:1, src: "9wF0RKycTJjvZfDlm6o75QsG`OL4", n: 0x1d)
000018a0      __builtin_strncpy(dest: &data_42b0:1, src: "2laXN3e85qSCmwK0Do9bJzYvdZE6", n: 0x1d)


000018c9  uint64_t increment(int32_t arg1)

000018dc      return zx.q(arg1 + 1)


000018dd  int32_t main(int32_t argc, char** argv, char** envp) __noreturn

000018f2      void* fsbase
000018f2      int64_t var_10 = *(fsbase + 0x28)
000018fd      set_flag()
00001915      void var_38
00001915      fgets(buf: &var_38, n: 0x1b, fp: stdin)
00001930      printf(format: "Password entered: %s\n", &var_38)
00001935      int32_t var_3c = 0
000019a4      do
00001951          uint64_t rdx_1 = zx.q(var_3c)
00001961          uint64_t rax_11 = ((rdx_1 + rdx_1 + rdx_1) << 2) + rdx_1
00001978          if (encrypt(*(&var_38 + zx.q(var_3c))) != *(rax_11 + rax_11 + &flag))
00001984              puts(str: "Wrong password")
0000198e              exit(status: 0)
0000198e              noreturn
0000199d          var_3c = increment(var_3c)
00001998      while (var_3c != 0x19)
000019b3      puts(str: "Correct password")
000019bd      exit(status: 0)
000019bd      noreturn

What we can see that is important : set_flag is used to initialize the variable flag.
var_38 is the variable that will hold the user input
var_3c is set to 0 and will be be increase at each iteration.
Seams to be used to check each chars from user input, so we can guess that it will be a bruteforce challenge char by char

encrypt function is used to process user input.

We could go further into analysis but let's convert it into python code

Conversion to python code

def encrypt(a1):
    if a1 == 123 or a1 == 125:
        return 90
    else:
        return (ord(a1) + 7) ^ 0xB

def set_flag():
    # Replace the encoded data with the decrypted version or leave it as it is.
    # Decoding the data requires the encryption logic, which is not provided here.
    flag = "PziP97vkc5sA6oJM0KwWEnQX2OFaH0nAFTuS42myr31GYbJIfBSdAFWsLpx8N0v4PzO7aIVQaHrVq6AW8c1K5ZyFXzMeRAOiJ2nWXYy2Pj7x96RzkcA3" \
           "inNqlDOBLKZ4rNFYGTn0Cl5U9aX2WIH1cOyIbm2AZ0k31u7FrxBECKPpMhYVUyvA5LfgXcW9eDSMTBlsorR22laXN3e8<qSCmwK0Do9bJzYvd5YgG3dR" \
           "BhwMvOp2qS08UWQKtLQbphJTXLd2~fktr45ES7OK3x0yNqu1XSC9nA`rGpBvQlbDktjIxLm2KlVYnXw0mpt5aOe8B4grGXFe06gaZv3PYdpS4CDquJnm" \
           "kR1Mn6sKScF3vV7pdzYfTkBRbqGbzu2wtPHkXsx1pK14ojTfJYIe0PpU1TjDKaW85uZ2mlFHYMSEkBvKo6WIdTnVRewMPk|3pU1SjNErN7s0HYlp9tMq" \
           "AmBh0dXD4VaK8NZWU1fnrsQaEc5Bht09eHwxDSpWj0ahd5rtIzyKETxUq9CkXC8DAP37Kc1UqOvdb2GT0Yvxuh1grzfdR4JiVpo83QOEWlL2<Bt9Xm7Q" \
           "5RNkljfOZogB8ctIzyra9wF0RKycTJjvZfDlm6o75QsG`2laXN3e85qSCmwK0Do9bJzYvdZE6"
    return flag

def main():
    flag = set_flag()
    s = input("Enter the password: ")
    print("Password entered:", s)

    v3 = 0
    while encrypt(s[v3]) == ord(flag[26 * v3]):
        v3 += 1
        if v3 == 25:
            print("Correct password")
            return

    print("Wrong password")

if __name__ == "__main__":
    main()

We can clearly see that it is a char by char comparison.
The goal is to go into the main loop comparison with each characters and see if we are going through a valid comparison.
We also know that the flag is 25 characters.

First solution : Bruteforce process

import string
def encrypt(a1):
    if a1 == 123 or a1 == 125:
        return 90
    else:
        return (ord(a1) + 7) ^ 0xB

def increment(v):
    return v + 1

def set_flag():
    flag = (
        "PziP97vkc5sA6oJM0KwWEnQX2OFaH0nAFTuS42myr31GYbJIfBSdAFWsLpx8N0v4PzO7aIVQaHrVq6AW8c1K5ZyFXzMeRAOiJ2nWXYy2Pj7x96RzkcA3"
        "inNqlDOBLKZ4rNFYGTn0Cl5U9aX2WIH1cOyIbm2AZ0k31u7FrxBECKPpMhYVUyvA5LfgXcW9eDSMTBlsorR22laXN3e8<qSCmwK0Do9bJzYvd5YgG3dR"
        "BhwMvOp2qS08UWQKtLQbphJTXLd2~fktr45ES7OK3x0yNqu1XSC9nA`rGpBvQlbDktjIxLm2KlVYnXw0mpt5aOe8B4grGXFe06gaZv3PYdpS4CDquJnm"
        "kR1Mn6sKScF3vV7pdzYfTkBRbqGbzu2wtPHkXsx1pK14ojTfJYIe0PpU1TjDKaW85uZ2mlFHYMSEkBvKo6WIdTnVRewMPk|3pU1SjNErN7s0HYlp9tMq"
        "AmBh0dXD4VaK8NZWU1fnrsQaEc5Bht09eHwxDSpWj0ahd5rtIzyKETxUq9CkXC8DAP37Kc1UqOvdb2GT0Yvxuh1grzfdR4JiVpo83QOEWlL2<Bt9Xm7Q"
        "5RNkljfOZogB8ctIzyra9wF0RKycTJjvZfDlm6o75QsG`2laXN3e85qSCmwK0Do9bJzYvdZE6"
    )
    return flag

def main():
    v3 = 0
    flag = set_flag()
    input_len = 26

    s= ""
    for x in range(input_len):
        for i in string.printable:
            input_test = s+i
            while encrypt(i) == ord(flag[26 * v3]):
                print("Found index " + str(v3) + " " + s)
                s += i
                v3 = increment(v3)
                if v3 == 25:
                    print("Correct password")
                    print(s)
                    exit(0)
    #print("Wrong password")
    #exit(0)

if __name__ == "__main__":
    main()

This will give us the flag

Output :

┌──(kali㉿kali)-[~/Downloads/Pass]
└─$ python bruteforce_password.py
Found index 0
Found index 1 T
Found index 2 TF
Found index 3 TFC
Found index 4 TFCC
Found index 5 TFCCT
Found index 6 TFCCTF
Found index 7 TFCCTFJ
Found index 8 TFCCTFJf
Found index 9 TFCCTFJf0
Found index 10 TFCCTFJf0u
Found index 11 TFCCTFJf0un
Found index 12 TFCCTFJf0und
Found index 13 TFCCTFJf0und_
Found index 14 TFCCTFJf0und_t
Found index 15 TFCCTFJf0und_th
Found index 16 TFCCTFJf0und_th3
Found index 17 TFCCTFJf0und_th3_
Found index 18 TFCCTFJf0und_th3_p
Found index 19 TFCCTFJf0und_th3_p4
Found index 20 TFCCTFJf0und_th3_p44
Found index 21 TFCCTFJf0und_th3_p44s
Found index 22 TFCCTFJf0und_th3_p44sv
Found index 23 TFCCTFJf0und_th3_p44sv0
Found index 24 TFCCTFJf0und_th3_p44sv0r
Correct password
TFCCTFJf0und_th3_p44sv0rd

Second solution : Reverse the encrypt function

import string
def encrypt(a1):
    if a1 == 123 or a1 == 125:
        return 90
    else:
        return (ord(a1) + 7) ^ 0xB

def decrypt(i):
    if i == 90:
        return 123
    else:
        return (i ^ 11) - 7

def increment(v):
    return v + 1

def set_flag():
    flag = (
        "PziP97vkc5sA6oJM0KwWEnQX2OFaH0nAFTuS42myr31GYbJIfBSdAFWsLpx8N0v4PzO7aIVQaHrVq6AW8c1K5ZyFXzMeRAOiJ2nWXYy2Pj7x96RzkcA3"
        "inNqlDOBLKZ4rNFYGTn0Cl5U9aX2WIH1cOyIbm2AZ0k31u7FrxBECKPpMhYVUyvA5LfgXcW9eDSMTBlsorR22laXN3e8<qSCmwK0Do9bJzYvd5YgG3dR"
        "BhwMvOp2qS08UWQKtLQbphJTXLd2~fktr45ES7OK3x0yNqu1XSC9nA`rGpBvQlbDktjIxLm2KlVYnXw0mpt5aOe8B4grGXFe06gaZv3PYdpS4CDquJnm"
        "kR1Mn6sKScF3vV7pdzYfTkBRbqGbzu2wtPHkXsx1pK14ojTfJYIe0PpU1TjDKaW85uZ2mlFHYMSEkBvKo6WIdTnVRewMPk|3pU1SjNErN7s0HYlp9tMq"
        "AmBh0dXD4VaK8NZWU1fnrsQaEc5Bht09eHwxDSpWj0ahd5rtIzyKETxUq9CkXC8DAP37Kc1UqOvdb2GT0Yvxuh1grzfdR4JiVpo83QOEWlL2<Bt9Xm7Q"
        "5RNkljfOZogB8ctIzyra9wF0RKycTJjvZfDlm6o75QsG`2laXN3e85qSCmwK0Do9bJzYvdZE6"
    )
    return flag

def main():
    v3 = 0
    flag = set_flag()
    input_len = 26

    correct_chars = ""
    for i in range(input_len):
        char_flag = ord(flag[i * 26])
        decrypted_char = decrypt(char_flag)
        correct_chars += chr(decrypted_char)
    print(correct_chars)

if __name__ == "__main__":
    main()

Output :

┌──(kali㉿kali)-[~/Downloads/Pass]
└─$ python reverse_encrypt_function.py
TFCCTF{f0und_th3_p44sv0rd{