WEBVTT
00:00:00.000 --> 00:00:00.958
[Translated by {Iikka}{Yli-Kuivila}
(ITKST56 course assignment at JYU.FI)]
00:00:00.958 --> 00:00:13.699
33C3 preroll music
00:00:13.699 --> 00:00:17.760
Herald: The Max is a security researcher
at Lookout has been doing this about 10
00:00:17.760 --> 00:00:22.780
years, he spent a lot of time in
obfuscation, exploit development, security
00:00:22.780 --> 00:00:28.160
research, previous Black Hat speaker,
currently focused on mobile security
00:00:28.160 --> 00:00:33.579
research and working on his PhD. He'll be
telling you about some of the internals of
00:00:33.579 --> 00:00:38.210
Pegasus malware today. With that, I will
turn over to Max to take it away.
00:00:38.210 --> 00:00:39.529
Max: Thank you.
00:00:39.529 --> 00:00:47.090
applause
00:00:47.090 --> 00:00:51.660
M: Hi, everyone, say my name
is Max Bazaliy, and today we'll talk about
00:00:51.660 --> 00:00:57.609
the Pegasus Internals. I'm from Kiev,
Ukraine, currently work as a security
00:00:57.609 --> 00:01:02.370
researcher at Lookout and last few years
focused on a jailbreak techniques. So
00:01:02.370 --> 00:01:06.540
that's why I co-founded the Fried Apple
team and we're working on a various
00:01:06.540 --> 00:01:12.979
iOS jailbreak, including eight and nine.
So Pegasus. Pegasus is a high quality
00:01:12.979 --> 00:01:19.704
espionage software that can be used for
complete surveillance of a device. Just
00:01:19.704 --> 00:01:23.710
everything from stealing your personal
data up to remotely activating a
00:01:23.710 --> 00:01:30.870
microphone or camera on a device without
any indication it's really happening. So
00:01:30.870 --> 00:01:35.820
in order Pegasus to work, it need to
jailbreak a device first because the iOS
00:01:35.820 --> 00:01:40.570
sandbox prevents application from spying
on each other. So that's why Pegasus rely
00:01:40.570 --> 00:01:49.320
on a trident exploit chain to completely
own a device and install persistence that
00:01:49.320 --> 00:01:55.250
can be used on each device. Here's a
really terrifying list of targeted apps,
00:01:55.250 --> 00:02:03.102
including even the known as most secure
ones, like Telegram, WhatsApp, Viber. And
00:02:03.102 --> 00:02:08.259
I'm pretty sure you can find your favorite
messenger in this list. Before going into
00:02:08.259 --> 00:02:12.150
a deep technical analysis of the
vulnerabilities used, I want to tell a
00:02:12.150 --> 00:02:18.300
story how we get it - a Pegasus sample. So
police met Ahmed Mansoor, who's mostly
00:02:18.300 --> 00:02:23.239
known for his job as a human right
defender. He's even a recipient of Martin
00:02:23.239 --> 00:02:29.459
Ennals award, sometimes called the Nobel
Prize for Human Rights. So I understand
00:02:29.459 --> 00:02:39.530
this year Ahmed received a message with a
text that someone in a state prison got -
00:02:39.530 --> 00:02:45.640
someone is imprisoned in a state prison.
So and he received another text with a
00:02:45.640 --> 00:02:52.300
similar thing the next day. But previously
he was targeted by hacking team in 2012
00:02:52.300 --> 00:02:58.910
and got FinFisher in 2011. So now, instead
of clicking on the link, he contacted the
00:02:58.910 --> 00:03:03.040
Citizen Lab because he was working with
those guys before. So he sent a link for
00:03:03.040 --> 00:03:09.469
Citizen Lab to analysis and we are in
Lookout research team. We get initial
00:03:09.469 --> 00:03:13.989
sample and a link from a Citizen Lab. So
in this story, I mostly will focusing
00:03:13.989 --> 00:03:23.840
about technical, part. So in order to work
- Pegasus rely on the Trident exploit
00:03:23.840 --> 00:03:29.819
chain and it uses three stages. So on the
first stage, it uses a memory corruption
00:03:29.819 --> 00:03:34.659
to achieve a remote code execution in a
Safari context. After that, it jumps -
00:03:34.659 --> 00:03:38.549
after this on a device - it jumps to a
second stage and uses two vulnerabilities
00:03:38.549 --> 00:03:42.299
to exploit the kernel. One is used for by
- by the Kernel Address Space layout
00:03:42.299 --> 00:03:47.590
randomisation and another to achieve
kernel - a remote - a kernel code
00:03:47.590 --> 00:03:51.510
execution kernel level code execution.
And finally, on the third stage it
00:03:51.510 --> 00:03:57.950
installs espionage software and uses a
special trick to achieve on device
00:03:57.950 --> 00:04:03.040
persistence. So I will focus on each stage
more detailed. The first stage, as they
00:04:03.040 --> 00:04:08.920
say, is a single use spear-phish url that
will be invalidated after the first click.
00:04:08.920 --> 00:04:13.629
It contains obfuscated JavaScript that
first thing it do it checking for a device
00:04:13.629 --> 00:04:20.340
type: Is it iPhone, is it iPad, is it 32
or 64 bit. And based on information about
00:04:20.340 --> 00:04:25.730
device processor type the different
versions of shellcode will be downloaded.
00:04:25.730 --> 00:04:30.380
Which is in stage two. And finally
exploits remote code execution
00:04:30.380 --> 00:04:34.525
vulnerability in a webkit in order to
execute the shellcode. So what
00:04:34.525 --> 00:04:42.600
vulnerability will it use it? CVE 4657
remote code execution in WebKit. Basically
00:04:42.600 --> 00:04:46.910
the vulnerability is use after free that
achieved by using two bugs and in a sample
00:04:46.910 --> 00:04:52.940
that we got it's not stable because it
relies on WebKit garbage collector. The
00:04:52.940 --> 00:04:57.760
problem itself lives in a -
MarkedArgumentBuffer that can be exploited
00:04:57.760 --> 00:05:02.030
by usage of the defined properties. So
defined properties is a method that
00:05:02.030 --> 00:05:07.870
defines new or modified properties
directly on object. It takes a few
00:05:07.870 --> 00:05:13.540
arguments and the object itself and the
properties objects which can have
00:05:13.540 --> 00:05:20.910
descriptors that constitute the property
to be defined or modified. It have a
00:05:20.910 --> 00:05:26.070
pretty simple algorithm, it contain few
loops on the very first iteration of each
00:05:26.070 --> 00:05:30.090
property descriptor checking for a
formatting and after that get appended to
00:05:30.090 --> 00:05:35.790
a descriptor's vector and to make sure
that the reference to property descriptors
00:05:35.790 --> 00:05:40.020
do not become stale, they need to be
protected from being garbage collected.
00:05:40.020 --> 00:05:44.740
For this purpose MarkedArgumentBuffer is
used. We see it at the very very end,
00:05:44.740 --> 00:05:49.530
MarkedArgumentBuffer append. So
MarkedArgumentBuffer prevents objects from
00:05:49.530 --> 00:05:59.250
being deallocated. And after each property
-get has been validated and it's okay, the
00:05:59.250 --> 00:06:03.240
defineOwnProperty associate each user
supplied property with a target object.
00:06:03.240 --> 00:06:08.150
And here is a problem, because it's possi-
ble when the defineProperty will be called
00:06:08.150 --> 00:06:13.610
it's possible to call any user defined
JavaScript methods. If in these JavaScript
00:06:13.610 --> 00:06:19.810
methods garbage collection can be
triggered, it will deallocate any unmarked
00:06:19.810 --> 00:06:26.410
heap-backed object. I will go a little bit
deeply in the details. First of all, a few
00:06:26.410 --> 00:06:30.390
words about MarkedArgumentBuffer and
JavaScript garbage collector. So
00:06:30.390 --> 00:06:33.640
JavaScript garbage collector is respon-
sible for deallocating an object from
00:06:33.640 --> 00:06:37.900
a memory when they are no longer
referenced. It runs at a - random
00:06:37.900 --> 00:06:42.670
intervals and based on the current memory
pressure, the current device types and so
00:06:42.670 --> 00:06:48.550
on. And when garbage collector checking if
objects should be deallocated, it walks
00:06:48.550 --> 00:06:53.190
through the stack and check for reference
to an object. A reference to an object
00:06:53.190 --> 00:06:57.500
also may exist in the application heap,
but in this case an alternative is used
00:06:57.500 --> 00:07:04.140
called the slowAppend. So
MarkedArgumentBuffer is initial inline
00:07:04.140 --> 00:07:10.510
stack contains eight values. Well, that's
mean when the ninth value will be added to
00:07:10.510 --> 00:07:15.570
the MarkedArgumentBuffer the capacity will
be expanded. It will be moved from a stack
00:07:15.570 --> 00:07:25.840
memory to a heap memory. This is what the
slowAppend is doing. SlowAppend move stack
00:07:25.840 --> 00:07:31.810
from a - move buffer from a stack to a
heap, and now object not automatically
00:07:31.810 --> 00:07:37.060
protected from a garbage collection. And
to make sure they were not deallocated,
00:07:37.060 --> 00:07:45.650
they need to be added to heap's
markListSet. This is what we see here. So
00:07:45.650 --> 00:07:50.170
slowAppend trying to acquire heap context
and it can be acquired adding an object
00:07:50.170 --> 00:07:59.639
like, marking an object into markListSet.
And here is a problem, because when the
00:07:59.639 --> 00:08:02.940
heap context can be acquired, it can be
acquired for a complex object, only for a
00:08:02.940 --> 00:08:08.110
complex object. So this mean for primitive
types like integer, booleans and so on,
00:08:08.110 --> 00:08:14.450
they're not heap backed object and they'll
be not marked as a markListSet. And there
00:08:14.450 --> 00:08:20.480
is a bug in the slowAppend. We should be
able to call it just once. So this mean
00:08:20.480 --> 00:08:27.720
when the buffer will be moved from a stack
memory to a heap memory and one of the
00:08:27.720 --> 00:08:31.750
properties will be a simple type, like an
integer, so they're not automatically
00:08:31.750 --> 00:08:35.959
protected by garbage collection and all
the next corresponding values will be not
00:08:35.959 --> 00:08:41.610
protected as well because of the bug in
the slowAppend. Here is a picture that's
00:08:41.610 --> 00:08:46.820
illustrating it and in reality the
reference to JavaScript objects still
00:08:46.820 --> 00:08:53.330
exist. But if, uh, in a in a call to
definedOwnProperty method, any of the user
00:08:53.330 --> 00:08:57.360
supplied methods will be called, they
can remove this reference and object will
00:08:57.360 --> 00:09:03.460
be deallocated. So to summarize, all the
information here is how it can be
00:09:03.460 --> 00:09:09.620
exploited. So we specify an props object
which contain 12 descriptors and first
00:09:09.620 --> 00:09:16.401
nine of them values are simple typed, like
zeroes, eight. Which mean that p8, which
00:09:16.401 --> 00:09:22.510
is the ninth value bit will be added to
markListSet. It will trigger the
00:09:22.510 --> 00:09:28.690
slowAppend and the buffer will be moved
from a stack to a heap. And the next
00:09:28.690 --> 00:09:34.090
corresponding value is just - length and
which not_number and array will be not
00:09:34.090 --> 00:09:37.390
marked by markListSet and not
automatically protected by garbage
00:09:37.390 --> 00:09:44.010
collection. What happened next, when
different properties will be called on the
00:09:44.010 --> 00:09:49.370
length property and you'll try to convert
not_number to a number which for that
00:09:49.370 --> 00:09:54.371
user's defined it toString method will be
called. The toString method remove the
00:09:54.371 --> 00:09:58.400
last reference for an array and forces the
garbage collection cycle by allocating a
00:09:58.400 --> 00:10:04.070
large amount of memory. Which leads that
object will be deallocated by garbage
00:10:04.070 --> 00:10:08.450
collector. The very next thing it is doing
is reallocate the new object over a stale
00:10:08.450 --> 00:10:14.180
one. So this is how specially crafted use
after free was used in Safari to achieve
00:10:14.180 --> 00:10:19.650
remote code execution and to execute a
shellcode. The shellcode exist in a second
00:10:19.650 --> 00:10:25.100
stage, which is a payload which contained
the shellcode and compressed data. The
00:10:25.100 --> 00:10:28.460
most interesting for us is the shellcode
because it's used for a kernel
00:10:28.460 --> 00:10:33.770
exploitation in Safari context and the
compressed data basically is a loader
00:10:33.770 --> 00:10:38.980
that downloads and decrypts the next
stage. One of the vulnerabilities used is
00:10:38.980 --> 00:10:45.820
a CVE 4655, which is a info leak that's
used to bypass a kernel address layout
00:10:45.820 --> 00:10:51.050
randomization. It exploits the information
that constructor and OSUnseralizeBinary
00:10:51.050 --> 00:10:58.140
method they miss bound checking. So that
mean that attacker can create OSNumber
00:10:58.140 --> 00:11:02.070
object with a really high number of bits
and call it within the application sandbox
00:11:02.070 --> 00:11:05.670
where
io_registry_entry_get_property_bytes.
00:11:05.670 --> 00:11:10.790
Here's how it looked like. So
OSUnseralizeBinary method to handle binary
00:11:10.790 --> 00:11:16.250
serializations in a kernel. It converts a
binary format to basic kernel data object.
00:11:16.250 --> 00:11:21.960
It supports different container types,
sets, dictionaries, array, object types,
00:11:21.960 --> 00:11:26.720
strings, numbers and the point of interest
in this is the OSNumber. So as we see
00:11:26.720 --> 00:11:34.200
here, it passed two arguments: value and
length and there is no real check that for
00:11:34.200 --> 00:11:39.950
- for length property. So this mean we can
control the length that is passed to an
00:11:39.950 --> 00:11:45.440
object. And why it is a problem, because
here is a constructor for OSNumber:init
00:11:45.440 --> 00:11:51.770
and as we see the length property passed
here is newnNumberOfBits and it
00:11:51.770 --> 00:11:56.060
overrides the size variable. And the
problem that size is used in other
00:11:56.060 --> 00:12:02.040
methods, in a case that OSNumber
numberOfBytes, which leads it return value
00:12:02.040 --> 00:12:08.370
of numberOfBytes is now fully controlled
by attacker. Which is real bad because
00:12:08.370 --> 00:12:12.400
it's used next in
io_registry_entry_get_property_bytes which
00:12:12.400 --> 00:12:17.920
handle OSNumbers and its use numberOfBytes
to calculate the object's length, the
00:12:17.920 --> 00:12:24.330
OSNumber length. But unfortunately it use
a stack based buffer to parse and save
00:12:24.330 --> 00:12:31.600
OSNumber value. And what happened next, it
is copying memory from kernel stack to
00:12:31.600 --> 00:12:37.420
heap used the attacker controlled length.
Which mean we can specify how many bytes
00:12:37.420 --> 00:12:43.960
will be copied from a kernel stack and
returned to user land. This is what
00:12:43.960 --> 00:12:52.800
happens: the first thing we are doing, we
are create a properties array that have a
00:12:52.800 --> 00:12:59.950
dictionary which have a OSNumber with a
high length in our case, is 256. Next, we
00:12:59.950 --> 00:13:04.560
need to spawn the user client by calling
IOService open extended, which will
00:13:04.560 --> 00:13:11.000
deserialize this OSNumber object and crea-
te this object in the - in the kernel. And
00:13:11.000 --> 00:13:16.089
now we need to read it by calling the
IORegistryEntryGetProperty, which leads it
00:13:16.089 --> 00:13:22.590
- we copied the 256 bytes of the kernel
stack memory and the kernel stack memory
00:13:22.590 --> 00:13:26.960
will contain kernel pointers. And from a
kernel pointer, we can determine the
00:13:26.960 --> 00:13:32.850
kernel base. So now we get a kernel base
and we can jump to the next vulnerability,
00:13:32.850 --> 00:13:40.110
which is CVE 4656 it is use-after-free to
achieve kernel level code execution. It
00:13:40.110 --> 00:13:44.180
exploits information because the
setAtIndex macro does not really retain an
00:13:44.180 --> 00:13:48.420
object and we can trigger it within the
application sandbox from
00:13:48.420 --> 00:13:56.940
OSUnserializeBinary. Again the
OSUnserializeBinary it's a function that
00:13:56.940 --> 00:14:01.940
parse and deserialize objects in the
kernel - it support different data types -
00:14:01.940 --> 00:14:06.550
different container types. And the
interesting thing it supports kOSSerialize
00:14:06.550 --> 00:14:12.490
object. It means that we can create a
reference to another object. Really
00:14:12.490 --> 00:14:18.270
useful in the future, because in a way of
deserializing and parsing objects
00:14:18.270 --> 00:14:24.490
OSUnserializeBinary saved object pointer
to a special objects array. And using
00:14:24.490 --> 00:14:29.170
setAtIndex for it. And as we see
setAtIndex just save object pointer to
00:14:29.170 --> 00:14:37.410
array with some index not retaining it.
It's bad, because the next code, which
00:14:37.410 --> 00:14:44.200
casting OSString to a OSSymbol it is
releasing the object pointer. What does it
00:14:44.200 --> 00:14:48.790
mean? We still have an array that holds
all the object pointers, which is objects
00:14:48.790 --> 00:14:55.770
array, and we just released one of the
objects but still hold the pointer. If we
00:14:55.770 --> 00:15:00.200
can create a reference to an object we can
exploit use-after-free. This is what
00:15:00.200 --> 00:15:03.560
happens because kOSSerializeObject allows
us to create a reference and we will just
00:15:03.560 --> 00:15:09.410
call retain on already deserialized,
already deallocated object. This is how
00:15:09.410 --> 00:15:14.490
exploit look like. So first of all, we
create OSdictionary and it will contain a
00:15:14.490 --> 00:15:19.530
string that due the bug will be
deallocated. So now we need to reallocate
00:15:19.530 --> 00:15:27.510
it with our controlled object to fit in
the same memory spot. It's OSString in our
00:15:27.510 --> 00:15:34.580
case, OSString class in a memory will be
32 bytes. We need to allocate the same
00:15:34.580 --> 00:15:39.930
size. For this purpose OSData is a perfect
candidate because we can control OSData
00:15:39.930 --> 00:15:46.460
buffer, buffer size and buffer content. So
what we can do, we can create a fake
00:15:46.460 --> 00:15:50.860
OSString with a fake vtable and this fake
vtable will point to some digits in the
00:15:50.860 --> 00:15:55.630
kernel. The very last thing we need to do
is trigger a user-after-free by adding a
00:15:55.630 --> 00:16:01.630
kOSSerializeObject. So once again,
OSString got deserialized, deallocated,
00:16:01.630 --> 00:16:05.290
reallocated to a new object, which is
OSData buffer, which will point to the
00:16:05.290 --> 00:16:12.649
same memory spot: we've got a use-after-
free. So after getting use-after-free,
00:16:12.649 --> 00:16:20.290
Pegasus uses some kernel patches to
disable security checks like setuid to
00:16:20.290 --> 00:16:26.190
easily escalate the privileges, bypass
amfi checks by patching out
00:16:26.190 --> 00:16:31.570
amfi_get_out_of_my_way, disable code
signment enforcement by patching
00:16:31.570 --> 00:16:36.060
cs_enforcement_disable variable and
finally, a remount the system partition to
00:16:36.060 --> 00:16:41.720
be readable, & writable so it can execute
a loader for the next stage to download
00:16:41.720 --> 00:16:50.990
and decrypt the next stage. The next stage
contain the real espionage stuff that will
00:16:50.990 --> 00:16:58.910
be used to sniff all the like SMS, all the
calls, all the like personal data. It have
00:16:58.910 --> 00:17:09.350
a three groups. One is a process group
which have a main process: sniffing
00:17:09.350 --> 00:17:14.850
services model that use a SIP protocol to
communicate with command control like a
00:17:14.850 --> 00:17:20.370
process manager and so on. The next
interesting thing is a group of the
00:17:20.370 --> 00:17:24.919
dylibs, because Pegasus rely on the Cydia
substrate - the jailbreak framework called
00:17:24.919 --> 00:17:29.410
- they renamed it as libdata. It uses
Cydia substrate to inject dynamic
00:17:29.410 --> 00:17:34.429
libraries into application process. So in
our case, we have a dynamic libraries for
00:17:34.429 --> 00:17:38.202
Viber, for Whatsapp which can be injected
into the application space to install
00:17:38.202 --> 00:17:44.990
application hooks. And the last thing is
com.apple.itunesstored file. Which is a
00:17:44.990 --> 00:17:53.870
JavaScript that contain code and the
shellcode that will execute - that can
00:17:53.870 --> 00:18:00.480
execute unsigned code. I will focus on it
next. So the bug exists in a JSC binary.
00:18:00.480 --> 00:18:06.870
JSC binary is like a helper for JavaScript
core, JavaScript and in Apple. And
00:18:06.870 --> 00:18:12.330
it can lead to unsigned code execution. In
combination with rtbyddyd trick it can be
00:18:12.330 --> 00:18:18.780
used to completely gain persistence on the
device. It exploits that it is a bad cast
00:18:18.780 --> 00:18:24.929
in setEarlyValue method and fortunately it
can be triggered only from Jesty
00:18:24.929 --> 00:18:32.030
application context. So what is a problem?
It exploits the problem in JavaScript
00:18:32.030 --> 00:18:37.190
binding SetImpureGetterDelegate which have
in C++ for function
00:18:37.190 --> 00:18:40.880
SetImpureGetterDelegate. This function
takes a few arguments - one is the
00:18:40.880 --> 00:18:47.890
impureGetter and the second one is a
generic isObject that will be set as this
00:18:47.890 --> 00:18:54.790
impureGetter delegate. The problem will be
next slide - so we just parse two
00:18:54.790 --> 00:18:59.370
arguments and call a setDelegate. The
setDelegate called set which finally
00:18:59.370 --> 00:19:05.080
called setEarlyValue. Here is a problem,
because there is no real check that the
00:19:05.080 --> 00:19:10.670
object type passed to
setImpureGetterDelegate is really
00:19:10.670 --> 00:19:15.950
ImpureGetter. So this means that if any
other object type will be passed, it will
00:19:15.950 --> 00:19:21.050
be improperly downcasted as ImpureGetter
pointer. That's what happened here. So
00:19:21.050 --> 00:19:28.180
it's a bad cast that have no real check
for object type and which lead that we can
00:19:28.180 --> 00:19:33.200
overwrite on those object fields. Here are
the same function, but now decompiled in IDA
00:19:33.200 --> 00:19:39.620
Pro. So in our case ImpureGetter is a base
variable here and the delegate is this
00:19:39.620 --> 00:19:46.020
generic JS object. We see that the
pointer, which is base plus 16, can be
00:19:46.020 --> 00:19:50.910
overridden with a pointer to a delegate.
Which lead - you see on the right
00:19:50.910 --> 00:19:55.760
JSArrayBufferView class - if I pass
JSArrayBufferView class as a first
00:19:55.760 --> 00:20:01.620
argument, the m_vector field will be
overwritten with a pointer to a delegate.
00:20:01.620 --> 00:20:09.720
Which is really bad, because it can lead
to readable, writeable primitives. To
00:20:09.720 --> 00:20:14.429
exploit that Pegasus uses two dataviews. I
will call them dataview one and dataview
00:20:14.429 --> 00:20:20.860
two. And to call and
setImpureGetterDelegate on both, which
00:20:20.860 --> 00:20:24.910
leads it m_vector field in the first
dataview will be overwritten with the
00:20:24.910 --> 00:20:31.080
pointer for the second dataview. And now
by setting and reading the values on the
00:20:31.080 --> 00:20:36.400
first dataview we can override object
fields in the second. While we need it, we
00:20:36.400 --> 00:20:42.500
can map the second dataview as entire
process memory by overwriting the second
00:20:42.500 --> 00:20:46.580
dataview arraybuffer offset to be zero by
overwriting the second dataview length to
00:20:46.580 --> 00:20:52.460
be four gigabytes in a case of 32 bit
process and set type as fast array type.
00:20:52.460 --> 00:20:56.630
So basically the second dataview now is
mapped to the entire process space and we
00:20:56.630 --> 00:21:05.390
can getint, setint to get arbitrary read
and write anywhere in the process memory.
00:21:05.390 --> 00:21:09.950
The same thing can be used even to get
execution primitive. But in this case, we
00:21:09.950 --> 00:21:16.400
can call setImpureGetterDelegate twice and
instead of exposing the entire process
00:21:16.400 --> 00:21:21.380
memory, we can leak just an object
address. If you can leak an object
00:21:21.380 --> 00:21:26.530
address, we can produce a function that
have like hundreds of try - empty try-
00:21:26.530 --> 00:21:33.230
catch constructions and force JIT to
compile it. And in a - in this process, a
00:21:33.230 --> 00:21:38.580
special, readable, writeable, executable
memory segment will be allocated. We can
00:21:38.580 --> 00:21:45.270
leak address of this JIT segment,
overwrite it with a shellcode and execute.
00:21:45.270 --> 00:21:51.790
So this is how the bad cast can be used to
like re-exploit even a kernel on each
00:21:51.790 --> 00:21:58.040
boot. It is used with a persistence
mechanism which is rtbuddyd. So the
00:21:58.040 --> 00:22:03.730
problem is that System spawning rtbuddyd
service with a special early-boot
00:22:03.730 --> 00:22:10.500
argument. This mean if you take any other
binary signed by Apple and name it as
00:22:10.500 --> 00:22:14.820
rbuddyd, it will be spawned on a boot.
That is what the Pegasus is doing. So they
00:22:14.820 --> 00:22:20.700
take JSC binary which is signed by Apple,
name it as rtbuddyd, then take a
00:22:20.700 --> 00:22:26.900
JavaScript that contain exploit. Make it a
sym link, call it early-boot which leads
00:22:26.900 --> 00:22:31.500
to when the rtbuddyd will be spawned it
with early-boot it will call JSC with the
00:22:31.500 --> 00:22:37.130
js-exploit instead. So with this trick and
the bad cast it re-exploits kernel on
00:22:37.130 --> 00:22:46.480
each device boot. There is some tricks
the Pegasus use to make it harder to
00:22:46.480 --> 00:22:51.540
reverse engineer, like use one time links.
So after you click on any of the link
00:22:51.540 --> 00:22:57.490
they'll be invalidated and now redirect to
Google or other sites. It re-encrypts all
00:22:57.490 --> 00:23:02.920
the payloads each time they are downloaded
just on the fly. And of course, they are
00:23:02.920 --> 00:23:09.900
trying to hide itself to make it look like
a system component. Um, of course, it
00:23:09.900 --> 00:23:15.100
blocks iOS system updates to make sure you
can't - you cannot batch your device just
00:23:15.100 --> 00:23:22.510
on the fly, to clear all the evidence:
clear Safari history and caches and we
00:23:22.510 --> 00:23:30.290
found a self-destruct mechanism that can
be triggered remotely or on a time out. So
00:23:30.290 --> 00:23:35.510
in addition to this terrifying list of
supported applications, it records any
00:23:35.510 --> 00:23:40.710
microphone usage, any camera usage, GPS,
location, keychain passwords, even
00:23:40.710 --> 00:23:47.250
including the Wi-Fi and the router one.
Why they need router - I don't know.
00:23:47.250 --> 00:23:51.280
Application hooking. So how how it
operates. As I mentioned earlier, it use
00:23:51.280 --> 00:23:57.299
Cydia substrate and with the help of Cydia
substrate it preloads dynamic libraries
00:23:57.299 --> 00:24:04.809
into application process and intercept
some critical functions. It uses Cynject
00:24:04.809 --> 00:24:10.870
to run into already - into already running
processes. So this is like a high level
00:24:10.870 --> 00:24:18.130
picture of how it looks like. So all the
application level critical functions and
00:24:18.130 --> 00:24:21.940
the framework level critical functions are
intercepted by Pegasus. So now Pegasus can
00:24:21.940 --> 00:24:27.570
control them, can collect them, can back
them, can send Command & Control and so
00:24:27.570 --> 00:24:36.150
on. To summarize, Pegasus is a remote
jailbreak spotted in the wild. It's pretty
00:24:36.150 --> 00:24:42.059
scary because it doesn't require any user
interaction. And the last similar thing
00:24:42.059 --> 00:24:47.753
was like five years ago when the comex
released his jailbreakme 3. This year Luca
00:24:47.753 --> 00:24:52.920
Todesco used one of the Trident
vulnerabilities for his jailbreaking.
00:24:54.290 --> 00:24:59.870
I want to say a special thanks to Citizen
Lab for helping out with achieving a
00:24:59.870 --> 00:25:05.289
Pegasus sample. All the Lookout research &
response team, the Divergent security guys
00:25:05.289 --> 00:25:11.310
and all the individual researchers who was
involved in the research. So last some
00:25:11.310 --> 00:25:17.470
useful links which contain a 44 page PDF
report with a really, really deep details
00:25:17.470 --> 00:25:23.710
on the vulnerabilities that is used even
with the difference between 32 and 64 bit
00:25:23.710 --> 00:25:31.059
ones. So if you're interested in. Please
take a look. I think this is it do you
00:25:31.059 --> 00:25:33.280
guys have any questions?
00:25:33.290 --> 00:25:41.562
applause
00:25:44.682 --> 00:25:48.432
M: Mm hmm.
H: OK, please keep it brief. We only have
00:25:48.432 --> 00:25:50.470
some minutes left for the questions, and
if there are any questions, please go to
00:25:50.470 --> 00:25:56.830
the microphones in the hall. And we start
with the Signal Angel from the Internet.
00:25:56.830 --> 00:26:03.530
SA: Thank you. Is there any way to build
your app, protect it from this exploit?
00:26:03.530 --> 00:26:13.160
M: Yes, it is, because the Pegasus use
some of the known jailbreak techniques it
00:26:13.160 --> 00:26:18.480
is possible to detect for example that
system partition is remounted as readable
00:26:18.480 --> 00:26:23.650
& writable. It could be one of the
indicators that some generic jailbreak is
00:26:23.650 --> 00:26:29.900
running on a device. Or like check for
especially file that Pegasus use but like
00:26:29.900 --> 00:26:33.870
better check it in general for jailbreak
pages, the kernel pages.
00:26:33.870 --> 00:26:37.540
audience shuffling noise
H: Please try to stay a bit quiet. We are
00:26:37.540 --> 00:26:40.170
still in the middle of the Q & A. If you
don't have to leave now, please stay
00:26:40.170 --> 00:26:47.100
seated until afterwards and if you have to
leave now, please do not talk. Microphone
00:26:47.100 --> 00:26:50.200
three, please.
M3: What's the user experience during
00:26:50.200 --> 00:26:53.480
this?
M: User experience, I mean - you mean -
00:26:53.480 --> 00:26:59.071
you mean when you get a device infected by
Pegasus? Well, there is it's scary there
00:26:59.071 --> 00:27:07.110
is no real indicators on a device that you
get something. That you click on the link,
00:27:07.110 --> 00:27:13.080
the mobile web browser opens and just
closes and crashes. There is no new
00:27:13.080 --> 00:27:19.340
applications spotted on your on visible
applications and so on. But in a real it's
00:27:19.340 --> 00:27:26.390
running like three new system services,
but they are not visible to a user.
00:27:26.390 --> 00:27:29.370
H: Thank you. And please, another question
from the Internet.
00:27:29.370 --> 00:27:33.300
SA: Thank you. Have you any idea how
active this exploit is in the world?
00:27:33.300 --> 00:27:39.590
M: Say it again please?
SA: Have you any idea how active this
00:27:39.590 --> 00:27:46.580
exploit is in the wild?
M: I'm sure it was a very targeted attack
00:27:46.580 --> 00:27:51.860
because, uh, these exploits are pretty
expensive. For example, uh, Zerodium now
00:27:51.860 --> 00:27:59.770
pays 1,5 million for remote jailbreaks
like these so I don't think that actors of
00:27:59.770 --> 00:28:06.860
this like spyware, want to like - want to
deal malware accessible for everyone. So I
00:28:06.860 --> 00:28:11.960
think it's a very very targeted attacks.
It is hard to predict how many devices was
00:28:11.960 --> 00:28:19.690
infected by Pegasus. Now we know about the
Mansoor one. So, again, I think it's very,
00:28:19.690 --> 00:28:22.480
very targeted thing because it's very
expensive.
00:28:22.480 --> 00:28:26.590
H: Thank you for this answer. Microphone
number five, please.
00:28:26.590 --> 00:28:33.300
M5: Do you have any more information on
the NSO or the group that's behind it? Are
00:28:33.300 --> 00:28:38.720
they using any other software? And how
spread is this in the wild again?
00:28:38.720 --> 00:28:42.919
M: Yeah. So in this case, we focused
mostly on the technicalities of the
00:28:42.919 --> 00:28:49.809
Pegasus itself, but Citizen Lab made their
investigation on NSO and the like the
00:28:49.809 --> 00:28:56.600
NSO is like cyber arms dealer. So please
take a look about in a Citizen Lab report
00:28:56.600 --> 00:29:00.140
on that. So they have much more
information.
00:29:02.280 --> 00:29:07.750
H: Do we have a question from the
Internet? Am I overlooking anyone? No,
00:29:07.750 --> 00:29:10.150
then this is it, thank you for your talk.
00:29:10.150 --> 00:29:14.480
applause
00:29:15.091 --> 00:29:24.670
postroll music
00:29:24.670 --> 00:29:37.610
Subtitles created by c3subtitles.de
in the year 2022. Join, and help us!
00:29:37.610 --> 00:29:39.000
[Translated by {Iikka}{Yli-Kuivila}
(ITKST56 course assignment at JYU.FI)]