1 00:00:04,520 --> 00:00:07,860 Hello everyone, thank you very much for having me. Yes, today we're going to be talking about 2 00:00:07,860 --> 00:00:12,440 physical attacks against smartphones. So the crux of this talk is that I was seeing a huge 3 00:00:12,440 --> 00:00:16,700 number of different conference talks about extremely complex attacks against smartphones 4 00:00:16,700 --> 00:00:20,260 due to the high measures of security that are placed on them from the boot level all the way 5 00:00:20,260 --> 00:00:24,860 up to the high level OS. And despite this, there are still times when very simple techniques can 6 00:00:24,860 --> 00:00:28,840 be used to bypass the security on smartphones and escalate privileges or get unauthorized 7 00:00:28,840 --> 00:00:33,900 access in ways that you would consider very simple in a general sense. So we're going to be 8 00:00:33,900 --> 00:00:37,920 doing two 20 minute case studies for this. The first one is going to be gaining root access on 9 00:00:37,920 --> 00:00:41,300 a smartphone with no boot loader unlocking capability. This is where the manufacturer 10 00:00:41,300 --> 00:00:45,240 removes the ability to unlock the boot loader and root it by itself. And the second is going to be 11 00:00:45,240 --> 00:00:49,300 gaining code execution in the boot loader of a Samsung smartphone in order to bypass secure 12 00:00:49,300 --> 00:00:54,980 boot and execute your own kernel and do other malicious things. So case study one, rooting on 13 00:00:54,980 --> 00:00:58,700 a locked boot loader. Essentially I'd bought a brand new phone and wanted to 14 00:00:58,700 --> 00:01:02,120 root my old one so that I could use it for AppSec testing and that sort of thing, install my own 15 00:01:02,120 --> 00:01:07,380 certificates, add for reader, etc. However, on this particular device, the manufacturer had gone 16 00:01:07,380 --> 00:01:11,640 into the code of the boot loader and removed the checks to allow you to access the USB interface. 17 00:01:12,220 --> 00:01:17,700 This meant that I would never be able to get into the fast boot mode and unlock the boot loader, 18 00:01:17,760 --> 00:01:22,720 add root access and that sort of thing. OEMs very rarely do this and they usually just add 19 00:01:22,720 --> 00:01:27,320 restrictions onto the boot loader that requires them to um you to sign up with their services in 20 00:01:27,320 --> 00:01:28,060 order to do this properly. 21 00:01:29,460 --> 00:01:35,180 Um the target device was a smartphone from a Chinese OEM released in 2019 that used an OEM 22 00:01:35,180 --> 00:01:39,640 developed fork of Android which had it's own security features and other um tweaks to it that 23 00:01:39,640 --> 00:01:44,960 were going to be the target of this uh particular project. So while I say that it didn't have 24 00:01:44,960 --> 00:01:48,580 boot loader and unlocking capabilities in the traditional sense, what it did have was a special 25 00:01:48,580 --> 00:01:52,900 engineering app that permitted boot loader unlocking. This used a uh signature stored in a 26 00:01:52,900 --> 00:01:57,240 partition on the device um which was inaccessible to standard users but could then be used by the 27 00:01:57,240 --> 00:02:01,080 special engineering app with special permissions and written into it. And then when the device 28 00:02:01,080 --> 00:02:05,440 rebooted it would give other engineering level access. It was not publicly available although 29 00:02:05,440 --> 00:02:09,320 there were some leaks online and it required an approved user account which was a long winded 30 00:02:09,320 --> 00:02:14,220 process I didn't want to go through. Um so when boot loader unlocking isn't available it's 31 00:02:14,220 --> 00:02:17,500 obvious that you're going to need some kind of exploit in order to escalate privileges to the 32 00:02:17,500 --> 00:02:21,800 root. Um and with no direct access to the boot loader USB interface which is my standard approach 33 00:02:21,800 --> 00:02:26,280 for attacking a device like this, a vulnerability was needed in the Android fork itself. I didn't think 34 00:02:26,280 --> 00:02:30,100 I'd find anything in Android that would be um particularly actionable in this sense and I 35 00:02:30,100 --> 00:02:33,440 thought the changes that had made to it would be probably the area where I'd find the most 36 00:02:33,440 --> 00:02:37,580 critical vulnerabilities I could have used. What I found was the Android fork contained a high 37 00:02:37,580 --> 00:02:42,440 number of custom system and root level applications um which could be potentially exploited in 38 00:02:42,440 --> 00:02:47,820 different ways. Um so the Android fork had a service running at root as root at all times that 39 00:02:47,820 --> 00:02:52,800 was called by the system level applications um for the facilitation of cloud upload and 40 00:02:52,800 --> 00:02:56,260 archiving of um app data. So we would take uh the system level applications um for the 41 00:02:56,280 --> 00:03:01,140 um all the data from the uh users protected um application and cordoned off partitions and 42 00:03:01,140 --> 00:03:04,480 package it all together and upload it to the cloud where it could be downloaded again if needed. 43 00:03:04,880 --> 00:03:08,440 Um brief analysis of this binary found that it had a immediate command injection vulnerability 44 00:03:08,800 --> 00:03:12,480 where if you had a file within the file system with back ticks in the name you could execute 45 00:03:12,480 --> 00:03:17,260 commands within it. Um what would happen is you'd upload this file and then download it again 46 00:03:17,260 --> 00:03:20,960 and as it was restoring the file it would then execute whatever command was in the back ticks. 47 00:03:21,120 --> 00:03:26,260 So very basic. Unfortunately for me Android also employs SE Linux which is an extremely strong 48 00:03:26,280 --> 00:03:30,560 security measure to cordon off different components of the um operating system even if they 49 00:03:30,560 --> 00:03:35,860 are all running as root. This meant that even though I had root access superficially I only had 50 00:03:35,860 --> 00:03:40,860 access to the app data sections of the device rather than having the access to um other 51 00:03:40,860 --> 00:03:46,380 components I wanted to modify. Um I found that pretty much every instance of um a command 52 00:03:46,380 --> 00:03:50,020 injection I could find on the device had a similar issue. So I'd have to find an another way 53 00:03:50,020 --> 00:03:56,260 of getting ex uh escalated privileges. Um most app vulnerabilities are very similar to 54 00:03:56,280 --> 00:04:01,260 the ones that are limited by SE Linux um uh context could probably be bypassed with a kernel 55 00:04:01,260 --> 00:04:04,760 exploit. However a kernel exploit is a very complex thing to do and not something you want to be 56 00:04:04,760 --> 00:04:08,960 doing for a very basic simple project you're just doing in your spare time. Um and as the 57 00:04:08,960 --> 00:04:13,640 boot loader was locked down and the exploit OS exploits were out of the question I decided to go 58 00:04:13,640 --> 00:04:19,700 for my next best option which would be recovery mode on the device. So recovery mode uh uh 59 00:04:19,700 --> 00:04:24,080 mode on an Android device is traditionally is a very very simple menu which you use the volume 60 00:04:24,080 --> 00:04:26,260 buttons and the power button in order to navigate through it. Um the recovery mode on the 61 00:04:26,280 --> 00:04:29,440 navigate through it. I found that on this Android fork they've actually updated this to include 62 00:04:29,440 --> 00:04:33,720 Wi-Fi access, access to more parts of external storage and a few other options as well as 63 00:04:33,720 --> 00:04:36,940 having the touch screen enabled. Which I found was due to the fact that they'd taken their 64 00:04:36,940 --> 00:04:40,780 Android kernel and dumped it into the recovery partition meaning that if I'd gain access to it 65 00:04:40,780 --> 00:04:44,100 I'd have access to all the same hardware components the traditional Android operating system 66 00:04:44,100 --> 00:04:52,180 was. So I wanted to find an update image um for the um uh entire operating system of the device 67 00:04:52,180 --> 00:04:56,260 so that I could extract recovery and then find a simple vulnerability. Unfortunately I 68 00:04:56,280 --> 00:05:01,780 downloaded the updated um the update files for this device found that they never updated the 69 00:05:01,780 --> 00:05:07,140 recovery um partition meaning that I couldn't find it within the operating system. That meant 70 00:05:07,140 --> 00:05:12,940 that um I would have to work out any vulnerabilities blind and just guess and just try things 71 00:05:12,940 --> 00:05:18,080 until something worked. Um so yeah with no recovery image to reverse engineer I just tried very 72 00:05:18,080 --> 00:05:23,020 basic attacks to begin with. Um as the menu option included uh the option to load in these 73 00:05:23,020 --> 00:05:26,260 encrypted zip files the OTA update images I decided to attempt those first. So I decided to attempt 74 00:05:26,280 --> 00:05:31,440 those first. So as I found a command injection vulnerability in the high level operating system I 75 00:05:31,440 --> 00:05:36,100 thought I would probably find one in the recovery image as well. So I took a legitimate encrypted 76 00:05:36,100 --> 00:05:41,400 update file for the device and renamed it to contain backticks and sleep 30,000. What would 77 00:05:41,400 --> 00:05:46,580 happen is if I had successfully executed this command the phone would be spending a few hours 78 00:05:46,580 --> 00:05:51,420 trying to update itself with never succeeding. Um yes and this did indeed cause the update 79 00:05:51,420 --> 00:05:55,220 process to hang demonstrating that I'd found yet another command injection vulnerability in the device. 80 00:05:56,280 --> 00:06:01,020 Um I disclosed all the command injection vulnerabilities I'd found to the OEM who very very 81 00:06:01,020 --> 00:06:05,980 swiftly remediated them and updated new versions to the software. Um but as the recovery mode 82 00:06:05,980 --> 00:06:10,700 command injection was very likely to be running as root and have no restrictions on it this would 83 00:06:10,700 --> 00:06:16,680 be a good basis for me to then gain further root access to Android. So I started with root cause 84 00:06:16,680 --> 00:06:20,920 analysis just so I could get out of the way and found that it was a SHA1 sum check um for some 85 00:06:20,920 --> 00:06:26,260 logging that was checking um data on the uh uh the SHA1 sum of the update file um which was a 86 00:06:29,720 --> 00:06:36,340 very basic um as there was a command injection vulnerability in the file name um this could 87 00:06:36,340 --> 00:06:41,660 probably be used to update a more complex script. So if I wrote a more complex script a base 64 88 00:06:41,660 --> 00:06:46,460 encoded it and piped it into a system bin SH um a shared shell script could then be loaded 89 00:06:46,460 --> 00:06:50,440 that's more complex from the file system and executed. So this um script here literally just 90 00:06:50,440 --> 00:06:56,180 cuts from the user data partition a much more complex script that can be used. Unfortunately, 91 00:06:56,280 --> 00:07:00,040 the file system that used by Android's user data does not support all special characters for 92 00:07:00,040 --> 00:07:05,120 instance the pipe character I would need to perform this exploit. So I would have to find a way 93 00:07:05,120 --> 00:07:09,760 around this. Luckily I found that they had modified the um recovery image to also support 94 00:07:09,760 --> 00:07:14,860 EXT4 file systems which is rare on Android. And usually when you put in an EXT4 um SD card 95 00:07:14,860 --> 00:07:20,160 into an Android device it says unsupported um file system and then tries to format it. Um 96 00:07:20,160 --> 00:07:23,960 luckily for me it didn't do that so I could just load my more complex update file onto that and 97 00:07:23,960 --> 00:07:24,460 execute it. 98 00:07:26,280 --> 00:07:30,380 So I wanted to get a more concrete shell on the device so I would have a look around and 99 00:07:31,260 --> 00:07:36,740 also work out what was going on in a more accessible manner. So what I did was I ran 100 00:07:36,740 --> 00:07:41,400 the ID command and ran it into the user data partition so that if I wanted to reboot the 101 00:07:41,400 --> 00:07:45,480 phone I would then find it was running ID root or ID system or whatever was going on. I 102 00:07:45,480 --> 00:07:49,640 also wanted to see if I could disable SC Linux to bypass all of the contacts that were there 103 00:07:49,640 --> 00:07:53,260 and found that that also worked. And then I also wanted to enable ADB on the device so I 104 00:07:53,260 --> 00:08:00,540 had a root shell into recovery which also worked quite well. Um so root access and recovery 105 00:08:00,540 --> 00:08:07,580 mode is great but you've then got a phone that's in a very not very fairly fleshed out mode. I 106 00:08:07,580 --> 00:08:12,240 can't access any apps from there, I can't modify my files in any real way and I can't usually 107 00:08:12,240 --> 00:08:17,940 access the internet, Bluetooth or anything like that. Um what I wanted to do was find a way to 108 00:08:17,940 --> 00:08:22,180 switch from recovery to Android without ever having to reboot the device and go to the 109 00:08:22,180 --> 00:08:23,240 bootloader. Because as soon as I got to the bootloader I had to reboot the device and go to 110 00:08:23,240 --> 00:08:26,400 recovery mode. And as soon as I do that I would lose my shell on the device because there was 111 00:08:26,400 --> 00:08:31,320 no persistence in an attack like this. My first port of call was to try to use KEXEC. Now 112 00:08:31,320 --> 00:08:36,980 KEXEC is a um kernel um component which allows you to load a new Linux kernel onto a Linux 113 00:08:36,980 --> 00:08:42,680 uh device and then execute that. Essentially switching from one Linux kernel to another. Um if 114 00:08:42,680 --> 00:08:45,460 I could do that that would be a very quick way for me to switch to the Android kernel and 115 00:08:45,460 --> 00:08:50,400 everything else. But unfortunately even compiling the module from scratch was blocked because it 116 00:08:50,400 --> 00:08:53,220 was using some um deny listed um uh code. Um so that was a very quick way for me to switch to the 117 00:08:53,220 --> 00:08:57,700 uh uh module components. So I just tried to do something, decided to try to do something that 118 00:08:57,700 --> 00:09:03,440 was in the user space rather than in the kernel itself. Luckily there was Ptrace. Now Ptrace is a 119 00:09:03,440 --> 00:09:08,960 system call allowing one process to observe and control another for debugging purposes. Um so 120 00:09:09,330 --> 00:09:14,480 typically this is for things like um logging and tracking and debugging on things that run on the 121 00:09:14,480 --> 00:09:19,800 operating system and doing things like you know the strace command within Linux. Um it can even 122 00:09:19,800 --> 00:09:23,200 um modify memory that is um write denied. Um it can even um modify memory that is um right denied 123 00:09:23,220 --> 00:09:27,760 um in the standard processes. Um which means you can modify running code even if they are not 124 00:09:27,760 --> 00:09:31,580 meant to be able to do that in the particular um ELF that you're working with. What I wanted to do 125 00:09:31,580 --> 00:09:36,900 was use Ptrace to essentially latch onto the init process and restart that but in the Android 126 00:09:36,900 --> 00:09:43,840 context. So init is um always process ID one um which uh means that it has some special 127 00:09:43,840 --> 00:09:49,280 privileges within Linux and also it has a lot of control over the rest of the system. Um what I 128 00:09:49,280 --> 00:09:53,200 wanted to do was use the execv key command which um executes a command um which um executes a command 129 00:09:53,220 --> 00:09:58,900 within one process that uses the same process ID to run more commands that would then get me to 130 00:09:58,900 --> 00:10:05,480 switch out init. Um luckily for me if I did this I could um execute uh init but never have to 131 00:10:05,480 --> 00:10:08,900 return back to it. I could just keep things going. There's one long process switching from one 132 00:10:08,900 --> 00:10:13,620 set of data to the other. Um and this could be very trivially done with a bit of uh um assembly 133 00:10:13,620 --> 00:10:20,240 code. So just moving in the parameters and then executing the service call. Um switch root is 134 00:10:20,240 --> 00:10:23,200 what's used during the boot process usually to switch from the init to the boot process. So 135 00:10:23,220 --> 00:10:28,400 the um the ram disc which contains some of the lower level stuff um for mounting the more 136 00:10:28,400 --> 00:10:33,560 complex file systems um into the new one. Uh it's a very common feature on Linux based devices 137 00:10:33,560 --> 00:10:39,380 and what I intended to do was switch from one init ram fs to the android init ram fs which 138 00:10:39,380 --> 00:10:45,960 would then load into the system operating system. Uh this could be very easily done if I 139 00:10:45,960 --> 00:10:50,060 just uh mounted a new ram disc and then loaded the data in and then hopefully I could then 140 00:10:50,060 --> 00:10:53,200 switch instead if I needed. So the process for uh uh uh uh uh uh uh uh uh uh uh uh uh uh uh uh uh 141 00:10:53,200 --> 00:10:56,100 uh uh uh oh init usually looks like this on Android. You do have the init process that 142 00:10:56,100 --> 00:10:59,200 starts as 1 then it sets up sc THEM warned me about annuance and then in its second stage 143 00:10:59,200 --> 00:11:02,520 which has all the hardware and everything and that's where the process sits most of the 144 00:11:02,520 --> 00:11:09,060 time. And essentially what I wanted to do was inject in a switch root command into init which 145 00:11:09,060 --> 00:11:13,400 would then start the whole process again killing the old recovery process and introducing the 146 00:11:13,400 --> 00:11:18,940 new one that was running android. Um there were a few caveats with this however because um 147 00:11:19,940 --> 00:11:23,180 the ones really intended to switch from one init ram fas to another and I've got a couple of 148 00:11:23,200 --> 00:11:25,520 and you're meant to reboot to get into other systems like this. 149 00:11:26,280 --> 00:11:29,560 So a core component of SwitchRoot is the remounting of mounted folders. 150 00:11:30,240 --> 00:11:33,820 However, most of the mounted folders that occur in Android at this point are shared. 151 00:11:34,040 --> 00:11:37,780 This means they're handled in slightly different ways than how you expect 152 00:11:37,780 --> 00:11:40,180 when it comes to things like moving the mounts to different places. 153 00:11:40,580 --> 00:11:43,300 However, this could be trivially resolved by just writing a small shell script 154 00:11:43,300 --> 00:11:45,740 that went through all the mounts, found out if they were shared, 155 00:11:45,860 --> 00:11:47,100 and made them private instead. 156 00:11:47,320 --> 00:11:49,860 And private means they could be moved around wherever I wanted 157 00:11:49,860 --> 00:11:50,600 within the file system. 158 00:11:51,700 --> 00:11:56,160 Also, I found that the init binary was checking prop command line 159 00:11:56,160 --> 00:12:00,920 within the file system for whether the image required SELinux to be enabled. 160 00:12:01,220 --> 00:12:05,060 And if it did, and it found it was disabled, it would enable SELinux, 161 00:12:05,620 --> 00:12:07,820 forcibly re-enabling it, even though I'd disabled it. 162 00:12:09,040 --> 00:12:12,140 Luckily for me, ptrace allows you to override system calls, 163 00:12:12,360 --> 00:12:16,220 so I modified the read system call whenever it touched the prop command line file 164 00:12:16,800 --> 00:12:20,380 to override the check for enforcing SELinux with one that allowed it 165 00:12:20,380 --> 00:12:20,580 to be disabled. 166 00:12:20,600 --> 00:12:25,420 I also found that this caused a lot of kernel panics, 167 00:12:25,460 --> 00:12:28,400 because init also does all the system hardware services set up. 168 00:12:29,160 --> 00:12:32,080 This includes things like saying the Wi-Fi interface, Bluetooth, etc. 169 00:12:33,040 --> 00:12:36,980 But the recovery operator side of things had already done this, 170 00:12:37,040 --> 00:12:39,260 so doing this again caused the kernel to not really know what to do. 171 00:12:40,360 --> 00:12:43,320 What I did was, in the same way as I've done with prop command line, 172 00:12:43,420 --> 00:12:46,380 just make it return empty files whenever it tried to access these .rc files. 173 00:12:46,680 --> 00:12:49,820 I did this because then I wouldn't have to modify them within the file system, 174 00:12:49,920 --> 00:12:50,580 which would require a lot of work. 175 00:12:50,600 --> 00:12:52,820 This would cause the device to not be able to work in a non-routed manner. 176 00:12:54,920 --> 00:12:58,540 I also found that when I tried to unlock my phone after getting through this entire process 177 00:12:58,540 --> 00:13:01,220 and getting it to boot, that I could no longer use my pin, 178 00:13:01,380 --> 00:13:04,700 because all of the security services were still running in the recovery context. 179 00:13:05,300 --> 00:13:08,700 Luckily for me, I could just kill all these processes and let init restart them again, 180 00:13:08,820 --> 00:13:10,680 right as I was starting this whole process up. 181 00:13:13,800 --> 00:13:16,840 While this is pretty much a read-only process, and if I rerouted the device, 182 00:13:16,880 --> 00:13:20,580 I'd lose all of this root access, what I could do was still overwrite it, 183 00:13:20,580 --> 00:13:21,800 and overwrite some read-only files. 184 00:13:22,080 --> 00:13:27,840 The system partition, which stores a lot of the system data, is a read-only file system, 185 00:13:28,020 --> 00:13:33,960 and it uses dm-verity to make sure it's got appropriate signatures working throughout the file system. 186 00:13:34,520 --> 00:13:41,100 However, if you use the mount-dash-dash bind command, you can override the files there temporarily with your own, 187 00:13:41,200 --> 00:13:46,080 meaning that if I wanted to modify, for instance, the frameworks which had root detection in and things like that, 188 00:13:46,200 --> 00:13:50,160 I just needed to do that temporarily, and it would work without damaging the device in any way. 189 00:13:52,000 --> 00:13:55,280 So, we're going to do a quick demo of this boot process now before we move on to the next one. 190 00:13:58,060 --> 00:13:59,920 So, hopefully this won't go to the next one. 191 00:14:03,600 --> 00:14:05,020 So, brilliant, sorry guys. 192 00:14:06,640 --> 00:14:12,400 As you can see, I've just pressed my little command there, and now it's now running through the init process. 193 00:14:12,800 --> 00:14:18,180 It then kills recovery, which was running the screen at that point, and starts the Android process booting up. 194 00:14:18,400 --> 00:14:18,760 So, 195 00:14:18,760 --> 00:14:22,700 then starting the full Android operating system and giving me root access. 196 00:14:23,040 --> 00:14:27,040 I also found that turning off the phone when I started this, I'd need to reboot the screen, 197 00:14:27,220 --> 00:14:29,060 otherwise I couldn't use the touch screen. 198 00:14:32,800 --> 00:14:35,640 And then, yeah, I have a telnet root backdoor into the device. 199 00:14:40,620 --> 00:14:41,420 Thank you. 200 00:14:46,580 --> 00:14:48,740 So, I observed something quite interesting afterwards. 201 00:14:48,760 --> 00:14:52,620 I was quite happy to have root access, but I realized that during the debugging process, 202 00:14:52,820 --> 00:14:57,520 I'd kept a BusyBox telnet server within the recovery context of the device. 203 00:14:57,960 --> 00:15:04,340 And when I'd remounted the new init RAMFS, I'd found that the old recovery one was still sitting in memory and accessible. 204 00:15:04,680 --> 00:15:09,040 So, there was a telnet service running in a file system that Android had no idea about. 205 00:15:10,180 --> 00:15:13,480 Switch root had deleted all the files within this file system because it was stored in RAM, 206 00:15:13,640 --> 00:15:17,100 but just using BusyBox, I could repopulate all the tools, and it gave me this, like, 207 00:15:17,100 --> 00:15:21,020 secret little section of the device which Android didn't really have access to. 208 00:15:23,040 --> 00:15:26,720 Because it was hidden from Android, I could do a lot of interesting things accessing the hardware and stuff, 209 00:15:26,940 --> 00:15:30,680 but I could also access the rest of Android itself without Android knowing that I was there. 210 00:15:30,940 --> 00:15:36,780 So, by CDing or shrooting into the directory proc1root, which was the root file system that the init process is using, 211 00:15:37,360 --> 00:15:42,340 recovery could access the Android root file system as root without Android knowing about it, which was fantastic. 212 00:15:43,200 --> 00:15:47,080 What I decided to do was expand this out, however, and add a whole Debian root file system, 213 00:15:47,100 --> 00:15:52,660 to the device, giving me a lot of debugging and testing tools I could also use to continue to compromise the device in further ways. 214 00:15:54,740 --> 00:15:58,000 So, in conclusion, root access by this method was very consistent. 215 00:15:58,180 --> 00:16:04,280 I left the thing running with the init parasite ptrace tool attached to it for days at a time without any crashes. 216 00:16:04,380 --> 00:16:06,800 It would just keep running and running and running and no problem whatsoever. 217 00:16:07,480 --> 00:16:11,500 I also found that just by rebooting the device, I had no real effects and it could operate normally, 218 00:16:11,620 --> 00:16:16,500 going back to a standard non-rooted device with no awareness that I'd manipulated in this way. 219 00:16:16,500 --> 00:16:21,700 And I also found that the biggest benefit for this whole project was having ptrace there. 220 00:16:22,320 --> 00:16:25,160 So, if you're compiling a kernel, do remove that if you need to. 221 00:16:26,460 --> 00:16:29,720 Now we move on to the second case study, which is a bit more technical and a bit more exciting, 222 00:16:29,860 --> 00:16:35,280 because we're not going for a device that I wanted to root for my own purposes, but I just wanted to exploit in some way. 223 00:16:36,320 --> 00:16:40,980 So, Exynos-based devices have had a significant amount of research done on them on this stage, 224 00:16:41,120 --> 00:16:46,380 and at Black Hat as well in previous years, but they all focused on the download mode of the bootloader. 225 00:16:46,380 --> 00:16:53,900 So, this is a high-level protocol used by Samsung to write and read files in different ways and debug the device and unbrick it in many ways. 226 00:16:54,660 --> 00:17:02,860 Because it all focused on the high-level download protocol, I decided to start a project to try and manipulate the low-level USB stack that was in use, 227 00:17:03,020 --> 00:17:06,660 to see if I could find a vulnerability that was as actionable as what had already been found. 228 00:17:07,660 --> 00:17:11,880 For this, I found the cheapest Samsung device I could that was still of decent quality and modern, 229 00:17:11,940 --> 00:17:16,060 which was a Samsung Galaxy A04s, which was actually quite a decent phone after I bought it. 230 00:17:16,380 --> 00:17:19,740 It was released in August 2022 and used an Exynos 850 chipset, 231 00:17:19,840 --> 00:17:25,460 and I knew that it would be quite an interesting target because it had a lot of the security features like Knox in place 232 00:17:25,460 --> 00:17:29,140 that more expensive, more modern, or more higher-end Samsung devices do. 233 00:17:30,800 --> 00:17:34,740 So, the secondary bootloader, which is what I was going for with this project, is called S-Boot in Samsung, 234 00:17:34,940 --> 00:17:39,680 and it facilitates a few things. It facilitates standard boot from the primary bootloader all the way up to Android. 235 00:17:40,040 --> 00:17:43,200 It facilitates download mode, which was the protocol we were just talking about. 236 00:17:43,480 --> 00:17:45,500 On my device, it also had fast boot mode, 237 00:17:46,380 --> 00:17:49,260 which is the standard Android administration's bootloader tool, 238 00:17:49,380 --> 00:17:53,860 and upload mode, which is what's usually found when you hit an unrecoverable error in some way. 239 00:17:54,240 --> 00:17:58,220 All of this was encompassed in a single firmware binary called S-Boot.bin, 240 00:17:59,760 --> 00:18:03,660 but because of this, I thought all three USB protocols, so download, fast boot, and USB, 241 00:18:03,940 --> 00:18:07,780 would probably be using the core USB stack underneath, which, if I could find a vulnerability in, 242 00:18:07,920 --> 00:18:09,940 I would have broken all of those in one go. 243 00:18:11,720 --> 00:18:16,260 So, when I'm talking about the core USB stack, I'm talking about USB control transfer. 244 00:18:16,380 --> 00:18:19,440 So, control transfers are used to send and receive, like, debugging information, 245 00:18:19,700 --> 00:18:22,660 or not debugging information, configuration information about the device. 246 00:18:22,960 --> 00:18:27,360 Sometimes it's used for more complex things, for instance, iPhones, DFU modes also use control transfers, 247 00:18:27,500 --> 00:18:31,020 but generally there's a very standardized approach for these, and they use standard parameters, 248 00:18:31,140 --> 00:18:35,360 which are BM request type, B request, W value, W index, buffer, and buffer size. 249 00:18:37,180 --> 00:18:43,540 So, what I really wanted to do was just fuzz it and find an actual exploit just by running a very basic fuzzer. 250 00:18:43,680 --> 00:18:46,160 Now, control transfers are mostly, 251 00:18:46,380 --> 00:18:49,640 extremely stateless, they do their own thing, you read and write data, 252 00:18:49,760 --> 00:18:52,260 and at a very high level, there's just not much else you need to do. 253 00:18:52,620 --> 00:18:57,840 And with this, you can just randomize all the parameters and send a randomized buffer size with randomized data in it, 254 00:18:57,880 --> 00:18:59,100 and see what happens. 255 00:18:59,440 --> 00:19:05,080 So, as you can see there, my very complex fuzzer, you know, way better than, you know, AFL, 256 00:19:05,100 --> 00:19:07,700 of rand, rand, rand, rand, rand for every parameter. 257 00:19:08,300 --> 00:19:11,700 And as you can see on the right, when I was running this, you'll see the minus nine errors, 258 00:19:11,760 --> 00:19:15,300 which are libUSB errors, which is where the device has gone, I don't know what the hell to do with this. 259 00:19:15,300 --> 00:19:18,480 All the ones without the minuses is where data has been transferred back and forth. 260 00:19:18,640 --> 00:19:20,300 So, very simple to keep track of. 261 00:19:20,460 --> 00:19:25,560 However, during my initial fuzzing attempts, I was sending purely random data, 262 00:19:25,720 --> 00:19:29,120 and it caused the device to reboot into a failure mode I couldn't recover from. 263 00:19:29,260 --> 00:19:31,160 Every time I tried to reboot, it said the same thing. 264 00:19:31,300 --> 00:19:36,380 An error has occurred updating the device software, and I thought I'd now got a brick on my hands. 265 00:19:36,960 --> 00:19:40,600 This occurred when the 0xf6 value was sent as the bRequest parameter, 266 00:19:40,880 --> 00:19:43,700 which was very interesting, because I didn't know why that would be, 267 00:19:43,760 --> 00:19:45,280 because it's not a standard command or anything like that. 268 00:19:45,300 --> 00:19:52,680 However, I found it was recoverable back to a working device by using the download mode tool. 269 00:19:52,840 --> 00:19:57,420 So I used the command line tool in Heimdall, which is an open source tool for manipulating download mode 270 00:19:57,420 --> 00:20:00,520 that's accessible on GitHub, and as soon as I tried to do anything with that tool, 271 00:20:00,620 --> 00:20:03,560 the device decided it was working again, so clearly it just didn't like my tool. 272 00:20:05,480 --> 00:20:08,300 So, I kept fuzzing and fuzzing and fuzzing for about half an hour, 273 00:20:08,380 --> 00:20:11,920 and found that the device would crash and reboot after a certain set of transfers. 274 00:20:12,300 --> 00:20:14,920 Luckily, I had a seed in this fuzzing, so I knew exactly what could be done, 275 00:20:14,920 --> 00:20:18,500 and I could just run the whole on-target fuzz again and see what happened. 276 00:20:18,820 --> 00:20:21,580 And what I did was essentially remove transfers in the sequence 277 00:20:21,580 --> 00:20:24,340 to see which ones were actually causing the crash in the first place. 278 00:20:24,440 --> 00:20:31,260 So, I essentially got that down to two control transfers after about 10,000, which was nice. 279 00:20:31,620 --> 00:20:35,000 So, the first transfer was a malformed get descriptor request, 280 00:20:35,200 --> 00:20:39,140 so in that instance it's got get, and it was sending data instead of receiving it. 281 00:20:39,420 --> 00:20:43,200 And the second was a valid get descriptor request, which was causing the crash. 282 00:20:44,920 --> 00:20:47,780 Now, get descriptor is a core component of the USB stack, 283 00:20:48,020 --> 00:20:50,800 and it's control transfers that retrieves descriptors about the device. 284 00:20:51,080 --> 00:20:56,020 These are configuration data, which includes things like strings about who manufactured the device, 285 00:20:56,560 --> 00:20:59,340 IDs, and also what the device does, which is very nice. 286 00:20:59,960 --> 00:21:04,900 In these descriptors, the first byte of the data is always going to be the size of the buffer itself, 287 00:21:05,080 --> 00:21:07,740 so you can see B length is 18, which is the size. 288 00:21:07,980 --> 00:21:14,360 And if you can overwrite this, you can then make your memory access push into the linked list next to it, 289 00:21:14,360 --> 00:21:16,340 which is where the other descriptors are stored, usually. 290 00:21:19,300 --> 00:21:25,340 So, what's interesting is most USB stacks don't check the control transfer direction. 291 00:21:25,960 --> 00:21:29,840 They're usually protected by how their own USB hardware works, so they have send and receive functions. 292 00:21:30,240 --> 00:21:33,680 So, for instance, in this case, this is the STM32 USB D stack, 293 00:21:34,150 --> 00:21:41,580 where if you send it a get device descriptor request, it will explicitly send a control send data request to its own hardware, 294 00:21:41,660 --> 00:21:43,620 meaning that it can't receive data back from it. 295 00:21:44,360 --> 00:21:50,960 However, in this instance, I could send data to it, meaning that I had full control overwriting data in memory, 296 00:21:51,080 --> 00:21:51,820 which was very nice. 297 00:21:53,020 --> 00:21:58,120 So, what I did was try to overwrite that first byte, just by sending data to the same memory that was there. 298 00:21:58,380 --> 00:22:00,600 However, this was ineffective, and it did change the byte. 299 00:22:00,820 --> 00:22:03,080 However, it didn't alter the size of the data received. 300 00:22:03,580 --> 00:22:06,840 Luckily for me, there was just a buffer overflow there anyway, so I was quite happy. 301 00:22:08,340 --> 00:22:12,140 Because of this, the data next to the buffer could be overwritten, but I didn't know what was there yet. 302 00:22:12,140 --> 00:22:14,840 But I could just try and guess. 303 00:22:16,000 --> 00:22:23,040 So, by sending a large buffer that caused the device to crash, I knew that I had a traditional buffer overflow hitting something. 304 00:22:23,380 --> 00:22:29,040 So, I decided to do a binary check until I found a data size that didn't cause the device to crash. 305 00:22:29,380 --> 00:22:33,640 Then I made that size one byte larger and saw if it crashed. 306 00:22:33,840 --> 00:22:39,040 And then, if it did crash, changed the value of that last byte, incrementing by one, until I found a value that didn't crash. 307 00:22:39,500 --> 00:22:42,020 Essentially, I was brute forcing my way up the adjacent memory. 308 00:22:42,140 --> 00:22:45,560 Until I found fully working memory that I could then manipulate if I wanted. 309 00:22:46,160 --> 00:22:51,180 What was excellent about this was that next to it was a linked list, which included pointers to other descriptors, 310 00:22:51,260 --> 00:22:52,620 which would then be overwritten themselves. 311 00:22:53,020 --> 00:22:54,900 And this had two key benefits to me. 312 00:22:55,020 --> 00:22:57,800 Number one, this could be used for a cold boot attack. 313 00:22:58,020 --> 00:23:02,500 So, for instance, if I had someone's Samsung phone and rebooted it, the memory wouldn't be cleared at that time. 314 00:23:02,620 --> 00:23:06,580 And I could dump the entirety of memory, EL1, so all of the external RAM, 315 00:23:06,760 --> 00:23:10,840 and then get their secrets out of it, something they'd been typing, anything that was stored in RAM at that time. 316 00:23:10,840 --> 00:23:15,000 The second thing I could do was write all of that data as well, including to the bootloader. 317 00:23:16,360 --> 00:23:21,560 So, the first thing I did was dump memory of the device, so I knew the memory layout of the bootloader itself, 318 00:23:21,720 --> 00:23:22,940 so I could then manipulate it later. 319 00:23:23,440 --> 00:23:28,420 So, I found that all of the pointers I was looking at were between OXF9 and the six zeros, 320 00:23:28,580 --> 00:23:30,440 and OXF8 and six zeros. 321 00:23:30,820 --> 00:23:37,180 So, I made a memory dump of a bit of data right before that, just to see if I could find the code of the bootloader itself right next to the RAM, 322 00:23:37,340 --> 00:23:38,040 which is what I expected. 323 00:23:38,600 --> 00:23:40,460 Luckily for me, the bootloader co-starter, 324 00:23:41,880 --> 00:23:43,240 OXF88 and five zeros, 325 00:23:43,660 --> 00:23:47,400 which meant that I could then dump it and just statically analyze it in Ghidorah if I needed to. 326 00:23:49,400 --> 00:23:51,400 What I really wanted to do was get code execution, 327 00:23:51,700 --> 00:23:55,880 so I could then modify the functionality of the device to pass secure boot, 328 00:23:56,040 --> 00:23:59,080 and get a bit more access to things, modify the kernel, etc. 329 00:24:00,020 --> 00:24:03,560 But I found that they'd actually implemented DEP on the device, so data execution prevention, 330 00:24:03,840 --> 00:24:06,480 meaning that I couldn't overwrite the code in the bootloader in RAM, 331 00:24:06,660 --> 00:24:09,720 because the memory management unit had disabled this. 332 00:24:10,840 --> 00:24:13,220 When I tried this, it caused the device to hang, because it hit a hardware error, 333 00:24:13,740 --> 00:24:14,900 implying that it was configured well. 334 00:24:16,100 --> 00:24:22,320 However, I found that attempting to execute code outside of the code that had been allocated for the bootloader was possible. 335 00:24:22,480 --> 00:24:25,560 So, if I just dumped a bunch of code just outside of what had been mapped already, 336 00:24:25,840 --> 00:24:29,240 I could execute code from anywhere at the same exception level as the bootloader itself. 337 00:24:31,100 --> 00:24:33,780 So, with this, I could patch in new functions if I wanted to, 338 00:24:33,880 --> 00:24:36,980 and when I'm writing even next-works for bootloaders, I like doing this in C. 339 00:24:37,220 --> 00:24:39,600 And just by using the GCC static no lib flags, 340 00:24:39,600 --> 00:24:43,400 and using object copy, you can create a raw binary of any functions you're writing, 341 00:24:43,540 --> 00:24:45,220 as long as you're not using standard libraries. 342 00:24:45,440 --> 00:24:47,360 So, you would have to re-implement memcopy, 343 00:24:47,400 --> 00:24:50,580 but you've still got a lot of ease over writing ARM assembly all day. 344 00:24:51,860 --> 00:24:54,280 And because I could write these directly into memory, 345 00:24:54,440 --> 00:24:57,900 if I wanted to then write into the stack to point to them, that would be very easy as well, 346 00:24:58,000 --> 00:24:59,000 but I had another idea instead. 347 00:25:00,900 --> 00:25:03,260 So, fastboot mode was used as the basis of this exploit, 348 00:25:03,400 --> 00:25:04,960 because I just really like fastboot mode, 349 00:25:05,080 --> 00:25:09,120 but also because it uses string-based commands for all of its administration. 350 00:25:09,600 --> 00:25:13,000 So, what you'll find on bootloaders using fastboot, 351 00:25:13,080 --> 00:25:16,260 is there will be a table of strings for the commands themselves, 352 00:25:16,480 --> 00:25:17,860 and then pointers to specific functions. 353 00:25:18,260 --> 00:25:21,440 And this is usually stored in writable RAM, regardless of where it is, 354 00:25:21,540 --> 00:25:23,120 because they're loaded in via other functions. 355 00:25:23,500 --> 00:25:26,460 And by modifying this table, it would allow me to have easy code execution, 356 00:25:27,100 --> 00:25:29,800 without modifying the stack, without having to do other complex things. 357 00:25:30,260 --> 00:25:32,760 I found that fastboot in this instance wasn't really used for administration, 358 00:25:33,280 --> 00:25:36,340 it only had two commands, which were get variable, which had system variables, 359 00:25:36,560 --> 00:25:38,660 and reboot, which would reboot the device. 360 00:25:38,660 --> 00:25:40,320 So, I chose get variable, because it was easier. 361 00:25:41,540 --> 00:25:43,120 So, the table usually looks like this, 362 00:25:43,160 --> 00:25:46,640 so you have an address pointing to the string, so reboot, 363 00:25:46,860 --> 00:25:48,660 and then address pointing to the function itself. 364 00:25:48,980 --> 00:25:53,980 This would mean that if there were any really complex things like stack canaries in place, 365 00:25:54,060 --> 00:25:55,540 where I could still bypass them very easily, 366 00:25:55,680 --> 00:25:57,040 they wouldn't be a problem at this point, 367 00:25:57,120 --> 00:26:01,540 because I was actually going to see someone loading in the address itself and execute them. 368 00:26:04,740 --> 00:26:07,860 Because I had code execution, it meant that secure boot bypass would be possible. 369 00:26:09,140 --> 00:26:12,260 So, I could then modify the kernel without hopefully tripping knocks, 370 00:26:12,520 --> 00:26:16,320 and add malicious code into someone's phone when it was booting, 371 00:26:16,340 --> 00:26:18,180 and do other interesting things. 372 00:26:18,440 --> 00:26:20,540 However, I found that none of the USB-based modes, 373 00:26:20,620 --> 00:26:21,780 so fastboot, download, et cetera, 374 00:26:21,960 --> 00:26:24,620 had the capability of just booting the phone itself, 375 00:26:24,820 --> 00:26:27,160 which would be a good thing to hook into for this particular attack. 376 00:26:27,700 --> 00:26:31,760 What I would have to do was call into the boot functionality 377 00:26:31,760 --> 00:26:33,440 that was already there for the standard boot mode. 378 00:26:33,640 --> 00:26:35,800 However, I found that this crashed the phone itself, 379 00:26:36,440 --> 00:26:38,580 which meant that I would actually have to implement boot function 380 00:26:38,660 --> 00:26:39,720 functionality in a bootloader myself. 381 00:26:41,060 --> 00:26:43,320 So, there are two options for re-implementing the boot process. 382 00:26:43,540 --> 00:26:46,260 The first was to copy the entirety of working memory from the bootloader 383 00:26:46,260 --> 00:26:47,920 and put it somewhere where I could modify as I wanted to, 384 00:26:48,320 --> 00:26:50,500 or just re-implement the boot functionality from scratch, 385 00:26:50,700 --> 00:26:52,000 calling in functions that I needed to, 386 00:26:52,060 --> 00:26:56,320 to things like set up the hardware, set up the TE, et cetera, et cetera. 387 00:26:56,760 --> 00:27:00,220 I chose the latter because it would be a lot easier for me to debug things, 388 00:27:00,380 --> 00:27:02,440 but also because there was a lack of writable memory at this point, 389 00:27:02,460 --> 00:27:03,060 because of all I was doing. 390 00:27:05,520 --> 00:27:08,640 So, functions in the bootloader could trivially be called by apps, 391 00:27:08,660 --> 00:27:09,420 and actually addresses in C. 392 00:27:09,580 --> 00:27:10,600 So, in C, you can literally say, 393 00:27:10,660 --> 00:27:12,100 I want to call a function at this address, 394 00:27:12,280 --> 00:27:13,900 and it will load it in and branch into them. 395 00:27:13,980 --> 00:27:16,020 And you can give it parameters, and that's what I wanted to do, 396 00:27:16,060 --> 00:27:20,680 so that I could just load in and check things that didn't work right, et cetera, 397 00:27:20,800 --> 00:27:23,520 or change parameters, or just remove functionality I didn't need. 398 00:27:23,600 --> 00:27:26,860 For instance, if the bootloader had already executed certain hardware setup, 399 00:27:27,220 --> 00:27:28,800 I wouldn't have to modify that anymore. 400 00:27:29,500 --> 00:27:31,160 So, I could literally cut down everything 401 00:27:31,160 --> 00:27:33,320 until I had the bare bones of a boot process for myself. 402 00:27:35,420 --> 00:27:37,660 What was really lucky for me was that the bootloader contained 403 00:27:37,660 --> 00:27:39,580 a huge number of print tests throughout it for debugging, 404 00:27:39,780 --> 00:27:42,040 saying things like, oh, we're setting up this, this has failed, et cetera, 405 00:27:42,200 --> 00:27:46,060 which were all written into RAM address 0xf0070s. 406 00:27:46,820 --> 00:27:50,200 By comparing my boot implementation to one that had worked legitimately, 407 00:27:50,500 --> 00:27:52,680 I could literally do a one-to-one comparison of what was broken, 408 00:27:52,840 --> 00:27:56,560 and then check down the until I had a boot process 409 00:27:56,560 --> 00:28:00,400 that looked almost identical superficially from the spring's perspective, 410 00:28:00,620 --> 00:28:01,380 which was really nice. 411 00:28:03,800 --> 00:28:05,440 Then, at the end of this whole boot process, 412 00:28:05,540 --> 00:28:07,020 of course, it would have to jump into the kernel. 413 00:28:07,660 --> 00:28:09,900 I found that on the bootloader, it was using KSLR, 414 00:28:10,020 --> 00:28:12,360 so it was putting the kernel at a randomized address within memory, 415 00:28:12,520 --> 00:28:15,500 but I also found that that randomized address was stored at a static pointer, 416 00:28:15,660 --> 00:28:17,860 which I could just load off and then execute into it, 417 00:28:18,580 --> 00:28:19,920 which was nice and easy. 418 00:28:21,180 --> 00:28:24,320 However, I found that even booting into the kernel had some problems. 419 00:28:24,520 --> 00:28:26,760 So, after I'd patched in all of what I thought were the appropriate functions, 420 00:28:27,380 --> 00:28:28,920 I wanted to execute the kernel. 421 00:28:29,020 --> 00:28:31,180 However, it started at the start of the process, 422 00:28:31,300 --> 00:28:33,460 it showed the boot screen and looked like it was going to start, 423 00:28:33,560 --> 00:28:35,120 and then hung and never started Android. 424 00:28:35,680 --> 00:28:37,640 However, I realized that because I'd already been modulating it, 425 00:28:37,660 --> 00:28:38,880 and modified the boot code like this, 426 00:28:39,000 --> 00:28:42,920 and because the MMU was still in a position where the kernel code was writable, 427 00:28:43,320 --> 00:28:45,380 I could modify the kernel after it started 428 00:28:45,380 --> 00:28:48,020 in order to see what was going on and remove security components 429 00:28:48,020 --> 00:28:52,400 or harder initialization components to see what was actually going on 430 00:28:52,400 --> 00:28:54,280 and hopefully find the thing that was causing a crash. 431 00:28:56,320 --> 00:29:00,740 After doing a bit of analysis by knocking out functions within the kernel itself, 432 00:29:00,940 --> 00:29:06,000 I found that the device was freezing after the kernel reinitialized the MMU, 433 00:29:06,000 --> 00:29:10,120 a key component of the kernel is it reinitializes a lot of the hardware registers 434 00:29:10,120 --> 00:29:12,880 that the bootloader has already done because they're not necessary anymore. 435 00:29:13,240 --> 00:29:17,460 And so as soon as it was reinitializing the MMU with its own rearrangement of the memory, 436 00:29:17,580 --> 00:29:19,840 so setting up things like for kernel memory protection and things, 437 00:29:20,420 --> 00:29:22,280 it was causing the rest of the device to hang. 438 00:29:22,500 --> 00:29:25,640 And the reason for that was most likely going to be that the bootloader itself 439 00:29:25,640 --> 00:29:29,460 had other threads going on that were accessing memory that would no longer be accessible at this point. 440 00:29:31,220 --> 00:29:34,340 So, most Android bootloaders use a single thread for all functionality. 441 00:29:34,480 --> 00:29:35,840 They start up, they have some interrupts, 442 00:29:36,000 --> 00:29:37,640 and then they've maybe got a USB interface, 443 00:29:37,840 --> 00:29:39,600 but literally all they want to do is get from A to B, 444 00:29:39,740 --> 00:29:42,180 which would be starting up to loading Android and executing. 445 00:29:42,740 --> 00:29:45,200 However, SBOOT was found to implement an RTOS, 446 00:29:45,320 --> 00:29:50,960 which was much more fully featured and handled things like a much more complex graphics setup 447 00:29:50,960 --> 00:29:58,460 and a much more fully featured thing for the debugging and addressing, etc. 448 00:29:58,740 --> 00:30:00,320 As you saw, there were a lot of print tests and things. 449 00:30:00,520 --> 00:30:03,880 There was a background process that was allowing this to be written into memory, etc., 450 00:30:03,880 --> 00:30:04,600 and it was really nice. 451 00:30:04,600 --> 00:30:07,560 And because the kernel was altering the MMU page tables, 452 00:30:07,920 --> 00:30:11,680 they were showing to execute unmapped memory, which was causing the hardware errors. 453 00:30:12,840 --> 00:30:14,860 So, there were three threads that were identified on the device. 454 00:30:15,020 --> 00:30:16,580 There was the background tasks, which I just talked about. 455 00:30:16,760 --> 00:30:19,640 There were the USB control transfers, which were what we were exploiting. 456 00:30:19,780 --> 00:30:21,480 And there was the high-level USB communication, 457 00:30:21,880 --> 00:30:24,500 which was the download mode, the fast boot mode, etc. we were talking about. 458 00:30:24,760 --> 00:30:28,220 And as each one was constantly polling for the next interrupt it wanted and things, 459 00:30:29,140 --> 00:30:31,180 it was that that was causing the issue. 460 00:30:31,360 --> 00:30:34,540 And I also felt that because I didn't know much about how the RTOS was working, 461 00:30:34,600 --> 00:30:37,240 there was no trivial way for me to disable them individually. 462 00:30:37,580 --> 00:30:40,380 So, I needed to come up with a much simpler solution for myself 463 00:30:40,380 --> 00:30:44,400 just to kick them over and get myself into a position where there were no threads running. 464 00:30:45,940 --> 00:30:49,220 So, a simple solution for me was going to be to throw an exception. 465 00:30:49,480 --> 00:30:52,560 When you throw an exception, all the threads sort of hang waiting for that exception to occur 466 00:30:52,560 --> 00:30:55,940 because they're usually doing something that's very timing or security critical. 467 00:30:57,420 --> 00:31:00,220 And also, recovering from the exception wouldn't be required 468 00:31:00,860 --> 00:31:02,760 because we were trying to execute against the kernel, 469 00:31:02,880 --> 00:31:04,320 which would then resettle off the exception 470 00:31:04,600 --> 00:31:05,320 and registers and things. 471 00:31:05,680 --> 00:31:08,640 So, I could literally just dump the kernel bootstrapping code into there, hopefully, 472 00:31:08,740 --> 00:31:09,860 and get where I wanted to be. 473 00:31:11,240 --> 00:31:14,580 So, vbyel1, which was the table that you just saw in the last slide, 474 00:31:15,780 --> 00:31:19,000 is a register that points to a table in memory 475 00:31:19,000 --> 00:31:21,900 which includes sequences of different exceptions, 476 00:31:22,140 --> 00:31:24,040 which are stored in 128 byte chunks. 477 00:31:24,380 --> 00:31:26,720 So, every 128 bytes is a different exception type. 478 00:31:27,180 --> 00:31:29,480 I didn't really want to work out which exception was what. 479 00:31:29,640 --> 00:31:32,780 So, what I ended up doing was doing a knob sled throughout the entirety of the exception table 480 00:31:32,780 --> 00:31:34,580 into my bootstrapping code at the end of it. 481 00:31:34,600 --> 00:31:35,940 And I did that by using a node of memory, which was then executed. 482 00:31:38,120 --> 00:31:40,620 So, even with the kernel booting like this, and it did work, 483 00:31:40,700 --> 00:31:41,820 it's got further down the line, 484 00:31:42,020 --> 00:31:45,440 Android was still failing to start, reverting to a special recovery mode 485 00:31:45,440 --> 00:31:48,380 that was telling me that the file system manager was failing. 486 00:31:48,820 --> 00:31:54,400 The error message that I saw suggested that it was due to the user data partition not being decrypted. 487 00:31:54,580 --> 00:31:58,580 So, on most Android devices now, user data is encrypted and using hardware key, 488 00:31:58,740 --> 00:32:03,200 which needs to be set up during boot to make sure that you can access your files. 489 00:32:03,920 --> 00:32:04,580 What this means is that, 490 00:32:04,600 --> 00:32:06,160 what this implied to me is that I'd messed up somewhere 491 00:32:06,160 --> 00:32:09,500 and that the key storage or something else was not being enabled properly 492 00:32:09,500 --> 00:32:11,520 or had been broken in some manner by my bootstrapping. 493 00:32:13,200 --> 00:32:16,980 So, analyzing the logs prior to boot found that there were multiple hardware initializations 494 00:32:16,980 --> 00:32:20,260 I'd missed or ignored because I was being quite lazy with this project. 495 00:32:21,000 --> 00:32:24,620 And this was due to the fact that they'd already been initialized by fastboot 496 00:32:24,620 --> 00:32:25,920 that required them for other purposes. 497 00:32:26,240 --> 00:32:28,760 This included things like reading data and setting other things up. 498 00:32:29,000 --> 00:32:33,420 But essentially, I was running the same functions twice before setting up the TE, etc. 499 00:32:35,640 --> 00:32:38,100 By looking at the logs, I could see the error messages. 500 00:32:38,300 --> 00:32:42,700 For instance, key storage in it failed and tgris register handler minus one, 501 00:32:42,820 --> 00:32:44,820 meaning that I'd have to do something to bypass this. 502 00:32:46,240 --> 00:32:50,320 So, both of these particular functions were enabled by a very, very large and complex function 503 00:32:50,320 --> 00:32:55,580 that would take a long time to modify or bring back from scratch. 504 00:32:56,020 --> 00:32:58,420 However, I did end up doing that by fully re-implementing it 505 00:32:58,420 --> 00:33:00,640 by checking for every if statement throughout the function 506 00:33:01,200 --> 00:33:02,980 for different self-hardware initializations 507 00:33:02,980 --> 00:33:06,420 and ignoring the code paths that I didn't think it would hit. 508 00:33:07,480 --> 00:33:10,920 However, with these errors removed, the phone could then complete booting to Android. 509 00:33:11,620 --> 00:33:13,080 So, I'm going to do another demo now, hopefully. 510 00:33:18,480 --> 00:33:22,140 So, here's the phone in fastboot mode and you'll see it very quickly go into the boot screen 511 00:33:22,140 --> 00:33:23,000 before switching back. 512 00:33:23,160 --> 00:33:26,980 So, that screen you just saw was the one that happens when you just hold the power button 513 00:33:26,980 --> 00:33:27,700 on and turn on the phone. 514 00:33:27,840 --> 00:33:29,580 But as part of the boot process, it required it. 515 00:33:29,760 --> 00:33:31,520 It then shows the secured by knock screen, 516 00:33:31,520 --> 00:33:34,920 which I'm not quite sure is true anymore at this point in the process. 517 00:33:35,380 --> 00:33:38,540 You'll see a flicker occasionally in the screen 518 00:33:38,540 --> 00:33:41,340 where the kernel is rewriting that secured by knock screen 519 00:33:41,740 --> 00:33:43,180 and then you'll see that disappear. 520 00:33:43,340 --> 00:33:44,800 Now, at this point, I was very excited 521 00:33:44,800 --> 00:33:49,560 because this was meaning that we'd bypassed all of the hardware issues, 522 00:33:49,740 --> 00:33:51,620 all the other issues I'd had in this process 523 00:33:51,620 --> 00:33:54,880 and we were now getting to the point where I was executing my custom modified kernel, 524 00:33:55,060 --> 00:33:57,180 which I was peeking and poking into through this process. 525 00:33:57,760 --> 00:34:00,280 So, in a second, we'll see the... 526 00:34:00,280 --> 00:34:04,460 the home screen and we'll know that my modified kernel was executing, 527 00:34:05,480 --> 00:34:06,580 which I was very happy with. 528 00:34:15,220 --> 00:34:15,660 Perfect. 529 00:34:17,540 --> 00:34:20,300 So, there's a lot of things that can be done with kernel code execution. 530 00:34:20,640 --> 00:34:22,560 You can disable some security features and things like that, 531 00:34:22,600 --> 00:34:25,680 but you have to be very careful because Samsung do put a lot of effort 532 00:34:25,680 --> 00:34:28,700 into making sure that there are checks in place that don't... 533 00:34:28,700 --> 00:34:30,180 that if you... 534 00:34:30,280 --> 00:34:31,920 do too many scary things, 535 00:34:32,120 --> 00:34:35,200 Knox will blow a fuse and permanently the device will say 536 00:34:35,200 --> 00:34:37,840 it can't be secured in the same manner because someone's been messing with it. 537 00:34:38,260 --> 00:34:40,620 But, very easily, I could modify the kernel... 538 00:34:41,960 --> 00:34:44,700 proc version just to show what happens in the strings. 539 00:34:45,000 --> 00:34:47,640 Now, I did modify this further to remove things like SELinux checks, 540 00:34:47,700 --> 00:34:49,760 regardless of whether it had SELinux in place, 541 00:34:49,940 --> 00:34:52,900 but I thought just a demonstrative picture of the version being modified 542 00:34:52,900 --> 00:34:53,920 was a good start for this. 543 00:34:55,160 --> 00:34:56,940 So, some final notes on this case study. 544 00:34:57,420 --> 00:35:00,100 Because the exploit can now be triggered by producing an exception, 545 00:35:00,280 --> 00:35:02,980 it would be much easier for me to re-implement it in the download mode, 546 00:35:03,120 --> 00:35:04,900 which is much more common on Samsung devices, 547 00:35:05,520 --> 00:35:09,000 which would mean that the exploit would be much more far-reaching 548 00:35:09,000 --> 00:35:10,860 if I implemented it on a more expensive device. 549 00:35:11,440 --> 00:35:13,900 And while code execution was possible, as I just said, 550 00:35:13,920 --> 00:35:15,560 there was still a risk of triggering Knox. 551 00:35:15,820 --> 00:35:19,600 However, I didn't manage to do that during my analysis of this device. 552 00:35:20,860 --> 00:35:23,820 So, in conclusion of the two case studies we've discussed today, 553 00:35:24,440 --> 00:35:26,520 the initial vulnerability was disclosed to... 554 00:35:26,520 --> 00:35:27,940 Sorry, we're doing disclosures first. 555 00:35:28,040 --> 00:35:28,780 I'm getting my slides mixed up. 556 00:35:28,780 --> 00:35:32,040 The initial vulnerability was disclosed to Samsung in December 2022, 557 00:35:32,680 --> 00:35:37,300 and they provided constant updates on progress 558 00:35:37,300 --> 00:35:39,780 and patched the finding within three months across all their devices, 559 00:35:39,900 --> 00:35:41,320 which was extremely impressive, 560 00:35:41,460 --> 00:35:43,540 considering the complexity of debugging this kind of thing. 561 00:35:44,240 --> 00:35:47,700 So, the target device that I had after recording my demos for DEF CON 562 00:35:47,700 --> 00:35:50,180 was updated, and I found it to no longer be vulnerable 563 00:35:50,180 --> 00:35:51,780 to the discrete probe write vulnerability, 564 00:35:52,140 --> 00:35:54,620 meaning code execution in this manner was no longer possible. 565 00:35:55,140 --> 00:35:57,660 I'll be releasing the tools for this on my GitHub, 566 00:35:57,660 --> 00:36:00,980 but you'll be able to find the link to my Twitter, 567 00:36:01,120 --> 00:36:02,700 where I'll announce this, in the slides, 568 00:36:02,760 --> 00:36:04,620 which you'll find on the DEF CON media server. 569 00:36:05,540 --> 00:36:06,520 So, now conclusion. 570 00:36:07,380 --> 00:36:11,140 So, most devices, regardless of how much effort people put into protecting them, 571 00:36:11,180 --> 00:36:13,960 still have exploitable vulnerabilities that can be exploited simply, 572 00:36:14,180 --> 00:36:15,500 despite there is resources. 573 00:36:16,200 --> 00:36:17,600 And even with basic vulnerabilities, 574 00:36:18,060 --> 00:36:21,300 the effort required sometimes to go from a proof of concept to a full exploit 575 00:36:21,760 --> 00:36:22,840 is really rewarding. 576 00:36:23,020 --> 00:36:25,720 For instance, you saw that there was two very basic vulnerabilities 577 00:36:25,720 --> 00:36:27,060 in both of those case studies. 578 00:36:27,060 --> 00:36:30,920 Which then took a certain amount of effort to actually make into a complete attack chain. 579 00:36:31,520 --> 00:36:35,200 And, last of all, even on targets which had a huge amount of research put on them, 580 00:36:35,600 --> 00:36:37,080 there'll still be a factor no one else has tried. 581 00:36:37,220 --> 00:36:38,220 So, shoot, you should try it first. 582 00:36:39,220 --> 00:36:39,900 Thank you very much. 583 00:36:49,100 --> 00:36:50,700 I think we have time for questions, 584 00:36:50,800 --> 00:36:52,140 and there's a microphone at the back of the room. 585 00:36:52,240 --> 00:36:54,020 I'm also happy for people to just shout at me, 586 00:36:54,060 --> 00:36:56,560 or I'll be outside in the hallway after this talk. 587 00:36:56,560 --> 00:36:57,740 So, whatever works for everyone. 588 00:36:58,200 --> 00:36:58,520 Thanks.