Of the thousand or so people who took part in the 2016 NSA Codebreaker Challenge, only 15 solved Task 6. I wasn’t one of them, but I figured I’d write-up what I found anyways. This will be two parts, because it’s a little lengthy. The goal was to create a script file, which contained a number of commands for the client executable to execute and hopefully trigger the bomb while it was disarmed. Task 6’s lengthy description:
Task 6 – Hardware Destruction
You are impressive! Our military partners report that the two IEDs were successfully disarmed, again saving countless lives. Also, thanks to the capability you developed, we can now remotely disarm any IED we find in the field, which is going to make travel through dangerous regions much safer. Agency leadership is very impressed!
Ideally we would like to go one step further and remotely render the IEDs completely inoperable. Given that we may not be able to find and recover disarmed IEDs before the terrorists reclaim them, it would be much better if we could ensure that the IEDs never work again (without actually triggering an explosion and potentially causing civilian causalities.) To that end, we had our hardware reverse engineers study the hardware of a captured IED and develop a hardware simulator to accurately model its operations. This enables more analysts across the enterprise to test and evaluate the system without requiring access to one of the very few captured devices. During development of the hardware simulator, they discovered that if we can somehow cause the hardware to be triggered without being armed then it will “brick” the hardware. This may be our best shot at having a remote disabling capability if we can find a vulnerability to exploit the trigger-before-arm weakness.
From the captured IED we also recovered the hardware driver that contains all the logic for arming/disarming/triggering the actual IED hardware (i.e., unlike the dummy driver that had these functioned stubbed out.) Using this driver with the hardware simulator and IED software provides the most accurate model of the IED hardware and software stack available. The driver appears to contain additional protections that might make analyzing it more difficult, so be on the lookout for code that might be trying to detect dynamic analysis tools.
Note: The client software has an interactive command-line interface. A client script may be provided that contains all the commands you wish to execute. Here is an example script to ARM, DISARM, ARM, and TRIGGER an IED.
Your final task is to figure out a way to cause the trigger-before-arm condition and break the hardware.
Two additional files were provided, including the hardware simulator and full driver. With that, a complete chain of functionality can be run.
There were a couple of things I discovered while trying to figure out how to trigger the bomb while disarmed. Starting with the most obvious one is how the hardware keeps track of its state. The hwsim program outputs the state, a semi-random hex value, and any updates it makes. I say “semi-random” because the values are different every time it is run.
Hardware Simulator Check Status: e983c5e9 Hardware Updating: e9 -> c5 Hardware Armed Hardware Simulator Check Status: c583c5e9 Hardware Updating: c5 -> e9 Hardware Disarmed Hardware Simulator Check Status: e983c5e9 Hardware Updating: e9 -> c5 Hardware Armed Hardware Simulator Check Status: c583c5e9 Hardware Updating: c5 -> 83 Hardware Triggered (BOOM! in 5 seconds) Hardware Simulator Check Status: 8383c5e9
The armed and disarmed states are made up of 4 bytes. x86 is little endian, so the bytes representing the above steps would look like this:
Bytes #0 and #1 never change. They’re used to represent the two states. Disarmed is byte #0 (e9) and armed is byte #1. Firing up IDA and watching values pass through, I was able to build up this pseudo-code representation of the handling of the disarm, arm, and trigger calls. A byte (arg1) would enter the function and then…
if arg1 == byte_0 disarm by setting byte_3 equal to arg1 if arg1 == byte_1 arm by setting byte_3 equal to arg1 if none of the above // trigger call that has passed other checks if byte_1 == byte_3 boom // bomb went off else victory // triggered while disarmed, we win
Unfortunately, I was never able to get to the victory condition. This section in IDA:
The next post on Task 6 will focus on the client’s ability to send raw commands, including what the five raw commands were, and unsuccessful attempts at using the optional arg_data_in_hex value to trigger a buffer overflow.
raw <command_id> [<arg_data_in_hex>]