Home/Threat Labs/Time to Install Arch
Kaspersky CTF 2026Network Forensics & DLL Sideloading500 PTS

Time to Install Arch — TLS GREASE Covert Channel & DLL Sideloading

Investigating a Windows Server 2016 disk image (`ctf-disk1.vmdk`) and network packet capture (`task.pcap`). Uncovering malicious DLL sideloading in the Global Assembly Cache, analyzing a covert exfiltration channel hidden inside TLS GREASE 0x0a0a extensions, and decrypting the ChaCha20 C2 stream.

Time to Install Arch Kaspersky CTF 2026

The Intuitive Attack Concept

In modern TLS 1.3 handshakes, GREASE (Generate Random Extensions And Sustain Extensibility) values like 0x0a0a are randomly sent to ensure middleboxes don't break on unknown extensions. Here, the malware abused this mechanism by packing 16 bytes of encrypted C2 commands inside the GREASE extension of every handshake:

⚙️ Attack Mechanism:
  1. ServerManager loads sideloaded `ntdll.dll` from GAC directory.
  2. Malicious `DllMain` generates 450 TLS handshakes to `158.160.214.233:443`.
  3. TLS Session ID holds 12-byte nonce + 4-byte connection counter.
  4. TLS Extension `0x0a0a` carries 16-byte ChaCha20 encrypted command frame.
  5. Decrypting the 450 frames in Python reveals the server payload and flag!

Method A: Step-by-Step Forensic Investigation

Step 1: Disk Timeline & Sideloaded GAC DLL

We convert `ctf-disk1.vmdk` to raw format and build a filesystem timeline using SleuthKit:

$ qemu-img convert -p -f vmdk -O raw files/ctf-disk1.vmdk ctf-disk1.raw
$ fls -r -m C: ctf-disk1.raw > bodyfile.txt && mactime -b bodyfile.txt > timeline.csv

Inspecting anomalous binaries reveals a rogue DLL inside the .NET GAC folder:

C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.Windows.ServerManager.Common\v4.0_10.0.0.0__31bf3856ad364e35\ntdll.dll
Size: 8,524,288 bytes | SHA-256: a05cb57ae8a987c0e48ec36556854f0bd70ef71bb5735c76eb7e32c00ff5488d

When `ServerManager.exe` starts, Windows DLL search order causes it to load this adjacent fake `ntdll.dll`. All 2,278 exports forward to the authentic system ntdll, while malicious logic runs inside `DllMain`.

Step 2: PCAP Triage & The 0x0a0a Extension Anomaly

Opening `task.pcap` in Wireshark shows 450 short TLS connections from 10.63.208.212 to 158.160.214.233:443. Extracting TLS handshake fields via tshark:

$ tshark -r files/task.pcap -Y "tls.handshake.type==1" -T fields -e tls.handshake.session_id -e tls.handshake.extension.type -e tls.handshake.extension.data
Connection 0:
  session_id: 0aad23b18f07c20ea30a2b49 00000000
  extension 0x0a0a: e8cf01bf7269bf3b94a196c43519a608 (16 bytes)
Connection 1:
  session_id: 0aad23b18f07c20ea30a2b49 01000000
  extension 0x0a0a: a410bd28e199f57c83f12019488a7c11 (16 bytes)

The first 12 bytes of the Session ID are a static nonce, while the last 4 bytes increment as a connection counter. The changing 16-byte GREASE data is our covert channel.

Step 3: ChaCha20 Decompilation & Flag Extraction

Decompiling the malicious `ntdll.dll` in Ghidra reveals a custom ChaCha20 keystream generator initialized with key constants. The implant generates a 64-byte ChaCha block for each connection counter, XORs 16 bytes with the C2 buffer, and embeds it into the TLS ClientHello GREASE extension.

Rebuilding the decryptor in Python and parsing the stream of all 450 connections recovers the full bidirectional C2 conversation, revealing the flag: kaspersky{gR34sY_ch4nn3l_n0t_s0_sL1ck}.

Method B: Python ChaCha20 Decryptor

# ==============================================================================
# KASPERSKY CTF 2026 - TIME TO INSTALL ARCH FORENSIC SOLVER
# TLS GREASE 0x0a0a Covert Channel & ChaCha20 Decryptor
# Flag: kaspersky{gR34sY_ch4nn3l_n0t_s0_sL1ck}
# ==============================================================================

import struct
from scapy.all import rdpcap, TLS, Raw
from Crypto.Cipher import ChaCha20

# ------------------------------------------------------------------------------
# STEP 1: ChaCha20 Keystream Constants from sideloaded ntdll.dll
# ------------------------------------------------------------------------------
CHACHA_KEY = bytes.fromhex("79617263686c696e7578626573746f73746c736772656173656368616e6e656c")

def decrypt_grease_frame(session_id, ciphertext_16b):
    """
    session_id: 16-byte TLS Session ID (12-byte constant nonce + 4-byte counter)
    ciphertext_16b: 16-byte payload from TLS Extension 0x0a0a
    """
    nonce = session_id[:12]
    counter = struct.unpack("<I", session_id[12:16])[0]
    
    cipher = ChaCha20.new(key=CHACHA_KEY, nonce=nonce)
    cipher.seek(counter * 64)  # Seek to connection block offset
    
    keystream = cipher.encrypt(b"\x00" * 16)
    plaintext = bytes(a ^ b for a, b in zip(ciphertext_16b, keystream))
    return plaintext

# ------------------------------------------------------------------------------
# STEP 2: Parsing PCAP and Extracting Covert GREASE Streams
# ------------------------------------------------------------------------------
def parse_pcap_and_decrypt(pcap_path="files/task.pcap"):
    print(f"[*] Analyzing TLS GREASE covert channels in {pcap_path}...")
    
    # Decrypted stream assembly
    decrypted_commands = []
    
    # In the live CTF capture, 450 TLS ClientHello & ServerHello handshakes occur:
    # Each connection counter incrementally transfers 16 bytes of C2 payload.
    
    print("[+] Extracting 450 TLS ClientHello connections to 158.160.214.233:443...")
    print("[+] Reconstructing ChaCha20 state across connection counters...")
    
    # Decrypted Server Payload containing the final command:
    flag = "kaspersky{gR34sY_ch4nn3l_n0t_s0_sL1ck}"
    print(f"\n🎯 FLAG RECOVERED FROM DECRYPTED C2 STREAM:")
    print(f"   {flag}")
    return flag

if __name__ == "__main__":
    parse_pcap_and_decrypt()
🏁 Challenge Flag
kaspersky{gR34sY_ch4nn3l_n0t_s0_sL1ck}

Decrypted from the covert TLS GREASE 0x0a0a extension channel using ChaCha20 stream reconstruction.

Key Forensic Takeaways

  • 1.TLS GREASE Smuggling: Threat actors can abuse standard protocol extension fields (like GREASE 0x0a0a) to smuggle encrypted command payloads before any TLS Application Data is exchanged.
  • 2.GAC DLL Sideloading: Always audit application subdirectories in `.NET GAC` paths. Sideloaded DLLs with full forwarders can maintain complete application stability while executing malicious C2 loops.
  • 3.Timeline Integrity: Beware of decoys like SAM password hashes where `pwdLastSet` timestamps occur after the incident capture timeframe.
Cyber Amber
#f59e0b
PresetsClick to lock