WEBVTT

00:04.350 --> 00:09.810
Hello everyone, my name is Christopher Wade and today I'm going to be talking to you about custom firmware for embedded mobile chipsets.

00:09.810 --> 00:18.770
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.

00:19.250 --> 00:28.130
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.

00:28.650 --> 00:43.450
So the origin of this project was that I'd found that smartphones that I'd bought and routed contained a huge amount of closed firmware and closed hardware, which you couldn't modify even after routing them due to signature checking restrictions or just lack of open knowledge about the protocols used by the devices.

00:43.730 --> 00:50.250
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.

00:50.850 --> 01:03.970
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 WiFi Monitor Mode, which can be activated in Snapdragon chipsets by echoing 4 into a specific kernel parameter in the file system,

01:03.970 --> 01:07.890
which converts it from two WiFi chipsets into a Monitor Mode chipset.

01:07.890 --> 01:17.450
Also, if you add custom firmware to a Broadcom chipset and modify your kernel slightly, you can get Monitor Mode that way on Broadcom.

01:18.390 --> 01:23.830
You can also modify the kernel on most mobile devices to use USB device emulation.

01:23.830 --> 01:39.910
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.

01:41.010 --> 02:03.750
Further to this, when I route mobile phones, I usually like to add a Debian route onto them, this being a Debian file system which can be built with QEMU DebutStrap, 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,

02:03.750 --> 02:05.450
but still affect the hardware.

02:06.510 --> 02:16.370
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.

02:16.550 --> 02:32.670
NFC on Android has restricted some very low-level features, such as Generic Reader Mode, reading from tags using certain applications, Mobile Payments, which are very popular nowadays, NDEF Communication, which was slightly more complex, and Host Card Emulation,

02:32.670 --> 02:35.910
which is emulation of NFC tags, but in a very limited manner.

02:35.910 --> 02:41.610
While these allowed for certain attacks, such as relay attacks, to be performed, they weren't complete in what they can be done with.

02:42.570 --> 02:58.890
NFC attack tools often have features such as Reader-Based Attacks, this being trying to decrypt or attack NFC tags via the reader, Raw Tagging 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.

02:59.530 --> 03:16.410
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 root it very easily and gain access to the hardware as needed.

03:16.490 --> 03:22.070
I found that it used a proprietary Samsung NFC controller, but this was not used in some US versions.

03:22.390 --> 03:32.190
This NFC controller was the S3FW-RN5, developed by Samsung Semiconductor, and was utilised in the non-US versions of the Samsung S6 and Note 4.

03:32.950 --> 03:46.870
This chipset boasted the ability to update firmware securely, meaning that people couldn't deploy custom firmware, utilised an ARM SC000 secure car architecture, and was communicated with via I2C and GPIO on a phone.

03:47.590 --> 04:00.290
As smartphones are 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.

04:00.490 --> 04:08.710
However, I found that Samsung kernel had abstracted these into a custom driver, which I can access using the device file slash dev slash sec nfc.

04:08.850 --> 04:17.270
I looked into how it communicated via this and found they use controls to power the chip on and off, and file reads and writes to communicate over I2C.

04:19.010 --> 04:22.790
NFC chips communicate with a very standard protocol called NCI.

04:22.790 --> 04:32.030
This is a protocol which is used to simplify NFC communication functionality in phones and other devices, but also restricts it quite heavily.

04:32.030 --> 04:45.910
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.

04:46.670 --> 04:55.950
It supports non-standard functionality via the vendor group ID, which is defined by F, which allows for non-standard functionality to be implemented.

04:55.950 --> 05:12.850
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.

05:12.850 --> 05:21.950
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.

05:23.250 --> 05:29.590
The SCFW-RN5 was found to support firmware updates via I2C via the same endpoint as NCI.

05:29.590 --> 05:35.790
However, I found that the firmware updates use their own custom protocol, which did not use any NCI communication.

05:35.790 --> 05:44.430
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.

05:44.510 --> 05:49.330
These firmware files were found in the vendor partition on the file system of the phone.

05:50.150 --> 06:07.650
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.

06:07.670 --> 06:11.830
Using this, I could now trace out any firmware updates that occurred via logcat.

