I have participated along with my awesome team 0xD4WN and ranked fifth

Here are the solutions to two reverse challenges, phantime and millionaire
[REV][phantime]
We are given a PE file

Detect it easy
Upon executing it ->

It just asks for a 4-character password (that is what we know until now)
Let’s analyze it in IDA

We need to check the true data that our input is being compared to

reading it from stack directly
now we got this ->

Let’s explore the functions being called

after passing the first check, there are three functions being called
first function is just opening a registry key and querying a value to get its data , which is irrelevant

first function
third function creates a registry key, sets a value inside this registry with a name “Flagcontent” and sets its data with the string -> “This is not the flag you’re looking for”

third function
second function is where we will get our solution

The function creates a random string, initializes a string called-> “MEOWMEOW” ,and it initializes an array called src with the values ->
data =[
0x3D, 0x24, 0x3C, 0x24, 0x3A, 0x2A, 0x3D, 0x33,
0x12, 0x31, 0x26, 0x3A, 0x24, 0x2B, 0x28, 0x08,
0x2C, 0x31, 0x3B, 0x36, 0x2E, 0x2E, 0x10]
Then, the random string is XORed with the string “MEOWMEOW”
The output of this operation is not used, so let’s continue exploring the function to get any clues

Again, it creates a key and sets some values, with data and the key (MEOWMEOW), and so on
We should notice an interesting thing here, the memory location ExclusivePurri, contains ->“Exclusive purring helps decode secrets”, purring means the sound of a cat XD, that why i labeled the hardcoded string “MEOWMEOW” as a key, this statement gives a hint that the flag can be obtained by xoring some data with the key, another interesting thing is that, the placeholder takes the random string asthe last part of the flag
Now we have a full picture of how the program works and how to get the flag
let’s xor the key with the extracted data
def decode(encoded_data, key):
result = ""
for i in range(len(encoded_data)):
decoded_byte = encoded_data[i]^ord(key[i % len(key)])
result += chr(decoded_byte)
return result
encoded_data = [
0x3D, 0x24, 0x3C, 0x24, 0x3A, 0x2A, 0x3D, 0x33,
0x12, 0x31, 0x26, 0x3A, 0x24, 0x2B, 0x28, 0x08,
0x2C, 0x31, 0x3B, 0x36, 0x2E, 0x2E, 0x10
]
key = "MEOWMEOW"
decoded = decode(encoded_data, key)
print(decoded)
password_timing_attack_
second part is the random string, so the flag is
EGCTF{password_timing_attack_9nw5pa}
[REV][millionaire]
We are given a PE file



Time to go to IDA…

part_of_main_function
Nownow we need to check the path_determining_function

first part of the function
The function does call CryptStringToBinaryA function on string , then it xor the resulting bytes with our input key,

It then computes the sha256 hash of the resulting string from the previous operation, and compares it specific hash, The flag consists of two parts, the first part is the str1, which results from xoring the key with the bytes resulting from applying crypt_string_to_binary on that string “IAAA…”
now, the problem is we do not know the intended result , we got only the hash (f4b….)
if we go back a little bit , we notice that , the text that is printed when we execute the program, is hardcoded but encrypted


there is interesing two things here , the encrypted text is transformed to bytes using the same crypt string to binary function , and after that it goes into second stage of decryption .
let’s try to apply the same process on the text “IAAA…”, and see what we got.
in order to do that , we should examine the register where the input parameter is passed to function. and then replace the address of the original encrypted text with the address of the text “IAAA…”


address of "IAAA"
now , we need to just modify the value of rcx register

here we got the data!
it seems that the program decrypted the text with two different approaches and compared them to each other
let’s confirm this by getting the sha256 of the resulting data ->
"W0rmy_Th0ught_1t_w4s_cl3ver_to_use_th3_r1ch_head3r_"

sha256 hash
so yes it does

now it is straightforward XOR decryption->
def get_key(input):
T="W0rmy_Th0ught_1t_w4s_cl3ver_to_use_th3_r1ch_head3r_"
for c in range(len(input)):
#print("counter",c)
key=chr(ord(T[c])^(input[c]))
print(key,end="")
final_stansoframion="W0rmy_Th0ught_1t_w4s_cl3ver_to_use_th3_r1ch_head3r_"
data = [
0x20, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x27, 0x1A, 0x01,
0x16, 0x0F, 0x46, 0x03, 0x6F, 0x43, 0x19, 0x26, 0x46, 0x47,
0x01, 0x6E, 0x00, 0x04, 0x1D, 0x01, 0x55, 0x00, 0x32, 0x0D,
0x5E, 0x2C, 0x07, 0x42, 0x06, 0x37, 0x5A, 0x1F, 0x03, 0x2D,
0x1F, 0x48, 0x52, 0x1B, 0x2D, 0x59, 0x06, 0x09, 0x4A, 0x44,
0x42, 0x2D
]
#print(len(data))
#print(len(final_stansoframion))
get_key(data)
w0rmy1sr1ch.w0rmy1sr1ch.w0rmy1sr1ch.w0rmy1sr1ch.w0r

EGCTF{W0rmy_Th0ught_1t_w4s_cl3ver_to_use_th3_r1ch_head3r_SM512-m$$bIph}