-
[Translated by {Iikka}{Yli-Kuivila}
(ITKST56 course assignment at JYU.FI)]
-
33C3 preroll music
-
Herald: The Max is a security researcher
at Lookout has been doing this about 10
-
years, he spent a lot of time in
obfuscation, exploit development, security
-
research, previous Black Hat speaker,
currently focused on mobile security
-
research and working on his PhD. He'll be
telling you about some of the internals of
-
Pegasus malware today. With that, I will
turn over to Max to take it away.
-
Max: Thank you.
-
applause
-
M: Hi, everyone, say my name
is Max Bazaliy, and today we'll talk about
-
the Pegasus Internals. I'm from Kiev,
Ukraine, currently work as a security
-
researcher at Lookout and last few years
focused on a jailbreak techniques. So
-
that's why I co-founded the Fried Apple
team and we're working on a various
-
iOS jailbreak, including eight and nine.
So Pegasus. Pegasus is a high quality
-
espionage software that can be used for
complete surveillance of a device. Just
-
everything from stealing your personal
data up to remotely activating a
-
microphone or camera on a device without
any indication it's really happening. So
-
in order Pegasus to work, it need to
jailbreak a device first because the iOS
-
sandbox prevents application from spying
on each other. So that's why Pegasus rely
-
on a trident exploit chain to completely
own a device and install persistence that
-
can be used on each device. Here's a
really terrifying list of targeted apps,
-
including even the known as most secure
ones, like Telegram, WhatsApp, Viber. And
-
I'm pretty sure you can find your favorite
messenger in this list. Before going into
-
a deep technical analysis of the
vulnerabilities used, I want to tell a
-
story how we get it - a Pegasus sample. So
police met Ahmed Mansoor, who's mostly
-
known for his job as a human right
defender. He's even a recipient of Martin
-
Ennals award, sometimes called the Nobel
Prize for Human Rights. So I understand
-
this year Ahmed received a message with a
text that someone in a state prison got -
-
someone is imprisoned in a state prison.
So and he received another text with a
-
similar thing the next day. But previously
he was targeted by hacking team in 2012
-
and got FinFisher in 2011. So now, instead
of clicking on the link, he contacted the
-
Citizen Lab because he was working with
those guys before. So he sent a link for
-
Citizen Lab to analysis and we are in
Lookout research team. We get initial
-
sample and a link from a Citizen Lab. So
in this story, I mostly will focusing
-
about technical, part. So in order to work
- Pegasus rely on the Trident exploit
-
chain and it uses three stages. So on the
first stage, it uses a memory corruption
-
to achieve a remote code execution in a
Safari context. After that, it jumps -
-
after this on a device - it jumps to a
second stage and uses two vulnerabilities
-
to exploit the kernel. One is used for by
- by the Kernel Address Space layout
-
randomisation and another to achieve
kernel - a remote - a kernel code
-
execution kernel level code execution.
And finally, on the third stage it
-
installs espionage software and uses a
special trick to achieve on device
-
persistence. So I will focus on each stage
more detailed. The first stage, as they
-
say, is a single use spear-phish url that
will be invalidated after the first click.
-
It contains obfuscated JavaScript that
first thing it do it checking for a device
-
type: Is it iPhone, is it iPad, is it 32
or 64 bit. And based on information about
-
device processor type the different
versions of shellcode will be downloaded.
-
Which is in stage two. And finally
exploits remote code execution
-
vulnerability in a webkit in order to
execute the shellcode. So what
-
vulnerability will it use it? CVE 4657
remote code execution in WebKit. Basically
-
the vulnerability is use after free that
achieved by using two bugs and in a sample
-
that we got it's not stable because it
relies on WebKit garbage collector. The
-
problem itself lives in a -
MarkedArgumentBuffer that can be exploited
-
by usage of the defined properties. So
defined properties is a method that
-
defines new or modified properties
directly on object. It takes a few
-
arguments and the object itself and the
properties objects which can have
-
descriptors that constitute the property
to be defined or modified. It have a
-
pretty simple algorithm, it contain few
loops on the very first iteration of each
-
property descriptor checking for a
formatting and after that get appended to
-
a descriptor's vector and to make sure
that the reference to property descriptors
-
do not become stale, they need to be
protected from being garbage collected.
-
For this purpose MarkedArgumentBuffer is
used. We see it at the very very end,
-
MarkedArgumentBuffer append. So
MarkedArgumentBuffer prevents objects from
-
being deallocated. And after each property
-get has been validated and it's okay, the
-
defineOwnProperty associate each user
supplied property with a target object.
-
And here is a problem, because it's possi-
ble when the defineProperty will be called
-
it's possible to call any user defined
JavaScript methods. If in these JavaScript
-
methods garbage collection can be
triggered, it will deallocate any unmarked
-
heap-backed object. I will go a little bit
deeply in the details. First of all, a few
-
words about MarkedArgumentBuffer and
JavaScript garbage collector. So
-
JavaScript garbage collector is respon-
sible for deallocating an object from
-
a memory when they are no longer
referenced. It runs at a - random
-
intervals and based on the current memory
pressure, the current device types and so
-
on. And when garbage collector checking if
objects should be deallocated, it walks
-
through the stack and check for reference
to an object. A reference to an object
-
also may exist in the application heap,
but in this case an alternative is used
-
called the slowAppend. So
MarkedArgumentBuffer is initial inline
-
stack contains eight values. Well, that's
mean when the ninth value will be added to
-
the MarkedArgumentBuffer the capacity will
be expanded. It will be moved from a stack
-
memory to a heap memory. This is what the
slowAppend is doing. SlowAppend move stack
-
from a - move buffer from a stack to a
heap, and now object not automatically
-
protected from a garbage collection. And
to make sure they were not deallocated,
-
they need to be added to heap's
markListSet. This is what we see here. So
-
slowAppend trying to acquire heap context
and it can be acquired adding an object
-
like, marking an object into markListSet.
And here is a problem, because when the
-
heap context can be acquired, it can be
acquired for a complex object, only for a
-
complex object. So this mean for primitive
types like integer, booleans and so on,
-
they're not heap backed object and they'll
be not marked as a markListSet. And there
-
is a bug in the slowAppend. We should be
able to call it just once. So this mean
-
when the buffer will be moved from a stack
memory to a heap memory and one of the
-
properties will be a simple type, like an
integer, so they're not automatically
-
protected by garbage collection and all
the next corresponding values will be not
-
protected as well because of the bug in
the slowAppend. Here is a picture that's
-
illustrating it and in reality the
reference to JavaScript objects still
-
exist. But if, uh, in a in a call to
definedOwnProperty method, any of the user
-
supplied methods will be called, they
can remove this reference and object will
-
be deallocated. So to summarize, all the
information here is how it can be
-
exploited. So we specify an props object
which contain 12 descriptors and first
-
nine of them values are simple typed, like
zeroes, eight. Which mean that p8, which
-
is the ninth value bit will be added to
markListSet. It will trigger the
-
slowAppend and the buffer will be moved
from a stack to a heap. And the next
-
corresponding value is just - length and
which not_number and array will be not
-
marked by markListSet and not
automatically protected by garbage
-
collection. What happened next, when
different properties will be called on the
-
length property and you'll try to convert
not_number to a number which for that
-
user's defined it toString method will be
called. The toString method remove the
-
last reference for an array and forces the
garbage collection cycle by allocating a
-
large amount of memory. Which leads that
object will be deallocated by garbage
-
collector. The very next thing it is doing
is reallocate the new object over a stale
-
one. So this is how specially crafted use
after free was used in Safari to achieve
-
remote code execution and to execute a
shellcode. The shellcode exist in a second
-
stage, which is a payload which contained
the shellcode and compressed data. The
-
most interesting for us is the shellcode
because it's used for a kernel
-
exploitation in Safari context and the
compressed data basically is a loader
-
that downloads and decrypts the next
stage. One of the vulnerabilities used is
-
a CVE 4655, which is a info leak that's
used to bypass a kernel address layout
-
randomization. It exploits the information
that constructor and OSUnseralizeBinary
-
method they miss bound checking. So that
mean that attacker can create OSNumber
-
object with a really high number of bits
and call it within the application sandbox
-
where
io_registry_entry_get_property_bytes.
-
Here's how it looked like. So
OSUnseralizeBinary method to handle binary
-
serializations in a kernel. It converts a
binary format to basic kernel data object.
-
It supports different container types,
sets, dictionaries, array, object types,
-
strings, numbers and the point of interest
in this is the OSNumber. So as we see
-
here, it passed two arguments: value and
length and there is no real check that for
-
- for length property. So this mean we can
control the length that is passed to an
-
object. And why it is a problem, because
here is a constructor for OSNumber:init
-
and as we see the length property passed
here is newnNumberOfBits and it
-
overrides the size variable. And the
problem that size is used in other
-
methods, in a case that OSNumber
numberOfBytes, which leads it return value
-
of numberOfBytes is now fully controlled
by attacker. Which is real bad because
-
it's used next in
io_registry_entry_get_property_bytes which
-
handle OSNumbers and its use numberOfBytes
to calculate the object's length, the
-
OSNumber length. But unfortunately it use
a stack based buffer to parse and save
-
OSNumber value. And what happened next, it
is copying memory from kernel stack to
-
heap used the attacker controlled length.
Which mean we can specify how many bytes
-
will be copied from a kernel stack and
returned to user land. This is what
-
happens: the first thing we are doing, we
are create a properties array that have a
-
dictionary which have a OSNumber with a
high length in our case, is 256. Next, we
-
need to spawn the user client by calling
IOService open extended, which will
-
deserialize this OSNumber object and crea-
te this object in the - in the kernel. And
-
now we need to read it by calling the
IORegistryEntryGetProperty, which leads it
-
- we copied the 256 bytes of the kernel
stack memory and the kernel stack memory
-
will contain kernel pointers. And from a
kernel pointer, we can determine the
-
kernel base. So now we get a kernel base
and we can jump to the next vulnerability,
-
which is CVE 4656 it is use-after-free to
achieve kernel level code execution. It
-
exploits information because the
setAtIndex macro does not really retain an
-
object and we can trigger it within the
application sandbox from
-
OSUnserializeBinary. Again the
OSUnserializeBinary it's a function that
-
parse and deserialize objects in the
kernel - it support different data types -
-
different container types. And the
interesting thing it supports kOSSerialize
-
object. It means that we can create a
reference to another object. Really
-
useful in the future, because in a way of
deserializing and parsing objects
-
OSUnserializeBinary saved object pointer
to a special objects array. And using
-
setAtIndex for it. And as we see
setAtIndex just save object pointer to
-
array with some index not retaining it.
It's bad, because the next code, which
-
casting OSString to a OSSymbol it is
releasing the object pointer. What does it
-
mean? We still have an array that holds
all the object pointers, which is objects
-
array, and we just released one of the
objects but still hold the pointer. If we
-
can create a reference to an object we can
exploit use-after-free. This is what
-
happens because kOSSerializeObject allows
us to create a reference and we will just
-
call retain on already deserialized,
already deallocated object. This is how
-
exploit look like. So first of all, we
create OSdictionary and it will contain a
-
string that due the bug will be
deallocated. So now we need to reallocate
-
it with our controlled object to fit in
the same memory spot. It's OSString in our
-
case, OSString class in a memory will be
32 bytes. We need to allocate the same
-
size. For this purpose OSData is a perfect
candidate because we can control OSData
-
buffer, buffer size and buffer content. So
what we can do, we can create a fake
-
OSString with a fake vtable and this fake
vtable will point to some digits in the
-
kernel. The very last thing we need to do
is trigger a user-after-free by adding a
-
kOSSerializeObject. So once again,
OSString got deserialized, deallocated,
-
reallocated to a new object, which is
OSData buffer, which will point to the
-
same memory spot: we've got a use-after-
free. So after getting use-after-free,
-
Pegasus uses some kernel patches to
disable security checks like setuid to
-
easily escalate the privileges, bypass
amfi checks by patching out
-
amfi_get_out_of_my_way, disable code
signment enforcement by patching
-
cs_enforcement_disable variable and
finally, a remount the system partition to
-
be readable, & writable so it can execute
a loader for the next stage to download
-
and decrypt the next stage. The next stage
contain the real espionage stuff that will
-
be used to sniff all the like SMS, all the
calls, all the like personal data. It have
-
a three groups. One is a process group
which have a main process: sniffing
-
services model that use a SIP protocol to
communicate with command control like a
-
process manager and so on. The next
interesting thing is a group of the
-
dylibs, because Pegasus rely on the Cydia
substrate - the jailbreak framework called
-
- they renamed it as libdata. It uses
Cydia substrate to inject dynamic
-
libraries into application process. So in
our case, we have a dynamic libraries for
-
Viber, for Whatsapp which can be injected
into the application space to install
-
application hooks. And the last thing is
com.apple.itunesstored file. Which is a
-
JavaScript that contain code and the
shellcode that will execute - that can
-
execute unsigned code. I will focus on it
next. So the bug exists in a JSC binary.
-
JSC binary is like a helper for JavaScript
core, JavaScript and in Apple. And
-
it can lead to unsigned code execution. In
combination with rtbyddyd trick it can be
-
used to completely gain persistence on the
device. It exploits that it is a bad cast
-
in setEarlyValue method and fortunately it
can be triggered only from Jesty
-
application context. So what is a problem?
It exploits the problem in JavaScript
-
binding SetImpureGetterDelegate which have
in C++ for function
-
SetImpureGetterDelegate. This function
takes a few arguments - one is the
-
impureGetter and the second one is a
generic isObject that will be set as this
-
impureGetter delegate. The problem will be
next slide - so we just parse two
-
arguments and call a setDelegate. The
setDelegate called set which finally
-
called setEarlyValue. Here is a problem,
because there is no real check that the
-
object type passed to
setImpureGetterDelegate is really
-
ImpureGetter. So this means that if any
other object type will be passed, it will
-
be improperly downcasted as ImpureGetter
pointer. That's what happened here. So
-
it's a bad cast that have no real check
for object type and which lead that we can
-
overwrite on those object fields. Here are
the same function, but now decompiled in IDA
-
Pro. So in our case ImpureGetter is a base
variable here and the delegate is this
-
generic JS object. We see that the
pointer, which is base plus 16, can be
-
overridden with a pointer to a delegate.
Which lead - you see on the right
-
JSArrayBufferView class - if I pass
JSArrayBufferView class as a first
-
argument, the m_vector field will be
overwritten with a pointer to a delegate.
-
Which is really bad, because it can lead
to readable, writeable primitives. To
-
exploit that Pegasus uses two dataviews. I
will call them dataview one and dataview
-
two. And to call and
setImpureGetterDelegate on both, which
-
leads it m_vector field in the first
dataview will be overwritten with the
-
pointer for the second dataview. And now
by setting and reading the values on the
-
first dataview we can override object
fields in the second. While we need it, we
-
can map the second dataview as entire
process memory by overwriting the second
-
dataview arraybuffer offset to be zero by
overwriting the second dataview length to
-
be four gigabytes in a case of 32 bit
process and set type as fast array type.
-
So basically the second dataview now is
mapped to the entire process space and we
-
can getint, setint to get arbitrary read
and write anywhere in the process memory.
-
The same thing can be used even to get
execution primitive. But in this case, we
-
can call setImpureGetterDelegate twice and
instead of exposing the entire process
-
memory, we can leak just an object
address. If you can leak an object
-
address, we can produce a function that
have like hundreds of try - empty try-
-
catch constructions and force JIT to
compile it. And in a - in this process, a
-
special, readable, writeable, executable
memory segment will be allocated. We can
-
leak address of this JIT segment,
overwrite it with a shellcode and execute.
-
So this is how the bad cast can be used to
like re-exploit even a kernel on each
-
boot. It is used with a persistence
mechanism which is rtbuddyd. So the
-
problem is that System spawning rtbuddyd
service with a special early-boot
-
argument. This mean if you take any other
binary signed by Apple and name it as
-
rbuddyd, it will be spawned on a boot.
That is what the Pegasus is doing. So they
-
take JSC binary which is signed by Apple,
name it as rtbuddyd, then take a
-
JavaScript that contain exploit. Make it a
sym link, call it early-boot which leads
-
to when the rtbuddyd will be spawned it
with early-boot it will call JSC with the
-
js-exploit instead. So with this trick and
the bad cast it re-exploits kernel on
-
each device boot. There is some tricks
the Pegasus use to make it harder to
-
reverse engineer, like use one time links.
So after you click on any of the link
-
they'll be invalidated and now redirect to
Google or other sites. It re-encrypts all
-
the payloads each time they are downloaded
just on the fly. And of course, they are
-
trying to hide itself to make it look like
a system component. Um, of course, it
-
blocks iOS system updates to make sure you
can't - you cannot batch your device just
-
on the fly, to clear all the evidence:
clear Safari history and caches and we
-
found a self-destruct mechanism that can
be triggered remotely or on a time out. So
-
in addition to this terrifying list of
supported applications, it records any
-
microphone usage, any camera usage, GPS,
location, keychain passwords, even
-
including the Wi-Fi and the router one.
Why they need router - I don't know.
-
Application hooking. So how how it
operates. As I mentioned earlier, it use
-
Cydia substrate and with the help of Cydia
substrate it preloads dynamic libraries
-
into application process and intercept
some critical functions. It uses Cynject
-
to run into already - into already running
processes. So this is like a high level
-
picture of how it looks like. So all the
application level critical functions and
-
the framework level critical functions are
intercepted by Pegasus. So now Pegasus can
-
control them, can collect them, can back
them, can send Command & Control and so
-
on. To summarize, Pegasus is a remote
jailbreak spotted in the wild. It's pretty
-
scary because it doesn't require any user
interaction. And the last similar thing
-
was like five years ago when the comex
released his jailbreakme 3. This year Luca
-
Todesco used one of the Trident
vulnerabilities for his jailbreaking.
-
I want to say a special thanks to Citizen
Lab for helping out with achieving a
-
Pegasus sample. All the Lookout research &
response team, the Divergent security guys
-
and all the individual researchers who was
involved in the research. So last some
-
useful links which contain a 44 page PDF
report with a really, really deep details
-
on the vulnerabilities that is used even
with the difference between 32 and 64 bit
-
ones. So if you're interested in. Please
take a look. I think this is it do you
-
guys have any questions?
-
applause
-
M: Mm hmm.
H: OK, please keep it brief. We only have
-
some minutes left for the questions, and
if there are any questions, please go to
-
the microphones in the hall. And we start
with the Signal Angel from the Internet.
-
SA: Thank you. Is there any way to build
your app, protect it from this exploit?
-
M: Yes, it is, because the Pegasus use
some of the known jailbreak techniques it
-
is possible to detect for example that
system partition is remounted as readable
-
& writable. It could be one of the
indicators that some generic jailbreak is
-
running on a device. Or like check for
especially file that Pegasus use but like
-
better check it in general for jailbreak
pages, the kernel pages.
-
audience shuffling noise
H: Please try to stay a bit quiet. We are
-
still in the middle of the Q & A. If you
don't have to leave now, please stay
-
seated until afterwards and if you have to
leave now, please do not talk. Microphone
-
three, please.
M3: What's the user experience during
-
this?
M: User experience, I mean - you mean -
-
you mean when you get a device infected by
Pegasus? Well, there is it's scary there
-
is no real indicators on a device that you
get something. That you click on the link,
-
the mobile web browser opens and just
closes and crashes. There is no new
-
applications spotted on your on visible
applications and so on. But in a real it's
-
running like three new system services,
but they are not visible to a user.
-
H: Thank you. And please, another question
from the Internet.
-
SA: Thank you. Have you any idea how
active this exploit is in the world?
-
M: Say it again please?
SA: Have you any idea how active this
-
exploit is in the wild?
M: I'm sure it was a very targeted attack
-
because, uh, these exploits are pretty
expensive. For example, uh, Zerodium now
-
pays 1,5 million for remote jailbreaks
like these so I don't think that actors of
-
this like spyware, want to like - want to
deal malware accessible for everyone. So I
-
think it's a very very targeted attacks.
It is hard to predict how many devices was
-
infected by Pegasus. Now we know about the
Mansoor one. So, again, I think it's very,
-
very targeted thing because it's very
expensive.
-
H: Thank you for this answer. Microphone
number five, please.
-
M5: Do you have any more information on
the NSO or the group that's behind it? Are
-
they using any other software? And how
spread is this in the wild again?
-
M: Yeah. So in this case, we focused
mostly on the technicalities of the
-
Pegasus itself, but Citizen Lab made their
investigation on NSO and the like the
-
NSO is like cyber arms dealer. So please
take a look about in a Citizen Lab report
-
on that. So they have much more
information.
-
H: Do we have a question from the
Internet? Am I overlooking anyone? No,
-
then this is it, thank you for your talk.
-
applause
-
postroll music
-
Subtitles created by c3subtitles.de
in the year 2022. Join, and help us!
-
[Translated by {Iikka}{Yli-Kuivila}
(ITKST56 course assignment at JYU.FI)]