06:13.010 --> 06:19.430
Doing this, I could dump all the communication out and analyze how the firmware updates were performed.

06:19.430 --> 06:36.670
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.

06:36.670 --> 06:41.770
I also found that there was a parity bit set on every command type at the start of each update.

06:44.070 --> 06:47.030
Firmware update files can be found throughout the Android file system.

06:47.030 --> 06:59.070
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.

06:59.830 --> 07:08.050
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 CRCs and relevant information.

07:08.150 --> 07:18.310
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.

07:19.850 --> 07:25.190
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.

07:25.350 --> 07:31.710
Looking through the firmware, I found that it was quite obviously going to be YIP thumb firmware.

07:31.890 --> 07:41.010
By running the strings command on the firmware itself, you can find that it has a large number of lowercase b, upcase g outputted by strings.

07:41.110 --> 07:49.850
What this translates to is hex 7047, which translates to thumbs bxlr operation branch and link.

07:50.270 --> 07:55.390
A high number of these generally means that it's going to be using ARM thumb firmware, something similar to a Cortex-M chip.

07:55.390 --> 08:08.670
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.

08:09.790 --> 08:18.430
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.

08:18.430 --> 08:20.050
By setting up the I.O.

08:20.050 --> 08:28.530
controls to set it into bootloader mode rather than standard power mode, I could deploy the firmware updates as needed.

08:28.890 --> 08:33.330
Header files from the open source kernel drivers for this chipset were very helpful for this.

08:33.330 --> 08:41.710
I used the slapdepsec__nfc.h file to perform this, and then I could just set the appropriate configurations with I.O.

08:41.710 --> 08:43.130
controls using this.

08:43.990 --> 08:50.230
I found that there was a very specific sequence that was used for firmware updates every time, using specific commands.

08:50.230 --> 09:09.730
There's command 0 for reset, command 1 for boot information, command 2 for beginning of updates, command 4 for updating 4096 bytes of the firmware, and command 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,

09:09.730 --> 09:12.850
and which was compared to the cryptographic signature.

09:13.030 --> 09:20.270
I noticed that there was a numbered command missing from the sequence command 3, and this meant that there was very likely to be some hidden commands that we didn't know about.

09:21.510 --> 09:30.490
Commands in this sequence only work at certain times, so you can't start writing firmware before setting up the signatures, etc.

09:30.530 --> 09:36.330
Due to this, I brute-forced my way through the entire firmware update process while trying different commands to see how they worked.

09:36.330 --> 09:43.930
I found that chips would return error 2 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.

09:44.070 --> 09:49.490
Now, this would allow me to find any valid commands at each point in this process.

09:50.210 --> 10:00.730
I found that hidden bootloader command 3 was the same functionality as command 4, except instead of sending 4096 bytes, it would write 512 byte blocks, so there were no real actionable weaknesses.

10:01.090 --> 10:04.910
However, I also found that there was a hidden bootloader command 6.

10:05.070 --> 10:15.590
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.

10:15.590 --> 10:20.690
I found that this was because I was giving it an address and a size during this process.

10:20.890 --> 10:27.010
This allowed me to dump the RAM of the chip, the firmware of the chip, hardware registers, and more importantly, the secure bootloader.

10:28.010 --> 10:36.950
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.

10:37.050 --> 10:43.970
This showed that it was using a standard Cortex-M firmware format, starting at address 0, which was the vector table.

10:43.970 --> 10:56.610
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.

10:58.050 --> 11:13.070
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, and 5, 0, 0, 0 for hardware peripherals, and E, 0, 0, 0, 0 for system addresses.

11:13.790 --> 11:17.450
This disassembled very nicely and was very easily assessed.

11:18.390 --> 11:27.990
It had some interesting artifacts, such as the fact that I could now work out exactly how the firmware updates were securely implemented and how these worked post-update.

11:27.990 --> 11:38.270
I found that on startup, the bootloader checked for a magic number at the start of the firmware update, this being 5IF00FA5, which I did not find when I looked in the firmware payload itself.

11:38.410 --> 11:47.570
This magic number was written only after firmware updates had occurred, if the signature was valid during that update, meaning that every time the chip started up, it wouldn't have to verify the signature.

