# MCC 2023 RE Challenge Writeup **Team Members (Group 4):** Alysha Firdaus Roheender Amin Safri Abdullah ## Level 1 (First Flag) --- The first thing we have to check is the **`level1()`** function, **without needing to look at other things** (according to the hints given by the crews)**.** For the level 1 challenge, we have decompiled the code as below. ```c // main int __fastcall main(int argc, const char **argv, const char **envp) { void *v3; // rsp __int64 v4; // rbx __int64 v5; // rdx char Str1[4]; // [rsp+30h] [rbp-90h] BYREF int v8; // [rsp+34h] [rbp-8Ch] BYREF __int64 v9; // [rsp+38h] [rbp-88h] BYREF __int64 v10; // [rsp+40h] [rbp-80h] BYREF __int64 v11[2]; // [rsp+48h] [rbp-78h] BYREF char v12[32]; // [rsp+58h] [rbp-68h] BYREF char Str[34]; // [rsp+78h] [rbp-48h] BYREF char v14[70]; // [rsp+9Ah] [rbp-26h] BYREF _main(); v11[0] = 0xAD000000DEi64; v11[1] = 0xEF000000BEi64; banner(); printf("\nHow about a deli style chicken sandwich?: "); scanf("%34s", Str); v9 = -1i64; xtea_encrypt((unsigned int *)&v9, (int *)v11); srand(v9 + HIDWORD(v9)); level1(Str); v3 = alloca(2 * strlen(Str) + 1); str2hexstr(Str, Str1); if ( !strcmp(Str1, "5A0E5471020201480C445F0F535D5E6C68076F320E74510202016C390A0D06564C") ) { Sleep(0xBB8u); if ( NtCurrentPeb()->BeingDebugged ) pfacts(); printf("\nHow many slices of cheese would you like to add?: "); scanf("%d", &v8); if ( level2(v8) ) { qmemcpy(v14, &unk_140012C23, 0x26ui64); decimalToHex(v8); v10 = 0x6C6B6A6968676665i64; s20_crypt((__int64)v12, 0, &v10, 0, (__int64)v14, 38); if ( v14[0] == 77 && v14[1] == 67 && v14[2] == 67 && v14[3] == 50 && v14[4] == 48 && v14[5] == 50 && v14[6] == 51 ) { v4 = 0i64; printf("\n"); do { v5 = (unsigned __int8)v14[v4++]; printf("%c", v5); } while ( v4 != 38 ); } } } else { printf("\nGordon Ramsay coming for you!\n"); } return 0; } ``` Let’s break the **`level1()`** function down into decompiled code. ```c //level1() size_t __fastcall level1(char *Str) { unsigned __int64 v1; // rsi char v3; // bl char v4; // bp size_t result; // rax char v6; // al v1 = 0i64; v3 = rand(); v4 = v3; while ( 1 ) { result = strlen(Str); if ( v1 >= result ) break; v6 = Str[v1]; Str[v1] = v6 ^ v3; if ( Str[v1 + 1] == v6 ) v6 = v4; ++v1; v3 = v6; } return result; } ``` It’s kind of difficult to understand all these variable names for **`level1()`** function. Let’s change the variable names to make it ************************************************meaningful and readable.************************************************ ```c //meaningful level1() var names added size_t __fastcall decryptMessage(char *message) { unsigned __int64 index = 0; char encryptionKey; char prevChar; size_t messageLength; char currentChar; encryptionKey = rand(); prevChar = encryptionKey; while (1) { messageLength = strlen(message); if (index >= messageLength) break; currentChar = message[index]; message[index] = currentChar ^ encryptionKey; if (message[index + 1] == currentChar) currentChar = prevChar; ++index; encryptionKey = currentChar; } return messageLength; } ``` Based on the code above, this seems like a normal **XOR encryption** as can be seen on the line of code below. ```c message[index] = currentChar ^ encryptionKey; ``` and in **`main()`**, there's also a **`strcmp()`** condition where you have to match the specific string below to proceed to the next level (which looks like a **flag**). ```c if (!strcmp(Str1, "5A0E5471020201480C445F0F535D5E6C68076F320E74510202016C390A0D06564C")) ``` It seems like we have to **reverse the XOR encryption (decrypt)** on the string and discover what is the content. But the problem is, the **XOR decryption requires the original key**, and the key is set by **`rand()`** which generates random number. **There's two way that we know to find the flag:** 1. Finding the seed number and predicting the random number generated ```c // This line of code sets the seed of the random number generator srand(v9 + HIDWORD(v9)); ``` 2. Bruteforcing the XOR key for decryption. **Our way:** What we did was, we bruteforced the possible XOR key which is between **`0-256`**. **Well... why 0-256?** Since we hypothesized that the long string `5A0E5471020201480C445F0F535D5E6C68076F320E74510202016C390A0D06564C` **is the flag**, then we can safely assume it must be ASCII characters (readable characters basically). Note: ASCII characters range usually from 0 until 127 for standard and 0 until 256 for extended. **Final Solution** We built a simple script to reverse the **XOR encryption** and bruteforced the key from **`0-256`**. Tbh, bruteforcing **`0-127`** would already suffice, but just to be safe. ```python # Function to reverse the level1 encryption def reverse_level1(encoded_bytes, initial_key): v3 = initial_key v4 = v3 decoded_bytes = bytearray() for i in range(len(encoded_bytes)): # XOR operation to reverse the encoding original_byte = encoded_bytes[i] ^ v3 decoded_bytes.append(original_byte) # Prepare the XOR key for the next iteration if (i+1 < len(encoded_bytes)) and (encoded_bytes[i+1] == original_byte): v3 = v4 else: v3 = original_byte return decoded_bytes # The original string provided is treated as ASCII characters representing hex digits original_string = "5A0E5471020201480C445F0F535D5E6C68076F320E74510202016C390A0D06564C" # Convert the ASCII hex representation to a byte array encoded_bytes = bytes.fromhex(original_string) # Iterate over all possible byte values for v3 for initial_key in range(0, 256): # Reverse the level1 encryption decoded_bytes = reverse_level1(encoded_bytes, initial_key) decoded_str = ''.join(chr(b) for b in decoded_bytes) # Show all text, even if not directly printable print(f"Decoded string with v3 = {initial_key}: {decoded_str}") ``` Though, we didn't get the flag straight away, the flag was dispersed between multiple keys and we need to combine them together. (Probably due to how we did the decryption algorithm, skill issue tbh) ``` Decoded string with v3 = 67: C2023{w3lc0m3_70_mcFDFG+E Decoded string with v3 = 55: mc7FDFGGDG+CD+c2023_flag1} ``` **Final flag:** ``` MCC2O23{w3lc0m3_70_mcc2023_flag1} ``` ## Level 2 (Second Flag) --- Reading the IDA output for the flag: ```c _BOOL8 __fastcall level2(int input) { int new_input; // eax int v2; // edx int result; // ecx int v5; // r8d if ( input < 0 ) { printf( "\n" "Oh, negative cheese? Are you trying to break the laws of deliciousness or just conducting a cheesy experiment in r" "everse munchonomics? Either way, I hope your sandwich doesn't develop an identity crisis - it might start question" "ing its own existence in a world without positive cheese vibes!\n"); return 0i64; } if ( 2 * input <= 20 ) { result = input - 5; v5 = result & 3; if ( (result & 3) != 0 ) return 0i64; while ( result > v5 ) { if ( v5 % 3 ) result -= v5; else result += v5; ++v5; } } else { new_input = input; v2 = 0; do { if ( (v2 & 1) != 0 ) new_input -= v2; else new_input += v2; ++v2; } while ( input > v2 ); if ( new_input <= 17 ) return 0i64; result = new_input + 10; } return result == 773314; } ``` based on this we know that we need to input an integer and after calculation it will output the `result` . The **`level2`** function in the provided C code is designed to perform a series of calculations on an input integer and return a boolean value. Here's a simplified explanation: 1. **Negative Input Check**: If the input is negative, it prints a humorous message and returns **`false`**. 2. **Calculation and Conditional Checks**: - For inputs where twice the input is less than or equal to 20, it modifies the input using a specific set of rules and a loop. If certain conditions are met, it may return **`false`**. - For other inputs, it performs a different set of calculations within a loop. If the modified input is less than or equal to 17 after the loop, it returns **`false`**. 3. **Final Check**: After the calculations, if the resulting value equals **`773314`**, the function returns **`true`**; otherwise, it returns **`false`**. **###Python script used:** ```python def level2(input): if input < 0: return False if 2 * input <= 20: v4 = input - 5 v5 = v4 & 3 if v5 != 0: return False while v4 > v5: if v5 % 3: v4 -= v5 else: v4 += v5 v5 += 1 else: v1 = input v2 = 0 while input > v2: if v2 & 1: v1 -= v2 else: v1 += v2 v2 += 1 if v1 <= 17: return False v4 = v1 + 10 return v4 == 773314 def main(): for i in range(1546600, 1546629): print(f"Checking: {i}") if level2(i): print(f"Input value that satisfies the condition: {i}") break if __name__ == "__main__": main() ``` lets try to input the number in the exe: ```bash └─$ wine sandwich.exe it looks like wine32 is missing, you should install it. as root, please execute "apt-get install wine32:i386" _.---._ _.-~ ~-._ _.-~ ~-._ _.-~ ~---._ _.-~ ~\ .-~ _.; :-._ _.-~ ./ `-._~-._ _..__.-~ _.-~ / ~-._~-._ / .__..--~----._ \_____(_;-._\. _.-~_/ ~).. . \ /(_____ \`--...--~_.-~______..-+_______) .(_________/`--...--~/ _/___ /\ /-._ \_ (___./_..-~__.....__..-~./ `-._~-._ ~\--------~ .-~_..__.-~ _.-~ ~-._~-._ ~---------' / .__..--~ ~-._\. _.-~_/ \`--...--~_.-~ `--...--~ How about a deli style chicken sandwich?: MCC2023{w3lc0m3_70_mcc2023_flag1} How many slices of cheese would you like to add?: 1546608 MCC2023{junk_c0d3_45_4lw4y5_huh_flag2} ``` Python script output: ```bash └─$ python3 flag2.py Current: 1546600 Current: 1546601 Current: 1546602 Current: 1546603 Current: 1546604 Current: 1546605 Current: 1546606 Current: 1546607 ok: 1546608 ``` Flag2 = `MCC2023{junk_c0d3_45_4lw4y5_huh_flag2}` ## Level 3 (Third Flag) ## Flag 3 For the flag 3, we know that the executable file already give us all the flag for `level1` and `level2`. But the challenge still want us the `flag3`. We consider that the flag maybe somewhere in the executable file. ![Pasted image 20231210131248](https://hackmd.io/_uploads/Hy-036MLa.png) We make some analyse of the strings on `ghidra` and we can see here there is a part of the flag3. So yeah there is some ways to give input and the executable will give us the flag. After a while, we found a way to bypass this so it will give us the flag. ![Pasted image 20231210131940](https://hackmd.io/_uploads/B1UZTafIa.png) In here, we found something juicy that maybe a key to bypass it and get the flag3. We will directly give command like this ![Pasted image 20231210132334](https://hackmd.io/_uploads/SyjG6azIa.png) ![Pasted image 20231210132412](https://hackmd.io/_uploads/ByNN66ML6.png) Give any input and.... ![Pasted image 20231210132449](https://hackmd.io/_uploads/r12Sa6GLa.png) WALLA!! We got the last flag. Thank you ---