Skip to main content

Inside Fast16's Physics Sabotage Engine

Introduction

This past friday Juan Andres Guerrero-Saade and Vitaly Kamluk published an extraordinary piece of research, which uncovered a 20 years old sophisticated malware, plausibly attributed to state actors. What is outstanding about this implant is, as the authors mention, that "fast16.sys selectively targets high-precision calculation software, patching code in memory to tamper with results."

That's insane…and very real. I'll try to contribute to the public understanding of Fast16 by digging into the function that targets the physics simulations.

At this point, there is little left to add about Stuxnet, but it is important to use it as a temporal reference, because Fast16 was allegedly active years before the malware that changed everything. Around 2005, Iran was most likely working on the IR-1 centrifuges that would later become the target of Stuxnet. There is also a possibility they were involved in other neutron-related initiatives at the time.

In any case, it is plausible that, as part of these efforts, Iran had been relying on well-known multiphysics simulation software such as LS-DYNA. In fact, the SentinelLabs blog post explicitly mentions this scenario, noting a public reference where Iranian scientists publicly acknowledged the use of this tool. It is equally plausible that the US, Israel, or both had "good visibility" into Iranian scientific networks and systems.



I bring this up because the analysis of the Fast16 physics payload reveals a very specific, tailored, mathematical model designed to target the simulation of an unknown physical process. As with Stuxnet, unless one knows virtually every internal detail of how the system works, it is almost impossible to carry out such an operation successfully.

But we also have to take into account the software that Fast16 potentially targets, as this kind of simulation software is really complex. The sophistication of this operation, at a technical level, likely means that the target was worth it.

PhysicsFiction

Fast16.sys contains a 1104-byte function, let's call it PhysicsFiction (PF), that is apparently injected into the target software, for now I'll assume the LS-DYNA, at runtime.


This function is not alone, it comes with a 170-byte configuration blob (and a trampoline). As we will see later on, this structure contains the physics-related fields required to attack the simulation.



Although the exact mechanisms remain unclear due to limited information about the target and the full infection flow, note that a series of pointers within PF's internal context structure, which is initialized from the configuration blob, point to data originating from the legitimate simulation (such as ext_event_id_ptr in the code below). It is also important to note that PF is able to operate in two precisions: double and float. I will elaborate on this feature later on.

PF is structured around two state machines: one that monitors certain data from the simulation to determine when to initiate the attack (state_monitor), and the other that implements the manipulation of data involved in the physics simulation (state_physics). Both are closely aligned and must reach a common state before the attack is fully activated.

Let's see how this is implemented.

state_monitor

At #0 state_monitor expects specific "events_ids", originating in the legitimate simulation, to collect data able to initialize a threshold that will serve to measure the progress of the simulation. By multiplying sp with the hardcoded scale value (5.0), state_monitor establishes the minimum progress the simulation needs to reach. Unfortunately, it's not possible to know the unit (pressure?, timing?...) that is measuring that progress…



At #1 this previously established threshold is now compared with the "mysterious" unit coming from the legitimate simulation to see the progress, and be able to move forward to #2.



state_physics

In the initial state, some kind of reference value coming from the legitimate simulation is captured and then it moves to monitor_PEAK.



monitor_PEAK is checking, and updating if required, what seems like a local maximum coming from the legitimate simulation. This will be important later.


At #1 the previous reference value is checked to be still consistent, and if so, we'll move to the #2, and eventually to #3, both play the central role in attacking the simulation.



state_physics #2 — A key part

The core concept behind the logic at #2 is defining parameters to model an adversarial response to the original simulation, which will ultimately modify the results produced by the LS-DYNA solver (or any other target's solver).

To understand the context I'll briefly introduce the following members of the internal structure, which are hardcoded in the configuration blob previously introduced.



evt_count is the number of entries in the following tables.

evt_tbl_keys: This table represents a series of internal "event" IDs (related to the simulation) where IDs < 0x20 are for float precision and > 0x20 for double.

