Hitchhiker's Guide — Cedar Lattice Phase 11: RE & Vuln Discovery Range
Operation Cedar Lattice. This guide walks through the fictional engagement environment for Phase 11. Meridian Freight International is the target. FIN-LATTICE is the emulated actor. Everything in this document is synthetic: binary metadata, source code snippets, IP addresses, domain names, and personnel are fabricated for educational use. No real malware is analyzed here. No real infrastructure is involved.
The Cedar Lattice Range Setup
Isolated Analysis Environment
Phase 11 RE work requires an isolated malware analysis environment. The range configuration:
| Component | Description |
|---|---|
| Analysis VM | Ubuntu 22.04 LTS, 8 GB RAM, no internet access |
| Snapshot | Fresh snapshot taken before each sample — revert after analysis |
| Network | Host-only adapter only — no bridge to host LAN, no internet routing |
| Shared folder | Disabled — samples transferred via encrypted archive to prevent accidental execution |
| Tools | Python 3.11, Ghidra 10.3, pefile, python-magic, Detect-It-Easy |
Why no internet? Binary samples may contain live C2 beacons. If executed or even partially parsed by a misconfigured tool on a networked host, the sample may attempt to phone home. Isolation prevents attribution of the analysis environment to FIN-LATTICE's C2 infrastructure.
The FIN-LATTICE Sample Set
Three synthetic samples are documented in this guide. Each has a corresponding metadata dict you can feed directly to the Lab 01 triage engine.
Sample 1: mfi_updater_v3.exe — Primary Cedar Lattice Artifact
This is the artifact documented in the Phase 11 README. It was found on Meridian Freight's internal update server during a file server enumeration. Filename and path:
\\MFIFILESERV01\IT_Tools\Updates\mfi_updater_v3.exe
Synthetic Metadata Dict
MFI_UPDATER_V3 = {
"file_type": "PE32+",
"architecture": "x86_64",
"sections": [
{"name": ".text", "entropy": 7.92, "size": 65536},
{"name": ".rsrc", "entropy": 5.10, "size": 16384},
],
"imports": [
{"dll": "kernel32.dll", "function": "LoadLibraryA"},
{"dll": "kernel32.dll", "function": "GetProcAddress"},
],
"exports": [],
"strings": [
"http://198.51.100.45/update",
"cmd.exe /c whoami",
"198.51.100.45",
],
"pdb_path": None,
"timestamp": 0,
"imphash": None,
"opsec_flags": ["timestamp_zeroed", "no_pdb", "minimal_imports"],
}
Running the Triage Engine
from solution import triage_report
report = triage_report(MFI_UPDATER_V3)
Expected Output and Interpretation
{
"file_type": "PE32+",
"architecture": "x86_64",
"packer": "likely_packed", # entropy > 7.0, import count <= 3
"high_entropy_sections": [".text"], # 7.92 > 7.0 threshold
"suspicious_strings": [
{"string": "http://198.51.100.45/update", "category": "url", "severity": "HIGH"},
{"string": "cmd.exe /c whoami", "category": "shell_command", "severity": "HIGH"},
{"string": "198.51.100.45", "category": "ip_address", "severity": "HIGH"},
],
"imphash": None,
"pdb_path": None,
"classification": "loader", # packer is truthy -> loader rule fires
"opsec_flags": ["timestamp_zeroed", "no_pdb", "minimal_imports"],
}
Interpretation for the Cedar Lattice report:
The .text section at 7.92 bits/byte is highly compressed or encrypted. Two imports only
means the unpacking stub is all that is statically visible. The classification is "loader":
packing is confirmed and the binary will reconstruct its real functionality at runtime.
The three suspicious strings in the unencrypted .rsrc section reveal operational intent:
a C2 URL (198.51.100.45) and a reconnaissance command (whoami). The zeroed timestamp
and missing PDB path are deliberate opsec measures consistent with professional threat
actor tooling.
Detection rule derivation:
This finding translates directly to detection rules:
# YARA-style detection concept (not functional — illustrative only)
rule FIN_LATTICE_LOADER {
meta:
description = "High-entropy PE with minimal imports and C2 URL strings"
condition:
pe_section_entropy > 7.0
and pe_import_count <= 3
and any_string matches /http:\/\/198\.51\.100\.\d+\//
}
A SIEM detection rule might alert on: endpoint process creation for mfi_updater_v3.exe
OR DNS resolution for 198.51.100.45 from any Meridian Freight endpoint.
Sample 2: mfi_reflective_dll.dll — In-Memory Loader
Found injected into svchost.exe by the endpoint EDR memory scanner. This sample was
never written to disk as a standalone file. It was recovered via process memory dump.
Synthetic Metadata Dict
MFI_REFLECTIVE_DLL = {
"file_type": "DLL",
"architecture": "x86_64",
"sections": [
{"name": ".text", "entropy": 6.45, "size": 32768},
{"name": ".rdata", "entropy": 4.20, "size": 8192},
{"name": ".data", "entropy": 3.80, "size": 4096},
],
"imports": [
{"dll": "kernel32.dll", "function": "LoadLibraryA"},
{"dll": "kernel32.dll", "function": "GetProcAddress"},
{"dll": "kernel32.dll", "function": "VirtualAlloc"},
],
"exports": ["ReflectiveLoader", "DllMain"],
"strings": [
"ReflectiveDLLInjection",
"NtCreateThreadEx",
"svchost",
],
"pdb_path": None,
"timestamp": 0,
"imphash": None,
"opsec_flags": ["timestamp_zeroed", "no_pdb", "in_memory_only"],
}
Expected Triage Output
{
"file_type": "DLL",
"architecture": "x86_64",
"packer": False, # entropy 6.45 is not > 7.0 for any section
"high_entropy_sections": [], # no sections above threshold
"suspicious_strings": [
{"string": "NtCreateThreadEx", "category": "high_entropy_str", "severity": "LOW"},
{"string": "ReflectiveDLLInjection", "category": "high_entropy_str", "severity": "LOW"},
{"string": "svchost", ...}, # too short for high_entropy_str
],
"imphash": None,
"pdb_path": None,
"classification": "loader", # "ReflectiveLoader" in exports -> loader rule
"opsec_flags": ["timestamp_zeroed", "no_pdb", "in_memory_only"],
}
Interpretation:
The ReflectiveLoader export is the defining signal. Reflective DLL injection is
Stephen Fewer's technique (2008, widely published): the DLL contains a custom loader
function exported as ReflectiveLoader that can map the DLL into memory without the
Windows loader's involvement, enabling the DLL to run without ever touching the filesystem.
The classification "loader" is correct: the ReflectiveLoader export fires the loader
rule before the injector rule is considered. (The injector rule requires both
NtAllocateVirtualMemory AND a write primitive — the string "NtCreateThreadEx" in the
string list does not count as an import.)
Detection:
Memory-resident DLLs with ReflectiveLoader exports are detectable via:
- EDR memory scanning for reflective loader signatures
- API call monitoring:
VirtualAllocof RWX memory followed by execution - Behavioral: unsigned DLL mapped without corresponding file on disk
Sample 3: mfi_inject.exe — Process Injector
Found as a scheduled task artifact: C:\Windows\System32\Tasks\MFIHealthCheck.
The task called a binary at a suspicious path with system-level privileges.
Synthetic Metadata Dict
MFI_INJECTOR = {
"file_type": "PE32+",
"architecture": "x86_64",
"sections": [
{"name": ".text", "entropy": 6.10, "size": 24576},
{"name": ".data", "entropy": 4.50, "size": 4096},
],
"imports": [
{"dll": "ntdll.dll", "function": "NtAllocateVirtualMemory"},
{"dll": "ntdll.dll", "function": "NtWriteVirtualMemory"},
{"dll": "ntdll.dll", "function": "NtCreateThreadEx"},
{"dll": "kernel32.dll", "function": "OpenProcess"},
{"dll": "kernel32.dll", "function": "GetCurrentProcessId"},
],
"exports": [],
"strings": [
"injecting into target",
"OpenProcess failed",
"NtAllocateVirtualMemory failed",
],
"pdb_path": None,
"timestamp": 0,
"imphash": "3a5f9c2d11e4b7a8",
"opsec_flags": ["timestamp_zeroed", "no_pdb"],
}
Expected Triage Output
{
"file_type": "PE32+",
"architecture": "x86_64",
"packer": False, # entropy 6.10 is not > 7.0; 5 imports > 3
"high_entropy_sections": [],
"suspicious_strings": [
# All three strings are >= 16 chars, no spaces (false: "injecting into target" has spaces)
# "OpenProcess failed" — has spaces -> not high_entropy_str
# "NtAllocateVirtualMemory failed" — has spaces -> not high_entropy_str
# "injecting into target" — has spaces -> not high_entropy_str
],
"imphash": "3a5f9c2d11e4b7a8",
"pdb_path": None,
"classification": "injector", # NtAllocateVirtualMemory + NtWriteVirtualMemory
"opsec_flags": ["timestamp_zeroed", "no_pdb"],
}
Interpretation:
The NtAllocateVirtualMemory + NtWriteVirtualMemory combination fires the injector
classification immediately. These are NT native API calls that bypass the Win32 API
layer — the standard hooks that EDRs and AV products instrument. Using the NT layer
directly is a deliberate evasion technique. The presence of NtCreateThreadEx (also
a native API) confirms the execution mechanism.
Detection:
- EDR behavioral detection:
OpenProcesson sensitive targets (lsass.exe, explorer.exe) followed byVirtualAllocEx/WriteProcessMemoryor their native NT equivalents - Kernel callback monitoring:
PsSetCreateProcessNotifyRoutineallows drivers to observe process handle creation; commercial EDRs use this - SIEM alert: scheduled task creation pointing to unsigned binary at non-standard path
Lab 02: Scanning Meridian Freight's Source Code
The red team accessed Meridian Freight's source repository via a misconfigured Gitea
instance exposed on dev.meridianfreight.com without authentication. Three modules from
the logistics backend are flagged for review.
Snippet 1: Shipment Tracking Query Module
SHIPMENT_SNIPPET = {
"language": "python",
"code": '''\
import sqlite3
def get_shipment_by_id(conn, shipment_id):
query = "SELECT id, origin, dest, status FROM shipments WHERE id = " + shipment_id
return conn.execute(query).fetchone()
def search_shipments(conn, carrier, status):
q = f"SELECT * FROM shipments WHERE carrier = '{carrier}' AND status = '{status}'"
return conn.execute(q).fetchall()
''',
"context": "Meridian Freight logistics backend — shipment query module",
}
Running scan_snippet(SHIPMENT_SNIPPET) produces:
Line 4: sql_string_concat / CRITICAL / CWE-89 SQL Injection
Line 8: sql_string_concat / CRITICAL / CWE-89 SQL Injection
Remediation: Replace with parameterized queries:
conn.execute("SELECT ... WHERE id = ?", (shipment_id,))
Detection / monitoring: Web Application Firewall rules for SQL metacharacters in
the shipment_id parameter. Structured query logging to detect anomalously long or
syntactically unusual query strings in the database audit log.
Snippet 2: Fleet Diagnostic Endpoint
FLEET_SNIPPET = {
"language": "python",
"code": '''\
import os
import subprocess
def ping_fleet_vehicle(vehicle_ip):
# Verify vehicle is reachable
result = os.system("ping -c 2 " + vehicle_ip)
return result == 0
def restart_vehicle_agent(vehicle_ip, agent_name):
cmd = f"ssh fleet-admin@{vehicle_ip} systemctl restart {agent_name}"
subprocess.run(cmd, shell=True)
''',
"context": "Meridian Freight fleet management — diagnostic endpoint",
}
Running scan_snippet(FLEET_SNIPPET) produces:
Line 5: os_system / HIGH / CWE-78 Command Injection
Line 10: subprocess_shell_true / HIGH / CWE-78 Command Injection
Remediation: Use list-form subprocess calls with explicitly controlled arguments.
Validate vehicle_ip against an allow-list of registered fleet vehicle IPs before use.
Snippet 3: Document Storage Service
DOC_SNIPPET = {
"language": "python",
"code": '''\
import os
DOCS_ROOT = "/var/app/freight-docs"
def serve_document(request):
doc_name = request.args.get("doc")
filepath = os.path.join(DOCS_ROOT, doc_name)
with open(filepath, "rb") as f:
return f.read()
def get_driver_manifest(args):
driver_id = args["driver_id"]
manifest_path = os.path.join("/etc/fleet/manifests", driver_id)
with open(manifest_path) as f:
return f.read()
''',
"context": "Meridian Freight document storage — file serving module",
}
Running scan_snippet(DOC_SNIPPET) produces:
Line 12: path_join_user_input / MEDIUM / CWE-22 Path Traversal
Note: Line 7 (os.path.join(DOCS_ROOT, doc_name)) also uses os.path.join with a
variable (doc_name) but the scanner checks for explicit user-input keywords
(request, input, param, args). Line 7 reads from request.args.get() but the
join itself does not contain those keywords on the same line. Line 12 is flagged because
args appears on the same line as os.path.join(. A human reviewer would flag line 7
as well — the scanner is a starting point, not a substitute for manual review.
Remediation: Apply os.path.realpath() and prefix validation after os.path.join().
Cedar Lattice Finding-to-Detection Mapping
Every RE finding in this phase connects to a concrete detection opportunity:
| Finding | RE Signal | Detection Method |
|---|---|---|
mfi_updater_v3.exe classified as loader | High entropy + minimal imports | YARA rule on PE section entropy; EDR process creation alert |
C2 URL 198.51.100.45/update in strings | Suspicious string extraction | DNS/firewall block for IOC IP; SIEM alert on HTTP connection to IP |
cmd.exe /c whoami string | Shell command indicator | Endpoint behavior monitoring for whoami execution |
mfi_reflective_dll.dll with ReflectiveLoader | Export table analysis | EDR memory scan for reflective loader signature |
mfi_inject.exe with NT injection imports | Import table analysis | EDR behavioral detection for cross-process memory write |
| SQL injection in shipment query | CRITICAL source code finding | WAF rule; query parameterization in code fix |
| Command injection in fleet diagnostic | HIGH source code finding | Input validation; restrict fleet admin endpoint to internal IP range |
| Path traversal in document service | MEDIUM source code finding | realpath() + prefix check in code fix; WAF path traversal rule |
Phase 11 Lab Quick Reference
# Set up environment
cd phase-11-reverse-engineering-vuln-discovery
# Lab 01 — Binary Triage Engine
cd lab-01-binary-triage-engine
pip install -r requirements.txt
# Develop your solution
# Edit lab.py
# Test stubs (all should fail with NotImplementedError)
pytest -q
# Test reference solution (all 19 should pass)
LAB_MODULE=solution pytest -q
# Lab 02 — Source Code Vulnerability Scanner
cd ../lab-02-source-code-vuln-scanner
pip install -r requirements.txt
# Test reference solution (all 13 should pass)
LAB_MODULE=solution pytest -q