🔰 Introduction
In the Codex Circuit incident, the MegaCorp SOC reports that confidential data has surfaced on a public forum. Suspicion immediately falls on collaboration tool misuse-specifically Slack. A PCAP file is provided to determine whether internal data was uploaded, shared, or exfiltrated to unauthorized workspaces.
My mission: reverse-engineer the entire incident, identify the flow of data, the users involved, the rogue workspace, and recover evidence from encrypted Slack traffic through metadata, JSON fragments, and Slack API artifacts.
This write-up reconstructs the event from scratch, using Python, Scapy, regular expressions, and packet correlation.
🟦 Artifact Overview
Provided:
A large PCAP file (megacorp.pcap) capturing internal Slack communications
No Slack credentials
No plaintext HTTP (all HTTPS)
Slack API metadata leaked in request/response bodies
The key to solving this challenge lies in understanding:
Slack files.upload events
Slack file_shared events
Workspace identification via domain strings
User attribution through fragmented profile JSON
Timestamp correlation
🟪 Step 1: Load the PCAP & Identify Slack Upload Patterns
Slack uses HTTPS, so file contents aren't visible. However, metadata often remains in the encrypted streams-especially multipart file metadata and JSON fragments.
I begin by loading the PCAP using Scapy:
from scapy.all import rdpcap
packets = rdpcap("megacorp.pcap")
print(len(packets))
This reveals 234,337 packets to analyze.
🟩 Step 2: Extract File Upload Events from Slack Traffic
Slack file uploads contain JSON fragments like:
"name":"sensitive_customer_list.xls","timestamp":1760097092
I scan the PCAP for such patterns:
import re
file_events = []
for i, pkt in enumerate(packets):
if pkt.haslayer('Raw'):
data = pkt['Raw'].load.decode('latin-1', errors='ignore')
matches = re.findall(r'"name":"([^"]+\.(?:xls|pdf|png|docx))"[^}]*"timestamp":(\d+)', data)
for name, ts in matches:
file_events.append({
"packet": i,
"filename": name,
"timestamp": int(ts)
})
Sorting by timestamps builds a chronological upload timeline:
Time (GMT) | File Uploaded |
|---|---|
11:46:58 | architecture_diagram.png |
11:47:16 | onboarding_checklist.docx |
11:47:25 | meeting-minutes_2025-10-09.pdf |
11:51:32 | sensitive_customer_list.xls |
✔ Task: What file was uploaded before the sensitive one? Answer: meeting-minutes_2025-10-09.pdf
🟧 Step 3: Identify Internal Sharing of the Sensitive File
Slack emits a file_shared event when a file becomes visible to a channel.
I search for it:
share_events = []
for i, pkt in enumerate(packets):
if pkt.haslayer('Raw'):
data = pkt['Raw'].load.decode('latin-1', errors='ignore')
if "file_shared" in data and "sensitive_customer_list" in data:
ts = float(re.search(r'"ts":"(\d+\.\d+)"', data).group(1))
share_events.append({
"packet": i,
"timestamp": ts
})
The extracted timestamp converts to:
2025-10-10 11:51:36 GMT
✔ Task: At what GMT time was the sensitive file shared internally? Answer: 2025-10-10 11:51:36 GMT
🟥 Step 4: Identify the Internal User Who Shared the File
The uploader has ID U09KA40P3F0, but no matching user profile exists in the PCAP.
Thus, attribution requires conversation context correlation.
By parsing Slack messages:
msg_matches = []
for pkt in packets:
if pkt.haslayer('Raw'):
text = pkt['Raw'].load.decode('latin-1', errors='ignore')
if "thanks for sharing, Ava" in text:
msg_matches.append(text)
A fragment reveals:
"thanks for sharing, Ava"
Another fragment references:
"no worries, here's the latest customer"
"user_id": "U09KA40P3F0"
Thus:
✔ Task: Which internal user shared the sensitive document? Answer: Ava
🟦 Step 5: Identify the Rogue Workspace
Slack workspace hostnames appear in plaintext in API requests:
I extract all domains:
domains = set()
for pkt in packets:
if pkt.haslayer('Raw'):
data = pkt['Raw'].load.decode('latin-1', errors='ignore')
hits = re.findall(r'([a-z0-9-]+\.slack\.com)', data)
for d in hits:
domains.add(d)
Resulting domains:
team-megacorp.slack.com → legitimate
secret-ops-workspace.slack.com → not part of MegaCorp
This second one is identified as the rogue.
✔ Task: What domain hostname FQDN is associated with the rogue server? Answer: secret-ops-workspace.slack.com
🟨 Step 6: Attribute the Exfiltration to a User
Next, I search for profile JSON fragments:
import re
users = {}
for pkt in packets:
if pkt.haslayer('Raw'):
data = pkt['Raw'].load.decode('latin-1', errors='ignore')
matches = re.findall(r'"id":"(U09K[A-Z0-9]+)"[^}]*"real_name":"([^"]+)"', data)
for uid, name in matches:
users[uid] = name
A key fragment appears:
{
"id": "U09KRBDV8S1",
"real_name": "james brown",
"name": "jamesb"
}
Then, in the rogue upload event:
"user": "U09KRBDV8S1",
"files": [{"name": "sensitive_customer_list.xls"}]
Thus, the exfiltrator is:
✔ Task: Which user uploaded the sensitive file to the rogue workspace? Answer: James Brown
🟩 Step 7: Recover Contents of the Exfiltrated File
Although the upload was encrypted, Slack leaks multipart file metadata, sometimes including raw binary blocks inside HTTP request bodies.
I extract the Excel binary via boundary splitting:
for pkt in packets:
if pkt.haslayer('Raw'):
raw = pkt['Raw'].load
if b"sensitive_customer_list.xls" in raw:
with open("extract.xls", "wb") as f:
f.write(raw)
Then parse using pandas:
import pandas as pd
df = pd.read_excel("extract.xls")
print(df)
The last customer's email is:
✔ Task: What is the last customer email? Answer: [email protected]
🟦 Final Answers Summary
Task | Answer |
|---|---|
File type of exfiltrated document | Excel (.xls) |
User who exfiltrated the file | James Brown |
GMT time the file was shared internally | 2025-10-10 11:51:36 GMT |
Internal user who shared the file | Ava |
Rogue workspace FQDN | |
File uploaded before sensitive one | meeting-minutes_2025-10-09.pdf |
Last customer's email |
🟦 Final Flow Reconstruction
[Ava] → Uploads sensitive_customer_list.xls (11:51:32 GMT)
↓
[Ava] → Shares it to #company_documents (11:51:36 GMT)
↓
[James Brown] downloads the file
↓
[James Brown] uploads the same file to secret-ops-workspace.slack.com (11:57:48 GMT)
↓
Exfiltration completed within 6 minutes 12 seconds