11:47.850 --> 11:53.690
I attempted to manually write this value into the firmware that I deployed, however, this did not do anything effective.

11:54.570 --> 12:04.350
I also found the state machine which handled the commands I was sending, so you see comparisons of 0, 1, 2, and 6, which were the commands that were valid at the start of the firmware update process.

12:04.630 --> 12:20.030
I also found the RSA public key, which was in use for this chipset, which was made up of 128 high-entry Pbytes, followed by 00010001, which translates to 65537, the exponent of a public key.

12:21.490 --> 12:26.470
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.

12:26.470 --> 12:36.490
I wanted to do it on an emulated chipset, so what I did was use this damped bootloader and looked into ways that I could emulate it effectively on a host computer.

12:37.430 --> 12:47.830
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.

12:47.830 --> 12:53.210
You can define the architecture, memory mapping, and hardware integration as needed to fit your own needs.

12:54.850 --> 13:06.090
The bootloader, I was found, was loaded into address zero, which was the start of the flash memory in the chip itself, and the program counter was set to the reset factor that I found in that bootloader, 2BD.

13:06.490 --> 13:11.830
Memory was then mapped to flash, RAM, and hardware registers as needed so they would perform as a chip as needed.

13:12.990 --> 13:19.550
Commands were found to just be received in a single thread that started from the main loop and just looped around receiving I2C commands.

13:19.550 --> 13:30.410
Because this meant that there was probably not going to be any interrupts in use, just due to the size of the bootloader and its 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.

13:31.470 --> 13:42.350
I found that execution was causing device resets 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.

13:42.790 --> 13:52.990
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 set up hardware in any meaningful manner.

13:55.910 --> 14:04.090
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.

14:06.350 --> 14:19.650
The address that it hit was 4.0.0.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.

14:19.690 --> 14:29.610
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.

14:30.070 --> 14:33.330
Because I implemented this, it would move on to the next stage of the process.

14:33.990 --> 14:40.250
Next, I made the firmware continually read bytes from a single address, 4.0.0.2.2.0.3.8.

14:40.310 --> 14:46.190
This implied that it was probably reading from I2C as well, but the first-in-first-out buffer.

14:46.270 --> 14:52.230
What I did was start sending bytes that I would usually send for firmware updates via this interface in Unicorn and to see what happened.

14:52.230 --> 14:59.510
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.

14:59.630 --> 15:04.530
These responses meant that I had full emulation of the I2C communication without ever having to touch my chip.

15:06.010 --> 15:09.950
What I wanted to do was find the memory corruption exploit so I could bypass the signature checking.

15:10.390 --> 15:16.110
And while I did start doing some randomized fuzzing that I thought would be viable, it didn't really come out with anything interesting.

15:16.470 --> 15:22.450
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.

15:22.550 --> 15:25.130
However, these were limited to only 256 bytes.

15:25.130 --> 15:32.390
I did, however, notice that some functions, especially ones for deploying large plots of data, could send data in chunks, like 256-byte chunks.

15:32.570 --> 15:40.290
I also found that the size of the hash and signature were defined at the start of the firmware update process, right before the hash and signature were sent.

15:41.690 --> 15:46.830
I found that I could increase the size of both the hashes and signature in order to send more data.

15:46.830 --> 15:54.490
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.

15:54.830 --> 16:02.170
When I did this in my emulator, I found that eventually this made my memory go out of bounds outside the 8K of memory I had allocated in my emulated firmware.

16:02.670 --> 16:07.430
Looking into this, I found that it also overwritten the stack with the memory that I had sent to it.

16:08.810 --> 16:14.710
Because I can now overwrite the stack, I can manipulate the program counter and start doing some more memory corruption exploits.

16:14.710 --> 16:24.770
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.

16:24.910 --> 16:32.450
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.

16:33.650 --> 16:43.730
What I ended up doing was making the program counter just dump directly back into the start bootloader, pass the check for the magic number, and into the part where it initializes the firmware.

16:43.830 --> 16:47.950
And this allowed me to bypass all of the signature checking and deploy my own firmware.

16:48.950 --> 17:00.070
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.

17:00.070 --> 17:04.350
I could then send NCI commands and receive them as needed with my custom firmware.

