Expand description
§Smoke and Mirrors: Systematic OT Malware Elicitation
We present Smoke and Mirrors (SaM), a dynamic analysis system that reframes OT malware triage as a network-response exploration problem.
SaM constructs a Network-Event Tree (NET) by systematically varying network reachability and protocol responses via dynamic binary instrumentation and coverage-guided fuzzing, to elicit:
- targeted endpoints
- protocol usage
- issued commands
all without physical devices or emulators.
§Motivation
Operational technology (OT) malware analysis remains an open problem:
- existing sandboxes lack network simulation which is required to trigger exploitation-stage behaviour,
- physical testbeds are costly and brittle across heterogeneous deployments.
Observing that:
OT malware is not sensitive to the physical process itself, but to the network responses it receives from field devices
we address this problem by:
- systematically varying the network environment through simulation, and
- eliciting the malware’s behaviour without physical hardware
As such, the challenge is not high-fidelity reconstruction but systematic exploration.
Evaluating SaM, our results suggest that systematic, protocol-aware elicitation offers a practical path toward scalable OT malware triage.
§SaM in action
The Network-Event Tree (NET) that SaM yields is a compact behavioural profile for the malware sample, capturing network interactions aggregated across many executions with different simulated network environments. An example is shown below:
§How SaM Works
SaM performs an iterative exploration loop.
-
Instrumentation: On each iteration, the sample is instrumented and executed to completion.
-
Network-Event Interposition: Network events are intercepted by the instrumentation, producing a chronological trace of events.
-
Network-Event Tree (NET) Construction: Sequences of network events are aggregated across consequtive executions of the sample.
-
Tree-guided exploration: The NET is traversed to find potentially unexplored branches. The proposed trajectory expresses a path throught the graph to an unexplored branch which will be tested on the next iteration of the loop.
Fuzzing: The NET search may identify a branching point in the tree where a network response must be generated by SaM.
- SaM enters a coverage-guided fuzzing session to explore the space of possible responses.
- Fuzzing terminates if a response is found that gives rise to previously unseen network events.
- This response payload is included in the proposed trajectory which is explored on the next iteration of the loop.
§Getting Started
SaM implements two network simulation modes, selected based on the target binary’s characteristics:
- Buffer-mode: Is preferable, integrating more naturally with fuzzing sessions, offering high throughput.
- Network-mode: Offers robustness when working with samples that implement custom networking stacks (e.g., Go binaries): SaM delegates to a network emulation layer (e.g., FakeNet-NG) that intercepts traffic at the network interface.
⚙️Network-mode vs. Buffer-mode → explains this in more detail.
See our ⚡Getting Started → guide for steps to install and run SaM in either Buffer-mode or Network-mode.
§Limitations
Below is a discussion of two limitations of SaM that arise when running SaM against binaries with non-C-like runtimes.
§Asynchronous runtimes (e.g. the Go runtime)
Async runtimes present two challenges. SaM implements a partial solution to the first, but not the second.
-
They typically use asynchronous networking stacks: (e.g. the
netpackage in the Go standard library implements Windows networking using async sockets). Injecting responses into async networking stack is challenging. Network-mode is the partial solution that SaM implements for this problem - it is a partial solution because network APIs must still be successfully hooked to gather outbound requests. A solution to this, and a deeper explanation of the problem can be found here. -
Persistant-mode fuzzing with soft-rollbacks is very unstable: SaM’s fuzzing sessions are built on WinAFL, which offers high-throughput fuzzing with Windows binaries. The mechanism for this (in the absence of process forking, which is available on Linux), is to select a target function (that the user wants to fuzz) and instrument the target binary so that it runs in a loop - as such, multiple candidate inputs can be executed, one after another, without restarting the target process. The target function must reliably execute from start to finish to maintain this loop. This is often not the case for functions in async runtimes which often include yield points where the async scheduler regains control and may schedule an entirely different task to run before execution of the target function is resumes. This causes very significant instability, and in our experience makes fuzzing programs with async runtimes infeasibile.
§Interpreted runtimes (e.g. the Python runtime)
Coverage-guided fuzzing requires that coverage information is collected whilst the target binary is executed. This information is used by the fuzzer to guide the selection of the next candidate input.
In an interpreted language, the source code for the target program is not compiled down to low-level instructions; instead the logic in the interpreter transforms the source code to low-level instructions at runtime. As a result, collecting coverage information on the target binary (and not the interpreter) will likely exclude all of the low-level instruction branching information required by the fuzzer. Alternatively, collecting coverage information on the interpreter results in a significant amount of noise (irrelevant coverage information with respect to fuzzing the target function) - and in our experience this is enough noise to make fuzzing infeasible.
§Research Paper
See the 📄 Research Paper → section for a link to our research and additional details for reproducing our experiments & analysis.
§Developer Documentation
For engineers & developers wishing to extend or build upon this work, see our 📚 Developer Documentation →
§API Reference
See the crate level API documentation for:
Modules§
- developer_
docs - 📚 Developer Documentation
- getting_
started - ⚡ Getting Started
- modes
- ⚙️ Network-mode vs. Buffer-mode
- research_
paper - 📄 Research Paper