We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Beyond Root

00:00

Formal Metadata

Title
Beyond Root
Subtitle
Custom Firmware for Embedded Mobile Chipsets
Title of Series
Number of Parts
374
Author
License
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
Rooting a smartphone is often considered the ultimate method to allow a user to take complete control of their device. Despite this, many smartphones contain hardware which is closed off to any modification. This talk aims to show how this hardware can be reverse engineered in order to bypass its protections and further expand its functionality. Using proprietary NFC Controllers as an example, we will cover analysis of the protocols used by the chips, how the firmware protections could be broken, and how custom firmware could be developed and deployed to the phone with no hardware modifications. This will include methodologies for analyzing weaknesses in firmware update protocols, leveraging the Unicorn CPU Emulator to bypass debugging restrictions, and techniques for reverse engineering the hardware capabilities of an unknown chip in order to implement custom features. This will end with demonstration of a smartphone with passive NFC sniffing capabilities and expanded tag emulation functionality.
Computer fileMathematical analysisFirmwareFile formatElectronic signatureMetadataComputer wormInformationRead-only memoryMobile WebAsynchronous Transfer ModeRootSet (mathematics)Computer hardwareAddress spaceVulnerability (computing)Pointer (computer programming)Crash (computing)Communications protocolTelecommunicationEmulatorEncryptionCyclic redundancy checkBlock (periodic table)Computer hardwarePublic-key cryptographyCommunications protocolFirmwareServer (computing)Flash memoryEinheitswurzelVirtual memoryFile systemReverse engineeringOpen sourceEmulatorFinite-state machineDevice driverOperating systemParity (mathematics)TelecommunicationAsynchronous Transfer ModeSemiconductor memoryBit1 (number)Address spaceConfiguration spaceSingle-precision floating-point formatEncryptionBuffer solutionOrder (biology)Projective planeFunctional (mathematics)Dependent and independent variablesData bufferKreisprozessBuffer overflowInstance (computer science)Android (robot)Thermal expansionProcess (computing)MultilaterationHash functionEnumerated typeNatural numberElectronic signatureCore dumpPoint (geometry)IdentifiabilityComputer programmingMultiplication signComputer wormSet (mathematics)Different (Kate Ryan album)Vulnerability (computing)Key (cryptography)AuthenticationHoaxMechanism designClassical physicsSmartphoneComputer fileBootingPairwise comparisonStandard deviationExploit (computer security)ResultantPatch (Unix)Kernel (computing)Entire functionProcedural programmingVector spaceInformationConstraint (mathematics)PlastikkarteFile formatArithmetic meanGame theoryMathematicsBlock (periodic table)Game controllerType theoryNumberString (computer science)Demo (music)TrailMobile appImplementationReading (process)QuicksortInterface (computing)Spectrum (functional analysis)Covering spaceData storage deviceStructural loadLatent heatLengthParameter (computer programming)Branch (computer science)Link (knot theory)Thread (computing)2 (number)Loop (music)Theory of relativityINTEGRALCodeScripting languageTask (computing)Ocean currentMereologyLibrary (computing)Sound effectArmSystem callLevel (video gaming)Open setInformation securityExponentiationInformation technology consultingClosed setComputer architectureAreaObject (grammar)Physical systemProxy serverSelectivity (electronic)Software developerInternet der DingeSoftware frameworkBinary codeMobile WebPartition (number theory)Error messageCASE <Informatik>Free variables and bound variablesUniform resource locatorOperator (mathematics)Revision controlGroup actionPower (physics)EmailFuzzy logicFunction (mathematics)Content (media)Right angleRaw image formatCuboidCartesian coordinate systemGeneric programmingAuthorizationWritingMetropolitan area networkMedical imagingHydraulic jumpState of matterRoutingSequenceThumbnailMultiplicationDirectory serviceSoftwareDivisorStaff (military)Bound stateDataflowValidity (statistics)HexagonLoginPointer (computer programming)Regulärer Ausdruck <Textverarbeitung>Table (information)Stack (abstract data type)Forcing (mathematics)NP-hardHand fanBridging (networking)Extension (kinesiology)Computer animation
Transcript: English(auto-generated)
Hello everyone, my name is Christopher Wade and today I'm going to be talking to you about custom firmware for embedded mobile chipsets. This being custom firmware built for chipsets that are found in mobile phones but are not part of the core operating system and usually deal with certain aspects of the hardware. A bit about me, I'm a security consultant at Pentest Partners where I mainly work in hardware,
automotive and maritime, but today we're mainly going to be talking about attacking mobile phones and embedded firmware. So the origin of this project was that I'd found that smartphones that I'd bought and rooted contained a huge amount of closed firmware and closed hardware which you couldn't modify even after rooting them due to signature checking restrictions or just lack of open knowledge about the protocols used by the devices.
Because of this, I thought if I could break the firmware protections on some of these chipsets I'd be able to expand the functionality of my phone more. There's a few ways one can do this without having to do too much modification of their phone and are well known such as Wi-Fi monitor mode which can be activated in Snapdragon chipsets by echoing 4 into a
specific kernel parameter in the file system which converts it from two Wi-Fi chipsets into a monitor mode chipset. Also if you add custom firmware to a Broadcom chipset and modify your kernel slightly you can get monitor mode that way on Broadcom. You can also modify the kernel on most mobile devices to use USB device emulation so by disabling the functionality
of things like ADB or standard MTP and PTP for Android devices you can enable features such as the gadget file system which allows you to emulate any USB device you'd like from a memory stick to anything more esoteric.
Further to this, when I root mobile phones I usually like to add a Debian root onto them, this being a Debian file system which can be built with QEMU to bootstrap and a small script which can be used to mount up all the correct device files in that file system and set up SSH so that one can SSH directly into this portion of their phone without affecting the main Android operating system but still affect the hardware.
I wanted to look at NFC on Android for this project because I'd found that there was very little research done on the firmware of NFC chips on almost any device but mainly on phones. NFC on Android has restricted some very low level features such as generic reader
mode so reading from tags using certain applications, mobile payments which are very popular nowadays, NDEF communication which was slightly more complex, and hostcard emulation which is emulation of NFC tags but in a very limited manner. While these allowed for certain attacks such as relay attacks to be performed, they weren't complete in what they can be done with.
NFC attack tools often have features such as reader-based attacks that's been trying to decrypt or attack NFC tags via the reader, raw tag emulation emulation of any NFC tag you wish, or passive sniffing of NFC communication by basically performing a man in the middle between the reader and the tag. My first target device was my Samsung S6, the SM-G920F, which is an older
smartphone found in the EU. There's different versions of the same phone in different countries. And I found that it allowed for OEM unlocking and deployment of custom ROMs which meant I could route it very easily and gain access to the hardware as needed. I found that it used a proprietary Samsung NFC controller but this was not used in some US versions.
This NFC controller was the S3FWRN5 developed by Samsung Semiconductor and was utilized in the non-US versions of the Samsung S6 and Note 4. This chipset boasted the ability to update firmware securely, meaning that people couldn't deploy custom firmware, utilized an ARM SC000 secure-car architecture, and was communicated with via I2C and GPIO on a phone.
As smartphones were essentially embedded Linux devices when you get rid of the Android side, I found that the chipset was communicated with via GPIO and I2C communication, which can be performed via device files in the Linux kernel.
However, I found that Samsung kernel has abstracted these into a custom driver, which I can access using the device file, slash dev slash sec NFC. I looked into how it communicated via this and found that it used IO controls to power the chip on and off, and file reads and writes to communicate over I2C. NFC chips communicate with a very standard protocol called NCI. This is a protocol which is
used to simplify NFC communication functionality in phones and other devices, but also restricts it quite heavily. It works by sending three bytes for the group ID, the operation ID, so what is being performed on that group, such as core, RF, vendor, or specific, and length, which is a one-byte parameter which sets the length of the payload.
It supports a non-standard functionality via the vendor group ID, which is defined by F, which allows for the non-standard functionality to be implemented. There's no restrictions in the protocol which dictate what should happen with what these functions
do, so any developer who creates an NFC chip can make these do things that they weren't necessarily intended to for debugging purposes or certain configurations that were specific to the chip. I found this to be used in the Samsung chip, mainly for deploying firmware files to it for things like frequency, etc., post-deployment of the core firmware.
The SCFW RN5 was found to support firmware updates via I2C via the same endpoint as NCI. However, I found that the firmware updates use their own custom protocol, which did not use any NCI communication. Now, this is the case in almost any NFC chip I tested. However, I found this
quite interesting as a lot of them had very similar protocols to NCI to do this. These firmware files were found in the vendor partition on the file system of the phone. I enabled debug mode on this via going into these vendor configurations in slash system and modifying the .RC configs for this chipset to enable logging and force firmware updates, as well as find the names and locations of the firmware files.
Using this, I could now trace out any firmware updates that occurred via logcat. Doing this, I could dump all the communication out and analyse how the firmware updates were performed. It was found to use a 4-byte header followed by a payload, so address 0 being the command type, address 1 being
the command itself, and 2 and 3 being the 16-bit payload size, which I found to be restricted only to 256 bytes. I also found that there was a parity bit settled on every command type at the start of each update.
Firmware update files can be found throughout the Android file system. I found these in the .RC configs, but they were found separately in other areas, and I found this to be due to the fact that sometimes phones want to update their firmware due to software updates that occur just generally on phones. I looked through the firmware file itself and found that it used metadata, highlighted in
red, which was just the date, as well as some other CRTs and relevant information. I then found the signature, which is highlighted in green, which was just the cryptographic signature for the firmware, and then in blue was the start of the firmware itself, so very easy to assess how this worked. I didn't originally know that this was going to be an ARM chip, so I decided to find out what the architecture was for myself.
Looking through the firmware, I found that it was quite obviously going to be thumb firmware. By running the strings command on the firmware itself, you can find that it has a large number of lowercase b, uppercase G outputted by its strings.
What this translates to is 0x7047, which translates to thumbs bxlr, operation, branch, and link. A high number of these generally means that it's going to be using ARM thumb firmware, something similar to a Cortex-M chip. This has some interesting features, such as the fact that in the chipset, as it's processing,
the PC register will always have the lowest bit set to differentiate between thumb and ARM code. To implement the firmware updates, all I needed to do was copy and paste all of them from the trace log and follow them in sequence while reading at the appropriate times as well. By setting up the IEO controls to set it into bootloader mode rather than standard power mode, I could deploy the firmware updates as needed.
Header files from the open source kernel drivers for this chipset were very helpful for this. I used the seccnfc.h file to perform this, and then I could just set the appropriate configurations with IEO controls using this.
I found that there was a very specific sequence that was used for firmware updates every time using specific commands. It was CMD-0 for reset, CMD-1 for boot information, CMD-2 for beginning of updates, CMD-4 for updating 4096 bytes of the firmware, and CMD-5 for completing the update, which verified the SHA-1 hash of the firmware against the
SHA-1 hash that was sent at the start of updates in the beginUpdate function, which was compared to the cryptographic signature. I noticed that there was a numbered command missing from the sequence CMD-3, and this meant that there was very likely to be some hidden commands that we didn't know about.
Commands in this sequence only work at certain times, so you can't start writing firmware before setting up the signatures, etc. Due to this, I brute forced my way through the entire firmware update process while trying different commands to see how they worked. I found that chips would return an error too if the command was not valid or not valid at that stage of the update process, and return 9 if the payload was too small.
This would allow me to find any valid commands at each point in this process. I found that hidden bootloader CMD-3 was the same functionality as CMD-4, except instead of sending 4096 bytes, it would write 512-byte blocks, so there were no real actionable weaknesses.
However, I also found that there was a hidden bootloader CMD-6. I found that this took 8 bytes of parameters, two 32-bit payloads, and by setting some individual bits in these parameters and sending it across to the chip, it would start dumping memory out to me. I found that this was because I was giving it an address and a size during this process.
This allowed me to dump the RAM of the chip, the firmware of the chip, hardware registers, and more importantly, the secure bootloader. By stitching together the responses from this command by increasing the addresses, I could make myself a binary of that bootloader for me to reverse engineer later. This showed that it was using a standard Cortex-M firmware format starting at address 0, which was the vector table, so it started
off with the stack pointer, followed by the reset vector of the chip, so that's the code that would get jumped to at the start of the firmware startup, and found that the firmware contained no strings, so all reverse engineering would have to be done by hand. I loaded this into IDA as an ARM lithium binary, as it should be, and set up a memory layout for 0 at flash memory, 2 0
0 0 0 at RAM, 4 0 0 0 0 and 5 0 0 0 for hardware peripherals, and E 0 0 0 0 for system addresses. This disassembled very nicely and very easily assessed. It had some interesting artefacts, such as the fact that I could now work
out exactly how the firmware updates were securely implemented, and how these worked post-update. I found that on startup, the bootloader checks for a magic number at the start of the firmware update, this being 5aF00FA5, which I did not find when I looked in the firmware payload itself. This magic number was written only after firmware updates occurred, if the signature was valid during
that update, meaning that every time the chip started up, it wouldn't have to verify this signature. I attempted to manually write this value into the firmware that I deployed, however this did not do anything effective. I also found the state machine which handled the commands I was sending, so you see comparisons for 0,
1, 2 and 6, which were the commands that were valid at the start of the firmware update process. I also found the RSA public key, which was in use for this chipset, which was made up of 128 high-entry p-bytes, followed by 0 0 0 1 0 0 0 1, which translates to 65537, the exponent of a public key.
Because I only had one phone and I didn't want to break it, I didn't want to fuzz it directly in the hardware. I wanted to do it on an emulated chipset, so what I did was use this bootloader and looked into ways that I could emulate it effectively on a host computer. I ended up using the Unicorn engine for this process, which is a library for emulating architectures
and hooking all functionality of a firmware as needed in order to emulate certain aspects of it. You can define the architecture, memory mapping and hardware integration as needed to fit your own needs. The bootloader I found was loaded into address 0, which was the start of the flash memory in the
chip itself, and the program counter was set to the reset vector that I found in that bootloader, 2BD. Memory was then mapped to flash, RAM and hardware registers as needed so that it would perform as a chip as needed. Commands were found to just be received in a single thread that started from the main loop and just looped around receiving I2C commands. Because this meant that there was probably not going to be any interrupts in use, just due to the size of the bootloader and
this content, it would mean that emulation would be a simpler task and all I'd need to do is straight up emulate what I had. I found that execution was causing device research during the startup process of this chip, however, because it was trying to access hardware registers which simply didn't exist because they weren't being emulated.
What I did was patch the bootloader image to bypass all this hardware initialization so that the chip could then move to the next part of the process but wouldn't need to actually need to set up the hardware in any meaningful manner. The firmware was allowed to run and continue until it hit another hardware address, so all hardware addresses started either 4.0.0.0 or 5.0.0.0.
The address that it hit was 4.0.0.2.2.0.3.0 and I showed that I analyzed the assembly at the point where this was being read and found that the firmware was checking for specific bits in this address.
By making it return random data, I found that it was just checking for status bits via that register and allowed me to work out that it was an I2C interface that was being communicated with. Because I implemented this, it would move on to the next stage of the process. Next, I made the firmware continually read bytes from a single address 4.0.0.2.2.0.3 .8. This implied that it was probably reading from I2C as well but the first-in-first-out buffer.
What I did was start sending bytes that I would usually send for firmware updates via this interface in Unicorn and see what happened. I then found that the chip started writing out responses on 4.0.0.2.2.0.3.4, so the address right next to it. These responses meant that I had full emulation of the I2C communication without ever having to touch my chip.
What I wanted to do was find a memory correction exploit so I could bypass the signature checking. And while I did start doing some randomized fuzzing that I thought would be viable, it didn't really come out with anything interesting. The commands were found to have 16-bit sizes, which were larger than the entire contents of RAM, which was found to be only 8K.
However, these were limited to only 256 bytes. I did, however, notice that some functions, especially ones for deploying a large box of data, could send data in chunks, like 256-byte chunks. I also found that the size of the hashing signature were defined at the start of the firmware update process, right before the hashing signature was sent.
I found that I could increase the size of both the hashes and the signature size in order to send more data. And while this would respond saying that hashes and signatures weren't valid, it did allow me to increase the size and send increasing amounts of data. When I did this in my emulator, I found that eventually this made my memory go out of bounds, so outside the 8K of memory I had allocated in my emulated firmware.
Looking into this, I found that it had also overwritten the stack with the memory that I had sent to it. Because I can now overwrite the stack, I can manipulate the program counter and start doing some more memory corruption exploits. However, SC000 chipsets, because they're meant to be for secure applications, don't
let you ever execute from RAM like a traditional Cortex-M chip would. And because the stack was very small at this point, only about 12 bytes when I checked, I wouldn't be able to do anything too complex with ROP either. What I ended up doing was making the program counter just dump directly back into the start of the bootloader, pass the check for the magic number and into the part where it initializes the firmware.
And this allowed me to bypass all of the signature checking and deploy my own firmware. I then ran this exploit on my physical chip instead of the emulated version and found that what would happen is I'd start up my bootloader, send this exploit and it would directly boot into the main firmware. I could then send NCCI commands and receive them as needed with my custom firmware.
What I did was first change the version number of the chip so that it was different. Here, EE, AA, BB, CC and DD and meant that custom firmware had been sent and validly was running. I then disclosed this vulnerability to Samsung. There were two ways they could have remediated this.
Firstly, they could have patched the bootloader from the main firmware, removing the buffer overflow. Now, while this does seem simple, it would be very difficult because what would have happened is the bootloader would have had to start the main firmware and then let the main firmware patch the bootloader. Now, if there's any kind of power cycling going on or any sort of deployment errors during this process, the bootloader would be erased and the chip would be essentially bricked and never able to work again.
One could also patch the kernel to disallow the commands that were being sent, so the large hash sizes and make them static. However, this would be trivially bypassed just by modifying the kernel. I looked into other NFC chips that Samsung Semiconductor had developed and found that there were four main ones that were advertised on their websites.
The S3-NRN74, S3-NRN81, S3-NRN82 and SEN82-AB. The most interesting of these to me was the S3-NRN82 as it seemed like their latest version at the time. I decided to go through the ROMs of lots of Samsung phones. Now, because this was not a US phone, there were not very many teardowns online for the phone and definitions of what hardware was in use.
So what I ended up doing was going to sammobile.com, which has a huge number of custom Android ROMs, dumped as many as I could and extracted them to see which firmware files were in the slash vendor partition. Occasionally these partitions are not stored in these because they are part of a special
vendor partition which is deployed to the phone and can only be extracted from a phone. So that should give some insight into what chipsets were being used. While the vendor directory does always contain these firmware files, this separate partition does make things a bit more difficult. I found that the S3-NRN82 was the latest chipset after looking through this and found
that there were multiple chip versions available in different versions of the firmwares that I was downloading. And I decided to go with the Samsung S9 which used this chip. It was also found to be available in the Samsung Galaxy S8 and S10, but I purchased the Samsung S9, routed it using OEM unlocking and a custom ROM and started looking through how it worked.
I found this firmware file to be in the same format as the F3FW-RN5, except the initial stack point was much larger, moving up to 12k over the 8k that the last chip had, and the reset vector was lower, implying a much smaller bootloader. I also found that the firmware size was 32kb larger.
Looking through my previous exploit and trying to port it over, I found that commands 3 and 6 were removed, meaning they'd made some changes there and meant I could no longer read out firmware as needed. I also found a new command 7 which was identified to just reboot the chip and nothing else. The new bootloader size implies that something else had been changed in here just because it was much smaller.
However, the lack of memory readout meant that I wouldn't be able to exploit this, and any exploitation I did do would have to be done blind. I also found that signature checks now no longer use SHA-1 hashes as before, and I needed to work out what they were using. Because they had modified their kernel to no longer dump out data via logcat, I
wouldn't be able to use the same logging procedure I did before to assess the protocol. What I found, however, was that the sizes of commands sent during firmware update processes were stored in slash proc slash nfc log in the file system. Looking through these, I could see the commands working in sequence, find the starter firmware updates, and then deploy them.
And I found that what was happening was during the starter firmware updates, when it was giving this hash, it was providing 32 bytes plus 4 bytes, implying that it moved from a SHA-1 hash to a SHA-256 hash. I modified my firmware update tool to reflect this, and I could now upload valid firmware to the chip.
I wanted to see if I could replicate the same buffer overflow I had before. Now, I'd need to work out how big the stack was before doing so to make sure that I'd overwritten the entirety of it. What I ended up doing was sending increasingly sized payloads to the chipset. Now, I found that when I sent these payloads to it, if I was just overflowing the stack, it would
still return and return data to me, just due to the nature of how the stack was being set up. However, if the device crashed before sending a response to me, it was likely that I'd overwritten into invalid memory outside of the 12k of RAM. What I ended up doing to find out where I could find an entry point was starting my program counter at 01 and filling the stack with this.
Filling the stack with the address 01 and seeing what would happen if the return pointers, which were somewhere in the stack I didn't know yet, jumped there. I then sent NCI initialization commands as we would at the start of the NFC setup.
If I received an NFC response, then I'd found a valid endpoint into the core firmware and bypassing the signature checking. If it failed, however, I restarted the chip and increased the address by 2. I found the signature bypass succeeded at address 165, as follows. So I would send my exploit, and if it failed, start it again, and if it failed, start it again.
And then in the next one, I found that I could receive data via NCI, meaning that the entry point had been found at address 165, which worked repeatedly and didn't have any problems.
I then disclosed this vulnerability to Samsung. I provided them an exploit and showed them how it was done. And they agreed to patch all newly manufactured chipsets from April 2020, as well as patch any new chipsets that they were going to develop. However, because they couldn't patch the bootloader as well as the chipsets like the ones I had in my phone, custom firmware would still be viable.
In order to patch existing firmware, one needs to basically modify what they have in there. They need to add their own code into what already exists. I decided to stick with the S300N82 rather than the S3FWRN5, because it was the latest chipset and would have the most power. The only method I could find for accessing data for debugging this, however, was I2C,
so I would have to debug via the same methods that I was writing data, etc. What I did was go back to my dump of ROMs that I had and go to a Galaxy SH ROM and find the oldest available firmware I could. What I found was that it had a huge number of FFs in the firmware file. Now the firmware files were always the
size of the available flash memory, meaning FFFFF is the areas where no code or no data has been deployed to the firmware. I could stick my own code in there and then jump to it as needed. C functions could easily be compiled as needed and dumped into there, just by using GCC-C.
When you use dash C, you're compiling code without linking or relocating or checking anything, so you can get object files and binaries, which can be dumped in and jumped to as if they were specific functions, but you wouldn't be able to use things like standard C libraries or any complex heap, etc.
I also found, however, that stack handling was performed just by virtue of how ARM works. C function calls are generated as branch and link instructions. These are instructions which jump relatively to the current program counter into code. Just by jumping to the code I had, which returned back to the link register after branch and links, meant that all my code would run as needed.
Branch and links are made up of two's complement relative addresses, so addresses that can be below or above the current program counter. Directly patching these over branch and links that were already in the firmware meant I could jump to my own custom code without causing any trouble in the rest of the firmware and changing what I needed to.
I made a small build application which compiled all my custom firmware code and also did all the relocation and integration of non-standard functions for me so that this would all get built so I could call functions from different areas and also patch over branch and links. I also created a firmware update tool that would deploy this code for me.
My initial project was I wanted to read out memory in the same way I had in the Samsung S6. In order to do this I decided to patch the NCI command to F24, which is a vendor specific command which I didn't find the purpose for ever. I could send repeated data to this with larger and smaller payload sizes and it would just take them as needed.
I searched for move dot star hash 0x24 which is regex just for searching quickly for certain instructions in IDA and found a function call which set up a response header using this value. I then looked through and assessed that this was indeed the function that handled this NCI call
and I overwrote Sub11A76 which was the last function call before it sent data back via I2C. I could then modify any data that had already been modified as needed. I did find however that writing a firmware took around 20 seconds which was a lot longer than I expected.
To receive parameters however I didn't know where in RAM these were located so what I had to do was find where they were located in RAM as my first port of call. This is where I'd be able to receive commands as well as send them back and responses based on what I'd sent. So if I want to send an address to read data back this is what I'd use. I crafted an NNCI request 2F240 for FAC FAC which was just a placeholder value that would easily be spotted in RAM.
And then I searched through the entirety of RAM via this I2C call and set the response payload via I2C to be the address it was found in. This allowed me to find where this data was stored in memory and read out parameters as needed.
Because I could do this I could now dump the S3-NRN82 bootloader which was extremely helpful for me modifying my exploit to make it just a bit more stringent. I didn't have any problems redeploying it several times and the exploit worked every time. However if you'll see what was happening when I returned in the stack to 165 was that it was loading from R0 into R0.
Meaning that it was loading from an address I had no control over which was slightly scary. What I did was move it to exactly the same place as I moved it into the bootloader of the SCFW-RN5. That being the address which loads the address of the firmware we're jumping to and then jumps into that firmware.
Now I'd added some custom functionality I wanted to add something a bit more NFSP specific. When I looked into the capabilities of the chip I found that it supported ISO 14443A. This being things like MIFARE classic tags, MIFARE ultralight and most things you'll see.
ISO 14443B which is a bit less common and several other protocols all of which were of the 13.56 MHz spectrum and didn't cover anything in the 125 kHz spectrum. I found that while I had access to some information regarding the I2C interface I didn't have any access to information regarding things like how NFC works on the chip.
And because this was a completely custom chip I would have to do a deep dive into how this works in order to assess all of its functionality. My initial goal was to emulate a MIFARE classic tag in its entirety on the S9. This is functionality that's not traditionally found in phones because its only use really would be for exploitation as far as anyone can tell.
What I did was use a prox mark for debugging to assess any responses sent back from the chip via NFC so I could keep track of what was going on from the NFC side while also debugging from I2C. I took all the NCI commands that were sent from the phone to the chip during traditional NFC startup and reading and just replayed them as needed.
I didn't have any access to NCI documentation so everything I looked at via NCI was reverse engineered. I went through each of these commands and deleted any ones which were unnecessary. I worked out they were unnecessary by removing them, replaying and seeing if NFC still worked. I found that this worked great and found that the last command that was sent was the ncirfdiscover command which is a command
that starts up the either pretending to be a tag, pretending to be a reader of different types or all of the above. And I modified this only to act as a tag for now. Now initial reverse engineering of this hardware required knowledge of the functions on the hardware in quite a large amount of depth.
I would have to look through how everything worked and understand it in quite a lot of detail in order to modify it. And because there were no strings and no function references, everything I did I'd have to do by hand. So I know quite a lot about my fake classic in ISO 14443A and what I ended up doing was searching for select command. Now there's enumeration and communication in NFC which largely works the
same communication wise, but there are timing constraints on certain enumeration functions. And due to this I'd want to find this first as it was very likely to be using different hardware than the traditional communication. What I ended up doing was searching for the select command, 0x93, just by searching for a comparison using RadioX in IDA,
and found an immediate result which was reading from a hardware address that specific value and then jumping if it found it. Placing my phone on a reader and then dumping the entire hardware address space of that particular address found that it was indeed the NFC functionality. So I dumped this while the NFC was running, while the chip was running, and found that at
address 200 where it was found in the hardware was all the data buffers being sent to the chip. So in this instance you can see a 0x52 there which was a NFC wake up command which requests startup of NFC tags. With this I could read all of the NFC read commands as well as some configuration data which would be helpful later.
This also allowed for one way passive sniffing and would have allowed for it later as well in different ways. So as I said enumeration works slightly different to traditional communication for various reasons including the size of payloads and the time it takes to respond.
However I wanted to modify specific aspects of this in order to modify how it worked. Now when it enumerates in order to define what kind of chip is being used you have to send three values that are relevant. So first thing that happens is the NFC reader either sends a wake up or a request A which is command 0x26 and what's responded by the NFC chip is an ATQA value.
Now this is a two byte value which defines what kind of chip it is and a few other relevant details just by which bits are set in this response. The reader then sends the select command as we saw earlier which then makes the tag respond with a unique identifier.
Now on phones each time this is read it is a unique value that is randomised except for the first byte which is 0x08. Now traditionally tags should keep these as a static value just by how the standards work and the reason it's randomised is so you can't emulate specific tag types. We were going to bypass this. And lastly after selection of this UID by the reader it sends an SAK value which defines a little bit more detail about
what kind of tag it is as well as saying whether the UID is slightly longer either for 7 or 10 bit bytes. I found that I could set the ATQA NCI and SAK values by certain NCI commands.
However I found that when I sent these specific bits were set just by the firmware to force it to always behave as a specific kind of chip. So you could never pretend to be any other type of chip apart from the ones supported by the firmware at the time. I used my patched ICC command to take a RAM dump and then look for the values I'd set.
I then compared these in IDA via the addresses in RAM to any functionality that was found. And I found one function which accessed all of the addresses that these were set for. Looking through I found that these were all accessing hardware addresses. These are the ones starting at 4002 and this meant that it was probably setting these in some configuration in the hardware.
I overrode this function and then called it within the new function I'd overridden. This meant that I would not have to modify anything about the functionality which was more complex like if any had any hardware setup which I didn't want to deal with. But all it'd mean is that I'd be able to override the values I wanted to.
So I let that function run and then set my own UID, ATQA and SAK values as needed so that I could pretend to be any chip. I then put this on a Proxmark again and used the reader mode to identify what data came out. I found that it had my custom UID that I'd implemented as well as the ATQA and SAK values which
relate to a MyFairClassic mini-TAC which was the one I was emulating for this part of the custom firmware. I then wanted to move on to the more high level communication of the MyFairClassic protocol. Now, as I stated before, enumeration and communication is very close together. However, it was very likely that this would be custom inside the firmware rather than handled by hardware registers.
I searched for the ATS value which returns certain configuration data about the TAC just by another comparison. I found that this had very quickly jumped out. I found four results in the firmware which I looked through and found the specific one which was most likely to be related to it. You can see a load byte followed by a comparison of that byte just in the disassembly there.
This meant that I got inside the state machine which handled all of the requests to the NFC chip from an NFC reader. I also noticed some other commands. Further tracing from this led me to the function which sent responses including
setting up the buffer address 0x100 as well as the size at address 0x08. And a few other settings which I couldn't work out the purpose of but were very important and if I removed them it wouldn't send responses anymore. I first implemented a basic read command. MyFair often uses 0x30 and then a block and then a CRC as just a standard read command.
This is common throughout a lot of different MyFair chips. Sometimes it's encrypted, sometimes it's not. But what this allowed me to do was, using a prox mark, read that raw data and make sure that it actually worked. And I found that this worked as well. I had to set up a CRC at the end but apart from that this worked as any other read command should in an NFC chip.
I could later add inappropriate encryption if I wanted. I overrode the entirety of the state machine function as I found it largely needless because I didn't want to touch anything else. Apart from one specific aspect which was the halt command. Now this one is part of more of the higher level communication. It's still somewhat part of enumeration as it sets up the state of the NFC tag to not respond to certain startup requests.
I just called the halt function that was found in the state machine as needed and it ran exactly as one would want to. I then also implemented the rest of the MyFair classic commands as needed including authorization as well as writing of block data etc.
I also added some debugging commands as needed so as you can see commented out there is debug command 70 which would be provided with an address and read raw memory just out of the RAM of the chip or any other part of the chip over NFC so I could use this to debug via the prox mark.
Because I had full control of this I could emulate any NFC tag as I wanted to as long as it was ISO 144438. Now I could have expanded this to different 13.56 MHz protocols but I stuck with this one for now. I implemented MyFair classic authentication which is quite simple just using a very weak encryption protocol
and I found that while this worked with the prox mark there was a very good reason why it wouldn't work in legitimate reason that a reader that I would need to get past. MyFair classic overrides a very specific part of the RF protocol used by the ISO 144438 standard which is the parity bit set at the end of every 8 bits.
So what happens is during all communication is that both the reader and the tag sends a parity bit after every 8 bits of the response this being a 1 or a 0 depending on how many bits were set in the previous 8 bits. This is auto generated in the hardware as far as I could tell and I was really concerned because this could have been a complete stopper on this project and stopped me being able to emulate this firmware as I wanted to.
However I thought that there was probably a hardware register setting that would allow me to modify this as needed in order to put in my own parity bits. What this would mean is however I'd have to stick 9 bits into 8 bit buffers inside the firmware which would make things quite complicated. What I did was go through the hardware registers and the ones that were specifically related to configuration and modified a single
bit in turn as often these used bit settings to define certain functionality and I wanted to see what each one did. Now this had some interesting outcomes like making my responses huge or adding randomised data or encrypting in weird ways or adding strange CRCs but it was all quite useless for what I wanted.
I found that the parity register which I wanted was at address 40020004 by setting the bit at 0x4000. With this set it shifted down all my data so that I now required adding in the size of the data I was sending.
This meant I had to change the length to be 9 bits for each byte instead of just 8 bits for each byte and also shift all the data I was sending left by 1 so I could add my encrypted bit. Within this in place however I could fully implement a myfairclassic tag with no problems whatsoever. One thing I wanted to add was persistent storage of data so when I was emulating myfairclassic I
set up the I2C interface so I could send tag data directly to the chip via the host phone. What I wanted to do was be able to store any modifications back to the host phone as well and all I did was modify I2C responses so that every time a write occurred it would send that written block back to me and I could write it to the file system as needed.
Here's a quick demo of this occurring. So what I've done here is taken a different phone on the NXP Tag Info app which tries all sorts of authentication styles and tag types to work out what a NFC chip is or NFC tag is. And what I did was let this run on my Samsung S9 to see if it
could work out whether it was myfairclassic tag or not and whether it could authenticate appropriately. So what I did is I set up the myfairclassic tag being emulated to have a number of different keys and authentication mechanisms in place just so I could see how that worked. And as you can see some keys were found, some weren't just by what I always got implemented in NXP Tag Info.
So tag emulation allowed for spoofing of access control cards as well as more esoteric uses. There's a lot of games and toys which use 13.56 MHz tags. But I also found that I could make it work so that all other NFC functionality including reader modes or standard functionality would work despite this patching.
Meaning while I had a custom firmware it didn't damage the core functionality of the chip as needed. But it did mean that I would need to access all of them via my tool rather than the host Android operating system. I felt that this was more subtle than a dedicated hack tool such as a Proxmark or a NFC comedian because it is a phone and people don't generally expect them to have this kind of functionality.
And also expansion of this functionality could allow one to do things like use dark side attacks or myfairclassic decryption attacks directly on the phone and then deploy them back again to the chip itself. I found that the same emulation could be performed on any supported protocol. In fact I found that the hardware registers I was accessing were the same for every protocol that was used by the chip.
So what was happening was it would switch between different protocols in that hardware by setting a specific setting. What this also meant is that you could set up things like certain amounts of two-way passive sniffing for different protocols or implement different ones as needed and have them all work in conjunction for different purposes. Now that a framework was in place and a lot of the reverse engineering had been done, I could do this if I wanted to.
In conclusion, all of the vulnerabilities that I found were outlined to Samsung as of April 2020. Or rather they patched them as of April 2020. Because of this, the chips won't be vulnerable going forward. However all chips that are currently out
in the world will be forever and we can use those to develop custom firmware as needed. The vulnerability did require root access so you could not compromise a smartphone using this interface by reflecting data back. However it did fully compromise this chip in particular. We've got to remember that phones are exploitable embedded devices in the same way as any IoT device.
However of course they're slightly higher security in some ways but they really should be treated like that. The chips in there are often running old bootloaders which will never be changed and because of this bootloader vulnerabilities are very common. This is not the only chip that I've broken in a similar manner and it's not the only NFC chip I've broken in this manner, especially on phones.
Developing custom firmware is a very difficult task sometimes and can take a lot of time. However it can be rewarding and you can get some very interesting outcomes. And lastly, if an undisclosed vulnerability is found in an old chip, it'll likely be in a new one. Thank you very much.