17:04.450 --> 17:14.930
What I did was first change the version number of the chip, it was different here, EE, AA, BB, CC, and DD, and meant that custom firmware had been sent and validly was running.

17:14.970 --> 17:17.270
I then disclosed this vulnerability to Samsung.

17:18.390 --> 17:20.490
There were two ways they could have remediated this.

17:20.490 --> 17:25.150
Firstly, they could have patched the bootloader from the main firmware, removing the buffer overflow.

17:25.290 --> 17:35.430
Now, while this does seem simple, it would be very difficult because what would have to happen is the bootloader would have had to start the main firmware and then let the main firmware patch the bootloader.

17:35.430 --> 17:44.910
Now, if there was 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.

17:45.470 --> 17:51.110
One could also patch the kernel to disallow the commands that were being sent, so the large hash sizes, and make them static.

17:51.110 --> 17:54.110
However, this would be trivially bypassed just by modifying the kernel.

17:55.710 --> 18:08.770
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, S3NRN74, S3NRN81, S3NRN82, and SEN82AB.

18:08.890 --> 18:14.030
The most interesting of these to me was the S3NRN82 as it seemed like their latest version at the time.

18:15.230 --> 18:18.550
I decided to go through the ROMs of lots of Samsung phones.

18:18.550 --> 18:26.550
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.

18:26.550 --> 18:37.950
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 what firmware files were in the slash vendor partition.

18:38.230 --> 18:51.410
Occasionally, these partitions are not stored in these because they are part of a special vendor partition which deploys the phone and can only be extracted from a phone, but it did give some insight in that to what chipsets were being used.

18:52.830 --> 18:58.050
While the vendor directory does always contain these firmware files, this separate partition does make things a bit more difficult.

18:58.670 --> 19:13.970
I found that the S3NRN82 was the latest chipset after looking through this, and found that there are 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.

19:13.970 --> 19:24.750
It was also found to be available in the Samsung Galaxy S8 and S10, but I purchased the Samsung S9, rooted it using OEM unlocking and a custom ROM, and started looking through how it worked.

19:25.610 --> 19:39.350
I found this firmware file to be in the same format as the S3FWRN5, 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, so implying a much smaller bootloader.

19:39.390 --> 19:42.810
I also found that the firmware size was 32 kilobytes larger.

19:44.290 --> 19:54.170
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.

19:54.170 --> 19:58.630
I also found a new command 7, which was identified to just reboot the chip and nothing else.

19:58.910 --> 20:09.070
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.

20:09.270 --> 20:15.690
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.

20:17.030 --> 20:28.350
Because they had modified their kernel to no longer dump out data via logcat, I wouldn't be able to use the same logging procedures I did before to assess the protocol.

20:28.350 --> 20:36.650
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.

20:36.790 --> 20:42.450
Looking through these, I could see the commands working in sequence, find the start of firmware updates, and then deploy them.

20:42.450 --> 20:54.790
And I found that what was happening was during the start of 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.

20:54.790 --> 21:01.130
I modified my firmware update tool to reflect this, and I could now upload valid firmware to the chip.

21:02.910 --> 21:07.610
I wanted to see if I could replicate the same buffer overflow I had before.

21:07.610 --> 21:13.510
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.

21:13.550 --> 21:18.150
What I ended up doing was sending increasingly sized payloads to the chipset.

21:18.150 --> 21:26.970
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.

21:26.990 --> 21:34.710
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.

21:36.130 --> 21:45.070
What I ended up doing to find out where I could find an entry point was starting my program counter at 0,1 and filling the stack with this.

21:45.070 --> 21:56.170
So filling the stack with the address 0,1 and seeing what would happen if the return pointers, which were somewhere in the stack I didn't know yet, jumped there.

21:56.530 --> 22:09.410
I then sent NCI initialization commands as you would at the start of the NFC setup, and if I received an NFC response then I'd found a valid endpoint into the core firmware and bypassing the signature checking.

22:09.450 --> 22:14.190
If it failed, however, I'd restart the chip and increase the address by two.

22:14.190 --> 22:18.730
I found the signature bypass succeeded at address 165 as follows.

22:19.870 --> 22:26.890
So I would send my exploit, and if it failed, start it again, and if it failed, start it again.

