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!