tbl_b_f: This table contains raw physical quantities related to the progression/intervals of the simulation (60.0, 48.0…), but I can't definitely infer the unit. Consider this the X axis. Each value is indexed by the IDs present in evt_tbl_keys.

tbl_a_f: In this case the range of values seems normalized within [0, 1.0]. It is plausible to interpret this as the Y-axis, representing fractions of the response.

k_d and k_f: This value (identical for both float and double precision) is a raw physical quantity sharing the same unit as in tbl_b_f whatever that unit may be. It represents a point of interest along the X-axis, serving as a reference for subsequent calculations.

With this information in mind we can now see how the simulation sabotage is designed.

Just to recap: at this point the two state machines of PF have converged to state #2, so the target simulation has reached the required state to trigger the attack. The first step in this process is to calculate the coefficients and regions that will define the adversarial response to the physical process being simulated.


The first thing to notice is that the code is designed to attack simulations in both float and double precision. While the logic remains the same in both cases, the parameters differ slightly in the configuration table, so the results will also be different.

Basically the code is calculating the coefficients to define three regimes, in terms of response: Pass-thru, Linear and Plateau.

In the X-axis (Quantity) the point of reference to calculate the linear region, which in turn defines the boundaries of the other two, is the running_max value, which was already introduced. thresh_a and thresh_b are calculated around this reference point.

The Y-axis is anchored by a fixed value (1.0) and anchor_a, which comes from the configuration.

The negative response in the linear region is defined by a common y-intercept method that varies according to the running_max value: the lower the value, the steeper the slope.

A crucial point to note is that, from this moment onward, these regions and coefficients remain fixed. They are not updated further, even as the simulation continues to progress. This is clearly engineered to produce a static, artificial response, independent of the expected legitimate simulation physics.

state_physics #3 - The attack



Now, the attack is fully activated. The input received from the original simulation is modified according to the three regions:

  • If it's within the pass-thru area (input < ctx->thresh_a), the value will remain intact, scaled and returned back to the solver via FINAL_STEP.
  • If it's within the plateau region (input >= ctx->thresh_b), the configuration-defined value anchor_a is returned instead.
  • If it's within the linear region, the result will depend on the linear coefficients calculated at state #2.

The linearity of the approach is interesting, so this may be part of a broader interpolation logic.

To sum up, a practical and neat approach for an Adversary-In-The-Simulation. Insane, if you ask me…but it likely worked.

According to the configuration embedded in the sample identified by SentinelLabs (SHA1 92e9dcaf7249110047ef121b7586c81d4b8cb4e5), I have simulated the artificial responses for the different key events, both float and double precision, with a running_max parameter equal to k (19.0). Maybe this rings a bell for someone.

FLOAT






DOUBLE



What about the target?

It's likely that LS-DYNA was the target (or one of them) of this implant. A production version I found from around 2005 hits several of the yara rules SentinelLabs provided, and its internals seems to initially align with the logic, but at this moment I don't really have solid evidence to support this theory.

Regarding the physical process being simulated, that is the big question. Unfortunately, I am not sure we will ever figure it out.

If I had to guess, I think the target was the simulation of specific material physics, and the implant was intended to mess with their characteristic curves (e.g. stress-strain). For example, this would make engineers think something is more resistant than expected, when in reality, it would fail earlier than expected…as in Stuxnet.

Anyway, I believe it is worth documenting the scenario as thoroughly as possible, so hopefully others may recognize a familiar pattern that could shed light on this operation.

Conclusions

If Fast16 was somehow successful, and it likely was, that is insane. That's it, that's the conclusion.

I've been, recreationally, researching similar attacks targeting nuclear-related devices, software, and radiation monitoring systems for some time. However, seeing something in the wild with the potential to cause physical failures by targeting the design phase is a paradigm shift.

The thing is, it happened 20 years ago...so it would be interesting to revisit some of the failures in certain countries over the years, stare at the monitor for a while, and just ponder the possibilities...

Popular posts from this blog

What Really Happened in Chernobyl During the Beginning of the Russian Invasion?

