<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>C2 on RockB</title><link>https://baeseokjae.github.io/tags/c2/</link><description>Recent content in C2 on RockB</description><image><title>RockB</title><url>https://baeseokjae.github.io/images/og-default.png</url><link>https://baeseokjae.github.io/images/og-default.png</link></image><generator>Hugo</generator><language>en-us</language><lastBuildDate>Sun, 13 Sep 2026 04:01:01 +0000</lastBuildDate><atom:link href="https://baeseokjae.github.io/tags/c2/index.xml" rel="self" type="application/rss+xml"/><item><title>Dark-Agent: The Mythic C2 Agent With an In-Memory BOF Loader for macOS and Linux</title><link>https://baeseokjae.github.io/posts/dark-agent-mythic-c2-macos/</link><pubDate>Sun, 13 Sep 2026 04:01:01 +0000</pubDate><guid>https://baeseokjae.github.io/posts/dark-agent-mythic-c2-macos/</guid><description>Dark-Agent is the first open-source Mythic C2 agent with a full in-memory BOF loader for macOS and Linux. Used by ServiceNow Red Team since 2024, it loads Beacon Object Files in-process with zero disk writes.</description><content:encoded><![CDATA[<p>Dark-Agent is the first open-source Mythic C2 agent with a full in-memory BOF (Beacon Object File / COFF) loader purpose-built for macOS and Linux. Written in Crystal, it loads Beacon Object Files entirely in memory — no disk writes, no temporary files, no child processes — and has been used operationally by the ServiceNow Red Team since 2024.</p>
<h2 id="what-is-dark-agent-a-mythic-c2-agent-purpose-built-for-linux-and-macos">What Is Dark-Agent? A Mythic C2 Agent Purpose-Built for Linux and macOS</h2>
<p>Mythic is an open-source, cross-platform C2 (command-and-control) framework that makes it easy to extend an agent and swap in alternative C2 profiles without recompiling. Most of the well-known Mythic agents — Apollo, Xenon, Poseidon, and the Java-based options — either focus on Windows or treat Unix as a second-class citizen. Dark-Agent, released by ServiceNow under an open license, is built explicitly to change that.</p>
<p>The gap it fills is real. Red teams operating against Linux servers and macOS workstations have historically had fewer first-class implant options that support the same offensive tooling as their Windows counterparts. Beacon Object Files — compiled C programs designed for Cobalt Strike&rsquo;s Beacon — have an enormous existing ecosystem of tools and techniques. Dark&rsquo;s core contribution is bringing that full ecosystem to Unix platforms with proper in-memory execution.</p>
<h2 id="the-core-innovation-a-full-in-memory-bof-loader-for-unix">The Core Innovation: A Full In-Memory BOF Loader for Unix</h2>
<p>The centerpiece of Dark-Agent is its in-memory BOF loader. A BOF, or Beacon Object File, is a compiled object file (PE/COFF or, on Unix, ELF) that gets loaded into a running process and executed without being written to disk. This is the same technique that made Cobalt Strike BOFs popular: small, flexible, and hard to detect as a file-based artifact.</p>
<p>What Dark does differently from every open-source Mythic agent before it is that this loader works natively on Linux (x86_64 and aarch64) and macOS (including Apple Silicon arm64). Previous agents either loaded BOFs only on Windows or required awkward workarounds on Unix. Dark&rsquo;s loader runs the BOF inside the agent&rsquo;s own process — there are no forked child processes, no memory-map files under /tmp, and no memfd-backed temp files.</p>
<p>According to the project&rsquo;s documentation, Dark ships 25 BOFs and 15 built-in commands out of the box. The minimal baked-in offensive capability is deliberate: the initial drop is essentially just a loader, and operators extend capability by pushing BOFs over the C2 channel.</p>
<h2 id="under-the-hood--how-dark-loads-and-executes-bofs-bof_load--bof_list--bof_exec">Under the Hood — How Dark Loads and Executes BOFs (bof_load / bof_list / bof_exec)</h2>
<p>The BofRegistry workflow is the heart of the design. It is split into three clear commands, each mapped to a function in the agent:</p>
<ul>
<li><strong>bof_load</strong> pulls a compiled object file (COFF on Windows-style BOFs, ELF on Unix) from the Mythic file store over the C2 channel, then registers the raw bytes in the BofRegistry. Critically, nothing is mapped to executable memory at this stage — the file is just stored as bytes in memory.</li>
<li><strong>bof_list</strong> shows which BOFs are currently loaded in the registry. This gives the operator a quick inventory of what is available without re-uploading.</li>
<li><strong>bof_exec</strong> actually fires the loader, mapping the registered bytes and executing the entry point. Because the BOF stays registered, it can be re-executed repeatedly without re-uploading the object — a workflow efficiency that operators value.</li>
</ul>
<p>The entry point for any BOF is <code>coffee()</code>, which keeps things familiar for operators who already build BOFs for Cobalt Strike. Dark also ships a <code>beacon.h</code> boilerplate header so that existing BOF development habits carry over.</p>
<p>The isolation trade-off is worth noting. Because Dark executes BOFs in-process (no subprocess), a crash inside a BOF can take the whole agent down. That is a deliberate architectural choice favoring a lower footprint and less process-level noise — and it is the main thing to understand before trusting an unvetted BOF on a live engagement.</p>
<h2 id="why-macos-and-apple-silicon-matter">Why macOS and Apple Silicon Matter</h2>
<p>MacOS support is Dark-Agent&rsquo;s standout differentiator. Most C2 frameworks and agents either ignore macOS entirely or support only the Intel architecture. Dark explicitly targets Apple Silicon (arm64) alongside macOS x86-64, which matters because M-series Macs are now the default hardware across enterprise fleets.</p>
<p>The significance goes beyond &ldquo;it runs on a Mac.&rdquo; Running a Beacon Object File, which was originally a Windows concept, natively in memory on Apple Silicon requires an ELF and architecture-appropriate loading path. Dark closes a gap that Poseidon and the Windows-focused agents left wide open: Linux and macOS operators can now use the same BOF tooling that Windows operators have enjoyed.</p>
<p>This is not theoretical. Apple Silicon Macs are common in sensitive environments — developers, executives, and security teams themselves — and a red team that cannot operate on them is operating with a blind spot.</p>
<h2 id="platform-support-and-build-matrix">Platform Support and Build Matrix</h2>
<p>Dark cross-compiles all four supported targets from a single Mythic Docker container:</p>
<ul>
<li>macOS arm64 (Apple Silicon)</li>
<li>macOS x86-64 (Intel)</li>
<li>Linux arm64 (aarch64)</li>
<li>Linux x86_64</li>
</ul>
<p>The agent is written in Crystal, which produces a single native binary with no runtime dependency on a garbage collector. It also statically links OpenSSL, so there is no libssl dependency to worry about on the target Linux host.</p>
<p>The build workflow is simple: <code>./build.sh -b</code> builds for Linux, and <code>./build.sh -B</code> builds for macOS aarch64 (this one requires Zig and a macOS SDK). Everything happens inside the standard Mythic Docker container, so the setup is reproducible and consistent with how most red teams already deploy Mythic.</p>
<h2 id="c2-profiles-encryption-and-malleable-traffic">C2 Profiles, Encryption, and Malleable Traffic</h2>
<p>Dark ships two C2 profiles: <strong>HTTP</strong> and <strong>HTTPX</strong>, the latter being Mythic&rsquo;s malleable profile format. The HTTPX configuration included in the repo is a working jQuery-based profile, which means operators can adopt realistic-looking web traffic rather than obviously synthetic beaconing.</p>
<p>Configuration options cover the usual operational concerns:</p>
<ul>
<li><strong>AES-256-CBC encryption toggle</strong> for the traffic channel</li>
<li><strong>Domain rotation</strong> with round-robin or fail-over strategies, so a taken-over domain can be rotated out without rebuilding the agent</li>
<li><strong>Transforms</strong> such as base64 and URL encoding</li>
<li><strong>Message placement</strong> in HTTP headers, URL parameters, cookies, or the request body</li>
</ul>
<p>These options matter because they let operators shape the agent&rsquo;s network footprint to blend with a target environment instead of advertising that a C2 connection is happening.</p>
<h2 id="the-25-bofs-and-15-built-in-commands">The 25 BOFs and 15 Built-in Commands</h2>
<p>Dark ships a curated set of BOFs and commands with MITRE ATT&amp;CK mappings so operators can see exactly which technique they are exercising. The documented mappings include:</p>
<table>
  <thead>
      <tr>
          <th>Technique ID</th>
          <th>Name</th>
          <th>Example use in Dark</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>T1059</td>
          <td>Command and Scripting Interpreter</td>
          <td>Command execution via BOF</td>
      </tr>
      <tr>
          <td>T1082</td>
          <td>System Information Discovery</td>
          <td>Host/OS fingerprinting</td>
      </tr>
      <tr>
          <td>T1070</td>
          <td>Indicator Removal on Host</td>
          <td>Cleanup and log manipulation</td>
      </tr>
      <tr>
          <td>T1129</td>
          <td>Shared Modules / BOF Execution</td>
          <td>The in-memory BOF loader itself</td>
      </tr>
      <tr>
          <td>T1033</td>
          <td>System Owner / User Discovery</td>
          <td>Username and identity enumeration</td>
      </tr>
      <tr>
          <td>T1016</td>
          <td>System Network Configuration Discovery</td>
          <td>Network interface and IP discovery</td>
      </tr>
  </tbody>
