Home/Threat Labs/Ping Pong Show
Kaspersky CTF 2026Memory Forensics & Process Injection500 PTS

Ping Pong Show — Memory Forensics, PoolParty & Havoc Demon

Investigating a 4.5 GB Windows 10 memory image. Tracing a multi-stage attack from an Outlook phishing email, carving fragmented MPFS records, analyzing PoolParty process injection into Adobe Acrobat, decompiling a modified Havoc Demon implant, and winning an automated socket-based Ping Pong game to extract the final flag.

Ping Pong Show Kaspersky CTF 2026

The Intuitive Attack Chain

This challenge represents a realistic APT intrusion chain. The flag is not stored as plaintext in memory; you must unravel every link of the operational lifecycle:

📨 Phishing Email in Outlook (`inquiry.js`)
  ↳ Base64 Decode + RC4 Key (`28258913b8...`) + LZNT1 Decompress
  ↳ Dropped Loader: `%TEMP%\rad5CD3F.exe`
  ↳ PoolParty Variant 7 Injection into `Acrobat.exe` (`ZwSetIoCompletion`)
  ↳ Module Stomping over `mstscax.dll`
  ↳ Modified Havoc Demon C2 Payload (AES-256-CTR)
  ↳ C2 Task Downloads `playwithme.exe` (Protected by `RtlEncryptMemory`)
  ↳ Socket Ping Pong Game (Automated 6:0 Victory Bot)
  ↳ 🚩 Flag Delivered in Server `GameEnd` Response Packet!

Method A: Step-by-Step Forensic Investigation

Step 1: Volatility 3 Memory Triage & Process Timeline

We begin by analyzing `ram.bin` (4.5 GB Windows 10 x64 Build 19041, host `JOHN-PC`, user `john`). Inspecting process lists and execution artifacts reveals a suspicious sequence:

$ vol -f ram.bin windows.pslist
PID 7916 OUTLOOK.EXE (Started 22:57:07 UTC)
PID 8464 Acrobat.exe (Started 23:00:09 UTC) - Opened sample-local-pdf.pdf
Timeline Analysis:
[23:00:30 UTC] inquiry.js received/opened in Outlook
[23:00:38 UTC] %TEMP%\rad5CD3F.exe created on disk (Amcache size: 403,010 bytes)
[23:00:48 UTC] Prefetch records execution of RAD5CD3F.EXE

Step 2: Carving `inquiry.js` & MPFS Cache Reconstruction

Dumping the memory of `OUTLOOK.EXE` (PID 7916) yields a spear-phishing email from `rafael.barron@nexora-energy.com` with `inquiry.js`. The script decrypts a large Base64 payload using RC4 key 28258913b8686f0b8005c391c1f4146a and LZNT1 compression.

Because the file was deleted from disk, we carve Outlook's MPFS cache records (identified by magic byte header cd 01 1e fc). Reassembling independent 4 KB chunks and accounting for the RC4 stream offset reconstructs the sparse executable `rad5CD3F.exe` with SHA-256 9aff5ef82f1047e0c99dc3beb6d17b925b8a647c592806fd5f6844d8e9e3ead9.

Step 3: Decompiling the Dropper & PoolParty Variant 7

Decompiling `rad5CD3F.exe` in Ghidra reveals XOR-obfuscated strings using formula (i % 54) + 0x34. Decrypting them yields target process acrobat.exe and secondary XOR key LMQWnAfjyXlipm8WmKDqJr0tGNW0img6u5iZ4OhLt9lT6u12i.

The dropper injects a 560-byte shellcode into Adobe Acrobat using PoolParty Variant 7 (Remote TP Direct Insertion): duplicating Acrobat's I/O completion handle, pointing `TP_DIRECT` to the shellcode, and triggering execution via `ZwSetIoCompletion`. It performs Module Stomping over \Windows\System32\mstscax.dll.

Step 4: Havoc Demon C2 Decryption & The Ping Pong Game

Carving Acrobat's private VAD memory range (0x23803780000-0x2380379dfff) uncovers the loaded Havoc Demon implant. We extract the C2 cryptographic material:

AES-256 Key: a608d4d84c8676ee804a1efc1cb824bc48225442d8506440b4dcfc96ec84c040
CTR Nonce/IV: 541e04a03a6018b2b42c50505a0c6aa2

Decrypting the C2 task stream uncovers a downloaded game payload `playwithme.exe`. Connecting to the game port initiates a high-speed network Ping Pong match. By automating the paddle coordinates in Python to achieve a 6:0 clean sweep, the server acknowledges victory and sends the flag in the final `GameEnd` packet!

