Dear viewer, these subtitles were generated by a machine via the service Trint and therefore are (very) buggy. If you are capable, please help us to create good quality subtitles: https://c3subtitles.de/talk/1262 Thanks!
So the next talk is
called Katie R W The Cherny
to build a debacle iPhone.
Well, hardware debugging of
an iPhone is usually not possible.
It's not possible if IOW devices or it
wasn't possible if I was devices
and security research of the kernel
is therefore quite a challenge.
Well, move the apple a 10
chip. Apple implemented a thing called
kernel text read only regions, which
is called Katie are
in charge.
And Brendan Asset
of Google Project 0.
He found a way to
make a debacle iPhone.
And tonight, he's gonna
tell us how he broke this.
Cathi. Katie are and
how he made, uh, debacle iPhone
out of a regular production iPhone.
Please give a warm round of applause to
Brendan.
Thanks.
Awesome.
Thank you very much. I'm very excited to
be here. Thank you for showing up to my
talk.
And today, I'm going to take you
along my journey to
build a capability that I've wanted to
have for a very long time.
A deep, huggable iPhone.
So what exactly do I mean by a deep,
huggable iPhone?
Well, in order to kind of give you the
context that you need to understand this,
I'm gonna need to talk about something
which isn't frequently talked
about in public.
And that's the thing called Dev fuzed
device's development fuzed devices,
prototype iPhones.
These are all names for similar
concept, which is a
type of device, a type of iPhone that
has extra
debug capabilities built into it.
So that's things like serial liar, debug
J Tag, basically functionality
that now allows you to debug
the phone at a very low level.
For example, doing things like single,
stepping through the bootloader, putting
breakpoints in kernel mode and dumping
registers, modifying registers,
sorts of things which would be very
important for Apple engineers to be
able to do, but which are
definitely not something Apple wants
available on production.
IPhone's distributed en masse.
Now, in order to connect to
the special type of iPhone's debug
capabilities, you need a
really special type of cable
usually called a probe.
It here's an example of what's called
a Kanzi cable.
It has a special lightning connector
on one end, which
has a special accessory.
I.T. burned into it, which allows it to
communicate with the debug hardware
on the phone.
It has a controller, which is the chunky
part in the middle, which is able to talk
the debugging protocol.
And it has a USP port
on the other end, which you can connect
to a laptop.
And on a laptop you would typically run
software.
For example, there's this tool which you
can find online called Astra.
This is not software which
Apple is willingly distributing.
This is kind of, as I understand it,
leaked code.
So it's not something which
is like, you know, sanctioned,
but there are people who are able to
obtain this software and use
it to operate these debugging probes.
Here's an example of a screenshot where
someone was able to use a
Kong serial wire debug probe
and connect it to a 32 bit
dev used iPhone and
you can see registered dumps.
You can read and write memory dos, all
sorts of really low level debugging
on this iPhone.
Now I need to say I
do not use dev use
devices.
I don't have access to these devices.
I don't want to have access to these
devices to do my work.
That being said, it would really
be incredibly useful to
have such a low level and
powerful debug capability.
So this is the motivation for
my research project.
I wanted to find some way to build
a debug capability on
a regular
Apple certified iPhone.
Some way to build my own home brewed
phone.
And there are a number of different features
that I wanted present in this homebrew
dev phone.
I wanted the ability to patch kernel
memory and in particular the ability
to patch the executable
code in the kernel.
For example, modifying existing
instructions or injecting
kernel shell code or things like that.
I wanted the ability to
kind of do your standard debugger feature
set breakpoints, set watch points.
The third item that I wanted this debug
phone to be capable of is I wanted it to
use only, you know, standard
off the shelf debugger.
So I didn't want to use to depend
upon a proprietary
Apple software like astronauts in order
to operate.
The next item is I wanted this
homebrew def phone to be
updated all. So I wanted to find
some sort of low level vulnerability
such that if I'm going to spend, you
know, three months trying to create this
debug cell phone and then Apple
is able to patch the
whatever technique was being used in the
next version of ISIS.
And now all of a sudden, I no longer am
able to debug the latest version.
Certainly this would be very useful.
I can always def
kind of the differences between
subsequent versions of IO.
Esta still got useful information
from my debugger, but
I would really love to be able to
amortize the development costs to
the debugger over many
iterations of the IO is operating
system. So keep this capability alive as
long as possible.
In practice, what this meant was I was
going to be looking for perhaps a
bootloader vulnerability,
maybe some sort of hardware bug,
something which was either difficult
to patch or even if it was
patched. It was early enough in the
boot process that it would still be
possible to update
the version of the ISIS
kernel running on the device.
And the final thing is I
wanted this damn phone to
use only parts that you could obtain
at an Apple store.
So no specially fuzed CPE
use. No
special debug cables.
Nothing of that sort.
Now, I want to mention something really,
really important that happened, probably
the most important thing to happen to
Iowa security research in
several years, and that is
pretty much just a couple of days before
I was about to open source.
OK, TRW Axiom X
released a boot rom exploit
for all iPhones between
the iPhone for us and the iPhone
10.
Now, the boot rom exploit is actually
strictly more powerful than
the capability used in K TRW.
Everything that I want to do in my debug
phone is totally possible to do using
the boot rom x alone.
So I want to tell you this just so that
you're aware that many of the assumptions
that I made going into this
project really don't hold anymore.
But they did hold at the time that I
started this research,
and I do expect that future debug
capabilities and future research
platforms on the iPhone will be based
around the boot rom exploit instead.
So with that, let's talk about the
main mitigation that makes Colonel
debugging on my phone right now, both
really hard to do and also
so important.
And that's a mitigation called Katara.
If we look back at the list of
requirements that I wanted in
my homebrew that found the very
first item on this list was I wanted
the ability to patch kernel memory
and in particular to patch the executable
code.
Now, normally on most systems, this isn't
actually that difficult.
Once you have the ability to read and
write kernel memory, you can just modify
page tables, makes some page
in memory, read, write, execute, stuff
your shell code in there and you're
basically done.
But on the iPhone, Apple, as I did a
mitigation called TRW.
And the idea is that we have
a kernel cache in memory that's been, you
know, put there by some sort of secure
brute process.
But once it's in memory and the system is
running, Apple would really like a way
to guarantee that the kernel
cache gets locked down as much as
possible.
And any data in it, which really
does not need to be readable, is
never going to be modified.
Basically, keep the guarantee
that once an iPhone is booted,
the code running in your kernel is
exactly the code that was protected by
and verified by the secure boot process.
So there is some data in your kernel
which does need to be rateable,
but there's also a bunch of data which
really does not need to be right of all
the most prominent example is the
executable code.
Clearly, we don't want that to be
changeable, but there's
also a bunch of other pieces of data
which are worth protecting.
For example, you have strings, maybe
format strings, virtual
method tables, the page tables
that are mapping in the kernel cache
itself into memory.
All of these additional pieces of data
Apple would really like to have them be
protected and not modifiable.
And that's what KKR does.
It's going to lock down all of this
data that we want to be read only
as the defenders.
So as far as we know, OK, here are stands
for a kernel text read only region.
So what Katara boils down to
is it's a very strong form of write
X or execute protection.
It's available an apple, a 10 C P use in
later, and it provides two very strong
guarantees.
First is that all rights to memory
inside of the region protected
by KKR will fail.
But this basically is what provides kind
of the lock down guarantee that what
was put there by the secure butane
kind of stays that way and can't be
changed.
But there's another part to it which is
equally important, and that is that all
instruction fetches from memory outside
of the protected region are guaranteed
to fail. This is what ensures that you
can't put new executable code in the
kernel, that the only code that you're
allowed to run is the
colonel's own code.
So in order to kind of understand how
this works and a little more detail,
let's look at a oversimplified diagram
of how CPE works.
So here we have the CPE cause
this is for example, in 11 CPO
with six course, the little
purple box and the bottom corner is the
M M U.
We have the highest level of the cash
hierarchies. The L2 cache
behind that is the memory controller
called AMC C and
then this is connected to D Ram.
Now the kernel lives continuously
in physical memory and D ram
and this is what Apple wants to protect
with k tr.
So the first step in order to lock
down this region happens on the MMO.
So let's zoom in to a single CPC core.
What Apple has done, as far as
I understand, is basically just add
a couple of registers to the MMO you
that point to the beginning and ending
address of the region to
protect.
What this allows us to do is the CPO
core can now check whether each
instruction it's about to execute
violates the security guarantees we want
from K TR.
So for example, let's say the CPC wants
to show a right to a physical address
outside of the Katara region.
That's fine. We can actually we can write
to that memory.
So this will be allowed by the enemy.
And the right will go through.
If, however, we try to issue a right to
an address that points to inside the K TR
region.
This violates the security properties of
K TR.
And so the MMR you will recognize this.
It'll deny the right and it'll cause
that instruction default.
Similarly, if the CPA tries
to execute an instruction
that is fetch from an address outside
of the courtyard region and
you can recognize this and cause that
instruction, fetch default.
But so here's the kind of the new picture
of the sea, cause we have a bunch of new
registers and an emu that kind of have
this catch ya protection
built into them the next.
However, this isn't the complete picture
that we need in order to
protect this memory.
See, there are other devices that are
connected to your system.
All sorts of peripherals.
This could be like a Wi-Fi chip.
This could be like a USP stack,
all sorts of thing.
Any sort of hardware device which could
issue DMA commands to your memory
controller.
So in order to protect against malicious
peripherals DRM hanging over
their protected region, we think
that Apple has added a registers
to the memory controller as well.
That also point to the beginning and
ending address of this
locked down region such that
that way any time some peripheral tries
to DMA over the secure region, the memory
controller sees that this DMA doesn't
look valid and it'll just discard the
right.
So this is kind of the picture
that the hardware now looks like in order
to support Katara.
But this isn't actually the complete
story either, because there
is one specific edge case that needs to
be properly handled and that's when ACP
Core goes to sleep for a little bit and
then wakes up what's called resetting.
Anytime they see you,
Core goes to sleep.
It's going to power down registers.
And in particular the MMO you
registers which store the K TR bounds
are going to lose their value and be
reset to zero.
So when the CPO wakes up from sleep,
we need some way to reset those registers
to point to the beginning and ending
bounds of the lock down region.
So the reset vector is
the first piece of code that gets
executed when a CPA core wakes from
sleep. And it does so with the M.M.
you off.
And what Apple has done is they've added
code to the reset vector that
basically just initialize as those KKR
registers the beginning and ending
bounds are stored in these global
variables.
These variables, by the way, happened to
lie inside of the locked down region
so they can't be modified.
And once it reads those values into
general purpose registers, it writes
those bounds into
special system registers
that are used by the imam you to
verify the KBR security properties.
So once this code executes,
K TR will be locked down on the M
you. And once again, you can no longer
execute memory that lies outside of the
lockdown down region.
So now that we have kind of a high level
understanding of how KKR
works, let's look at how
it's possible to break K TR
and we'll start with a few historical
examples.
There are two
historical instances of
partial KKR bypasses up till
now and the first one
came out pretty soon after
the KKR mitigation was first introduced
and it was discovered by Luca Tedesco,
who was gonna be giving a talk.
I think in this room tomorrow evening.
So what Luca found was
that Apple
had left an instruction in the kernel
cache that they
didn't mean to leave executable, but it
accidentally was.
This was the MSR TPR one
instruction which sets the
special TPR one
register.
This register stores the physical address
of the root of the page table hierarchy,
which means that if you're able to modify
the value of this register, then you
are able to supply your own custom page
table hierarchy and therefore remap
virtual memory onto new physical pages.
So this is exactly what he did.
He just chose a
remapping that placed the read
only regions of kernel memory
onto new physical pages that contained
a copy of the original
kernel data.
Now it's important to note that Courtyard
was still actually fully initialized
at the point at which you were able to
execute this MSR instruction.
So we can patch read only
data, but we can't execute
new kernel code because KKR locked
down on the atom. You still did occur.
So what? The K TR bypass
and ten point one basically
achieved was limiting what was protected
by KKR down from the whole read
only region to only the executable
code. But we get a whole bunch
of new data in the kernel, which
is now right.
Well the second
case here are bypass that
was released was more of a bypass
in spirit than in practice.
But it's definitely a very important
tool and a huge inspiration for
my research.
So back in Iowa, eleven 1 2
in beer. Found that
the debugging functionality
in the arm specification was actually
implemented in apples processors
and could be used to implement a full
featured kernel debugger.
So if you read the ARM Architecture
Reference manual, you'll find that there
are documentation on a feature
called Self Hosted Debugging.
Basically, the architecture provides a
set of debug registers which you can
access via MSR
instructions, and you can
use these debugging registers to set
breakpoints in kernel mode and also
to by implementing
exe exception handling code
in your exception handler.
You can catch your own break point
exceptions and basically have the
kernel implement its own debugger.
For example, this might be somewhat
analogous to using
a KDP to debug a MacBook.
Now KDE has actually been removed from
the IOW kernel that's distributed.
On production devices, however,
the debugging registers that one
might use to implement this are still
present, still fully functional, and
what he found was that he could use
return oriented programing to set
the values of these registers correctly
in order to implement a
rather full featured kernel debugger.
He built something that works with Al to
be proved quite useful,
and in particular it was able to,
by setting a breakpoint single stepping,
modify, register values, execute
existing instructions in the kernel and
basically arbitrary order.
So not native like
arbitrary shell code execution, but
pretty darn close.
So I started
this project of trying to find some sort
of caterer bypass by looking and kind
of the places that I thought would be
more powerful, find more
powerful TR bypass is more likely
to lead to something that would be
persistent across multiple versions by
OS.
Where I started was looking and I boot.
I was trying to find some sort of eye
boot bug in the image for passing
and verification functions.
I didn't end up finding anything there.
Next, I kind of read through several
sections of the ARM architecture manual,
saw some interesting things about, you
know, maybe you know, if you have weird
malformed DLP
entry, if you have weird malformed page
table entries, you could do something
weird with the T L.B.
that didn't really end up building
anything useful.
I played around a little bit with, you
know, I kind of misunderstood how KKR
worked a little bit.
And I thought, you know, maybe there's a
way to corrupt the L2 cache
and then bypass KKR that way.
That didn't end up really working either.
So I kind of, you know, tried a bunch of
things. None of them really panned out.
And I put this research on
the backburner for a while.
And it was actually while I was doing
something totally unrelated that I
happened to generate a kernel panic which
reignited my interest.
So I was playing around with interrupts
and I'd managed to get a C Q course
stuck in an infinite loop
with interrupted disabled in kernel mode.
And I got a panic message which said, you
know, panic watchdog time or time
out CPO on has failed to respond.
It's kind of the exact thing you would
expect when you isn't responding because
it's stuck burning you cycles
in an infinite loop.
Eventually system notices and panics
because you know, there's some
significant problem here.
But what really caught my attention about
this panic message was something much
earlier in it where it says attempting to
forcibly halt CPR, you won.
Now, this was really interesting to me
because according to what I'd read
from the Army Manual,
there wasn't any
standard way for one CPR
corps to halt a second CPR you
like. There's no MSR that you can
write to. I didn't really remember any
way to accomplish this.
So what I figured was there's probably
some sort of like proprietary interface
going on here where, you know, maybe
there's a special
CPR control registers which are
accessible via an amnio.
And somehow he was trying
to leverage those in order to halt the
CPR.
So this seems like a pretty interesting
I've never seen something like this
before.
So I decided to, you know, pull up the
security engineering tools needed to
figure out what was going on here.
So I crept through the X and you source
code to try to find the string
attempting to forcibly held CPR.
You pretty quickly came to
the function M.L.
debug wrap hold CPR, which seemed
to implement this functionality.
It takes the index of which CPR
you you want to halt.
So on a CPA with six,
that would be the index 0 through 5.
And the actual part which holds
the CPA is just right down here,
a couple lines lower.
So what this does is it reads a
pointer to some volatile memory from a
person AP data structure.
This is memory.
This variable that stores the pointer to
the memory is called debug wrap drag.
And then the actual part of the code
which holds the CPA is
simply consists of the single line where
it writes some special
debug halt value to the debug wrap
rack.
So this really strongly supports
the idea that this is some, you know,
special M Io register.
And when I was looking online for trying
to find references to this debug wrap
thing, I wasn't really getting
any results. So it kind of really
strongly suggested that, yes, this is
some sort of proprietary Apple specific
interface.
The other thing I kind of caught my
attention was this reference to
something called core site.
I remembered hearing, you know, core site
somewhere else before, but it doesn't
really. Didn't really know what it was.
Market is something to come back to,
but we're really caught my attention.
When I was looking through this file, it
was a function just a few lines down
called M.L. Debug wrap halts CPA with
state.
This does basically the same thing as
the other function, except in addition
to halting a CPA.
It also reads out the values of the
registers on that CPA.
That was just halted.
And the way that does this is actually
quite remarkable.
So first off, you can see that there is
another reference to this core site
thing. It says ensure a memory map course
that registers can be written.
So clearly something with core site is
important here. Maybe it should be block
of registers that contain this
functionality.
But the important part is this a
for loop right below which iterator
ie over the indices of your general
purpose registers.
What this code does is first it's going
to generate the numerical
code for the instruction
which writes the value of general
purpose register x ie into
the special system, register debug
DDR.
So this isn't an instruction which
already exists in the kernel cache, it is
just literally generating the
numerical value of the code for that
instruction.
Next, it passes that
code into M.L.
debug wrap stuff instruction.
And finally, it reads the value of
the debug DDR register and writes
the value into the
output buffers ex AI field.
So this is actually really interesting
because of what it suggests is that
M.L. debug wrap stuff instruction
is somehow executing dynamically
generated instructions.
And this really flies in the face of the
security model that
KKR is designed for.
So KKR is meant to ensure
that, you know all of the instructions
here. Colonel Cash. Those are the only
ones that you're allowed to execute.
But here there's some sort of interface
which seems to be able to execute any
instruction you want on
a halted CPO.
So this is definitely really interesting.
Now, just because there is code to do
something and execute doesn't actually
mean that it necessarily works in
practice.
So I basically just decided to
test to see if this code actually runs.
I pulled up an old kernel exploit that
I'd written and I
basically just wrote and
hacked together something that would call
the function AML debug wrap halts CPA
with state pass it output buffer
and then dump the contents of that
buffer.
And what I found was that the
output buffer really did look like a
bunch of registers.
So there's a bunch of stuff which was 0,
which was kind of weird.
But the value of CPS CSR
does look correct.
It actually looks like a CPA, you running
in kernel mode and the value
of P.C., it doesn't really look like a
normal kernel virtual address.
Those usually start with, you know, like
f f f f, but
it does really look like some sort of
physical address perhaps.
And with a little bit of digging
into this, I pretty quickly discovered
that this is a physical address
of an instruction in the reset vector.
Now, things are really, really getting
interesting because what this suggests
is that we've managed to halt the
execution of a CPE core while
it's actually running the reset vector
and in particular before the EMU
has been turned on.
Now, this is a really critical point in
time for TR because before
the enemy has been turned on K TR
is unable to protect
the CPSU from executing instructions
outside of the locked down region.
So of course what I really wanted to know
was how do we use this capability
in order to bypass Katara?
Well, it turns out that there's kind of a
more fundamental question that I need to
answer first, which was what exactly
is this core site thing?
Anyway, it's really hard in practice to
at least for me to exploit something
without kind of knowing a general sense
of how something works.
And so I basically just searched for a
core site in the arm reference manual
and came across a bunch of references
to core site in connection with
something called the external debug
interface.
Now the external debug interface, it
turns out, is pretty much just a
different way of accessing the
same functionality that Ian used
in his self hosted kernel
debugger.
So the in a self hosted debugging
interface you write to
these debug registers using MSR
instructions.
The external debug interface
provides kind of a similar, very similar
functionality. It's probably the same
debugging hardware under the hood that
you're driving, but the interface
to access these registers is via
MMI O rather than
via executing MSR instructions.
So this means that basically the
functionality that is necessary
to build a kernel debugger is still
there, even though the Brock gadgets
that even used to activate it are
taken away, the memory mapped interface
still exists.
And in fact, this isn't even the first
time.
Not even close to the first time that
someone has tried
to use debugging registers
and an arm processor in order to mount
some sort of privilege.
Just hack.
She knew Nang and Feng ways.
Yang presented an attack at most
like 20 19, where they
basically were able to leverage these
same debugging registers
on Android phones to
break the protection of the
secure world.
So they were able to
make one for you for
debug another CPO core
make that same second CPA core execute
instructions to enter the secure world at
E L3 and then also
make it execute instructions that would
cause it to read and write memory
in the secure world.
So just to summarize kind of the key
concepts behind the external debug
interface, it is an on chip
debugging architecture.
It provides Percy you
debug registers which are accessible
by MMI. So
the actual interface itself, how to use
these registers is really extensively
documented in our manual.
It talks about, you know, what the names
of all the registers are.
The offsets of them
like how to program the registers in
order to do things like set breakpoint
and watch points.
So I'm not going to go over all of that
right here.
But what I will say is that the external
debug interface is certainly more
than powerful enough to do any sort of
kernel debunking that we might be
interested in. Definitely capable of
setting breakpoints and watch points,
single stepping execution, executing
arbitrary instructions, poking
at memory, all this sort of stuff.
So the idea for my attack was we
have these debugging registers.
We can do things like single stepping and
we know that we can halt execution and
the reset vector.
So I basically decided I would
try to use the external debug interface
to single step the reset vector.
And then once the reset vector is about
to execute that Katie or lockdown
instructions just jump over that piece
of code. OK, here are never gets
initialized.
So if we look at the reset vector, we'll
just step through all of the first
instructions. And then once we see that
we've hit this conditional branch
where we're just about to start doing
the. Katie, are registered initialization
set at 17 to zero jump over
the TR code altogether.
Now, this is a nice idea,
but we don't actually have all the tools
yet necessary in order to carry it out.
We know that we can hold the CPO and we
know that we can execute arbitrary
instructions on it and do things like
modify the values and registers.
But we haven't yet found
the ability to resume executing
on the CPSU after it's been halted.
So if we set a breakpoint on the
reset vector, for example, that's nice,
but it's not gonna be of much use if we
can't continue execution after
that point.
Furthermore, there's another somewhat
more subtle issue, which is that
we're using one CPSU
to hijack another CPSU as
it resets, but CPE
resets happen all the time.
Anytime a CPA corps is idle for a couple
of seconds, it'll eventually just do
a reset as it powers down and powers
back up again.
So we're going to have to do
this.
Here are a hijack.
We need to modify the execution
of a reset vector and skip the K TR
initialization every single time
that a few core resets unless
we can find some way to disable the core
from resetting.
So I didn't know how to do either of
these two things.
So I kind of just decided to play around
with that original proprietary
register that I'd found earlier.
So the actual new source code documents a
couple of the bits. I think it documents
two of the bits in that register.
The remaining bits are undocumented.
So I figured, you know, might as well set
some dates, clear some bits.
See what happens. See if I learned
anything interesting.
And I kid you not by sheer dumb
luck. It happens that that register
contained exactly the pieces of
functionality we needed to pull
this hijack together.
So bit 30 actually
will clear the
Haltern and allowed the CPO to resume
executing, and bit twenty six
will keep the CPA powered up
so that it doesn't subsequently
reset. And then we have to re hijack
the reset vector.
So basically, the attack that we
describe before works perfectly
well.
Once we have this new functionality, we
just make sure that once we hit this
branch, we skip over the Katara
Register lockdown code and
then these registers never get written to
Katie are is never initialized on the
system and kernel memory becomes
executable.
So what this looks like is first we
have k tr enabled.
Once we do this hijack, KBR
is disabled on an menu.
And now any
page in kernel memory could now
potentially be executed.
Got a little bit more to go.
Thank you.
So now that we've found a
way to break a terror, I
want to talk about how to build an actual
debugger on top of this, because I
found it to be a quite non-trivial
challenge.
So there are a number of steps involved
in this process, and actually in many
of them I encountered issues that I
thought would be basically
insurmountable.
So the first step in the process is we
need to remap the kernel
because even though we've enabled the
ability to execute arbitrary kernel shell
code, we don't yet have the ability to
patch kernel memory.
Next, we need to figure out
some way to load a kernel extension.
We need to make sure that we're properly
handling interrupts because we're going
to be disabling our.
Sorry, we're gonna be halting CPE use.
And once the CPC was halted, it of course
can't service interrupts anymore.
We're going to need to establish some
sort of communication channel between the
kernel extension running in your iPhone
and your laptop running LTE.
And finally, we need to implement a GDP
stub to process the packets
sent by Al LGB and to drive
the debugging hardware.
So at the point at which we bypass KKR,
we have the ability
to execute arbitrary Colonel Shell code.
But we don't yet have the ability to
patch kernel memory.
The reason for this is that even though
we've disabled K char on the M M use,
it still fully enabled on the
memory controller.
So even though we can
execute code outside of the read only
region, the read only regions physical
pages are still fully protected
and we can't modify them persistently.
So this is actually kind of problematic
for us. We really do need to modify
the page table permissions in order to
make the kernel extensions memory
executable and the root
of the page table hierarchy
lies inside of the K TR region,
which is still protected.
So the solution to this is to basically
do exactly the same thing that Luca did
and the ten point one point one
bypass, which is to remap the kernel
onto fresh readable pages and set TPR
one to point to the new page tables
instead.
So what that looks like is initially
the TPR one registers is going
to point to the
root of the page tables, which lies
inside the protected region.
What we have to do is we need to copy
the kernel, the pages containing
the kernel, we need to copy the data of
that onto new rateable pages
that are outside of the protected region.
Update the page tables in kernel
memory and then make TTR
one point to the new modified
page tables instead.
And with that, we do now have the ability
to patch the kernel.
So the next step in this process is we
need the ability to load kernel
extensions.
This actually turns out is pretty simple
once we bypass KKR.
All we have to do is we need to allocate
some memory to put the kernel extension
in copy in the binary
dynamically link the kernel extension
against the kernel that's running.
Because if you want to have a kernel
extension, presumably you're going to
want to call kernel functions at various
points.
After that, we need to modify page
tables to make the kernel extension
executable.
And finally, we need to call some
function in the kernel extension to begin
it running.
And with that, we're now ready to start
designing a kernel debugger.
So what I eventually settled on was a
pretty simple design.
I would have one core in the CPSU,
which I call the monitor.
Core is going to be exclusively reserved
for the K TRW debugger itself.
So it's no longer going to be running X
and all of the other
cores in the system are going to continue
to run your operating system as they do
normally when you set
a breakpoint or a watch point on one of
the debug cause it's going to cause
that core to halt and enter debug state.
So the monitor core is just
going to sit in a tight loop pulling
all of the other cores to see when
they enter debug state.
And when it notices this, it'll send
a message to L.L.
D.B. over some communication channel
saying, hey, this court halted because it
hit a break point and then LTE can
take care of the rest.
Now, when I implemented this, I pretty
quickly encountered weird panic messages.
So this is one example AP panic.
No pulse on something or other.
And it took a little bit of effort.
But what I eventually learned was this
was being caused by
a process around the vise call it
called the always on processor,
sending periodic interrupts
to the main application processor
and the interrupts that are sent by the
always on process or need to be handled,
or else the GOP will panic.
And once the LP panics, it brings down
the whole system.
Now some of these interrupts are actually
relatively easy to disable.
I reverse engineered the watchdog
timer kernel extension and found
the hardware interface the
set of registers needed to disable
that. But there are other interrupts
which I wasn't able to narrow down.
I wasn't able to disable
now.
I strongly suspect that
the dev used devices that
some are able to acquire do have the
ability to
disable these interrupts or other or in
some way are not affected by this
problem. Because presumably when Apple's
engineers are using
one of these devices to debug the kernel
and they hold the kernel for a few
seconds, it's not a great user interface.
If when they resume execution,
the whole kernel panics because of this
interrupt problem.
So I strongly suspect there's a way to
fix this problem, but I wasn't able
to find it.
Instead, I basically implemented a big
hack, which is that I started servicing
interrupts from the EOP on
the monitor core itself.
Now this introduced its own problem,
which is that now execution on the
monitor core can jump back into X
and you and start running
the IRA Q handler at basically
any time, and that includes
when any of the debug
cause is halted holding
an IRA. Q Critical spent lock.
This is a huge problem because once
we try to acquire that same spent lock,
we can't acquire it.
It's already held.
And the only way that lock can be
released is if that debug the cords
resume, which has to be done by us.
So we entered this deadlock for a
very long time.
I thought that this was pretty much an
unsolvable problem for my debugger,
but it actually turns out there's a
really, really simple solution.
And the reason is that the action new
kernel itself has to deal with this
problem.
See when an IRA Q is delivered
and some code is processing the IQ
if interrupts were enabled.
Then a second IQ
could be delivered and cause the
IQ handler to be reentered.
In which case that same lock would be
grabbed a second time.
What that means is that interrupts
have to be disabled while
in an IQ critical region,
which means it's really easy to test for
whether it's safe to halt one of the
debug because you just check whether
interrupts are enabled or not if
interrupts are disabled.
That means that it's possibly in an IRA.
Q Critical region and you just wait a
little bit of time before halting that
core and after that,
all of my interrupt problems pretty much
disappeared.
So now we're at the point where we have
a text running
in the kernel. We seem to be able to halt
and resume CPR course, but we need
some way for L.L.
D.B. running on your laptop to
communicate with the debugger running
on your iPhone's kernel.
I considered a number of different
options, each with various advantages
and disadvantages.
Serial is really, really nice because
it's incredibly simple to implement
USP.
I liked because it would be really,
really fast Wi-Fi.
I kind of just threw in there in case the
other two didn't work. There wasn't any
really compelling reason to implement
a debugger over Wi-Fi.
What really made the decision was the
disadvantages of each
technique.
So for Serial, as far as I'm aware,
you do need special hardware
in order to operate
communicate with the iPhone over serial.
So this basically violates the first
goal. One of the goals of my
homebrew dev phone, which is that you
don't need any special hardware.
Everything can be purchased from
an Apple store.
The other two techniques, you SBN Wi-Fi,
both suffered from the same problem,
which is that I would need to write a
custom driver for the hardware.
The reason for this is that I cannot rely
in my debugger on the code
that I'm debugging.
If I set a breakpoint and a
few core halts while it has
some block used by the Wi-Fi
or the USP drivers, then
when my application in my kernel
debugger tries to communicate over that
mechanism using the stock
built in to X and you, it's
going to try to take the same lock and
deadlock, same problem we had before.
So whatever communication channel we use,
we to implement a custom driver for
it, which is self-contained.
So out of USP and Wi-Fi.
I basically figured that writing a USP
stock was slightly less painful.
It was pretty easy to figure out with
some Googling. Which hardware
USB controller wasn't used in the iPhone.
It's a controller by synopsis called
the design where high speed USB 2.0
on the go controller
was somewhat unfortunate about this
controller is that it is
proprietary. The interface that it uses
to communicate is not one of the standard
USP interfaces, which means that you
cannot use kind of your stock
open source off the shelf drivers
for it.
And when I tried to look at the data
sheet to see how I could
program my own driver, I quickly ran
into a log in while I couldn't
actually access it.
And I was unable to obtain
the data sheet for it.
So this seemed really problematic.
But one thing that I could find was
open source header files for this
hardware.
Now there are open source drivers
for operating it, but all the ones that I
was able to find that
operated this hardware did so in a
host mode.
So kind of as a laptop rather than as
a device, you plug into it.
And that didn't really work for me.
So that wouldn't
be that wasn't what I wanted.
But I was able to use the header
files which contained the register
definitions.
Now, the only place that I could think of
that contained a fully
self-contained implementation
of the
USP stock that operated the exact same
hardware as using the iPhone
was the iPhone's very
own secure ROM.
So the secure Rahm is the
very first piece of code that runs on
the application process or when it starts
up and it needs the USP stack
in order to communicate with
a computer over for DFA.
You firmware upgrades.
So I basically took Apple
secure from their dumps of it that you
can find online.
And I put it into IDA and
reverse engineered the
secure ROMs USP stock basically
back to source and then re implemented it
in C.
And so this was a rather painful process,
but the end result was that
I was able to make my iPhone
appear to my laptop as a
special key TRW USP
device.
And with that, the only step left in
actually implementing a debugger is
implementing the GDP stub.
This is pretty easy
as compared to kind of the other stuff
in this project.
The GDP specification is open source.
It's basically just a bunch of passing
and then driving the external debug
interface.
And once that was done, I had
the ability to debug a production
iPhone over USP.
No special cables, no leaks, software
involved.
Yeah, it was pretty cool.
So here I'll do a hopefully very quick
demo of how to operate
this debugger.
So I have an iPhone, which
you can see here.
Right now you're able to see the
kind of the screenshot of it on the
laptop. But as soon as I operate the
debugger, the USP stack will be taken
over and you'll no longer be able to see
this part of it. So
what I'll do is I'll simply start the
app that loads the kernel extension.
And so once that's running, we'll lose
connectivity with advice, but we can
connect to it with LGB.
And yeah. OK.
So I'll LGB has recognized
this device as an OS device
and I OS kernel cache, it's discovered
the load address and it's halted the
kernel so we can now resume execution.
Now I can't show this on the display,
but for those of you in person, you can
see that the device is still responsive.
You can do things like load apps
and yet there's still a kernel debugger
attached to the device
so we can do things.
For example, all set a breakpoint
on the sister call main core.
All right. So we have a breakpoint set.
Now I have an application on the device
that is simply going to call Main Core
with very distinctive arguments.
It is possible to load an app
onto the device over Wi-Fi even once
the USP hardware has been co-opted.
But for this demo, I'm just going to
have the app pre install the device.
I'm going to click on the application
icon and it basically
immediately halts.
The phone is no longer responsive because
we're halted our breakpoint and we can do
things like get a back trace, we can
examine registers all look at
the memory point you do by
register x1 and we can indeed
see are arguments that were passed
from user space.
We can do things like that, watch points,
kind of all of your standard debugging
functionality.
So we'll set a watch point on this memory
address and resume execution
and we basically immediately hit the
watch point.
And you can see the instruction that
triggered this watch point loads x10 an X
eleven.
And these are indeed the values that we
expect. So at what point seemed to
function correctly, we can
disable the breakpoint
and the watch point and
resume execution.
The app runs again. Your phone is
responsive.
So basically a full feature kernel
debugger.
So thank you very much.
The Debugger Source code
is available on the Google project zero
GitHub.
I also wrote a blog post kind
of describing in more detail
the process of finding the KKR bypass.
This was a really, really fun project
and I am really
excited to hopefully make Colonel
debugging on the iPhone just a little bit
easier. Future versions will probably be
based on the BU RAM exploit, which
I'm really excited to see what comes out
of that. So thank you.
Thank you very much.
So we have five minutes left for
a Q and A, please queue up on the
microphones in between microphone
one, two, three, four.
We have some more. So
and maybe you have questions from the
Signal Angels, Signal Angel.
No questions from the Signal Angels.
So microphone one, please.
Yeah. Thanks for the amazing talk.
At the beginning you showed us a tweet of
the exploit and just
said that everything you could
do was possible with this one as well.
It said that it's not touchable.
So do you see any problems
regarding security or anything
using such a technique?
And is it possible to run
it like without
having the iPhone unlocked?
And is there any way to sort of abuse
this?
Do you mean the RAM bug
or do you mean the debugging registers
used here or both or either?
Yeah, just.
Everything. All the above.
I don't really know.
This isn't really kind of my area of
expertise. I can see, you know, some
people might be able to leverage
these types of vulnerabilities for, you
know, proximal physical attacks.
The debugging registers that I'm using
here aren't really all that useful
for a remote attack because
you encounter that problem or, you know,
CPE or resets and the KKR bypass
gets lost.
And really, once you have a kernel
code execution, you should really
consider your advice fully compromised
anyway. So I don't really think that
the debug registers are a security issue
to boot rom.
You know, maybe for physical stuff, but
it depends on your threat model.
Thank you.
Microphone four, please.
Did you have a look in to do you Linux
kernel for the design?
What to quote a driver because it's in
drivers use BTC too I think.
Yeah. So this was actually really funny.
Basically as soon as I had finished
implementing the USP stack
and I'd got it working, I realized
that the reason I couldn't find any
open source drivers online was because
I was searching for the wrong things in
Google. I'm just really bad at googling
and the files containing
the driver for operating
it in device mode
were just named something different than
I expected.
So you learn as you go.
Great. Thanks. Microphone one, please.
Hi.
Great talk. I really enjoyed it.
So I have a quick comment and then
a question.
So comment is
this is the first time this is publicly
revealed. But the veto was
actually the trust zone was
first dumped exactly the same
way through the course site registers.
That was 2014.
That's pretty financing.
Is this still happening again?
Again, my question is, you said
you reversed the
USP from secure.
So did you find checkmate?
So first about your comment.
Definitely. I know that there
are tons of people who have found similar
capabilities. Basically, nothing
that I've done in this project is
original work. All of it is building off
of stuff which other people have done.
So absolutely. That's definitely the case
about whether I discover checkmate or
not. The first time I was looking at I
boot, I basically saw the USP
stock code and I was like, oh my god,
this is so complicated.
I want to avoid touching this if at all
possible. So now I completely missed
that.
Thank you.
So no more questions, please.
Another big round of applause for
Brandon.