
Application-scoped Windows network brownouts in native C and BOF form
Application-scoped Windows network brownouts for deterministic red-team validation.
Native C • Windows Filtering Platform • IPv4 + IPv6 • Dynamic cleanup
Read the accompanying blog post →
Quick start • Profiles • CLI • How it works • Build • BOF • Validation
[!CAUTION] Controlled environments only. Run DutchOven only on systems you own or are explicitly authorized to assess. It changes live Windows network policy and requires an elevated Administrator token. Review SECURITY.md before use.
DutchOven is a deliberately small Windows red-team primitive that places explicit executable paths behind a deterministic network gate. During each period, matching applications are blocked for a bounded interval and allowed to pass for the remainder.
The result is a repeatable brownout, not a service stop or permanent firewall rule. It creates a controlled way to measure retry logic, buffering, health-state transitions, delayed delivery, and recovery behavior while a process remains alive.
| Design choice | Operator value |
|---|
| Application-scoped WFP filters | Limits the experiment to paths supplied by the operator |
| Timed block/pass duty cycle | Produces measurable degradation instead of only online/offline states |
| Atomic IPv4 and IPv6 changes | Keeps both address families on the same schedule |
| Dynamic WFP session | Removes filters and the generated sublayer when the engine session closes |
| Native C implementation | No Go, .NET, service installation, or custom driver dependency |
| Explicit targets only | No product enumeration, process guessing, or embedded target database |
DutchOven gates new outbound connection authorization. An existing connection that WFP has already authorized is not retroactively terminated; use a fresh canary connection or independently force the target to reconnect when validating an uninterrupted long-lived flow.
Open an elevated PowerShell window.
Validate the resolved target and timing without changing WFP:
.\dutchoven.exe --app 'C:\Path\To\Target.exe' --dry-run
Run the default brownout profile:
.\dutchoven.exe --app 'C:\Path\To\Target.exe'
That is the complete minimum invocation. --app is the only required flag. The default profile
blocks the target for 1.5 seconds in every 5-second period and exits after one minute.
Use Ctrl+C to stop early. DutchOven removes active filters before closing its WFP session; the
dynamic session is the cleanup backstop if the process is interrupted.
Profiles bake in useful schedules so operators do not need to specify every timing value.
| Profile | Block | Pass | Period | Duration | Intended use |
|---|---|---|---|---|---|
light | 0.5 s | 4.5 s | 5 s | 60 s | Low-impact retry observation |
brownout | 1.5 s | 3.5 s | 5 s | 60 s | Balanced default experiment |
heavy | 3.5 s | 1.5 s | 5 s | 60 s | Queue and recovery-pressure testing |
blackout | 5 s | 0 s | 5 s | 30 s | Short, bounded full interruption |
Select a profile with one optional flag:
.\dutchoven.exe --app 'C:\Path\To\Target.exe' --profile heavy
dutchoven --app <absolute.exe> [--app <absolute.exe> ...] [options]
| Flag | Required | Description |
|---|---|---|
--app <absolute.exe> | Yes | Target executable path; repeat for multiprocess applications |
--profile <name> | No | light, brownout, heavy, or blackout |
--period-ms <ms> | No | Override the complete block/pass period |
--block-ms <ms> | No | Override the blocked portion of each period |
--duration-ms <ms> | No | Override the bounded total runtime |
--warmup-ms <ms> | No | Allow traffic before the first block interval |
--dry-run | No | Validate and print configuration without opening WFP |
--json | No | Emit configuration and state transitions as JSON Lines |
--help | No | Print command help |
Print the build version with dutchoven version.
Advanced timing flags override the selected profile regardless of argument order:
.\dutchoven.exe `
--app 'C:\Path\To\Target.exe' `
--period-ms 8000 `
--block-ms 2000 `
--duration-ms 120000 `
--warmup-ms 5000
JSON Lines are intended for test harnesses and evidence collection:
.\dutchoven.exe --app 'C:\Path\To\Target.exe' --profile heavy --json
Timing limits are enforced by the parser:
100–60000 ms1 ms through the complete period900000 ms (15 minutes)60000 msexplicit executable path
│
▼
WFP application ID
│
├── ALE_AUTH_CONNECT_V4 ──┐
└── ALE_AUTH_CONNECT_V6 ──┤── BLOCK / PASS schedule
│
└── dynamic WFP session cleanup
Windows targets are resolved as Unicode and canonicalized to their long path before DutchOven asks
WFP for an application identity. This prevents an 8.3 path alias such as ADMINI~1 from silently
creating a filter that cannot match the process's long-form image identity.
The console prints state transitions with wall-clock and schedule-relative timestamps:
Targets: 1
C:\Path\To\Target.exe
Schedule: block=1500ms pass=3500ms period=5000ms duration=60000ms warmup=0ms
Profile: brownout
Mode: brownout
BLOCK cycle=1 filters=2 wall_ms=1786973903811 elapsed_ms=0
PASS cycle=1 wall_ms=1786973908813 elapsed_ms=5000
...
CLEAN filters=0 session=closed cycles=12 wall_ms=1786973963812 elapsed_ms=60000
The default Linux build exercises parsing and dry-run behavior. The live WFP gate requires the native Windows cross-build.
make check
make release
make check runs the portable tests, cross-builds the Windows artifacts, and verifies the BOF
import contract. make release produces stripped release artifacts and SHA256SUMS under
artifacts/v<version>/.
Primary outputs:
| Artifact | Purpose |
|---|---|
build/dutchoven | POSIX parser and dry-run binary |
build/dutchoven_tests | Core unit tests |
build-windows/dutchoven.exe | Native Windows WFP gate |
build-windows/dutchoven_tests.exe | Native Windows test binary |
build-windows/windows_canary.exe | Routed integration-test canary |
bof/dutchoven.x64.o | Versioned x64 Beacon Object File |
artifacts/v<version>/ | Stripped release EXE, BOF, and checksums |
The Windows executable links only against Windows system libraries: fwpuclnt, rpcrt4, and
advapi32.
The BOF packages DutchOven as a short, synchronous pulse that runs inline in an x64 Beacon. Build the COFF object, refresh the versioned artifact, and verify its import contract with:
make bof
Load bof/dutchoven.cna in Cobalt Strike's Script Manager, then invoke it from a Beacon console:
dutchoven "C:\Path\To\Target.exe"
dutchoven "C:\Path\To\Target.exe" heavy
The default profile is brownout. Profiles map to a single bounded block interval:
| Profile | Pulse |
|---|---|
light | 0.5 s |
brownout | 1.5 s |
heavy | 3.5 s |
blackout | 5 s |
Each invocation opens a dynamic WFP session, atomically installs IPv4 and IPv6 connect filters, waits for the selected pulse, explicitly removes both filters, and closes the session before returning. Closing the dynamic session remains the cleanup backstop if explicit removal fails.
The BOF uses Dynamic Function Resolution for Kernel32, Rpcrt4, and Fwpuclnt; it has no C
runtime imports. It accepts one existing absolute executable path, requires an elevated Beacon,
and refuses to gate the process hosting the BOF. Because it executes inline, it intentionally does
not reproduce the standalone binary's one-minute multi-cycle scheduler.
A useful red-team result needs independent evidence. Do not treat a successful filter-add call as proof that the target experienced the intended brownout.
The repository includes a Windows integration harness that automates those assertions with two copies of a harmless TCP canary. It requires an elevated PowerShell session and a reachable non-local TCP listener; loopback traffic is not a valid substitute for routed WFP validation.
.\tests\windows_integration.ps1 `
-DutchOvenPath '.\build-windows\dutchoven.exe' `
-CanaryPath '.\build-windows\windows_canary.exe' `
-ServerAddress '192.0.2.10' `
-ServerPort 8443
The harness proves baseline connectivity, targeted blocking, an unaffected control, normal recovery, forced-termination recovery through the dynamic session, and zero WFP residue.
DutchOven 0.4.1 was validated on Windows Server 2022 with Elastic Defend 9.4.2:
Elastic recorded DutchOven's process start, process end, SYSTEM identity, and complete command line, then delivered buffered telemetry after recovery. It did not produce an Elastic Defend alert in that configuration. Treat this as one measured result, not a universal detection or evasion claim.
DutchOven intentionally does not:
Administrator rights are required because adding WFP objects requires write access to the Base Filtering Engine. Application identity must match the executable that actually owns the network flow. Multiprocess agents, proxies, kernel networking, and long-lived connections can change the observed result and must be measured rather than assumed.
| Path | Contents |
|---|---|
src/main.c | Minimal command-line entry point |
src/gate.c | WFP gate, profiles, timing, and cleanup |
tests/test_gate.c | Parser, profile, and boundary tests |
tests/windows_canary.c | Harmless TCP canary for routed Windows integration tests |
tests/windows_integration.ps1 | Normal and forced-cleanup WFP integration harness |
bof/ | x64 BOF source, Aggressor wrapper, and contract checker |