22:27.250 --> 22:39.930
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.

22:40.790 --> 22:43.530
I then disclosed this vulnerability to Samson.

22:43.530 --> 22:56.850
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.

22:56.850 --> 23:02.710
However, because they couldn't patch the bootloaders of all the chipsets, like the ones I had in my phone, custom firmware would still be viable.

23:04.570 --> 23:09.970
In order to patch existing firmware, one needs to basically modify what they have in there.

23:09.970 --> 23:12.670
They need to add their own code into what already exists.

23:12.730 --> 23:19.310
I decided to stick with the S300N82 rather than S3FWRN5, because it was the latest chipset and would have the most power.

23:19.770 --> 23:27.530
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.

23:29.490 --> 23:38.010
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.

23:38.250 --> 23:42.470
What I'd found was that it had a huge number of FFs in the firmware file.

23:42.470 --> 23:51.030
Now, the firmware files were always the size of the available flash memory, meaning FF, FFF is the areas where no code or no data has been deployed to the firmware.

23:51.250 --> 23:54.150
I could stick my own code in there and then jump to it as needed.

23:55.450 --> 24:01.270
C functions could easily be compiled as needed and dumped into there just by using GCC-C.

24:01.270 --> 24:19.190
When you do use that 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 there were specific functions, but you wouldn't be able to use things like standard C libraries or any complex heap,

24:19.190 --> 24:19.970
etc.

24:20.290 --> 24:25.190
I also found, however, that stack handling was performed just by virtue of how ARM works.

24:26.310 --> 24:30.590
Now, C function calls are generated as branch and link instructions.

24:30.590 --> 24:36.050
These are instructions which jump relatively to the current program counter into code.

24:36.050 --> 24:44.370
And 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.

24:45.450 --> 25:02.890
Branch and links are made up of two complement relative addresses, so addresses that can be below or above the current program counter, and 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.

25:03.490 --> 25:19.610
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 this would all get built so I could call functions from different areas and also patch over branch and links.

25:19.770 --> 25:23.330
I also created a firmware update tool that would deploy this code for me.

25:24.730 --> 25:31.410
My initial project was I wanted to read out memory in the same way I had in the Samsung S6.

25:31.410 --> 25:39.310
In order to do this, I decided to patch the NCI command 2F24, which is a vendor-specific command which I didn't find the purpose for ever.

25:39.310 --> 25:45.130
I could send repeated data to this with larger and smaller payload sizes and it would just take them as needed.

25:45.130 --> 25:56.450
I searched for move.star-ox24, 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.

25:56.610 --> 26:09.070
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.

26:09.330 --> 26:12.750
I could then modify any data that had already been modified as needed.

26:12.890 --> 26:17.350
I did find, however, that writing firmware took around 20 seconds, which was a lot longer than I expected.

26:20.230 --> 26:29.750
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.

26:29.750 --> 26:35.050
This way, I'd be able to receive commands as well as send them back in responses based on what I'd sent.

26:35.050 --> 26:38.030
So if I want to send an address to read data back, this is what I'd use.

26:38.150 --> 26:55.890
I crafted an NCI 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.

26:55.890 --> 27:01.330
This allowed me to find where this data was stored in memory and read out parameters as needed.

27:02.590 --> 27:10.870
Because I could do this, I could now dump the S3NRN82 bootloader, which was extremely helpful for me modifying my exploit to make it just a bit more stringent.

27:10.870 --> 27:16.150
I didn't have any problems redeploying it several times, and the exploit worked every time.

27:16.150 --> 27:29.630
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.

27:29.650 --> 27:43.050
What I did was move it to exactly the same place as I moved it into the bootloader of the SCFWRN5, that being the address which loads the address of the firmware we're jumping to, and then jumps into that firmware.

27:44.170 --> 27:46.770
Now I'd added some custom functionality.

27:46.770 --> 27:49.670
I wanted to add something a bit more NFC-specific.

27:50.410 --> 28:00.310
When I looked into the capabilities of the chip, I found that it supported ISO14443A, this being things like MIFARE Classic Tags, MIFARE Ultralight, and most things you'll see.