</table>
<p>The full list totals 25 BOFs and 15 built-in commands. The point of shipping them pre-built is that an operator can get operational the moment the agent is installed, then extend with custom BOFs rather than baking more capability into the initial payload.</p>
<h2 id="writing-your-own-bofs">Writing Your Own BOFs</h2>
<p>Because Dark uses the familiar <code>coffee()</code> entry point and ships <code>beacon.h</code>, developers who have built BOFs for other platforms can adapt quickly. The project also integrates with <strong>Forge</strong>, Mythic&rsquo;s build tooling for generating BOFs, so the authoring pipeline is first-class within the ecosystem.</p>
<p>There is also a <strong>direct mode</strong>: you can build a standalone COFF loader to test a BOF locally without standing up a full Mythic server. This dramatically speeds up the development-and-test loop — iterate on the BOF, run it through the standalone loader, verify behavior, then push to the live agent.</p>
<h2 id="dark-vs-the-alternatives-fawkes-kassandra-woopsie-poseidon">Dark vs. the Alternatives: Fawkes, Kassandra, Woopsie, Poseidon</h2>
<p>To understand where Dark sits, it helps to compare it against the other active Mythic agents:</p>
<table>
  <thead>
      <tr>
          <th>Agent</th>
          <th>Language</th>
          <th>Platforms</th>
          <th>BOF support</th>
          <th>Key strength</th>
          <th>Key limitation</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Dark-Agent</strong></td>
          <td>Crystal</td>
          <td>Linux + macOS</td>
          <td>In-memory, native, in-process</td>
          <td>First-class Unix BOF loader, Apple Silicon</td>
          <td>In-process crash risk</td>
      </tr>
      <tr>
          <td><strong>Fawkes</strong></td>
          <td>Java</td>
          <td>Win/Linux/macOS</td>
          <td>Inline via Forge</td>
          <td>213 commands, broadest coverage</td>
          <td>Bigger footprint, not Unix-first</td>
      </tr>
      <tr>
          <td><strong>Kassandra</strong></td>
          <td>—</td>
          <td>Win/Linux/macOS</td>
          <td>Isolated subprocess</td>
          <td>Crash isolation protects agent</td>
          <td>Subprocess spawn is noisier</td>
      </tr>
      <tr>
          <td><strong>Woopsie</strong></td>
          <td>Java</td>
          <td>Win/Linux/macOS</td>
          <td>Windows only</td>
          <td>GraalVM Native Image, WebSocket</td>
          <td>No Unix BOF support</td>
      </tr>
      <tr>
          <td><strong>Poseidon</strong></td>
          <td>Swift</td>
          <td>macOS (mostly)</td>
          <td>Limited</td>
          <td>Apple-native feel</td>
          <td>Not really a BOF loader</td>
      </tr>
  </tbody>
