--- ### Challenge Description For the extreme-level challenge, submit your walkthrough (or link to it) as well as the solution. The judges will review submissions at least once a day. Good luck! --- ### Summary In this challenge, the objective is to reverse-engineer a binary to extract an encrypted flag. The program employs RC4 encryption, multithreading, and various anti-debugging techniques. The primary goals are to patch the `win` function to decrypt the encrypted flag -- instead of encrypting the input -- and to modify the `encrypt` function to bypass anti-debugging checks. After applying these patches and debugging the program, the decrypted flag becomes visible on the stack. --- ### Understand the Program Note: Some function and variable names have been changed to enhance the reader's understanding of the program flow. ###### main ^abdeb5 ![[images/Pasted image 20230904144927.png]] Important details: - Lines 6 and 7 enable multithreading in the program - Line 8 and 9 are anti-debugging techniques, that ultimately don't end up doing anything(described later) - The function requires a command line argument ###### win ^59850e ![[images/Pasted image 20230904145318.png]] ![[images/Pasted image 20230904174546.png]] Important details: - The encrypted flag is stored in `enc_flag` - The for loop on line 69 reads the values from `argv[1]`, and stores each byte of the flag into the local variable v2 (line 70), and each contiguous variable in memory - The flag is encrypted with the `encrypt` function ###### encrypt ^a55152 ![[images/Pasted image 20230904174107.png]] Important details: - On line 39, the RC4 Key-Scheduling algorithm is ran. - During the for loop starting on line 40, the RC4 Pseudo-Random Generation Algorithm is ran 8192 times. - Note that there is a `sleep(0);` function call each loop iteration, this is another anti-debugging feature. - Line 42 checks if the result of the `getTickCount();` call equals 1 (another anti-debugging technique) - On the for loop starting on line 48, the flag is XOR'd, resulting in the encryption of the flag. --- ### Patch the `win` Function After doing some research on RC4, I discovered that encrypting a RC4 encrypted string is the equivalent of decrypting it, due to the nature of the xor function. We need to modify the `win` function to use the `enc_flag` array, so the program decrypts the flag, instead of encrypting our input. **main** ![[images/Pasted image 20230904150744.png]] Here is the corresponding assembly code: ![[images/Pasted image 20230904152011.png]] Modifying the loop in [[#^abdeb5|main]] to use `enc_flag` can be accomplished by patching the bytes with IDA's Assemble feature. First, click `inp_flag` in the assembly view. Then, go to Edit-->Patch Program-->Assemble ![[images/Pasted image 20230904152500.png]] (Note, you must use a `lea` instruction, as you need to reference the *memory address* of a *local variable*, not the actual value stored in `[ebp+enc_flag]`). The disassembly should look like this: ![[images/Pasted image 20230904152627.png]] --- ### Patch the `encrypt` Function This loop in the [[#^a55152|encrypt]] function is causing us some issues: ![[images/Pasted image 20230904160330.png]] As a reminder, the result of the `getTickCount()` function is put into `tick_count_1`. Since debugging a program usually results in this value being much larger than if it ran naturally, we need to patch the for loop to skip checking if `dword_4244C4` is 0. ![[images/Pasted image 20230904161447.png]] This can be accomplished by modifying the highlighted `jz` instruction. Change it to unconditionally jump after the `cmp` instruction is ran: Edit-->Patch Program-->Assemble ![[images/Pasted image 20230904161648.png]] Your disassembly should look like this: ![[images/Pasted image 20230904161745.png]] Finally, apply the patches we made. Edit --> Patch Program --> Apply Patches to Input File![[images/Pasted image 20230904165411.png]] --- ### Debug the program The [[#^abdeb5|main]] function requires a command line argument `(argv[1])`: ```c if ( argc == 2 ) { if ( win(argv[1]) ) { printf("[+] You achieved level 12!\r\n"); uExitCode = 0; } ``` Set the argument by going to Debugger-->Process Options: ![[images/Pasted image 20230904161918.png]] Set a breakpoint on line 72 in the [[#^59850e|win]] function (right after decryption has occurred): ![[images/Pasted image 20230904165540.png]] Hit `F9` to start the debugging process Looking at the General Registers, it appears that `ESP` is pointing to the flag on the stack: ![[images/Pasted image 20230904170028.png]] ![[images/Pasted image 20230904165822.png]] Hit `Shift+F12` to open strings to view the full flag: ![[images/Pasted image 20230904163028.png]] Flag: `flag_{8079b1c9a4844ecd9e5d33dc6642d779}`