WEBVTT 00:00:09.029 --> 00:00:12.320 Herald: So, in this talk we will hear about 00:00:12.320 --> 00:00:15.730 what UEFI is, how it can be used, 00:00:15.730 --> 00:00:18.560 and how it can be executed in userspace, 00:00:18.560 --> 00:00:20.259 and our speaker is Jethro Beekman, 00:00:20.259 --> 00:00:25.649 and... the stage is yours. 00:00:25.649 --> 00:00:27.820 Jethro Beekman: Thank you for the introduction. 00:00:27.820 --> 00:00:32.499 applause 00:00:32.499 --> 00:00:34.790 Alright, thank you for the introduction. 00:00:34.790 --> 00:00:38.180 So, I'm a PhD student at UC Berkeley, 00:00:38.180 --> 00:00:40.070 and in my copious amounts of free time, 00:00:40.070 --> 00:00:43.440 I like to reverse-engineer things. 00:00:43.440 --> 00:00:45.270 In particular, this time, 00:00:45.270 --> 00:00:47.250 I reverse-engineered UEFI, 00:00:47.250 --> 00:00:49.620 which is the modern BIOS replacement. 00:00:49.620 --> 00:00:52.820 And, in this talk, I will discuss some tools 00:00:52.820 --> 00:00:55.030 that you can use - that you too can use 00:00:55.030 --> 00:00:57.140 to reverse-engineer UEFI, 00:00:57.140 --> 00:00:58.750 including some tools that I wrote, 00:00:58.750 --> 00:01:01.670 and tools that other people wrote. 00:01:01.670 --> 00:01:04.860 So, this whole project started 00:01:04.860 --> 00:01:08.040 when I bought a new SSD for my laptop 00:01:08.040 --> 00:01:10.670 and, as you might know, modern SSDs have 00:01:10.670 --> 00:01:13.510 built-in encryption capabilities, 00:01:13.510 --> 00:01:16.310 whether this is secure or not is a question, 00:01:16.310 --> 00:01:18.310 is a good question, but really, 00:01:18.310 --> 00:01:19.850 reverse-engineering SSD firmware 00:01:19.850 --> 00:01:23.300 is a talk for another day. 00:01:23.300 --> 00:01:27.810 So, I decided to use this encryption, 00:01:27.810 --> 00:01:31.460 and use it using the built-in 00:01:31.460 --> 00:01:32.990 hardware password option 00:01:32.990 --> 00:01:35.950 of my UEFI firmware. 00:01:35.950 --> 00:01:38.560 This is the password I chose, 64 characters, 00:01:38.560 --> 00:01:42.120 "correct horse battery staple galaxy piece position require house". 00:01:42.120 --> 00:01:47.520 It's very secure, obviously. 00:01:47.520 --> 00:01:49.790 So this all seemed to be working fine, 00:01:49.790 --> 00:01:51.390 and I was trusting that my hard drive 00:01:51.390 --> 00:01:53.880 was encrypted properly, 00:01:53.880 --> 00:01:54.909 but once you start to think about 00:01:54.909 --> 00:01:56.159 how it actually works, 00:01:56.159 --> 00:01:59.480 there's a small discrepancy, really, 00:01:59.480 --> 00:02:02.500 because the way this password's input 00:02:02.500 --> 00:02:04.720 to the hard drive is using 00:02:04.720 --> 00:02:06.970 the ATA security feature set, 00:02:06.970 --> 00:02:09.408 the security-unlock command. 00:02:09.408 --> 00:02:11.489 And if you look at the unlock command, 00:02:11.489 --> 00:02:12.930 you clearly see that the password 00:02:12.930 --> 00:02:16.889 is supposed to be 32 bytes. 00:02:16.889 --> 00:02:21.310 How are these 64 characters turned into 32 bytes? 00:02:21.310 --> 00:02:22.709 That is my question, 00:02:22.709 --> 00:02:25.450 because if my laptop dies 00:02:25.450 --> 00:02:28.310 but my SSD is still functional, 00:02:28.310 --> 00:02:29.650 I want to be able to take my SSD 00:02:29.650 --> 00:02:31.680 and put it into another computer 00:02:31.680 --> 00:02:34.430 to get access to my data. 00:02:34.430 --> 00:02:36.349 I tried all the standard things, 00:02:36.349 --> 00:02:40.629 like truncating it, or using a standard 00:02:40.629 --> 00:02:42.980 hash function like SHA-256 00:02:42.980 --> 00:02:44.909 that has 32-byte output, 00:02:44.909 --> 00:02:47.680 but these things all didn't work. 00:02:47.680 --> 00:02:49.540 So then I decided to, you know, 00:02:49.540 --> 00:02:52.989 really dive into the firmware 00:02:52.989 --> 00:02:54.609 to figure out how it works. 00:02:54.609 --> 00:02:56.249 So this talk will also be called 00:02:56.249 --> 00:03:00.480 "How to turn 64 characters into 32 bytes". 00:03:00.480 --> 00:03:06.759 applause 00:03:07.629 --> 00:03:09.120 So what are some challenges 00:03:09.120 --> 00:03:12.010 when reverse-engineering UEFI? 00:03:12.010 --> 00:03:14.109 So first of all, this is the first thing 00:03:14.109 --> 00:03:17.510 that runs when your computer is booted up. 00:03:17.510 --> 00:03:18.919 So that means you will not be able 00:03:18.919 --> 00:03:21.230 to use a standard debugger. 00:03:21.230 --> 00:03:24.200 Surely people who develop firmware for a living 00:03:24.200 --> 00:03:27.069 have some kind of hardware debugger 00:03:27.069 --> 00:03:30.510 but that's unlikely to work on a commodity system 00:03:30.510 --> 00:03:34.620 such as this laptop, which is all I got from the store. 00:03:34.620 --> 00:03:37.309 Maybe you think you can emulate the firmware 00:03:37.309 --> 00:03:39.340 using qemu or something like that, 00:03:39.340 --> 00:03:41.120 but the hardware that the firmware 00:03:41.120 --> 00:03:42.590 is designed to support 00:03:42.590 --> 00:03:45.999 is unlikely to be correctly emulated by qemu. 00:03:45.999 --> 00:03:50.309 So that is also probably not a viable way 00:03:50.309 --> 00:03:52.249 to debug this. 00:03:52.249 --> 00:03:57.629 Also, because UEFI is basically one big process, 00:03:57.629 --> 00:04:01.299 using one address space, 00:04:01.299 --> 00:04:02.329 there's no operating system 00:04:02.329 --> 00:04:04.849 so there's no system calls. 00:04:04.849 --> 00:04:07.089 Also there's no dynamic linker, 00:04:07.089 --> 00:04:09.029 so there's no dynamic symbols, 00:04:09.029 --> 00:04:10.439 there's no symbol table that you can use 00:04:10.439 --> 00:04:13.290 as a starting point in your reverse-engineering. 00:04:13.290 --> 00:04:16.478 You know, if you were reverse-engineering 00:04:16.478 --> 00:04:20.099 a standard password utility in userspace 00:04:20.099 --> 00:04:22.009 or something, you might start at 00:04:22.009 --> 00:04:24.190 the read system call for, 00:04:24.190 --> 00:04:26.900 that would be displayed to the user 00:04:26.900 --> 00:04:28.280 to enter the password. 00:04:28.280 --> 00:04:35.150 But in UEFI, no, that is not an option. 00:04:35.150 --> 00:04:36.930 And even though there's no dynamic linker, 00:04:36.930 --> 00:04:38.500 the whole firmware consists 00:04:38.500 --> 00:04:42.030 of 281 different modules, in my case, 00:04:42.030 --> 00:04:46.030 and it could be similar numbers on your UEFI laptop. 00:04:46.030 --> 00:04:50.589 And these modules all need to interact in some way. 00:04:50.589 --> 00:04:54.300 So, let's take a look at these different modules. 00:04:54.300 --> 00:04:56.680 There's a tool called UEFITool, 00:04:56.680 --> 00:04:58.729 written by Nikolaj Schlej, and 00:04:58.729 --> 00:05:00.300 this really should be in your bag of tricks 00:05:00.300 --> 00:05:01.840 if you're interested in doing anything 00:05:01.840 --> 00:05:05.389 with UEFI firmware. 00:05:05.389 --> 00:05:11.430 So, here I'll just go and use UEFIExtract, 00:05:11.430 --> 00:05:15.300 which is a command line utility 00:05:15.300 --> 00:05:17.020 included with UEFITool 00:05:17.020 --> 00:05:20.229 that allows you to extract a firmware blob, 00:05:20.229 --> 00:05:21.800 so in this case I took the firmware blob 00:05:21.800 --> 00:05:26.460 from the Lenovo firmware update CD 00:05:26.460 --> 00:05:29.949 and we're going to extract that. 00:05:29.949 --> 00:05:34.240 After extracting it, we get this nice directory structure 00:05:34.240 --> 00:05:37.979 with one subdirectory per module 00:05:37.979 --> 00:05:40.419 and as you can see, there's quite a few of them. 00:05:40.419 --> 00:05:44.720 Here's, there's system management mode control module, 00:05:44.720 --> 00:05:47.560 timer module, things like that. 00:05:47.560 --> 00:05:48.700 And as you can see, 00:05:48.700 --> 00:05:50.569 each module has a bunch of subdirectories 00:05:50.569 --> 00:05:51.589 for the different sections 00:05:51.589 --> 00:05:53.199 that are included in that module. 00:05:53.199 --> 00:05:57.060 And one that appears a lot is the PE32+ image. 00:05:57.060 --> 00:05:59.110 This is a portable execution image, 00:05:59.110 --> 00:06:02.580 this is a format that Windows uses for executables. 00:06:02.580 --> 00:06:05.840 So, you might think you might be able to run 00:06:05.840 --> 00:06:11.419 these modules, and that is true. 00:06:11.419 --> 00:06:14.110 But first, let's take a look at 00:06:14.110 --> 00:06:16.169 what happens when you run a module like that. 00:06:16.169 --> 00:06:19.639 Each module has an entry point, main, 00:06:19.639 --> 00:06:22.930 and the main function gets passed 00:06:22.930 --> 00:06:24.659 a pointer to the system table. 00:06:24.659 --> 00:06:26.860 The system table is just... 00:06:26.860 --> 00:06:30.050 contains more pointers to other structures. 00:06:30.050 --> 00:06:32.370 For example, for the terminals, 00:06:32.370 --> 00:06:34.639 cons in, cons out, standard error, 00:06:34.639 --> 00:06:38.099 the standard text inputs and outputs, 00:06:38.099 --> 00:06:41.259 and also the boot services structure. 00:06:41.259 --> 00:06:43.069 The boot services structure contains 00:06:43.069 --> 00:06:44.960 a bunch of function pointers, 00:06:44.960 --> 00:06:47.909 including these install protocol interface 00:06:47.909 --> 00:06:51.259 and locate protocol functions. 00:06:51.259 --> 00:06:53.060 The install protocol interface allows 00:06:53.060 --> 00:06:56.080 a module to install a protocol interface 00:06:56.080 --> 00:07:00.300 using, specified by a particular GUID 00:07:00.300 --> 00:07:03.169 and the interface is specified by just some pointer. 00:07:03.169 --> 00:07:05.719 Then, later, another module can call 00:07:05.719 --> 00:07:08.810 a locate protocol function with the same GUID 00:07:08.810 --> 00:07:10.840 and it will receive a pointer 00:07:10.840 --> 00:07:12.849 to this interface that was previously installed 00:07:12.849 --> 00:07:14.199 by the other modules. 00:07:14.199 --> 00:07:17.840 So, most modules in their main function 00:07:17.840 --> 00:07:20.759 start by loading a bunch of protocols 00:07:20.759 --> 00:07:24.389 and then, after that, installing one more 00:07:24.389 --> 00:07:28.050 of their own protocols. 00:07:28.050 --> 00:07:29.189 This is all done at runtime. 00:07:29.189 --> 00:07:31.129 So there's really no static way of 00:07:31.129 --> 00:07:32.650 viewing the dependencies 00:07:32.650 --> 00:07:34.749 between the different modules. 00:07:34.749 --> 00:07:36.290 Luckily, we might be able to 00:07:36.290 --> 00:07:37.349 execute these modules, 00:07:37.349 --> 00:07:40.810 as I was alluding to before. 00:07:40.810 --> 00:07:42.089 These modules, they're written 00:07:42.089 --> 00:07:44.280 for the hardware you're currently using, 00:07:44.280 --> 00:07:47.039 with your current operating system. 00:07:47.039 --> 00:07:49.060 So they have a compatible instruction set. 00:07:49.060 --> 00:07:50.259 So in order to execute them, 00:07:50.259 --> 00:07:51.539 you just need a compatible 00:07:51.539 --> 00:07:54.659 application binary interface, or ABI. 00:07:54.659 --> 00:07:55.860 This is what I've written, 00:07:55.860 --> 00:07:58.229 with the efiperun tool. 00:07:58.229 --> 00:08:01.909 You can think of efiperun as WINE for UEFI. 00:08:01.909 --> 00:08:03.889 Just like WINE allows you to run 00:08:03.889 --> 00:08:06.189 Windows applications on Linux, 00:08:06.189 --> 00:08:08.650 efiperun allows you to run EFI modules 00:08:08.650 --> 00:08:11.850 on Linux. 00:08:11.850 --> 00:08:19.310 applause 00:08:22.000 --> 00:08:24.990 So, efiperun has a bunch of features, 00:08:24.990 --> 00:08:29.129 it includes many of the standard EFI APIs 00:08:29.129 --> 00:08:31.609 and it's very easy to add implementations 00:08:31.609 --> 00:08:33.280 for missing APIs. 00:08:33.280 --> 00:08:35.919 Also, at runtime, a missing API 00:08:35.919 --> 00:08:37.380 will be generated automatically 00:08:37.380 --> 00:08:39.600 with some stub functions. 00:08:39.600 --> 00:08:41.309 It supports memory map annotations, 00:08:41.309 --> 00:08:45.570 so that you can see which parts of memory 00:08:45.570 --> 00:08:47.720 have been allocated by which module 00:08:47.720 --> 00:08:49.810 and you can all run these in your standard 00:08:49.810 --> 00:08:53.420 debugger environments, like gdb. 00:08:53.420 --> 00:08:55.450 Also, as an interesting aside, 00:08:55.450 --> 00:08:56.830 I think this the only project 00:08:56.830 --> 00:08:58.060 I could find online 00:08:58.060 --> 00:09:00.060 that uses the cross-stdarg header 00:09:00.060 --> 00:09:02.620 which is used for calling 00:09:02.620 --> 00:09:04.130 variable-argument functions 00:09:04.130 --> 00:09:07.310 across calling conventions. 00:09:07.310 --> 00:09:14.010 So, let's do a little demo of efiperun. 00:09:14.010 --> 00:09:15.970 In this demo, I will just 00:09:15.970 --> 00:09:20.970 run efiperun on each different module 00:09:20.970 --> 00:09:24.150 to see which other modules it interacts with. 00:09:33.740 --> 00:09:35.780 So, I just wrote this little Ruby script 00:09:35.780 --> 00:09:37.530 which traverses the directory tree 00:09:37.530 --> 00:09:41.710 that we just saw from the UEFIExtract utility 00:09:41.710 --> 00:09:44.270 and then it executes efiperun 00:09:44.270 --> 00:09:47.300 for each different module. 00:09:47.300 --> 00:09:48.040 Whee! 00:09:50.500 --> 00:09:52.400 Assertion error that I've never seen before, 00:09:52.400 --> 00:09:53.580 that's always fun. 00:09:53.580 --> 00:09:56.500 As you can see, 281 processes are launched, 00:09:56.500 --> 00:09:58.000 most modules return 00:09:58.000 --> 00:09:59.760 from the main function, normally, 00:09:59.760 --> 00:10:01.400 but some of them get stuck 00:10:01.400 --> 00:10:04.040 in an infinite loop, 00:10:04.040 --> 00:10:06.230 so efiperun will automatically terminate 00:10:06.230 --> 00:10:07.840 after 10 seconds in this case. 00:10:07.840 --> 00:10:10.100 Let's look at the output of 00:10:10.100 --> 00:10:13.980 all these different efiperun modules. 00:10:16.680 --> 00:10:18.430 You can see a bunch of them segfault, 00:10:18.430 --> 00:10:21.340 which, you know, can be, is understandable 00:10:21.340 --> 00:10:23.400 because they might be expecting 00:10:23.400 --> 00:10:26.410 some memory setup from the early boot 00:10:26.410 --> 00:10:28.810 that is not existent anymore, 00:10:28.810 --> 00:10:32.430 but there are a bunch of modules that do work 00:10:32.430 --> 00:10:36.770 such as system boot manager. 00:10:36.770 --> 00:10:40.480 You can see that it prints out a bunch of stuff, 00:10:40.480 --> 00:10:43.580 version information, copyright information, 00:10:43.580 --> 00:10:45.570 then it requests a protocol, 00:10:45.570 --> 00:10:48.060 this protocol has a GUID that is specified 00:10:48.060 --> 00:10:50.200 by the EFI specification, 00:10:50.200 --> 00:10:53.380 so we can interpret that GUID 00:10:53.380 --> 00:10:56.060 and then it calls some stub functions 00:10:56.060 --> 00:10:57.910 that we have not implemented 00:10:57.910 --> 00:10:58.930 and then afterwards, 00:10:58.930 --> 00:11:00.190 it installs its own protocol, 00:11:00.190 --> 00:11:02.190 which is also a protocol specified 00:11:02.190 --> 00:11:07.080 by the EFI specification. 00:11:07.080 --> 00:11:08.040 Another interesting module 00:11:08.040 --> 00:11:12.170 is the system splash module, 00:11:12.170 --> 00:11:15.630 which we see over here. 00:11:15.630 --> 00:11:18.760 As you can see, it actually requests 00:11:18.760 --> 00:11:21.480 a bunch of protocols that are not implemented 00:11:21.480 --> 00:11:22.910 by efiperun and you will see 00:11:22.910 --> 00:11:24.640 it will automatically generate 00:11:24.640 --> 00:11:27.950 a dummy interface for that purpose. 00:11:27.950 --> 00:11:30.560 And then you will see that it calls 00:11:30.560 --> 00:11:31.910 a function in this dummy interface 00:11:31.910 --> 00:11:34.360 that was created here, 00:11:34.360 --> 00:11:35.930 namely function number 2, 00:11:35.930 --> 00:11:39.760 and because we are unable to handle this function 00:11:39.760 --> 00:11:43.480 we just abort. 00:11:43.480 --> 00:11:46.480 Okay, so now that I've shown you 00:11:46.480 --> 00:11:48.680 that we can run these different modules, 00:11:48.680 --> 00:11:50.040 we really need to get started with 00:11:50.040 --> 00:11:51.930 the reverse-engineering of my BIOS 00:11:51.930 --> 00:11:54.210 to figure how to turn those 64 characters 00:11:54.210 --> 00:11:56.600 into 32 bytes. 00:11:56.600 --> 00:12:00.060 You might remember this picture from slide 2. 00:12:00.060 --> 00:12:01.620 You can see that there's a little graphic 00:12:01.620 --> 00:12:03.890 displayed in the password prompt. 00:12:03.890 --> 00:12:05.100 So this graphic needs to be stored 00:12:05.100 --> 00:12:05.940 somewhere in the BIOS, 00:12:05.940 --> 00:12:08.180 and it needs to be coded to display 00:12:08.180 --> 00:12:11.940 this graphic to the user at some point. 00:12:11.940 --> 00:12:13.690 So, let's take a look at the different modules 00:12:13.690 --> 00:12:15.200 that might have something to do with images 00:12:15.200 --> 00:12:17.810 and graphics and things like that. 00:12:17.810 --> 00:12:19.610 Turns out there's only 4 of the 281 00:12:19.610 --> 00:12:22.310 that have a file names that seems to correspond 00:12:22.310 --> 00:12:24.440 to something with graphics or images. 00:12:24.440 --> 00:12:28.350 And if this, the first module is called 00:12:28.350 --> 00:12:30.440 by another module, 00:12:30.440 --> 00:12:32.370 which is Lenovo prompt service. 00:12:32.370 --> 00:12:34.350 And Lenovo prompt service contains 00:12:34.350 --> 00:12:36.000 in one of its data sections, 00:12:36.000 --> 00:12:38.080 this image over here. 00:12:38.080 --> 00:12:40.070 So now we know that we've found something 00:12:40.070 --> 00:12:44.510 that has to do with the password prompt. 00:12:44.510 --> 00:12:47.040 This prompt module is called by only one 00:12:47.040 --> 00:12:47.980 other module, which is 00:12:47.980 --> 00:12:49.820 the Lenovo password CP module, 00:12:49.820 --> 00:12:51.130 which probably means something like 00:12:51.130 --> 00:12:55.550 password control panel or something like that. 00:12:55.550 --> 00:12:57.010 The password CP module also calls 00:12:57.010 --> 00:12:59.500 into 3 other modules, namely 00:12:59.500 --> 00:13:01.700 the sound service module, presumably to 00:13:01.700 --> 00:13:04.130 play beeps if the user does something wrong 00:13:04.130 --> 00:13:05.990 while entering the password, 00:13:05.990 --> 00:13:08.440 the translate service module, which is used 00:13:08.440 --> 00:13:10.340 to translate characters, 00:13:10.340 --> 00:13:11.880 which I've reverse-engineered, 00:13:11.880 --> 00:13:16.030 I've figured out that it's used to translate 00:13:16.030 --> 00:13:20.470 ascii characters back into keyboard scan codes. 00:13:20.470 --> 00:13:22.460 Keyboard scan codes are codes that are assigned 00:13:22.460 --> 00:13:24.450 to each different key on your keyboard. 00:13:24.450 --> 00:13:26.440 It's the way the hardware keyboard 00:13:26.440 --> 00:13:29.860 communicates with your computer. 00:13:29.860 --> 00:13:32.420 And then there's the Lenovo crypt service module, 00:13:32.420 --> 00:13:34.130 which turns out to be 00:13:34.130 --> 00:13:36.550 standard SHA-256 hash function. 00:13:40.400 --> 00:13:42.280 Right, so let's see and have a demo, 00:13:42.280 --> 00:13:43.830 in which we are going to call 00:13:43.830 --> 00:13:45.220 one of the functions in 00:13:45.220 --> 00:13:48.470 this Lenovo password CP module. 00:13:53.790 --> 00:13:58.130 So, efiperun allows you to write code 00:13:58.130 --> 00:14:00.030 to interact with the EFI modules 00:14:00.030 --> 00:14:02.930 that are loaded at runtime. 00:14:02.930 --> 00:14:04.700 Here I've written this Lenovo-specific 00:14:04.700 --> 00:14:07.420 debug module and you can specify 00:14:07.420 --> 00:14:09.810 two functions that will be called. 00:14:09.810 --> 00:14:11.500 The first function in it will be called 00:14:11.500 --> 00:14:14.980 before all the EFI modules are loaded, 00:14:14.980 --> 00:14:16.790 the second function will be called after 00:14:16.790 --> 00:14:18.710 all the EFI functions are loaded. 00:14:18.710 --> 00:14:20.260 So in this case, we'll first call 00:14:20.260 --> 00:14:21.950 the install something function, and then 00:14:21.950 --> 00:14:24.360 call, after loading the EFI modules, 00:14:24.360 --> 00:14:26.830 the call something function. 00:14:26.830 --> 00:14:30.760 The install function installs a stub 00:14:30.760 --> 00:14:34.060 Lenovo crypt service protocol. 00:14:34.060 --> 00:14:35.690 This is necessary because the standard 00:14:35.690 --> 00:14:37.390 Lenovo crypt service calls into system 00:14:37.390 --> 00:14:39.290 management mode to do the hashing, 00:14:39.290 --> 00:14:41.130 which is currently not possible from 00:14:41.130 --> 00:14:43.540 Linux userspace. 00:14:43.540 --> 00:14:48.390 The second function, call_LenovoPasswordCp_8cc, 00:14:48.390 --> 00:14:50.890 will determine the address of the function 00:14:50.890 --> 00:14:52.480 in the Lenovo password CP module 00:14:52.480 --> 00:14:55.100 at offset 8cc and then call it. 00:14:55.100 --> 00:14:57.480 It will take two parameters, in and out. 00:14:57.480 --> 00:15:01.490 In will use this unicode string, my password, 00:15:01.490 --> 00:15:02.470 and for the output, 00:15:02.470 --> 00:15:05.770 we'll just pass this array buffer. 00:15:06.970 --> 00:15:10.440 Then we'll just print the output 00:15:10.440 --> 00:15:13.150 of the buffer after calling the function. 00:15:29.510 --> 00:15:31.850 So, as you can see here, 00:15:31.850 --> 00:15:33.600 the Lenovo translate service module 00:15:33.600 --> 00:15:37.260 installs this protocol E3AB-etc. 00:15:37.260 --> 00:15:39.280 and then later Lenovo password CP module 00:15:39.280 --> 00:15:43.260 requests the same protocol E3AB-etc. 00:15:43.260 --> 00:15:46.100 Also, you will see that 00:15:46.100 --> 00:15:48.190 the Lenovo password CP module 00:15:48.190 --> 00:15:52.050 requests the protocol C73E4-etc. 00:15:52.050 --> 00:15:53.530 which is the Lenovo crypt service protocol 00:15:53.530 --> 00:15:55.800 that we installed earlier. 00:15:55.800 --> 00:15:57.780 Then it does a bunch of memory operations, 00:15:57.780 --> 00:15:59.550 and at the end, we get the output. 00:15:59.550 --> 00:16:02.340 So I reverse-engineered this function 00:16:02.340 --> 00:16:07.570 at offset 8cc, and it turns out that 00:16:07.570 --> 00:16:10.170 it is, in fact, the following function: 00:16:10.170 --> 00:16:12.660 it takes the input password and 00:16:12.660 --> 00:16:15.050 converts it into scan codes, 00:16:19.650 --> 00:16:25.560 and then it pads it to 64 characters, 00:16:25.560 --> 00:16:30.360 and then it takes a SHA-256 hash 00:16:30.360 --> 00:16:33.520 and then it displays the first half of that. 00:16:36.580 --> 00:16:40.390 Alright, here we go, so... 00:16:40.390 --> 00:16:46.250 applause 00:16:46.250 --> 00:16:47.450 We have reverse-engineered to 00:16:47.450 --> 00:16:51.470 the first half of the password algorithm. 00:16:51.470 --> 00:16:52.870 Took me about three weeks to decode 00:16:52.870 --> 00:16:54.840 the entire algorithm, 00:16:54.840 --> 00:16:57.530 and here it is. 00:16:57.530 --> 00:16:59.060 So this is the hash that we just saw 00:16:59.060 --> 00:17:01.580 of the password, and then this hash is 00:17:01.580 --> 00:17:03.740 concatenated with the serial number and 00:17:03.740 --> 00:17:06.050 model number of the hard drive. 00:17:06.050 --> 00:17:08.800 That all is then hashed again, 00:17:08.800 --> 00:17:12.300 and that is then passed to the SATA drive 00:17:12.300 --> 00:17:13.569 over the ATA protocol. 00:17:13.569 --> 00:17:15.349 Now this is actually quite a good idea 00:17:15.349 --> 00:17:17.770 because it means that if you sniff 00:17:17.770 --> 00:17:20.530 the password on the SATA bus 00:17:20.530 --> 00:17:22.569 you will only be able to then later 00:17:22.569 --> 00:17:24.449 unlock the same drive. 00:17:24.449 --> 00:17:25.480 Because other drives, even though 00:17:25.480 --> 00:17:26.900 they might be using the same password, 00:17:26.900 --> 00:17:28.050 will have a different serial number 00:17:28.050 --> 00:17:29.640 and model number. 00:17:29.640 --> 00:17:33.390 So this hash will not work for them. 00:17:33.390 --> 00:17:35.820 Unfortunately, the algorithm is 00:17:35.820 --> 00:17:40.750 a little more complex than this. 00:17:40.750 --> 00:17:43.490 The password hash, as I said, actually 00:17:43.490 --> 00:17:45.350 uses the scan codes of the password, which 00:17:45.350 --> 00:17:47.260 means that there is no distinguishing in 00:17:47.260 --> 00:17:49.030 case of the letters. 00:17:49.030 --> 00:17:51.980 Also, after hashing it, it truncates it 00:17:51.980 --> 00:17:54.150 to only 12 bytes. Which means that 00:17:54.150 --> 00:17:56.550 there's a maximum of 96 bits of entropy 00:17:56.550 --> 00:18:00.050 in this password hash. 00:18:00.050 --> 00:18:02.090 This is quite unfortunate. 00:18:02.090 --> 00:18:05.240 But most human passwords have less than 00:18:05.240 --> 00:18:08.100 96 bits of entropy to start with, 00:18:08.100 --> 00:18:11.550 so it's probably not that big of a deal. 00:18:11.550 --> 00:18:15.170 Okay, then again this part of the hash is 00:18:15.170 --> 00:18:17.050 concatenated with the serial number 00:18:17.050 --> 00:18:18.170 and the model number, 00:18:18.170 --> 00:18:19.490 except the bytes are swapped. 00:18:19.490 --> 00:18:21.720 And I really can't figure out why 00:18:21.720 --> 00:18:22.990 the bytes are swapped here. 00:18:22.990 --> 00:18:24.930 But it probably has to do something with 00:18:24.930 --> 00:18:27.510 the fact that the ATA protocol uses 00:18:27.510 --> 00:18:30.310 16-bit words while this model number and 00:18:30.310 --> 00:18:32.740 serial number are 8-bit character strings. 00:18:32.740 --> 00:18:35.240 So maybe they did some endianness mess-up 00:18:35.240 --> 00:18:36.990 or something like that. 00:18:36.990 --> 00:18:40.650 Alright, so in this talk, I've shown you 00:18:40.650 --> 00:18:43.760 how you too can reverse-engineer UEFI 00:18:43.760 --> 00:18:45.190 with some tools that you can use 00:18:45.190 --> 00:18:47.320 in this including the efiperun tool 00:18:47.320 --> 00:18:49.290 which allows you to run EFI modules 00:18:49.290 --> 00:18:50.860 in linux userspace. 00:18:50.860 --> 00:18:52.680 The code of this is of course available 00:18:52.680 --> 00:18:55.000 under GPL license on github, 00:18:55.000 --> 00:18:56.140 and if you want to read about 00:18:56.140 --> 00:18:58.010 the second part of reverse-engineering 00:18:58.010 --> 00:18:59.210 the algorithm, you can find more 00:18:59.210 --> 00:19:00.850 information on my blog. 00:19:00.850 --> 00:19:02.650 Thank you very much. 00:19:02.650 --> 00:19:11.980 applause 00:19:11.980 --> 00:19:14.560 H: So, thank you, Jethro, and we have 00:19:14.560 --> 00:19:17.240 more than ten minutes' time for Q&A. 00:19:17.240 --> 00:19:19.370 Is there a question from the Internet, 00:19:19.370 --> 00:19:21.340 signal angel? 00:19:21.340 --> 00:19:22.850 Signal: Not right now. 00:19:22.850 --> 00:19:23.950 H: And do we have questions 00:19:23.950 --> 00:19:25.210 from the audience? 00:19:25.210 --> 00:19:31.100 Please line up at the microphones. 00:19:31.100 --> 00:19:35.380 Then we'll start with microphone 2, please. 00:19:35.380 --> 00:19:37.520 Q: Thanks a lot for making your tools available, 00:19:37.520 --> 00:19:38.710 as someone else who does a lot of 00:19:38.710 --> 00:19:41.640 UEFI reversing, I've been through similar 00:19:41.640 --> 00:19:44.800 rabbit holes of trying to track this down. 00:19:44.800 --> 00:19:46.760 You mentioned that SMM is not supported 00:19:46.760 --> 00:19:48.670 and I assumed also the real mode 00:19:48.670 --> 00:19:50.980 in the transition into long mode 00:19:50.980 --> 00:19:51.850 is not supported. 00:19:51.850 --> 00:19:53.640 Is that on your roadmap or something, 00:19:53.640 --> 00:19:55.920 that you're interested in continuing 00:19:55.920 --> 00:19:57.340 development on? 00:19:57.340 --> 00:20:00.030 A: Yeah, I'm interested in it, but 00:20:00.030 --> 00:20:02.300 I'm not quite sure how to do it, 00:20:02.300 --> 00:20:05.840 especially calling into system management mode, 00:20:05.840 --> 00:20:07.180 protected mode should probably, 00:20:07.180 --> 00:20:08.540 you know, also be possible, 00:20:08.540 --> 00:20:11.250 but currently I'm also doing 64-bit mode 00:20:11.250 --> 00:20:15.070 but, yeah, if anyone wants to help me 00:20:15.070 --> 00:20:23.570 implement it, obviously I welcome your support. 00:20:23.570 --> 00:20:25.370 H: Okay, and from the Internet, please. 00:20:25.370 --> 00:20:27.059 Q: Yes. The Internet wants to know 00:20:27.059 --> 00:20:32.510 what is the advantage of UEFI compared to coreboot? 00:20:32.510 --> 00:20:33.470 A: I'm sorry, I didn't... 00:20:33.470 --> 00:20:35.300 Q: The Internet wants to know 00:20:35.300 --> 00:20:38.030 what is the advantage of UEFI compared 00:20:38.030 --> 00:20:40.110 with coreboot, for example? 00:20:40.110 --> 00:20:41.840 A: The advantage of UEFI compared to what? 00:20:41.840 --> 00:20:44.800 Q: To coreboot, coreboot, this open source 00:20:44.800 --> 00:20:46.030 BIOS replacement. 00:20:46.030 --> 00:20:48.160 A: Oh okay. coreboot is UEFI, 00:20:48.160 --> 00:20:49.780 coreboot is Intel's open source 00:20:49.780 --> 00:20:51.330 implementation of UEFI. 00:20:51.330 --> 00:20:53.800 Q: Actually, well, actually it's not. 00:20:53.800 --> 00:20:56.220 A: Oh, it's not, no, that's tianocore, 00:20:56.220 --> 00:20:59.940 you're right. 00:20:59.940 --> 00:21:03.430 The only advantage is, 00:21:03.430 --> 00:21:05.050 I don't know what the advantage is, 00:21:05.050 --> 00:21:06.910 this is just what's supported on my laptop. 00:21:06.910 --> 00:21:08.910 So that's what I was interested in. 00:21:08.910 --> 00:21:14.850 laughter, applause 00:21:14.850 --> 00:21:17.520 H: Okay. Microphone 3, please. 00:21:17.520 --> 00:21:19.620 Q: Hi. Thank you for your talk. 00:21:19.620 --> 00:21:20.980 Have you looked at any other firmware 00:21:20.980 --> 00:21:24.740 besides your Lenovo? 00:21:24.740 --> 00:21:27.550 A: I've not personally, but 00:21:27.550 --> 00:21:32.740 I know other people have. 00:21:32.740 --> 00:21:34.710 H: Okay. 4, please. 00:21:34.710 --> 00:21:37.059 Q: Thank you for the talk. How did you 00:21:37.059 --> 00:21:42.059 come out how to get the password, the hash 00:21:42.059 --> 00:21:47.680 with the combination of the serial number 00:21:47.680 --> 00:21:50.210 and the module number? 00:21:50.210 --> 00:21:53.200 A: So, the full details of this 00:21:53.200 --> 00:21:55.600 are in my blog post, but in short, 00:21:55.600 --> 00:21:58.880 there is a EFI protocol for talking 00:21:58.880 --> 00:22:01.180 to the hard drive, which is 00:22:01.180 --> 00:22:02.270 the ATA support protocol, 00:22:02.270 --> 00:22:04.430 if I remember correctly, 00:22:04.430 --> 00:22:05.630 there's a special module, 00:22:05.630 --> 00:22:06.640 there are only a few modules, 00:22:06.640 --> 00:22:08.650 that invoke this protocol, 00:22:08.650 --> 00:22:12.110 so I just disassembled those, and looked 00:22:12.110 --> 00:22:13.470 at what they did, and what commands 00:22:13.470 --> 00:22:15.220 they sent to the ATA drive. 00:22:15.220 --> 00:22:16.650 Q: Thank you. 00:22:16.650 --> 00:22:19.280 H: And there is another question from the chat. 00:22:19.280 --> 00:22:22.390 Q: Yes. The chat wants to know if you found 00:22:22.390 --> 00:22:24.790 any other unexpected bugs and 00:22:24.790 --> 00:22:28.510 if it is possible to check UEFI code, 00:22:28.510 --> 00:22:31.170 for example, when running it with valgrind 00:22:31.170 --> 00:22:34.520 or something. 00:22:34.520 --> 00:22:36.740 A: I've not really run into any other 00:22:36.740 --> 00:22:39.140 unexpected bugs, but I must say I also 00:22:39.140 --> 00:22:42.250 really wasn't looking for them. 00:22:42.250 --> 00:22:44.040 H: Okay. 2, please. 00:22:44.040 --> 00:22:48.600 Q: I have little understanding of EFI, but 00:22:48.600 --> 00:22:55.400 I had the idea to look into trying to get 00:22:55.400 --> 00:23:00.570 boot ROMs from PC graphic cards 00:23:00.570 --> 00:23:04.340 to be running on a MacOS computer, 00:23:04.340 --> 00:23:09.520 old Mac Pros when they still were having cards, 00:23:09.520 --> 00:23:12.320 and I was wondering, I wanted to figure out... 00:23:12.320 --> 00:23:15.870 these cards run, apparently, the old BIOS, 00:23:15.870 --> 00:23:19.020 real mode, and I wanted to figure out 00:23:19.020 --> 00:23:23.380 if I can write a stub that gets loaded 00:23:23.380 --> 00:23:27.050 by the EFI system and then that... 00:23:27.050 --> 00:23:31.000 my code would then invoke the initialization boot ROM 00:23:31.000 --> 00:23:33.940 for the graphics card and provide the functions. 00:23:33.940 --> 00:23:38.360 Would your toolset, would that help me in 00:23:38.360 --> 00:23:40.929 tracing that while my Mac is running, 00:23:40.929 --> 00:23:43.360 because I can't do it while it's booting? 00:23:43.360 --> 00:23:48.230 A: I don't... it sounds like a, quite a complex setup, 00:23:48.230 --> 00:23:49.890 I think it would be possible to write 00:23:49.890 --> 00:23:52.050 an EFI module to do what you're saying, 00:23:52.050 --> 00:23:53.179 but I'm not sure if you'll be able 00:23:53.179 --> 00:23:57.200 to run that while your operating system is also running. 00:23:57.200 --> 00:24:01.660 So... I'm not sure, I'll have to talk more 00:24:01.660 --> 00:24:05.560 offline to discuss your specific situation. 00:24:05.560 --> 00:24:07.920 H: Okay, and microphone 3, please. 00:24:07.920 --> 00:24:16.240 Q: Hi. Have you looked into using SerialICE for emulation of the UEFI 00:24:16.240 --> 00:24:22.850 which is essentially qemu but it has, does forward all of the hardware accesses 00:24:22.850 --> 00:24:25.770 to real hardware, so you can just trace it 00:24:25.770 --> 00:24:29.780 and run arbitrary BIOS or UEFI code in it? 00:24:29.780 --> 00:24:31.420 A: I've not looked into that, but that 00:24:31.420 --> 00:24:33.970 sounds a very interesting avenue to explore. 00:24:33.970 --> 00:24:36.009 Q: Thank you. 00:24:36.009 --> 00:24:37.909 H: Okay. I see no more questions. 00:24:37.909 --> 00:24:39.920 Thank you to our speaker. 00:24:39.920 --> 00:24:41.250 applause 00:24:41.250 --> 00:24:53.000 subtitles created by c3subtitles.de Join, and help us!