Enthusiastically agreed. I’ve spent thirty years in various roles in technology companies, and if I had a krugerrand for every time I heard some business-side stakeholder say something like, “why are you making this so complicated, it seems simple, you should just do X,” I would be an honorary South African banker.
(Example: A while back, it took me three weeks of patient, repetitive explanation to get an executive steering committee to understand that their personal experience with antivirus software on their workstations was entirely disconnected from the difficulty and complexity of integrating an AV tool into the background stack of a cloud-based enterprise app. Eventually they got it, but it took a long time.)
For the benefit of the less-technical reader who thinks this kind of thing should be easy, let’s dig into an illustrative example — those overhead screens at the airport showing flight status and departure times.
The monitor has one job, to render a table of flight information. That’s their only job. They don’t do anything else. You don’t want them to do anything else. You would think you could make a machine that does that one thing, and disallows any other kind of operation. That would result in a perfectly secure, highly-limited piece of technology, which would make defensive software like Crowdstrike irrelevant. Right?
So, let’s think through it. (This will be deliberately expressed in a simplified way which might irritate technically savvy readers who will notice where I’m compressing concepts and jumping over steps. I know this. Please don’t yell at me.)
First, consider the architecture. Is this a dumb monitor, which is displaying only what is being broadcast to it by a computer elsewhere? Or is it an actual limited-purpose computing device with a small onboard program, receiving and parsing packets of schedule data and transforming them into the on-screen grid? There are advantages and disadvantages either way. If it’s a dumb monitor, then you just push the vulnerability upstream to the central computer (and that, by its nature, pretty much has to be a proper computer, not just a limited-purpose device). Also, if it’s a dumb monitor, then it has to receive a display signal somehow. If it’s wireless, then that becomes a vulnerability; somebody could interrupt and hijack the signal and make the monitor display something else. This wouldn’t be good for much more than just mischief, but you still don’t want that. The alternative is a hard-wired connection for signal transmission, which requires laying and maintaining literally kilometers of cable from all the screens to a distribution station, which quickly becomes cost-prohibitive.
So let’s say you don’t like the purely-a-dumb-monitor solution, and you go with devices that have limited onboard functionality. To begin with, they cannot be strictly isolated. They need to receive packets of schedule data, as flight status changes minute to minute. They have to be willing to receive data over some sort of open connection, or they don’t serve their intended function to show flight status being updated. This constitutes a potential vulnerability, yes? Okay, but the computer is just receiving a structured data file, and it’s transforming the structured data into the visual table of departure information, and that’s all it’s doing, so this should be simple, right? Not necessarily. Any time you have data incoming like this, you need to consider overflow attacks, where somebody figures out how to flood the intake channel in such a way that stuff begins spilling outside the normal boundaries, and overwrites things in memory that weren’t supposed to be overwritten. In other words, you may put your simple display program on the device so that’s all it can do, but after an overflow attack, some or all of your simple program gets replaced with something else.
Okay, so let’s lock down that display program so it can’t be affected or altered by an overflow attack. There’s a thing called protected memory, where you authorize your various processes to take action only in certain areas and prevent them from acting outside those areas. This is pretty standard nowadays, and there are several ways to approach it. They’re not foolproof (e.g. if you use some form of key-based permissioning, you have to guard against key breach), and some sophisticated attacks have been devised which get around the defense, but this does block the more elementary intrusion attempts.
That sounds complicated, though. What if we totally lock down the display program by essentially hard-wiring it? Consider an old Space Invaders stand-up console, where the game’s code is permanently written on a handful of physical chips. There’s nothing rewriteable about this, so there’s nothing to attack. Yes?
Yes, that’s true, but now you’ve locked yourself out from making any changes at all to the display program. Once encoded, that’s it, it’s static and unchanging, unless physically replaced. So if something happens in the future that requires you to change the display program somehow, you can’t do it. Let’s say your airport started small, and your program switches back and forth between two pages of data; but now you’ve grown, and you want to cycle through an arbitrary number of pages based on the number of flights. Or, let’s say there’s a regulatory change which requires airlines to state not just whether a flight is on-time or delayed, but also how much it’s delayed; you need a new column in your display table. You can imagine all kind of scenarios which require you to be able to update your program in response to evolving requirements. But if you’ve locked the machine down with unchangeable read-only memory, you can’t, unless you’re willing to physically rip out all the devices and replace them with new models.
Okay, so go back to the protected-memory idea. You’ve got a simple device which is capable of running this small info-display program, and you keep that small program in some sort of protected memory, isolated from the part of the computer that ingests and parses data packets and passes the structured information to the display renderer, so an overflow attack on the intake channel shouldn’t be able to affect the program. Right? Yes, great. But — you still need to be able to update that protected program, whenever the display requirements change. So there still has to be a way of accessing or unlocking the protected memory and deploying a new program. That, obviously, constitutes a different kind of vulnerability.
Okay, so, let’s put in a parallel watchdog program that monitors the display program, and prevents it from being changed unless the change request is confirmed to be legitimate. How would this work? Maybe it has its own copy of the display program for comparison; anything that isn’t part of that reference copy is disallowed. Okay, but any time you want to update the actual display program, you first have to update this reference copy used by the watchdog program. That means the watchdog program itself has to be accessible and updateable, which just moves the potential vulnerability somewhere else.
All right, well, what about a watchdog program that watches for any changes, and blocks anything that doesn’t have some form of authorization? Say, a combination of a security key and an originating internet address, which tells the watchdog program, this is a valid change; anything else is seen as a potential attack, and is refused. Right? Where do we find this kind of watchdog?
Well, hello, Crowdstrike.
That’s why this stuff is so difficult. As Mangetout suggests, the more you lock down a system and prevent it from doing anything, the less useful it becomes. Any time you want a system to be able to do anything useful, by definition that capability becomes vulnerable to exploit. It’s inherent and fundamental, and there’s no way around it. And so these programs and devices need some sort of defense if they’re going to be deployed in the world. It’s inescapable.