Weird machines - unexpected behavior from unexpected (crafted) inputs

in security •  8 years ago  (edited)

Weird machines - unexpected behavior from unexpected (crafted) inputs

enter image description here

To understand how exploits such as what happened with TheDAO and future exploits upcoming we have to understand the concept of weird machines. Programs typically rely on inputs, and from these inputs there are deterministic behaviors which take place within the app which we can call the functionality. The quality of the input of any program is a determining factor for the predictable functioning of the program and ultimately the expected output.

Garbage in garbage out

Many "hackers" or exploit code writers know about SQL injection. SQL injection is a good example of an unexpected (crafted) input which creates an unintended functionality (weird machine) which results in unexpected behavior (the backdoor). Garbage in garbage out is the principle behind the creation of weird machines.

My own experiences

enter image description here

When I was a teenager I used to play video games quite a bit and used to mess around with technology. One of the first times I ever discovered how to create exploits was through literally trying to break programs. I learned this originally from video games where you have the concept of "button mashing" and this "button mashing" eventually led to the discovery that there is always some probability that if you find a bug somewhere in a game, that you can leverage that little mistake in the game to escalate the bug further. In the case of a game like Mario it might be to get infinite lives:

An example of this could be the bug where you get stuck between the wall in Super Mario Bros. The discovery of bugs by random input (equivalent to button mashing) is called fuzzing and while I did not know the name of this as a child or teenager, I did intuitively know that you could intentionally break the functionality of certain programs simply by doing stuff like overflowing the buffer with a really large or unexpected input.

In certain chat applications for example there was a buffer overflow exploit where if the input in the text window was much more than the programmers expected the application would crash. In some cases if the programmers did not write the program right then the entire chatroom might crash or even worse a computer might crash on the other end. This is an example of a buffer overflow exploit and this category of exploits is also based on crafted inputs.

Some technical details of fuzzing

enter image description here
I described the concept of fuzzing as the equivalent to button mashing in a video game. When you button mash in certain games you might discover errors or bugs in the game. I also described how in the 90s you could do something similar with chat applications to discover buffer overflow exploits. Today there are applications which allow developers to automate and simulate what teenage "hackers" and gamers do instinctively and these apps make up the procedure for fuzz testing.

enter image description here

Fuzz testing is employed as part of black box testing where you try random valid or invalid unexpected inputs to a program. This will trigger unexpected behavior if they can be triggered by producing functionality which perhaps the developers never intended. This behavior could be a memory leak which leads to a "blue screen of death" for instance. Fuzzing only finds simple exploits and to go further and create weird machines may require more than just random inputs or crafted inputs.

Altering the flow of execution

While the techniques may differ, the goal of a weird machine is to take over the flow of execution of a program. By hijacking the flow of execution then the functionality of the program itself is altered.
enter image description here
The three main steps for creating a weird machine are below, taken from here:

1 .  identifying computational structures in the targeted platform

that allow the attacker to affect the target’s internal state via

2 .  distilling

the effects of these structures on these inputs to tractable and
isolat- able primitives ;

3 .  combining crafted inputs and primitives into  programs  to comprehensively  manipulate the target computation .

Conclusion

The fact is that certain languages are much more vulnerable to this category of exploits than others. C, C++, and certain other languages are particularly vulnerable to stack overflows and require very skillful developers to avoid the sorts of errors which could allow for crafted inputs. There are forms of testing such as blackbox testing, and there are development methods such as correct by construction, which can lower the risk of the this kind of attack vulnerability.

The way to resolve this issue in the most comprehensive way is to go with langsec. The easiest way if it's a new project would be simply to avoid the languages which don't have built in protections against unexpected behaviors or crafted inputs. The other way is to process the input in a safe way, using sophisticated input handling, to allow for "trusted input". I will not go into detail in this article on how to do that as it is quite a dense topic but input handling is the answer for security when you can't just change the language but can filter and secure the input.

References

  1. https://en.wikipedia.org/wiki/Weird_machine
  2. https://en.wikipedia.org/wiki/Garbage_in,_garbage_out
  3. https://en.wikipedia.org/wiki/Fuzz_testing
  4. https://en.wikipedia.org/wiki/Random_testing
  5. http://langsec.org/papers/Bratus.pdf
  6. http://langsec.org/bof-handout.pdf
Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Awesome article!

Totally agree on the choice of language point - C is an incredibly dangerous language to write in if you don't need to, and there are some pretty good alternatives surfacing these days that are garbage collected like Go or have a very strict compile time borrow checker like Rust.

The argument that programmers "should" be able to manage memory safely is all well and good but it's backed more by ego than pragmatism... just look at the continual stream of CVEs and security patches.