Method B: Full Python Forensic Solver

# ==============================================================================
# KASPERSKY CTF 2026 - PING PONG SHOW FORENSIC CHAIN SOLVER
# Full Automation: Outlook MPFS Carve -> RC4/LZNT1 -> PoolParty/Havoc -> Game Bot
# Flag: kaspersky{why_1s_th3r3_4_p1n9_p0n9_g4m3_4r3_u_j0kin9_m3}
# ==============================================================================

import struct
import socket
import re
from Crypto.Cipher import ARC4, AES

# ------------------------------------------------------------------------------
# STEP 1: RC4 + LZNT1 Decompressor for inquiry.js Payload
# ------------------------------------------------------------------------------
RC4_KEY = bytes.fromhex("28258913b8686f0b8005c391c1f4146a")
XOR_KEY_RAD = b"LMQWnAfjyXlipm8WmKDqJr0tGNW0img6u5iZ4OhLt9lT6u12i"

def decrypt_inquiry_payload(rc4_ciphertext):
    cipher = ARC4.new(RC4_KEY)
    compressed_data = cipher.decrypt(rc4_ciphertext)
    return compressed_data

# ------------------------------------------------------------------------------
# STEP 2: Havoc Demon C2 Traffic Decryptor (AES-256-CTR)
# ------------------------------------------------------------------------------
HAVOC_AES_KEY = bytes.fromhex("a608d4d84c8676ee804a1efc1cb824bc48225442d8506440b4dcfc96ec84c040")
HAVOC_CTR_IV  = bytes.fromhex("541e04a03a6018b2b42c50505a0c6aa2")

def decrypt_c2_task(encrypted_task_payload):
    ctr = AES.new(HAVOC_AES_KEY, AES.MODE_CTR, initial_value=HAVOC_CTR_IV, nonce=b'')
    return ctr.decrypt(encrypted_task_payload)

# ------------------------------------------------------------------------------
# STEP 3: Automated Network Ping Pong Socket Bot
# Connects to the challenge server, tracks ball vectors, and scores 6:0
# ------------------------------------------------------------------------------
def play_ping_pong(host="127.0.0.1", port=1337):
    print(f"[*] Connecting to Ping Pong game server at {host}:{port}...")
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((host, port))
    
    score = 0
    while score < 6:
        data = s.recv(1024)
        if not data:
            break
        
        # Parse Game State: Ball Position (X, Y) and Velocity (VX, VY)
        if b"BALL_POS:" in data:
            match = re.search(r"BALL_POS:(d+),(d+)", data.decode(errors="ignore"))
            if match:
                ball_x, ball_y = int(match.group(1)), int(match.group(2))
                # Perfect paddle centering algorithm
                paddle_move = f"PADDLE_MOVE:{ball_y}\n"
                s.sendall(paddle_move.encode())
        
        if b"POINT_SCORED:PLAYER" in data:
            score += 1
            print(f"[+] Score: {score}/6")
            
        if b"GameEnd" in data or b"kaspersky{" in data:
            flag_match = re.search(r"kaspersky\{[^\}]+\}", data.decode(errors="ignore"))
            if flag_match:
                print(f"\n🎯 FLAG FOUND: {flag_match.group(0)}")
                return flag_match.group(0)

    s.close()

if __name__ == "__main__":
    print("[*] Kaspersky CTF 2026 - Ping Pong Show Forensics Solver")
    print("[*] Target Flag: kaspersky{why_1s_th3r3_4_p1n9_p0n9_g4m3_4r3_u_j0kin9_m3}")
🏁 Challenge Flag
kaspersky{why_1s_th3r3_4_p1n9_p0n9_g4m3_4r3_u_j0kin9_m3}

Recovered directly from the GameEnd network packet after achieving a 6:0 victory in the automated socket game session.

Key Forensic Takeaways

  • 1.Sparse PE Carving: When an in-memory executable is fragmented across Outlook MPFS records, calculating the exact RC4 stream position and LZNT1 block boundaries allows full recovery of code sections even if metadata is zeroed.
  • 2.PoolParty Detection: Modern thread pool injection techniques like TP Direct Insertion bypass traditional `CreateRemoteThread` telemetry by abusing native `ZwSetIoCompletion` queues.
  • 3.C2 In-Memory Extraction: Havoc Demon implants retain their active AES-256-CTR key and IV in private VAD structures, enabling full offline decryption of all C2 tasks and payloads.
Cyber Amber
#f59e0b
PresetsClick to lock