The NXP PN533 is a NFC chip used on mobile phones. They all use the ARM Cortex-M architecture. The chip communicates over the I2C interface (/dev/nq-nci) and uses a custom protocol for updates. The updates sound nice but how do we get the update to occur?
The Android phone had two firmware files on it. By changing the name of these files, the firmware updater will notice that the version numbers are different than the current. As a result, the update occurs, which can be snooped by logcat.
To do the firmware update, a hash chaining process is used. The write command goes to any location in memory that we would like to use but needs to have a valid hash.
After reversing the file format, the update process and much more, the author wrote a targeted fuzzer on the firmware update and NCI interfaces. From fuzzing, the author discovered vendor specific NCI commands. One of these was a NCI Config Write command. Although something useful may have been possible here, the author bricked the firmware on the chip by corrupting the configuration.
While fuzzing, the author noticed that the last block of the firmware update could be written multiple times. This implied that the hash of the previous block was still in memory, was global in some sense. Because of this, the author was looking for a potential buffer overflow to corrupt parts of the firmware. When sending an invalid command with the same size as the firmware update block, the update would fail. This implied a buffer overflow on the static RAM.
What does this mean? The author could create a modified hash to write to portion of memory. Because this is a hash chain and they could overwrite it, the security of the hash chain had now been broken. By doing this overwrite over and over again, we could write to any memory block on the chip. With this overflow, the author could overwrite parts of memory that we using the firmware.
Now, it was time to patch in new features! The first thing was that the author changed the NCI version command to read from an arbitrary location in memory and send this out. The author found that the global pointer pointed to 0x100007, which could be used to dump the bootloader directly.
The entire bootloader was dumped using read commands from above. With this in hand, the author noted that the firmware could be overwritten in arbitrary ways (on the chip) for a consistent backdoor or just extended functionality on NFC. The PN5180 had the same exact vulnerability. Although, this was likely to be on all similar chip sets.
The reverse engineering and blackbox testing is incredible to see in action. Instead of having access to GDB, very subtle assumptions need to be made in order for this work. Even though the vulnerabilities were fairly straight forward, the hard part lies in actually finding them and figuring out how to exploit them in the blackbox setting. Great research!