28:01.310 --> 28:12.470
ISO14443B, which is a bit less common, and several other protocols, all of which were of the 13.56MHz spectrum and didn't cover anything in the 125kHz spectrum.

28:12.850 --> 28:22.330
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.

28:22.330 --> 28:28.350
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.

28:29.070 --> 28:33.530
My initial goal was to emulate a MIFARE Classic Tag in its entirety on the S9.

28:33.530 --> 28:40.950
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.

28:41.370 --> 28:51.510
What I did was use a Proxmark 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.

28:52.690 --> 29:01.850
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.

29:01.850 --> 29:08.210
I didn't have any access to NCI documentation, so everything I looked at via NCI was reverse-engineered.

29:08.330 --> 29:12.730
I went through each of these commands and deleted any ones which were unnecessary.

29:12.730 --> 29:18.310
I worked out they were unnecessary by removing them, replaying, and seeing if NFC still worked.

29:18.310 --> 29:32.130
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.

29:32.130 --> 29:34.890
I modified this only to act as a tag for now.

29:36.250 --> 29:42.090
Now, initial reverse engineering of this hardware required knowledge of the functions on the hardware in quite a large amount of depth.

29:42.090 --> 29:47.450
I would have to look through how everything worked and understand it in quite a lot of detail in order to modify it.

29:47.450 --> 29:52.370
And because there were no strings and no function references, everything I did I'd have to do by hand.

29:52.830 --> 30:09.610
So I know quite a Now, there's enumeration and communication in NFC, which largely works the same communication-wise, but there are timing constraints on certain enumeration functions.

30:09.670 --> 30:15.190
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.

30:15.470 --> 30:27.770
What I ended up doing was searching for the select command, 0x93, just by searching for a comparison using regex and either, and found an immediate result, which was reading from a address, that specific value, and then jumping if it found it.

30:28.850 --> 30:38.550
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.

30:38.550 --> 30:48.690
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.

30:48.690 --> 30:58.050
So in this instance, you can see a 0x52 there, which was a NFC wakeup command, which requests startup of NFC tags.

30:58.590 --> 31:04.110
With this, I could read all of the NFC read commands, as well as some configuration data, which would be helpful later.

31:04.470 --> 31:09.650
This also allowed for one-way passive sniffing, and would have allowed for it later as well, in different ways.

31:10.450 --> 31:19.350
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.

31:19.970 --> 31:26.150
However, I wanted to modify specific aspects of this in order to modify how it worked.

31:26.150 --> 31:34.310
Now, when it enumerates, in order to define what kind of chip is being used, you have to send three values that are relevant.

31:34.390 --> 31:42.770
So, the first thing that happens is the NFC reader either sends a wakeup or a request A, which is command 0x26.

31:43.270 --> 31:47.210
And what's responded by the NFC chip is an ATQA value.

31:47.210 --> 31:54.130
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.

31:54.390 --> 32:01.690
The reader then sends the select command, as we saw earlier, which then makes the tag respond with a unique identifier.

32:01.770 --> 32:07.310
Now, on phones, each time this is read, it is a unique value that is randomized, except for the first byte, which is 0x08.

32:07.310 --> 32:13.150
Now, traditionally, tags should keep these as a static value, just by how the standards work.

32:13.150 --> 32:16.830
And the reason it's randomized is so you can't emulate specific tag types.

32:16.830 --> 32:18.470
We were going to bypass this.

32:18.590 --> 32:32.590
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 4, 7, or 10 bytes.

32:36.370 --> 32:45.910
I found that I could set the ATQA NCI and SAK values by certain NCI commands.

32:45.910 --> 32:53.290
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.

32:53.290 --> 32:58.590
So you could never pretend to be any other type of chip apart from the ones supported by the firmware at the time.

32:58.790 --> 33:04.430
I used my patched ICC command to take a RAM dump and then look for the values I'd set.

33:04.430 --> 33:10.090
I then compared these in IDA via the addresses in RAM to any functionality that was found.

33:10.090 --> 33:14.530
And I found one function which accessed all of the addresses that these were set for.

33:15.110 --> 33:24.050
Looking through, I found that these were all accessing hardware addresses, these ones starting at 4002, and this meant that it was probably setting these in some configuration in the hardware.