</table>
<p>The meaningful trade-offs are between Dark, Fawkes, and Kassandra. Fawkes is broader and carries more total commands, but spread across many platforms; Dark is deliberately lean and Unix-first with pre-built BOFs. Kassandra runs BOFs in an isolated subprocess, which protects the agent from a crashing BOF but adds a process-spawn footprint that Dark avoids by running in-process.</p>
<p>The right choice depends on the environment. If the target set is Windows-heavy, Fawkes or Apollo may be a better fit. If the engagement is Linux servers and macOS workstations — the exact segment Dark targets — the first-class, in-memory Unix BOF loader is the differentiator.</p>
<h2 id="operational-provenance-servicenow-red-team-since-2024">Operational Provenance: ServiceNow Red Team Since 2024</h2>
<p>Dark is not a hobby project. The ServiceNow Red Team has been using it operationally since 2024, well before the public open-source release. That is a meaningful signal: the loader has been exercised against modern defenses in real engagements, and the &ldquo;on arrival&rdquo; design is a product of that operational feedback.</p>
<p>The public release, with the repository created in August 2026 (gathering roughly 100 stars and 13 forks in its early days), carries an explicit intent from ServiceNow: let operators break it, open issues, write bad BOFs, and harden it through community use. It is already listed in the Mythic v4.0.0 community overview, signaling that the framework maintainers treat it as a first-class agent.</p>
<h2 id="strengths-and-honest-trade-offs">Strengths and Honest Trade-offs</h2>
<p>Strengths:</p>
<ul>
<li><strong>First Unix-native in-memory BOF loader</strong> for Mythic, closing a real gap.</li>
<li><strong>Operationally proven</strong> by a real red team since 2024.</li>
<li><strong>Stealth-lean design</strong>: zero disk writes, no temp/memfd files, no child processes, BOFs run in-process.</li>
<li><strong>Apple Silicon support</strong>, which most agents ignore.</li>
<li><strong>Static OpenSSL and Crystal&rsquo;s native binary</strong>, meaning no libssl or runtime dependency on target.</li>
</ul>
<p>Honest trade-offs:</p>
<ul>
<li><strong>In-process execution risk</strong>: a crashing BOF kills the agent, unlike Kassandra&rsquo;s isolated subprocess.</li>
<li><strong>Young public codebase</strong>: the open-source release is recent (2026), so the community hardening is still early.</li>
<li><strong>Lean by design</strong>: only a loader ships, so operators must be comfortable pushing BOFs over the wire rather than relying on baked-in commands.</li>
<li><strong>macOS build requires Zig + a macOS SDK</strong>, a slightly heavier dependency for the Apple Silicon target.</li>
</ul>
<h2 id="how-to-get-started">How to Get Started</h2>
<p>Getting Dark running follows the standard Mythic agent flow: install the agent into your Mythic server (for example via the mythicmeta community overview or building the Docker image from the repo), cross-compile your four targets with <code>./build.sh</code>, and drop the binary on the target. Then <code>bof_load</code> your compiled BOFs over the C2 channel, confirm with <code>bof_list</code>, and execute with <code>bof_exec</code>.</p>
<p>For development, use direct mode with the standalone COFF loader to test BOFs locally against a mock harness before you ever touch a live server.</p>
<h2 id="key-takeaways-for-red-teams">Key Takeaways for Red Teams</h2>
<p>If your engagements touch Linux or macOS — and most modern ones do — Dark-Agent is worth evaluating. It brings the mature BOF ecosystem to Unix for the first time as a first-class, in-process, in-memory loader, with operational provenance from ServiceNow&rsquo;s own red team and a working, hardened design philosophy. The Apple Silicon support alone puts it ahead of most alternatives for enterprise Mac fleets, and the lean payload philosophy means the compromise surface of the initial drop stays small.</p>
<p>Weigh the in-process crash risk against the footprint benefits, pick the environments where a Unix-first loader matters, and Dark becomes a legitimate new tool in the red-team arsenal.</p>
<h2 id="faq">FAQ</h2>
<h3 id="what-is-a-bof-beacon-object-file-loader">What is a BOF (Beacon Object File) loader?</h3>
<p>A Beacon Object File is a compiled C object file (COFF on Windows-style tooling, ELF on Unix) that a C2 agent maps into memory and executes without writing it to disk. A BOF loader is the code that performs that in-memory execution, letting operators run small, flexible post-exploitation tools that leave no file-based artifact.</p>
<h3 id="why-is-dark-agent-significant-for-macos-and-linux">Why is Dark-Agent significant for macOS and Linux?</h3>
<p>Dark-Agent is the first open-source Mythic C2 agent with a full, native in-memory BOF loader for macOS (including Apple Silicon) and Linux. Previously, full BOF loading was largely a Windows capability, forcing Unix-focused red teams to work around the gap.</p>
<h3 id="is-dark-agent-production-grade-or-experimental">Is Dark-Agent production-grade or experimental?</h3>
<p>It is operationally proven. The ServiceNow Red Team has used Dark since 2024 in real engagements, and the public open-source release in August 2026 is an explicit invitation to harden it further. It is listed in the Mythic v4.0.0 community overview as a first-class agent.</p>
<h3 id="what-are-the-main-trade-offs-of-running-bofs-in-process">What are the main trade-offs of running BOFs in-process?</h3>
<p>Executing BOFs in-process means no child processes and zero disk/process-spawn footprint, which reduces observability. The trade-off is that a crashing BOF can kill the entire agent, whereas an agent like Kassandra that runs BOFs in an isolated subprocess protects the agent at the cost of a larger footprint.</p>
<h3 id="how-do-i-test-a-bof-without-a-full-mythic-server">How do I test a BOF without a full Mythic server?</h3>
<p>Dark offers a direct/standalone mode where you build a standalone COFF loader and execute a BOF locally. This lets you iterate on a BOF, verify its behavior, and only then push validated BOFs to a live agent over the C2 channel.</p>
]]></content:encoded></item></channel></rss>