Zigerions

A VMProtect-packed dropper chain whose final payload is an unrunnable ELF carrying an AES key next to its own ciphertext.

2026.09.19 PwnSec CTF 2026 Reversing
FLAG psctf{U_sh0u1dvebeen_@_g@m3r_0rHighIQ!}

Reverse Engineering | malware analysis, VMProtect, AES

Overview

A 3-stage dropper chain (update.exestage3.exe, VMProtect-packed) wrapped in a “maze with no wrong answers” UI flavour built around WTSSendMessageW message boxes. The maze itself turned out to be misdirection.

Investigation

  • Extracted the challenge archive (password infected) with extract.py, statically unwrapping all 3 stages with no execution.
  • stage3.exe is VMProtect-protected and anti-VM: it detects a hypervisor-present bit (Windows 11’s own VBS/Core Isolation sets this system-wide) and bails with a MessageBoxW before reaching any interesting logic.
  • Once runnable, a Frida hook (hook.py) traced the process and caught it dropping two files into %TEMP% before any WTS-related activity fired.

The actual payload

Of the two dropped files, AURA.gb was a decoy referenced in a wsprintfA/ShellExecuteA call but never actually written to disk.

The real payload was a file named svchost — not a runnable executable at all despite an ELF header (e_type=EXEC, e_machine=x86-64): _start is undefined and no section carries the executable flag. It is a data mule: an ELF shell built purely to smuggle a hand-rolled AES-128 implementation and its ciphertext past casual inspection.

symbolsectionsizecontent
__3.rodata16 BASCII M68K_AES_FLAGKEY (doubles as the AES-128 key)
__2.rodata11 B00 01 02 04 08 10 20 40 80 1b 36 (AES Rcon table)
__1.rodata256 BAES S-box
__0.rodata256 BAES inverse S-box
__4.data48 Bciphertext (3 AES blocks)

Decrypt

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad

d   = open(r'%TEMP%\svchost', 'rb').read()
ct  = d[0x2220:0x2220 + 0x30]          # .data section
key = b'M68K_AES_FLAGKEY'

print(unpad(AES.new(key, AES.MODE_ECB).decrypt(ct), 16).decode())

Result

AES-128-ECB with the key sitting right next to its own ciphertext, PKCS7-unpadded, yields the flag directly — no interaction with the maze UI was ever required. VMProtect was only protecting the delivery wrapper (anti-VM/anti-debug), not this stage.

#malware#vmprotect#aes#frida