33:25.450 --> 33:29.130
I overrode this function and then called it within the new function I'd overridden.

33:29.130 --> 33:41.950
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 would mean is that I'd be able to override the values I wanted to.

33:41.950 --> 33:49.170
So I let that function run and then set my own UID, ATQA, and SAK values as needed so that could pretend to be any chip.

33:50.190 --> 33:55.150
I then put this on Approximate again and used the reader mode to identify what data came out.

33:55.150 --> 34:07.330
I found that it had my custom UID that I'd implemented, as well as the ATQA and SAK values, which relates to a MyFairClassic mini-tack, which was the one I was emulating for this part of the custom firmware.

34:08.450 --> 34:15.090
I then wanted to move on to the more high-level communication of the MyFairClassic protocol.

34:15.090 --> 34:19.170
Now, as I stated before, enumeration and communication are very close together.

34:19.170 --> 34:25.170
However, it was very likely that this would be custom inside the firmware rather than handled by hardware registers.

34:25.290 --> 34:31.730
I searched for the ATS value, which returns certain configuration data about the TAC, and just by another comparison.

34:31.810 --> 34:34.030
I found that this very quickly jumped out.

34:34.190 --> 34:40.110
I found four results in the firmware, which I looked through and found that a specific one, which is most likely to be related to it.

34:40.110 --> 34:45.410
You can see a load byte followed by a comparison of that byte just in the disassembly there.

34:45.770 --> 34:53.310
This meant that I got inside the state machine, which handled all of the requests to the NFC chip from an NFC reader.

34:53.350 --> 34:55.110
I also noticed some other commands.

34:56.610 --> 35:14.930
Further tracing from this led me to the function which sent responses, including setting up the buffer at 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.

35:15.970 --> 35:23.230
I first implemented a basic read command, so MIFARE often uses 30 and then a block and then a CRC as just a standard read command.

35:23.230 --> 35:25.670
This is common through a lot of different MIFARE chips.

35:25.670 --> 35:33.530
Sometimes it's encrypted, sometimes it's not, but what this allowed me to do was, using a Proxmark, read that raw data and make sure that it actually worked.

35:33.550 --> 35:35.670
And I found that this worked as well.

35:35.690 --> 35:42.270
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.

35:42.570 --> 35:45.250
I could later add inappropriate encryption if I wanted.

35:46.290 --> 35:55.270
I overwrote 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.

35:55.270 --> 36:06.430
Now this, while it's part of more of the higher level communication, is still somewhat part of enumeration, as it sets up the state of the NFC tag to not respond to certain startup requests.

36:06.490 --> 36:12.650
I just called the HALT function that was found in the state machine as needed, and it ran exactly as one would want to.

36:13.390 --> 36:21.190
I then also implemented the rest of the MIFARE classic commands as needed, including authorization, as well as writing a block data, etc.

36:21.290 --> 36:23.470
I also added some debugging commands as needed.

36:23.470 --> 36:39.350
So I, 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 can use this to debug via the Proxmark.

36:40.850 --> 36:48.850
Because I had full control of this, I could emulate any NFC tag as I wanted to, as long as it was ISO14443A.

36:48.850 --> 36:54.150
Now I could have expanded this to different 13.56 MHz protocols, but I stuck with this one for now.

36:55.310 --> 37:08.110
I implemented MIFARE classic authentication, which is quite simple, just using a very weak encryption protocol, and I found that while this worked with the Proxmark, there was a very good reason why it wouldn't work, and a legitimate reason that a reader that I would need to get passed.

37:09.370 --> 37:20.470
MIFARE classic overrides a very specific part of the RF protocol used by the ISO14443A standard, which is the parity bit set at the end of every eight bits.

37:20.590 --> 37:32.790
So what happens is, during all communication, is that both the reader and tag send a parity bit after every eight bits of the response, this being 1 or 0 depending on how many bits were set in the previous eight bits.

37:33.030 --> 37:44.070
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.

37:44.230 --> 37:51.390
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.

37:51.610 --> 37:58.650
What this would mean is, however, I'd have to stick nine bits into eight-bit buffers inside the firmware, which would make things quite complicated.

37:59.330 --> 38:11.810
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 use bit settings to define certain functionality, and I wanted to see what each one did.

