# Some cool RE chall ## 2024 ### Trustme ![image](https://hackmd.io/_uploads/rkSA9ak3kg.png) Open the trustme.exe in IDA, checking the main wont find us anything so special beside an antidebug and checking debugger function ![image](https://hackmd.io/_uploads/Sy_N2py3Je.png) But these 2 lines, definately cause an exception, this is some type of exception handler RE. ``` MEMORY[0] = 0; JUMPOUT(0); ``` ![image](https://hackmd.io/_uploads/S1JCg0k3Je.png) But I'm still too new with this so I will be open the string and find where it start doing it's magic ![image](https://hackmd.io/_uploads/HkrG-Ay2Jg.png) I see it connect to a IP and Port, so I just start from it. The address of the function that we need to focus was an offset with no calling or jumping into it, maybe it must have something to do with the "Exception Handling" ![image](https://hackmd.io/_uploads/ryydZA12ke.png) ![image](https://hackmd.io/_uploads/Hy6KW0k3kx.png) If you debug a little bit you will see it sending and receive thing from that IP address ![image](https://hackmd.io/_uploads/HyQvf0ynkg.png) So what it was retrieving was the RC4 key to decrypt something ![image](https://hackmd.io/_uploads/BJMSXRJ3ke.png) ![image](https://hackmd.io/_uploads/r1XQNCyhJe.png) after the 4 bytes Length must be data it got encrypted with the key that it received ![image](https://hackmd.io/_uploads/rk9-SRknye.png) This look right because the string was a random generated string ![image](https://hackmd.io/_uploads/S1iwH0khkg.png) The size seem correct, since the hex-value of the size it 0x40 and it sent 4 bytes so its "40000000" convert to decimal is 64, the string was 64 bytes longs ![image](https://hackmd.io/_uploads/BkjJ80ynJx.png) original key ``` WTPjWbJafqNPqrZFswaijmyVKMddOrKzukegbVDpXJqDfulPDmDwDasqTwxvibnM ``` Next the server send something back to us, maybe a DLL or PE since there was a a function was validating the header "MZ" then run the thing got decrypted. ![image](https://hackmd.io/_uploads/HyilwR1nke.png) ![image](https://hackmd.io/_uploads/rkjUP01n1l.png) ![image](https://hackmd.io/_uploads/Hk0OD0121x.png) Now, let's get back the file got sent back from the server, since we already got the key, this should be it! ![image](https://hackmd.io/_uploads/BJNyOAk2Je.png) So this was a DLL, it exported 4 option to run, gen0-3 ![image](https://hackmd.io/_uploads/HknNu0knkg.png) ![image](https://hackmd.io/_uploads/Sk-FdRknJg.png) ![image](https://hackmd.io/_uploads/rJQquAJn1g.png) ![image](https://hackmd.io/_uploads/HkjqOC12yx.png) ![image](https://hackmd.io/_uploads/SJzjdCJnyl.png) To summerize this was the function of those option **Gen0:** write the string backward **Gen1:** upper -> lower and lower -> upper **Gen2:** which rotates the string right by 1 **Gen3:** Caeser Cipher +13 So the how does the server and client exchange the encrypt and key? Actually it like the the first part, since the server already got our key so we can skip that part, but it send the byte that set the mode of the encryption key ![image](https://hackmd.io/_uploads/SJhOjAy3Jl.png) ![image](https://hackmd.io/_uploads/BJ-Ao0khyg.png) This is all the mode in order ![image](https://hackmd.io/_uploads/Syn1h01n1g.png) ``` mode: 2,1,1,2,3,2,3,1,2,3,1,0,2,3,0,0,2,1,1,0,0,3 ``` So we just need to dump this stream out, get rid of the first part about the DLL and the original key, the mode was set for the type of the key, using the original key we can get all of the 4 keys ``` 00 MnbivxwTqsaDwDmDPlufDqJXpDVbgekuzKrOddMKVymjiawsFZrqPNqfaJbWjPTW 01 wtpJwBjAFQnpQRzfSWAIJMYvkmDDoRkZUKEGBvdPxjQdFULpdMdWdASQtWXVIBNm 02 MWTPjWbJafqNPqrZFswaijmyVKMddOrKzukegbVDpXJqDfulPDmDwDasqTwxvibn 03 JGCwJoWnsdACdeMSfjnvwzlIXZqqBeXmhxrtoIQcKWdQshyCQzQjQnfdGjkivoaZ ``` With a little skill of prompting, we can ask Claude or GPT to write a script to solve this. ```python! def rc4_decrypt(encrypted_data, key): if isinstance(key, str): key = key.encode('utf-8') S = list(range(256)) j = 0 for i in range(256): j = (j + S[i] + key[i % len(key)]) % 256 S[i], S[j] = S[j], S[i] i = j = 0 result = bytearray() for byte in encrypted_data: i = (i + 1) % 256 j = (j + S[i]) % 256 S[i], S[j] = S[j], S[i] k = S[(S[i] + S[j]) % 256] result.append(byte ^ k) return bytes(result) def hex_to_bytes(hex_data): try: hex_data = ''.join(hex_data.split()) return bytes.fromhex(hex_data) except Exception as e: print(f"Error converting hex to bytes: {str(e)}") return None def process_file(input_file, output_file, rc4_keys): try: with open(input_file, 'r', encoding='utf-8', errors='replace') as f: content = f.read() decoded_data = [] lines = content.splitlines() i = 0 current_mode = None hex_chunks = [] while i < len(lines): line = lines[i].strip() if line in ["00", "01", "02", "03"]: if current_mode is not None and hex_chunks: key_name = f"gen{current_mode[-1]}" current_key = rc4_keys[key_name] combined_hex = ''.join(hex_chunks) byte_data = hex_to_bytes(combined_hex) if byte_data: try: decoded = rc4_decrypt(byte_data, current_key) decoded_data.append(decoded) #print(f"Mode {current_mode}: Decoded {len(byte_data)} bytes") except Exception as e: print(f"Error decoding with mode {current_mode}: {str(e)}") current_mode = line hex_chunks = [] print(f"mode {current_mode}") i += 1 # Move to the next line if i < len(lines): #print(f"Skipping line: {lines[i]}") i += 1 elif current_mode is not None: if line: hex_chunks.append(line) i += 1 else: i += 1 if current_mode is not None and hex_chunks: key_name = f"gen{current_mode[-1]}" current_key = rc4_keys[key_name] combined_hex = ''.join(hex_chunks) byte_data = hex_to_bytes(combined_hex) if byte_data: try: decoded = rc4_decrypt(byte_data, current_key) decoded_data.append(decoded) print(f"Mode {current_mode}: Decoded {len(byte_data)} bytes") except Exception as e: print(f"Error decoding with mode {current_mode}: {str(e)}") with open(output_file, 'wb') as f: for data in decoded_data: f.write(data) print(f"Successfully decoded data and wrote to {output_file}") except Exception as e: print(f"Error: {str(e)}") def main(): input_file = "input.txt" output_file = "IloveCarlotta.bmp" rc4_keys = { "gen0": "MnbivxwTqsaDwDmDPlufDqJXpDVbgekuzKrOddMKVymjiawsFZrqPNqfaJbWjPTW", "gen1": "wtpJwBjAFQnpQRzfSWAIJMYvkmDDoRkZUKEGBvdPxjQdFULpdMdWdASQtWXVIBNm", "gen2": "MWTPjWbJafqNPqrZFswaijmyVKMddOrKzukegbVDpXJqDfulPDmDwDasqTwxvibn", "gen3": "JGCwJoWnsdACdeMSfjnvwzlIXZqqBeXmhxrtoIQcKWdQshyCQzQjQnfdGjkivoaZ" } process_file(input_file, output_file, rc4_keys) if __name__ == "__main__": main() ``` ![image](https://hackmd.io/_uploads/ryqChCy3yx.png) ## 2023 ### Oxygen This challenge force you to read asm instead of pseudocode so I wont be showing pseudocode ![image](https://hackmd.io/_uploads/S1vyR0J2Je.png) ```asm! mov eax, 8 imul rax, 0 mov rcx, [rbp+7A0h+arg_8] mov rcx, [rcx+rax] ; int call j_maybe_imporatnt mov [rbp+7A0h+var_5B8], 0FFFFFFFFFFFFFFFFh mov [rbp+7A0h+s], 0FFFFFFFFFFFFFFFFh mov [rbp+7A0h+ppResult], 0 mov [rbp+7A0h+len], 200h lea rdx, [rbp+7A0h+WSAData] ; lpWSAData mov cx, 202h ; wVersionRequested call cs:WSAStartup mov [rbp+7A0h+var_5DC], eax cmp [rbp+7A0h+var_5DC], 0 jz short loc_7FF70822B99C mov eax, 1 jmp check_stack ; loc_7FF70822B99C: ; CODE XREF: main_0+B0↑j mov r8d, 30h ; '0' ; Size xor edx, edx ; Val lea rcx, [rbp+7A0h+pHints] ; void * call j_memset mov [rbp+7A0h+pHints.ai_family], 2 mov [rbp+7A0h+pHints.ai_socktype], 1 mov [rbp+7A0h+pHints.ai_protocol], 6 mov [rbp+7A0h+pHints.ai_flags], 1 lea r9, [rbp+7A0h+ppResult] ; ppResult lea r8, [rbp+7A0h+pHints] ; pHints lea rdx, pServiceName ; "1337" xor ecx, ecx ; pNodeName call cs:getaddrinfo mov [rbp+7A0h+var_5DC], eax cmp [rbp+7A0h+var_5DC], 0 jz short loc_7FF70822BA14 call cs:WSACleanup mov eax, 1 jmp check_stack ; loc_7FF70822BA14: ; CODE XREF: main_0+122↑j mov rax, [rbp+7A0h+ppResult] mov r8d, [rax+0Ch] ; protocol mov rax, [rbp+7A0h+ppResult] mov edx, [rax+8] ; type mov rax, [rbp+7A0h+ppResult] mov ecx, [rax+4] ; af call cs:socket mov [rbp+7A0h+var_5B8], rax cmp [rbp+7A0h+var_5B8], 0FFFFFFFFFFFFFFFFh jnz short loc_7FF70822BA67 mov rcx, [rbp+7A0h+ppResult] ; pAddrInfo call cs:freeaddrinfo call cs:WSACleanup mov eax, 1 jmp check_stack loc_7FF70822BA67: ; CODE XREF: main_0+168↑j mov rax, [rbp+7A0h+ppResult] mov r8d, [rax+10h] ; namelen mov rax, [rbp+7A0h+ppResult] mov rdx, [rax+20h] ; name mov rcx, [rbp+7A0h+var_5B8] ; s call cs:bind mov [rbp+7A0h+var_5DC], eax cmp [rbp+7A0h+var_5DC], 0FFFFFFFFh jnz short print_phase1 mov rcx, [rbp+7A0h+ppResult] ; pAddrInfo call cs:freeaddrinfo mov rcx, [rbp+7A0h+var_5B8] ; s call cs:closesocket call cs:WSACleanup mov eax, 1 jmp check_stack ``` **ai_family to 2 (AF_INET, IPv4) ai_socktype to 1 (SOCK_STREAM, TCP) ai_protocol to 6 (IPPROTO_TCP) ai_flags to 1 (AI_PASSIVE)** This mean it setting up a connection, with the port is 1337, its binding that port and pNodeName is the value for getaddrinfo() null along with AI_PASSIVE flag is on so it actually open listenning on **0.0.0.0:1337** ![image](https://hackmd.io/_uploads/ry6UlJx2ke.png) This function here, printing the word "gimme oxygen!" then start listenning. I was saying about this above. After receiving the data sending to, it start the next process, we can see here it was getting the key or something, it will do something with data "maybe_unpack", and using ope virtual protect ![image](https://hackmd.io/_uploads/rJasb1xh1g.png) Checking the data, we can see this is some kind of data and it got called in another function look like a xor algorithm ![image](https://hackmd.io/_uploads/HJZgzyln1l.png) ![image](https://hackmd.io/_uploads/B1EMfkxhJx.png) Using CypherChef we can xor the whole data easily, but the outcome will be weird but do not let that stop you. ![image](https://hackmd.io/_uploads/SJc-V1g2kl.png) This is a shellcode, we can put it in IDA and investigate furthur, using IDA we will know what will the shellcode do ![image](https://hackmd.io/_uploads/BkTOVkehkl.png) ![image](https://hackmd.io/_uploads/rkzar1xn1g.png) ```py! def sub0(key): v3 = 0 for j in range(11): i = 0x20 if (v3 & 1 != 0): while True: a = i | 0xA b = i & 0xA if ((a + b) == ord(key[j])): print(chr(i),end="") break i += 1 else: while True: a = i | 0xA b = i & 0xA if ((a - b) == ord(key[j])): print(chr(i),end="") break i += 1 v3 += 1 print(sub0("n[}>}C]qRm[")) ``` After decoding with the hardcoded key we get the value "dQw4w9WgXcQ" ![image](https://hackmd.io/_uploads/HJe9owJg2ye.png) So it receive the value got send to it then encode the key if it equal to the hardcoded key it will print congratz and send something back. ![image](https://hackmd.io/_uploads/SyXxWkenJe.png) ``` import socket host = "127.0.0.1" port = 1337 message = "dQw4w9WgXcQ" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((host, port)) s.sendall(message.encode()) data = s.recv(1024) if data: print("Received:", data.decode()) ``` ![image](https://hackmd.io/_uploads/H1xJtke2ke.png) ---