Cobalt Strike .VBS Loader – Decoding with Advanced CyberChef and Emulation

This post demonstrates manually decoding a heavily obfuscated .vbs loader to extract and validate Cobalt Strike shellcode using CyberChef, regex, and emulation. The author fixes negative decimal byte representations, identifies a C2 IP, and confirms HTTP-based shellcode behavior with the SpeakEasy emulator. #CobaltStrike #SpeakEasy

Keypoints

  • Saved and opened the obfuscated .vbs file (zip password: infected) to inspect content referencing Excel objects and Wscript.Shell.
  • Identified three obfuscation patterns: string concatenation with “&”, decimal-encoded characters via Chr(n), and line-continuation underscores.
  • Removed simple splits and quotes with text-editor search/replace and removed Chr(…) decimal values using CyberChef subsections and “From decimal”.
  • Cleaned remaining whitespace/underscores and extracted a short hex blob consistent with shellcode targeted at rundll32.exe.
  • Fixed negative decimal byte values by converting each negative n to (256 – |n|) in CyberChef or Python to produce valid bytes (notably 0xFC at start).
  • Detected C2 IPs (47.98.51[.]47, 47.98.41[.]47) and an EICAR marker; emulated the decoded shellcode with SpeakEasy to confirm HTTP downloader behavior.

MITRE Techniques

  • [T1027] Obfuscated Files or Information – Script used concatenation, decimal encoding, and line-continuations: ‘the script is broken up into lots of small strings’ and ‘the script utilises decimal encoded values that are decoded using Chr’.
  • [T1059.005] Command and Scripting Interpreter: Visual Basic – The loader leverages VBScript and Excel objects for execution: ‘the script references some Excel objects, as well as Wscript.Shell’.
  • [T1055] Process Injection – The decoded script calls APIs common for injection (VirtualAllocEx, WriteProcessMemory, CreateProcessA) to inject bytes into another process: ‘references to api’s commonly used in process injection (VirtualAllocEx, WriteProcessMemory, CreateProcessA etc)’.
  • [T1105] Ingress Tool Transfer – The shellcode functions as an HTTP-based downloader that retrieves further payloads from a remote IP: ‘acts as a http-based downloader from the ip of 47.98.41[.]47’.
  • [T1071.001] Application Layer Protocol: Web Protocols – Communication with C2 is performed over HTTP, as observed in the emulation and decoded strings: ‘http-based downloader from the ip of 47.98.41[.]47’.

Indicators of Compromise

  • [File Hash] sample SHA-256 – e8710133491bdf0b0d1a2e3d9a2dbbf0d58e0dbb0e0f7c65acef4f788128e1e4
  • [IP Address] potential C2 – 47.98.51[.]47, 47.98.41[.]47
  • [Process Name] likely injection target – rundll32.exe (used as the target process for injected shellcode)
  • [String] signature marker found in decoded payload – EICAR test string (used in sample to trigger AV / indicates Cobalt Strike trial marker)

The technical decoding workflow begins by extracting the .vbs and opening it in a text editor to inspect structure and execution hints (Excel objects and Wscript.Shell). The obfuscation consisted of three primary patterns: fragmented string concatenation using “&”, decimal character encoding via Chr(n), and Visual Basic line-continuation underscores. To remove the splits and trivial noise, perform a global search/replace for “&” and strip trailing underscores and extraneous quotes in the editor, which collapses the visible script substantially.

For decimal-encoded characters, prototype a regex (e.g., Chr(d+)) in CyberChef using “Regular Expression” with highlight matches, then switch that into a Subsection so only matched segments are transformed. Extract the decimal values and apply “From decimal” to decode characters. After restoring the textual script, identify the hex/decimal blob representing shellcode and the API call names (VirtualAllocEx, WriteProcessMemory, CreateProcessA) indicating process injection into a target like rundll32.exe.

Fix negative byte values by converting each negative n to 256 – |n| (this can be done in CyberChef via a SubSection plus arithmetic or via a short Python loop over the decimal array). The corrected byte sequence begins with 0xFC and contains cleartext indicators including a C2 IP (47.98.51[.]47 / 47.98.41[.]47) and the EICAR marker. Finally, emulate the reconstructed shellcode in SpeakEasy to validate behavior; the emulation confirmed HTTP download activity to the decoded IP, corroborating the loader’s purpose as a Cobalt Strike shellcode downloader. Read more: https://embee-research.ghost.io/decoding-a-cobalt-strike-vba-loader-with-cyberchef/