This blog post contains the web version of my research paper: " Seeing Through the Invisible: Radiation Spikes Detected in Chernobyl During the Russian Invasion Show Possible Evidence of Fabrication ", which was unveiled at BlackHat USA 2023 . It is intended to ease the indexing and dissemination of the information collected during this research.  In a few days, I'll be in Brussels presenting this research.  The original paper (PDF) can be downloaded here . Additional references: https://www.wired.com/story/chernobyl-radiation-spike-mystery/  (Kim Zetter) https://www.zetter-zeroday.com/p/radiation-spikes-at-chernobyl-a-mystery  (Kim Zetter) https://medium.com/war-notes/chornobyl-3-92216d21b223  (Olegh Bondarenko) INDEX Foreword Executive summary Introduction 1. Physical      1986      Resuspension      Transport      Humidity      Traffic 2. Cyber    ...

De-Anonymization attacks against Proton services

  In November 2021 YesWeHack invited me to participate in a private bug bounty program organized by  Bug Bounty Switzerland on behalf of Proton AG.  The scope of the program was quite interesting and heterogeneous, as it covered most of the applications and services offered by Proton, such as ProtonMail and ProtonVPN. As a result, multiple technologies and codebases were in scope, ranging from typescript, in the open-source part of Protonmail, to .NET/Swift used by ProtonVPN apps for Windows and macOS respectively. Proton is well-known for its privacy-driven services offer, so they are based on Switzerland where the legislation seems to match Proton's requirements to provide that kind of services: thus maximizing the privacy of their communications, minimizing the amount of data they log from their users while keeping a law-abiding status.  It wouldn't be realistic to think of Proton users as an homogenous group; you may be using Proton because you're genuinely w...

Finding vulnerabilities in Swiss Post's e-voting system: part 3

Exactly two years ago I brought my blog back to life, after many years of hiatus, with " Finding vulnerabilities in Swiss Post’s future e-voting system - Part 1 ". That was the first of a series of blog posts covering that system. During these two years I've been periodically assessing the security posture of this e-voting solution, as part of their Bug Bounty program , which I personally recommend.   Since the first time I reviewed their codebase a lot of things have changed, for good, as many areas have been dramatically improved. To be honest, from a security perspective the codebase back then was kind of a mess.   When the first Swiss Post e-voting platform was published, back in 2019, it faced some public scrutiny, mostly from the academic community.  As a result, some significant issues were uncovered , so eventually Swiss Post decided to suspend the deployment of the system. That first version had been developed by Scytl , Spanish company specializ...

Beware of Java's String.getBytes

Sometimes there are subtle bugs whose origin can be found in some quirks from the underlying language used to build the software. This blog post describes one of those cases in order to let both fellow security researchers and developers, who didn't know about it, become aware of this potential vulnerable pattern. In fact, I'm pretty sure that similar bugs to the one herein described likely affect a bunch of products/codebases out there. In previous posts , I've already described some bugs in the Swiss Post's future E-voting system. While reading their  Crypto-Primitives specification , which among other things describes the custom Hashing algorithm Swiss Post implemented, I noticed something potentially interesting. Basically, there are 4 different types that are supported: byte arrays, strings, integers and vectors. Before being hashed, strings are converted to a byte array via the ' StringToByteArray ' algorithm. However, by comparing ' StringToByteArray...

Losing control over Schneider's EcoStruxure Control Expert

  During Q2 2022, in view of the geopolitical situation that unfolded after the Russian invasion of Ukraine, I decided that it wouldn't do any harm to kill some bugs in some of the main players within the ICS arena. I focused in those software frameworks that are running on the engineering workstations so, if compromised, attackers would be in a privileged position to manipulate controllers logic, thus enabling sophisticated attacks with a potential physical impact (i.e triton). I responsibly reported a bunch a unauthenticated remotely exploitable bugs to the corresponding vendors. In one case, after being ignored for months, I had to resort to the 'twitter, do your magic' approach and tweeted that I would be disclosing the issues if the situation persisted. It took just few hours for the vendor to get back to me. The positive side is that they found the bugs interesting and all that mess ended up in paid work.   This blog post covers a similar scenario in a different ven...