38:11.810 --> 38:21.910
Now this had some interesting outcomes, like making my responses huge, or adding randomized data, or encrypting in weird ways, or adding strange CRCs, but it was all quite useless for what I wanted.

38:22.810 --> 38:32.270
I found that the parity register, which I wanted, was at address 400200004 by setting the bit at 0x400... 4000, rather.

38:32.430 --> 38:39.890
With this set, it shifted down all my data so that I now required adding in the size of the data I was sending.

38:39.890 --> 38:50.770
This meant I had to change the length to be nine bits for each byte instead of just eight bits for each byte, and also shift all the data I was sending left by one so I could add my encrypted bit.

38:50.970 --> 38:55.830
With this in place, however, I could fully implement a MyFair Classic tag with no problems whatsoever.

38:56.570 --> 38:59.290
One thing I wanted to add was persistent storage of data.

38:59.290 --> 39:08.710
So when I was emulating MyFair Classic, I set up the I2C interface so I could send tag data directly to the chip via the host phone.

39:08.750 --> 39:20.390
What I wanted to do was be able to store any modifications back to the host phone as well, and what 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.

39:21.170 --> 39:23.050
Here's a quick demo of this occurring.

39:23.150 --> 39:44.330
So what I've done here is taken a different phone and 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 a MyFair Classic tag or not,

39:44.330 --> 39:46.650
and whether it could authenticate appropriately.

39:46.650 --> 39:55.230
So what I did is I set up the MyFair Classic tag being emulated to have a number of different keys and authentication mechanisms in place, just so I could see how that worked.

39:55.230 --> 40:00.750
And as you can see, some keys were found, some weren't, just by what I got implemented in NXP Tag Info.

40:02.190 --> 40:08.150
So tag emulation allowed for spoofing of access control cards, as well as more esoteric uses.

40:08.150 --> 40:11.850
There's a lot of games and toys which use 13.56MHz tags.

40:12.530 --> 40:24.830
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.

40:24.930 --> 40:31.270
But it did mean that I would need to access them via my tool rather than the host Android operating system.

40:31.310 --> 40:40.590
I felt that this was more subtle than a dedicated attack 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.

40:40.950 --> 40:53.850
And also, expansion of this functionality could allow one to do things like use dark side attacks or Wi-Fi classic decryption attacks directly on the phone and then deploy them back again to the chip itself.

40:54.310 --> 40:57.990
I found that the same emulation could be performed on any supported protocol.

40:57.990 --> 41:03.590
In fact, I found that the hardware registers I was accessing were the same for every protocol that was used by the chip.

41:03.590 --> 41:09.810
So what was happening was it would switch between different protocols in that hardware by setting a specific setting.

41:09.810 --> 41:19.390
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.

41:19.590 --> 41:24.790
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.

41:25.430 --> 41:35.370
In conclusion, all of the vulnerabilities that I found were outlined to Samsung as of April 2020, or rather they've patched them as of April 2020.

41:35.670 --> 41:39.830
Because of this, the chips won't be vulnerable going forward.

41:39.830 --> 41:46.270
However, all chips that are currently out in the world will be forever, and we can use those to develop custom firmware as needed.

41:46.330 --> 41:53.970
The vulnerability did require root access, so you could not compromise a smartphone using this interface by reflecting data back.

41:53.970 --> 41:56.950
However, it did fully compromise this chip in particular.

41:57.370 --> 42:03.050
We've got to remember that phones are exploitable embedded devices in the same way as any IoT device.

42:03.090 --> 42:07.410
However, of course, they're slightly higher security in some ways, but they really should be treated like that.

42:07.410 --> 42:14.070
The chips in there are often running old bootloaders which will never be changed, and because of this, bootloader vulnerabilities are very common.

42:14.070 --> 42:21.330
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.

42:22.030 --> 42:25.990
Developing custom firmware is a very difficult task sometimes, and can take a lot of time.

42:25.990 --> 42:29.210
However, it can be rewarding, and you can get some very interesting outcomes.

42:29.550 --> 42:34.210
And lastly, if an undisclosed vulnerability is found in an old chip, it'll likely be in a new one.

42:34.210 --> 42:35.510
Thank you very much.

