- Published on
TFCCTF 2023 – Pass
- Authors
- Name
- Lumy
Pass (50 points, 239 solves)
Can you get the right password?
Table of Contents
- Binary ninja
- Conversion to python code
- First solution : Bruteforce process
- 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{