1
00:00:00,000 --> 00:00:19,520
36c3 preroll
2
00:00:19,520 --> 00:00:25,990
Herald: To everybody here, please be
welcome to this fantastic kid here. I
3
00:00:25,990 --> 00:00:31,249
learned a lot from him, even though he's
only since two years playing around with
4
00:00:31,249 --> 00:00:37,380
iOS. I mentioned as well the first
untethering case that I had with my phone
5
00:00:37,380 --> 00:00:44,010
was something about iOS 5.1 and with every
update, you had to do the whole shebang
6
00:00:44,010 --> 00:00:50,910
again. Of course, that's what I remember.
So please give a warm welcome here too
7
00:00:50,910 --> 00:00:54,470
littlelailo. Do I spell this correctly?
Offscreen: Yeah.
8
00:00:54,470 --> 00:01:03,250
Herald: Yes, littlelailo is really a very
fascinating geek. He actually hacks any
9
00:01:03,250 --> 00:01:08,610
kind of OS device, to my opinion. Any kind
of. Yeah. So throw it to him and it comes
10
00:01:08,610 --> 00:01:14,390
back in pieces. He's as sharp as a knife.
Please give him a warm, well, welcoming
11
00:01:14,390 --> 00:01:17,850
applause. We're gonna untether iOS. Yay!
12
00:01:17,850 --> 00:01:23,760
applause
13
00:01:23,760 --> 00:01:28,470
littlelailo: Okay, so yeah, I'm
littlelailo, as already introduced. I'm
14
00:01:28,470 --> 00:01:34,120
interested in I.T. security in general.
And I started to look into iOS about two
15
00:01:34,120 --> 00:01:40,670
years ago and then I met three awesome
guys: @s1guza, @stek29 and @iBSparkes. And
16
00:01:40,670 --> 00:01:46,790
we basically started to chat a lot and in
the end also released the "jailbreak me"
17
00:01:46,790 --> 00:01:50,950
for iOS 10 on https://totally-
not.spyware.lol/. For everybody who isn't
18
00:01:50,950 --> 00:01:55,430
familiar with the jailbreak scene, it's
like rooting on Android. So it basically
19
00:01:55,430 --> 00:02:02,420
is a tool that gives the user the
capability to tweak the device, and that's
20
00:02:02,420 --> 00:02:06,170
mostly done by basically installing a
jailbreak in this case. You just go to a
21
00:02:06,170 --> 00:02:07,920
website on the slide there
[https://totally-not.spyware.lol/] and it
22
00:02:07,920 --> 00:02:12,490
will install a package manager on your
phone and then the end user can install
23
00:02:12,490 --> 00:02:17,980
tweaks. So just a little dynamic libraries
and they get injected into all the other
24
00:02:17,980 --> 00:02:21,500
system processes and then they can
obviously modify their memory. And that,
25
00:02:21,500 --> 00:02:25,620
for example, allows customization of the
home screen or something like that. And
26
00:02:25,620 --> 00:02:31,770
basically with the release, we also formed
the team @Jakeblair420 was created with a
27
00:02:31,770 --> 00:02:35,070
Twitter account. There are also a few
demos there if you want to check it out
28
00:02:35,070 --> 00:02:39,699
after the talk. And I basically had this
pipe dream that in my life. I really want
29
00:02:39,699 --> 00:02:44,740
to achieve an untethered jailbreak using
only some sort of plist or other save file
30
00:02:44,740 --> 00:02:49,890
corruption. So basically there are
different kinds of jailbreaks. In modern
31
00:02:49,890 --> 00:02:54,480
jailbreak the most common kind are semi-
untethered, which means that the users has
32
00:02:54,480 --> 00:02:59,580
to connect their device to a PC when they
first install a jailbreak and then they
33
00:02:59,580 --> 00:03:04,250
sideload an app onto the device or it just
installs itself there. And then on each
34
00:03:04,250 --> 00:03:09,160
reboot, the user has to go into the app
and press a button to jailbreak the phone.
35
00:03:09,160 --> 00:03:14,370
And basically, after they reboot, they
lose the jailbreak and have to go through
36
00:03:14,370 --> 00:03:19,510
this process again. And with an untethered
jailbreak, the jailbreak gains persistent
37
00:03:19,510 --> 00:03:24,250
installation and then they will
automatically jailbreak the device on each
38
00:03:24,250 --> 00:03:31,900
boot. So the device automatically boots
jailbroke. The untether can be divided
39
00:03:31,900 --> 00:03:37,390
into four stages. The first stage is when the
config file or database stage. I would go
40
00:03:37,390 --> 00:03:42,150
over how we gain execution of the boot.
Then the config parser bug that gives us
41
00:03:42,150 --> 00:03:47,970
the right opey primitive. And then I will
talk about the main bug, the ASLR bypass,
42
00:03:47,970 --> 00:03:53,090
which allows us to get into ROP. Then
stage two is basically a kernel exploit
43
00:03:53,090 --> 00:03:58,360
and completely written in ROP and there I
will go over the two main kernel bugs: the
44
00:03:58,360 --> 00:04:03,570
kASLR leak and then the racy double free
we used to get the kernel read/write, and
45
00:04:03,570 --> 00:04:09,690
I will also talk about the kASLR weakness
and RootDomain user client memory leak
46
00:04:09,690 --> 00:04:14,440
which aided us in exploitation. And after
we get kernel read/write, we can remove a
47
00:04:14,440 --> 00:04:19,810
few restrictions from Apple. Mainly we can
bypass code signing and that gives us the
48
00:04:19,810 --> 00:04:24,380
ability to load an unsigned dynamic
library into our process. So now in stage
49
00:04:24,380 --> 00:04:30,210
3, we are basically C, we are dynamic
library and there we are stashing the
50
00:04:30,210 --> 00:04:36,830
kernel task port to host special port 4.
So iOS has this concept of ports and task
51
00:04:36,830 --> 00:04:41,770
ports. And basically, if you have a send
right to a task port of a process, you can
52
00:04:41,770 --> 00:04:48,219
read and write its memory. They're most
used for inter process communication. And
53
00:04:48,219 --> 00:04:53,409
where modern jailbreaks used to stash the
kernel task port into a special port 4 so
54
00:04:53,409 --> 00:04:57,830
that other user mode applications can then
retrieve it and with that retrieved and
55
00:04:57,830 --> 00:05:01,810
with send right they can just read and
write process memory. And after that I
56
00:05:01,810 --> 00:05:07,740
just fix up everything and then spawn
stage four and that's basically running in
57
00:05:07,740 --> 00:05:12,599
a separate process. That has a few
advantages I will go into later. It's
58
00:05:12,599 --> 00:05:15,699
basically performing the whole post
exploitation process, including launching
59
00:05:15,699 --> 00:05:19,689
substrate - the framework that's used for
tweek injection and then performing
60
00:05:19,689 --> 00:05:24,099
ldrestart to restart or launch demons on
the system and inject the tweaks into
61
00:05:24,099 --> 00:05:30,931
them. In stage 1, we first need to get
execution after boot, and when iOS boots
62
00:05:30,931 --> 00:05:35,830
launchd is the first process that's
running on the system and it then loads a
63
00:05:35,830 --> 00:05:41,871
dynamic library with a list of executables
- that are LaunchDaemons - and there are a
64
00:05:41,871 --> 00:05:47,219
few flags associated with them. If the
"run and load" flag is set, launchd will
65
00:05:47,219 --> 00:05:52,759
then spawn all of those LaunchDaemons
afterwards. And we basically just take one
66
00:05:52,759 --> 00:05:58,591
of those launch demons, namely Racoon. So
what is Racoon? Basically Racoon is part
67
00:05:58,591 --> 00:06:07,030
of the ipsec package. And it's a VPN
client used to interact with an IPSec VPN
68
00:06:07,030 --> 00:06:13,919
server. And the problem is though, that
IPsec-Tools project has been abandoned
69
00:06:13,919 --> 00:06:18,649
since 2014. So they officially here state
on their website that the development of
70
00:06:18,649 --> 00:06:22,789
the project has been abandoned and that
IPsec-Tools has security issues. You
71
00:06:22,789 --> 00:06:29,059
should not use it. Apple still decided it
was a good idea to ship it after 2014 and
72
00:06:29,059 --> 00:06:34,680
they now maintain their own fork on
https://opensource.apple.com . And yeah,
73
00:06:34,680 --> 00:06:39,099
basically the only thing that's important
for the talk is that raccoon has a
74
00:06:39,099 --> 00:06:43,560
configuration parser. So on startup it
will just look for a file on disk and
75
00:06:43,560 --> 00:06:49,080
start to parse that. And that's written in
yacc so completely written in C. So memory
76
00:06:49,080 --> 00:06:53,789
corruption might become a problem. And it
actually is a problem as we can see if the
77
00:06:53,789 --> 00:07:00,409
config parser bug and for that when we
have to go back a bit. Basically in 2011
78
00:07:00,409 --> 00:07:08,619
Pod2g released Corona for iOS 5, which was
also an untethered. He used a bug in
79
00:07:08,619 --> 00:07:15,699
Racoon in the configuration parser and
Pod2g found this one on an old bug tracker
80
00:07:15,699 --> 00:07:20,789
and basically the IPsec website had this
bug tracker there. There users could just
81
00:07:20,789 --> 00:07:27,460
report problems with their programs and
one user in 2009 I think reported a bug
82
00:07:27,460 --> 00:07:31,509
that if he would use the specific config
Racoon would just segfault, but nobody
83
00:07:31,509 --> 00:07:36,930
looked at this for two years. So in 2011
Pod2g realized that this was actually
84
00:07:36,930 --> 00:07:40,539
exploitable and then used in a jailbreak.
And after that, obviously Apple got aware
85
00:07:40,539 --> 00:07:45,610
of it. And then they also said that they
fixed it. And it's got a CV, assigned
86
00:07:45,610 --> 00:07:53,910
CVS-2012-2737. And yeah, they say that
this was improved through improved bounds
87
00:07:53,910 --> 00:07:58,869
checking. So let's look at the patch.
That's the function before the patch and
88
00:07:58,869 --> 00:08:03,249
that's the function after the patch. And
if this was too fast for you, here's the
89
00:08:03,249 --> 00:08:07,559
diff. So basically there is no difference.
The bug is still there and Apple didn't
90
00:08:07,559 --> 00:08:13,029
patch it. What really happened here was
that basically this is obviously a
91
00:08:13,029 --> 00:08:17,529
configuration parser. So there are
different statements that nearly do the
92
00:08:17,529 --> 00:08:22,610
same thing. There are these nbns4
statements to parse an IP address and
93
00:08:22,610 --> 00:08:27,180
there are wins4 statement followed by an
IP address and both of them have to parse
94
00:08:27,180 --> 00:08:33,940
the IP address. So the function for
parsing that was just copy pasted from
95
00:08:33,940 --> 00:08:41,130
another one. And yeah, basically Apple
fixed the bug in the other function. Which
96
00:08:41,130 --> 00:08:47,520
I don't get because basically the engineer
there had to look at PoC Pod2g provided
97
00:08:47,520 --> 00:08:51,250
then they had to realize okay, the bug is
in there, fix it, then they had to
98
00:08:51,250 --> 00:08:55,050
recompile and never tested against the
original PoC because otherwise Racoon
99
00:08:55,050 --> 00:08:59,620
would have crashed again. Yeah, it's
basically an off by one which allows you
100
00:08:59,620 --> 00:09:05,640
to overwrite the index of an array and
Pod2g gave a talk about this and we can
101
00:09:05,640 --> 00:09:11,390
basically reuse his strategy from back in
2011 to get a write primitive.
102
00:09:11,390 --> 00:09:16,730
Again, the one function here at the top.
You can see the yacc syntax so an addrwins
103
00:09:16,730 --> 00:09:21,240
list has to consist of either an addrwins
statement or addrwins statement followed
104
00:09:21,240 --> 00:09:25,600
by a comma, followed by an addrwins list.
So that's a recursion. There can be
105
00:09:25,600 --> 00:09:31,020
multiple addrwins statements in a row. And
then below that, an addrwins statement is
106
00:09:31,020 --> 00:09:35,390
defined as containing an address string.
And that's just a regex to match an IP
107
00:09:35,390 --> 00:09:38,950
version 4 address. And if the parcel finds
that it would run the code between those
108
00:09:38,950 --> 00:09:44,480
two brackets. So they get the pointer to a
global struct and then they check if this
109
00:09:44,480 --> 00:09:50,500
nbns4_index is bigger than MAXWINS and if
so, they return an error. The problem here
110
00:09:50,500 --> 00:09:54,620
is that this is off by 1. It shouldn't be
checking if it's greater than so, but it
111
00:09:54,620 --> 00:09:58,440
should be a check for greater or equal
than MAXWINS. And after that, they use
112
00:09:58,440 --> 00:10:03,090
thisinet_pton function to basically parse
the address, which is in this variable
113
00:10:03,090 --> 00:10:10,130
into the nbns4 array at the nbns4 index
and then post-increment the index. And
114
00:10:10,130 --> 00:10:13,990
that will also be coming in handy when
exploiting this bug. So yeah. How is
115
00:10:13,990 --> 00:10:18,740
exploitation done? Basically there are
here the globals, there is this Lcconfig
116
00:10:18,740 --> 00:10:23,610
pointer in the globals pointing to a heap
structure and that the parser also uses.
117
00:10:23,610 --> 00:10:29,670
And then there is this dns4 array followed
by the dns_area_index and then the nbns4
118
00:10:29,670 --> 00:10:35,341
array followed by the nbns_4_array_index
so we can just use mode_cfg statement
119
00:10:35,341 --> 00:10:39,270
followed by this wins4 statement with the
IP address to parse the IP address in the
120
00:10:39,270 --> 00:10:44,630
first array element and we can repeat this
process four times to then move the index
121
00:10:44,630 --> 00:10:49,680
out of bounds. So now it's pointing to
itself and the cool thing is about that is
122
00:10:49,680 --> 00:10:53,910
that therefore there would be a good idea
to use integers for those area indexes
123
00:10:53,910 --> 00:10:59,110
instead of unsigned integers so we can
just point them... you just use negative
124
00:10:59,110 --> 00:11:04,260
numbers to bypass the bounds check. So
we'll overwrite it with -1 to point it to
125
00:11:04,260 --> 00:11:09,110
an dns_array_index and then we use another
wins statement to override the
126
00:11:09,110 --> 00:11:13,130
dns_array_index with a negative number.
And the cool thing about this is that
127
00:11:13,130 --> 00:11:16,400
because of the post-incrementation, it
will move it back to zero so we can repeat
128
00:11:16,400 --> 00:11:20,760
this process as often times as we want,
and we will use a negative number to
129
00:11:20,760 --> 00:11:24,740
basically point it to the Lcconfig
pointer. And then we can use two dns4
130
00:11:24,740 --> 00:11:28,940
statements to override the Lcconfig
pointer and point it anywhere in memory.
131
00:11:28,940 --> 00:11:34,660
And after that we can use a timer
statement with a counter. Then the
132
00:11:34,660 --> 00:11:39,510
parsible just tried to write it to the
Lcconfig structure so it will de-reference
133
00:11:39,510 --> 00:11:44,200
our pointer and write it there and the
interval statement will basically write to
134
00:11:44,200 --> 00:11:49,740
an uint32, which is followed by the uint
where the counter statement is written so
135
00:11:49,740 --> 00:11:53,500
we can turn this into a 64 bit write
anywhere primitive and write anywhere in
136
00:11:53,500 --> 00:11:59,560
process memory and that gives us an
ability to basically exploit the ASLR
137
00:11:59,560 --> 00:12:05,030
bypass. So this is the main bug of the
whole untethered and allows us to
138
00:12:05,030 --> 00:12:10,350
basically have this primitive. And it's
also the reason why I decided to give this
139
00:12:10,350 --> 00:12:14,530
talk this year and not last year, because
there the bug was pretty fresh and only
140
00:12:14,530 --> 00:12:20,550
patched in iOS 12 and it gives to an
attacker the ability to exploit zero click
141
00:12:20,550 --> 00:12:23,680
more easily because they just need the
write anywhere primitive. And that's why I
142
00:12:23,680 --> 00:12:29,740
held back on it. Siguza found it after
looking into Apple's patches of the Corona
143
00:12:29,740 --> 00:12:35,410
ASLR bypass and basically from Pod2g's
presentation, we as a team learned that
144
00:12:35,410 --> 00:12:40,160
ASLR is always bypassed when a writable
region is larger than the maximum slide,
145
00:12:40,160 --> 00:12:45,100
because then there's always a writable
address in process memory and you can use
146
00:12:45,100 --> 00:12:51,230
this to brute force the slide and Siguza
found out that there was what was also the
147
00:12:51,230 --> 00:12:56,680
same problem with the cache in iOS 11 and
a few versions of iOS 10 actually. So
148
00:12:56,680 --> 00:13:02,200
what's the cache? Basically, the cache is
a pre compiled blob containing the dynamic
149
00:13:02,200 --> 00:13:07,550
link libraries from Apple. So on each
released, you just move all of those into
150
00:13:07,550 --> 00:13:13,430
one big file to optimize load times of
apps and keep memory pressure low. So it's
151
00:13:13,430 --> 00:13:19,230
a pretty big file. And for that on boot
the kernel needs to calculate a slide and
152
00:13:19,230 --> 00:13:23,940
slide it in memory. But they only slide it
once on boot because it's used in every
153
00:13:23,940 --> 00:13:30,070
process. And so Apple defines an area of
memory for the cache with a base address
154
00:13:30,070 --> 00:13:35,890
and the size and that's hardcoded on iOS
11. The cache got so big that a maximum
155
00:13:35,890 --> 00:13:42,630
slide is now smaller than its data
segment. So the conditioning is satisfied
156
00:13:42,630 --> 00:13:47,910
and ASLR can be bypassed, basically. And
the weird thing about this is that
157
00:13:47,910 --> 00:13:54,040
actually the same thing also happened in
iOS 7. Back then, the size was defined as
158
00:13:54,040 --> 00:13:58,220
500 megabytes and the cache got bigger
than 500 megabytes. But before that, it
159
00:13:58,220 --> 00:14:02,650
was also in a few versions possible to
have the same condition that the data
160
00:14:02,650 --> 00:14:06,910
segment again was bigger than the maximum
slide. And Apple was actually also aware
161
00:14:06,910 --> 00:14:11,150
of this because Acer talked about it
in one of his talks, but they just
162
00:14:11,150 --> 00:14:15,950
increased the maximum slide to 1 gigabyte
and didn't edit any asserts. And now in
163
00:14:15,950 --> 00:14:22,240
iOS 11, it again got so big that the same
thing happened. And we believe that they
164
00:14:22,240 --> 00:14:27,380
didn't even really notice that up until
iOS 12 where the cache was now bigger than
165
00:14:27,380 --> 00:14:31,150
1 gigabyte so the kernel just couldn't fit
it in the memory region and paniced. And
166
00:14:31,150 --> 00:14:35,250
because of that they just thought well,
then we will increase it to 4 gigabyte
167
00:14:35,250 --> 00:14:41,140
while developing so we might see this
reoccurring in I don't know, iOS 15 or
168
00:14:41,140 --> 00:14:47,300
something like that. Exploitation is also
pretty simple. We can just brute force the
169
00:14:47,300 --> 00:14:52,210
slide now and there are a lot of function
pointers in the data segment. So we
170
00:14:52,210 --> 00:14:58,550
decided to go with __platform_mem_move
because we can reach it via strlcpy from
171
00:14:58,550 --> 00:15:02,730
the conflict parser. And the basic
strategy behind this is we write a slid
172
00:15:02,730 --> 00:15:08,640
rop chain into an address we can always
write to for a specific slide abc and then
173
00:15:08,640 --> 00:15:13,220
we overwrite the __platform_mem_move
pointer at its unslid address plus the
174
00:15:13,220 --> 00:15:19,590
slide we just chose with a gadget that
would pivot to our slid rop chain and then
175
00:15:19,590 --> 00:15:25,550
we call strlcpy. And now there are
basically two possibilities. Either we
176
00:15:25,550 --> 00:15:30,220
guessed the right slide and then we jump
to our gadget and pivot the stack or we
177
00:15:30,220 --> 00:15:33,500
guessed the wrong slide. But obviously
nothing happened because we can just write
178
00:15:33,500 --> 00:15:38,540
there so we can go back to step one and
try again. And then with that we can just
179
00:15:38,540 --> 00:15:41,650
brute force the slide till we get the
right one. The catch with this, however,
180
00:15:41,650 --> 00:15:45,590
is that the write what were is pretty slow
and it also needs a lot of storage. So for
181
00:15:45,590 --> 00:15:53,461
a 64 bit write I need about 120 bytes in
the config file. And because there are so
182
00:15:53,461 --> 00:16:01,720
many possible slide values, the chain I
have currently is around... it's only to
183
00:16:01,720 --> 00:16:07,010
rop gadgets, but the config file is
already 12 megabytes, I think. And because
184
00:16:07,010 --> 00:16:11,490
of that, it takes around 10 seconds to run
if it's a really bad slide. So the rop
185
00:16:11,490 --> 00:16:16,050
chain has to be as short as possible. And
the other problem is that if we have a bad
186
00:16:16,050 --> 00:16:19,570
slide, we will basically smash the whole
data segment and we can't really recover
187
00:16:19,570 --> 00:16:23,520
from that. So we had crashes in malloc and
stuff like that while developing,
188
00:16:23,520 --> 00:16:27,650
basically. There are some solutions to
that, we can have a really short rop chain
189
00:16:27,650 --> 00:16:34,100
in stage one and we can achieve this by
basically just opening the big cache file
190
00:16:34,100 --> 00:16:39,440
to get a file descriptor to it and then we
can map it at a static address and then
191
00:16:39,440 --> 00:16:43,300
get many gadgets there because the file is
obviously code signed by Apple so we can
192
00:16:43,300 --> 00:16:47,900
just jump there after mapping it. But the
problem with that is that nothing is set
193
00:16:47,900 --> 00:16:53,110
up. So malloc and other functions aren't
working. But as I said earlier, the
194
00:16:53,110 --> 00:16:57,830
current cache has a smashed data segment
so we don't really lose anything. And
195
00:16:57,830 --> 00:17:01,530
after having the cache at a static address
we can use the open and mmap functions
196
00:17:01,530 --> 00:17:05,569
from that cache to basically map stage two
into the process memory and stage two is
197
00:17:05,569 --> 00:17:16,480
just a really big rop stack. So, yeah. And
then we are basically in ROP, but we can
198
00:17:16,480 --> 00:17:21,200
only use raw syscalls and not much more
because everything else will either use a
199
00:17:21,200 --> 00:17:26,449
function that uses malloc or will use
malloc on it's own. And the other problem
200
00:17:26,449 --> 00:17:30,360
is that basically errno is also broken. So
every syscall which fails will crush the
201
00:17:30,360 --> 00:17:35,110
binary. So the first thing I do is
basically map a few pages so that errno
202
00:17:35,110 --> 00:17:40,610
works again because we have a few syscalls
that might fail. And then the other big
203
00:17:40,610 --> 00:17:45,150
problem is that we now need to implement
the whole kernel exploit in rop. So I
204
00:17:45,150 --> 00:17:50,480
start to write a framework around this
awesome gadget which is present in all the
205
00:17:50,480 --> 00:17:54,059
cache versions I looked at. Basically at the
top you can see that all the high
206
00:17:54,059 --> 00:18:00,559
registers are moved into x0 through x7. So
all the registers used for the calling
207
00:18:00,559 --> 00:18:07,610
convention are and then we branch with
link to register based on x27. So also
208
00:18:07,610 --> 00:18:11,950
high register. And after that we load all
the register values back from the stack so
209
00:18:11,950 --> 00:18:16,749
we can just chain those gadgets together
to call any functions. You basically rop
210
00:18:16,749 --> 00:18:22,309
into the lower half and then chain another
one of those afterwards and then they can
211
00:18:22,309 --> 00:18:26,889
load all the values, call the function and
then load all the values from the stack
212
00:18:26,889 --> 00:18:32,399
again. And that's how the whole rop chain
works. So yeah, I also used another gadget
213
00:18:32,399 --> 00:18:37,480
to basically add two registers together
and another one which stores x0 so that I
214
00:18:37,480 --> 00:18:42,799
can store the return value on the stack
and later reuse it. And for loops I use a
215
00:18:42,799 --> 00:18:46,950
gadget which just returns if x0 is zero.
So it's basically just a read instruction
216
00:18:46,950 --> 00:18:51,300
then and otherwise it will tail call a
function using function pointer from the
217
00:18:51,300 --> 00:18:54,890
data segment. And because I can control
the whole data segment, I can just put a
218
00:18:54,890 --> 00:19:00,230
function pointer there that that will then
jump to an epilog and misasligning the stack
219
00:19:00,230 --> 00:19:05,119
with that. And then I can call longjmp
with two different register values and
220
00:19:05,119 --> 00:19:10,399
because of that pivot the stack to another
location. And when we basically didn't
221
00:19:10,399 --> 00:19:16,399
jump outside of the loop, I just mmap the
part of stage 2 which has the loop in it
222
00:19:16,399 --> 00:19:23,050
back over old stack again. And then I can
just reuse to stack every time. And then
223
00:19:23,050 --> 00:19:27,529
pivot up using longjup. The problem wih
this, however, is obviously that it's
224
00:19:27,529 --> 00:19:33,590
pretty slow because I use mmap as a
syscall. But this can be solved by just
225
00:19:33,590 --> 00:19:38,980
unrolling your loops like for 10
iterations and then mmapping the file so
226
00:19:38,980 --> 00:19:43,390
that I get more loop iterations basically
per second, which is important for the
227
00:19:43,390 --> 00:19:52,310
race. So now we will go over the kernel
bug so the kASLR leak is CVS-2018-4413 by
228
00:19:52,310 --> 00:19:58,130
panicall. It was fixed in iOS 12.1 and
it's luckily reachable from the Racoon
229
00:19:58,130 --> 00:20:03,289
sandbox because Apple is sandboxing most
userland processes and the Racoon sandbox
230
00:20:03,289 --> 00:20:08,390
is really tight. We didn't have that much,
many bugs that would work in Racoon, but
231
00:20:08,390 --> 00:20:14,510
luckily this one does because Racoon has
access to the sysctl functions and this
232
00:20:14,510 --> 00:20:20,240
one is in the sysctl_progargsx function.
The progargsx function basically allocates
233
00:20:20,240 --> 00:20:25,500
a page using kmem_alloc. But it doesn't
zero it so it might contain old heap data
234
00:20:25,500 --> 00:20:30,889
and then they copy the process arguments
to the front of the page. And now if you
235
00:20:30,889 --> 00:20:35,139
supply a wrong size from user space and
there are a few other conditions that have
236
00:20:35,139 --> 00:20:40,059
to be met for some weird reason it copies
from the end of the page into user space
237
00:20:40,059 --> 00:20:44,559
which I don't get why does this even get
by code review. But here's a graphical
238
00:20:44,559 --> 00:20:49,909
illustration: there is basically this page
is full of uninitialized data and then
239
00:20:49,909 --> 00:20:53,240
they put the process arguments in the
front and copy out uniinitialized heap
240
00:20:53,240 --> 00:20:58,909
data from the back into user land and we
can obviously just spray specific heap
241
00:20:58,909 --> 00:21:04,429
objects with kernel pointers in them and
then free them again and use this
242
00:21:04,429 --> 00:21:08,191
primitive to maybe leak them. And if we
find a kernel pointer in there, we can
243
00:21:08,191 --> 00:21:15,379
just calculate this kernel slide. So yeah.
And then we come to the racy double free.
244
00:21:15,379 --> 00:21:19,679
As I said, the main problem of the
untether is the racoon sandbox, so many of
245
00:21:19,679 --> 00:21:24,720
the kernel bugs that would work in iOS 11
from an app, didn't work from racoon. But
246
00:21:24,720 --> 00:21:30,080
luckily on Halloween Sparky told me about
Lightspeed bug from Synacktiv, which is
247
00:21:30,080 --> 00:21:35,960
reachable from the sandbox. It's a double
free in kalloc.16. The kernel allocator's
248
00:21:35,960 --> 00:21:42,879
based on zones and with different sizes.
So there's, for example, kalloc.16 and
249
00:21:42,879 --> 00:21:47,270
then all objects in that zone have a size
of 16 or less bytes and they are obviously
250
00:21:47,270 --> 00:21:55,460
also other zones for bigger objects. And
basically there is a structure in there
251
00:21:55,460 --> 00:22:00,690
that then gets doubled. And there is the
syscall that's handling async file events.
252
00:22:00,690 --> 00:22:04,370
So a user mode application can just call
it and tell the kernel, hey, please write
253
00:22:04,370 --> 00:22:09,720
a buffer to a file and then move on with
execution and it uses a kernel thread to
254
00:22:09,720 --> 00:22:13,639
perform those. And for that, that
basically allocates a structure to contain
255
00:22:13,639 --> 00:22:18,330
some metadata like where the buffer is and
to which file it should write, and the
256
00:22:18,330 --> 00:22:23,590
kernel thread obviously has to free the
structure after it's done because it just
257
00:22:23,590 --> 00:22:27,850
gets into the query for
the kernel thread, that then wakes up and
258
00:22:27,850 --> 00:22:33,000
maybe sees it has a new job, then performs
the operation and then it has to free it,
259
00:22:33,000 --> 00:22:36,450
otherwise it will leak. But the problem
here is that if an error occurred while
260
00:22:36,450 --> 00:22:41,419
setting the structure up, the second field
in the structure will be zero. And then
261
00:22:41,419 --> 00:22:46,440
the structure also isn't included into the
jobs list. So the kernel thread will never
262
00:22:46,440 --> 00:22:51,460
wake up and look at it. So the syscall has
to free it because otherwise it will leak.
263
00:22:51,460 --> 00:22:55,100
And the problem here is that we can
basically reallocate the structure before
264
00:22:55,100 --> 00:22:58,929
the syscall checks. So what happens here
is that the syscall allocates the
265
00:22:58,929 --> 00:23:04,400
structure, fills it up, and then it gets
added to the list and then the kernel
266
00:23:04,400 --> 00:23:09,999
thread is so fast that it runs while the
syscall isn't finished yet and basically
267
00:23:09,999 --> 00:23:17,780
gets the gets the job done and frees it.
And then we can spray heap objects pretty
268
00:23:17,780 --> 00:23:22,980
fast to overlay with that structure. And
then the syscall finishes and checks the
269
00:23:22,980 --> 00:23:27,619
field and sees that it's zero because we
just replaced it with an object that has
270
00:23:27,619 --> 00:23:32,749
zero at that location so it frees it again
leading to a double free. And yeah, we can
271
00:23:32,749 --> 00:23:38,909
obviously exploit it. So for exploitation
I just spam the syscall on one thread
272
00:23:38,909 --> 00:23:42,869
which is pretty hard to do in ROP, but I
just call threadCreate. We've appointed
273
00:23:42,869 --> 00:23:46,970
two long jump and then pivot the stack to
the application and then in the other
274
00:23:46,970 --> 00:23:52,930
thread I spray Mach messages with
MACH_PORT_NULL in it. And the thing with
275
00:23:52,930 --> 00:23:58,590
Mach messages is they can be used to do
inter-process communication and you can
276
00:23:58,590 --> 00:24:03,350
also transfer port rights from one process
to another. So in this case we just send
277
00:24:03,350 --> 00:24:07,709
an empty port, but you could also place
something else there and that will create
278
00:24:07,709 --> 00:24:14,289
a structure and kalloc.16 containing zero
at that location. And and then if the Mach
279
00:24:14,289 --> 00:24:18,690
message gets freed, we can replace it with
something and basically point it to
280
00:24:18,690 --> 00:24:22,859
somewhere in kernel where fake port
structure lives. And when we receive the
281
00:24:22,859 --> 00:24:26,809
Mach message again, it will basically
think that this is a real port and treat
282
00:24:26,809 --> 00:24:32,600
it as such. And with that we can create a
fake kernel task port. But for that we
283
00:24:32,600 --> 00:24:38,409
obviously need to replace it and we need
to heap spray. And most commonly iOS
284
00:24:38,409 --> 00:24:43,519
surface is used for that as a kernel
extension, but because of our sandbox we
285
00:24:43,519 --> 00:24:48,419
are so limited that we don't have iOS
surface access. So the question is how we
286
00:24:48,419 --> 00:24:54,310
actually spray and the
rootDomainUserClient comes to rescue with
287
00:24:54,310 --> 00:25:01,179
a memory leak. So actually this function
secureSleepSystemOptions is reachable from
288
00:25:01,179 --> 00:25:07,020
the raccoon sandbox and Apple has a way of
basically passing data to the kernel via
289
00:25:07,020 --> 00:25:12,850
XML. So a userland application can just
pass the XML to the kernel and then they
290
00:25:12,850 --> 00:25:18,039
will use this OSUnserializeXML function to
turn the XML back into C++ objects which
291
00:25:18,039 --> 00:25:21,789
the kernel can then use. And if this
sounds dangerous to you, it actually is.
292
00:25:21,789 --> 00:25:27,549
There were a few bugs in that. But in this
case we basically this just makes sure
293
00:25:27,549 --> 00:25:33,309
with the OSDynamicCast that the data the
user mode application supplied isn't
294
00:25:33,309 --> 00:25:38,499
always dictionaries so that it can use it
afterwards. And the problem here is that
295
00:25:38,499 --> 00:25:44,130
we can basically just OSDataObject or an
always OSArray. So this OSDynamicCast
296
00:25:44,130 --> 00:25:48,899
will fail and serialized options will
become null. But the original point of
297
00:25:48,899 --> 00:25:55,570
return from OS under the XML will get lost
and so we will leak that memory and we
298
00:25:55,570 --> 00:26:02,010
can just use this for spraying. So then
about those two primitives, I will use to
299
00:26:02,010 --> 00:26:06,860
basically exploitation. The case law
weakness, Darrell Justice CCL buffers and
300
00:26:06,860 --> 00:26:10,980
they are located in the kernel data region
and because of that they are stacked with
301
00:26:10,980 --> 00:26:17,080
the same slide as the kernel text region.
And this means that as long as we know the
302
00:26:17,080 --> 00:26:21,159
kernel slide we already do, that from the
case of largely and we can control the
303
00:26:21,159 --> 00:26:27,659
contents of a CCL buffer and we can get
data to a known address and we can easily
304
00:26:27,659 --> 00:26:33,010
do that with racoon because it runs US
route. And so we can just switch all of
305
00:26:33,010 --> 00:26:37,320
this of CCL buffer, for example, place the
same point structure there will be later.
306
00:26:37,320 --> 00:26:44,369
Also, place a fake trust constructively,
but I will get into that. So yeah, now we
307
00:26:44,369 --> 00:26:49,869
can use that primitive to basically spray
tan or state objects pointing to the CCL
308
00:26:49,869 --> 00:26:53,739
buffer. And then we just received the
message again and check if the polls are
309
00:26:53,739 --> 00:27:00,120
now. And if that's the case, we best place
the structure. And then for the non SMP
310
00:27:00,120 --> 00:27:04,830
version we can even get the case load by
traversing a few pointers. But that's not
311
00:27:04,830 --> 00:27:10,710
needed for SMP Version because there we
already got it with the case logic but
312
00:27:10,710 --> 00:27:15,039
young, Non CCL IP devices, we also don't
need a CCL buffers because we can just
313
00:27:15,039 --> 00:27:20,110
place the fake port structure and use the
land and then we get the kernel slide this
314
00:27:20,110 --> 00:27:24,090
way. And with the kernel slide and this
fake port, we can create a fake user
315
00:27:24,090 --> 00:27:28,789
client and from there we can create a
called primitive and then we can use this
316
00:27:28,789 --> 00:27:33,539
to override that pierce's trusses pointer
and pointed to a buffer with two hashes
317
00:27:33,539 --> 00:27:38,179
and four stage 3 and stage 4. So basically
Apple has two ways of doing code signing.
318
00:27:38,179 --> 00:27:42,749
Either it has a used land daemon that
verifies third party applications or a
319
00:27:42,749 --> 00:27:48,110
test, so-called trust cache, which is a
list of hashes from all of their system
320
00:27:48,110 --> 00:27:54,279
applications. And as soon as the process
spawned or dynamic link library is loaded
321
00:27:54,279 --> 00:27:59,309
and they will basically first verify if
the hash of that file is inside of the
322
00:27:59,309 --> 00:28:02,800
trust cache. And if so, they will just
trust a binary blindly because it comes
323
00:28:02,800 --> 00:28:07,309
from Apple, basically. And now when we
override this trust cache point and
324
00:28:07,309 --> 00:28:13,769
pointed to our buffer, we can basically
place the hash of stage 3 and 4 there. And
325
00:28:13,769 --> 00:28:20,000
then the system will think those are apple
binaries and we can just load them. So.
326
00:28:20,000 --> 00:28:24,470
Yeah. And for that we need to use a geter
open. We can't use the real deal open
327
00:28:24,470 --> 00:28:29,779
because that uses malock. So we just
open stage 3 to get a file descriptor.
328
00:28:29,779 --> 00:28:34,440
Then we attached a signature which now
succeeds as the caches and trust cache and
329
00:28:34,440 --> 00:28:39,559
then we can map it as read executed and
jump there. And then we are after two
330
00:28:39,559 --> 00:28:46,099
months of writing options. We are finally
in C and we can write code more easily.
331
00:28:46,099 --> 00:28:51,229
And the problem there is that we still
don't have a working cache. So we are
332
00:28:51,229 --> 00:28:57,220
still limited to the basic functionality
and because of the ghetto dlopen link is
333
00:28:57,220 --> 00:29:02,599
obviously not working. So we just rely on
raw as somebody follows syscalls. And I
334
00:29:02,599 --> 00:29:07,910
also pass some function pointers which I
already use for stage 2. So for example,
335
00:29:07,910 --> 00:29:13,700
open and a map to stage 3. And from there
we remove the con task and session into
336
00:29:13,700 --> 00:29:20,759
our special port 4 so that other user mode
applications can use it. And then we can
337
00:29:20,759 --> 00:29:24,510
basically escape the sandbox by removing
the sandbox label in the process
338
00:29:24,510 --> 00:29:30,700
structure, so that we can launch a new
binary, because otherwise the raccoons and
339
00:29:30,700 --> 00:29:35,350
bugs doesn't allow it. But in the kernel,
those process structures basically have
340
00:29:35,350 --> 00:29:39,009
this label, which tells the kernel of
which sandbox to use. And as you're doing
341
00:29:39,009 --> 00:29:45,539
it, you can just tell it to not use any
samples. And and then we can launch stage
342
00:29:45,539 --> 00:29:49,799
3, 4 and with that, get a working
cashback. And that's the big advantage
343
00:29:49,799 --> 00:29:55,359
from like having a separate file. We now
have the full cache functions working and
344
00:29:55,359 --> 00:30:01,480
can do work more easily. And then I it's
just called two opposing spawn and then a
345
00:30:01,480 --> 00:30:06,449
raw exit. This to exit the daemon without
crashing because of launch. You would see
346
00:30:06,449 --> 00:30:10,610
that one of the launch demons crashed and
the specifics flag inside it would try to
347
00:30:10,610 --> 00:30:14,340
restart it. And then our option would run
again. We obviously want to prevent that.
348
00:30:14,340 --> 00:30:21,449
So we use the exits as call to exit it.
And then we are in stage 4. And from my
349
00:30:21,449 --> 00:30:25,780
side, that was just basically to block or
signal. So we don't get killed by launchd.
350
00:30:25,780 --> 00:30:31,110
Because when launchd the launch and
exits, it will send the kill to all this
351
00:30:31,110 --> 00:30:35,520
child process. And I need to catch that.
Otherwise Stage 4 would get killed. And
352
00:30:35,520 --> 00:30:40,250
then I just called the Post Exploitation
Framework, which was written by Sparky.
353
00:30:40,250 --> 00:30:45,200
And basically that does the following. It
first elevates the process to root with
354
00:30:45,200 --> 00:30:50,220
current credentials, then it performs a
remount of the root file system because on
355
00:30:50,220 --> 00:30:56,249
stock IOS, a file system was mounted as
read only and we obviously need to
356
00:30:56,249 --> 00:31:01,470
mount it as read/write to modify some files
on there and then set non it sets the
357
00:31:01,470 --> 00:31:06,589
nonce so that the user might be able to
downgrade to an older version if they are
358
00:31:06,589 --> 00:31:12,099
flops. Verifies that the bootstrap was in
place from the installation. And then
359
00:31:12,099 --> 00:31:17,450
checked substrates or the framework that's
used for them to perform tweak injection
360
00:31:17,450 --> 00:31:23,599
and it's plugging into trust us and starts
them so that they can start to inject into
361
00:31:23,599 --> 00:31:27,870
newly spawn processes. Then it's Ponce or
the launch demons associate with the
362
00:31:27,870 --> 00:31:33,520
jailbreak and unloads or own demons so
that we don't respawned by extended
363
00:31:33,520 --> 00:31:38,809
run. They kernel exploit again and then
performs an LUV start to basically restart
364
00:31:38,809 --> 00:31:43,649
all of the launch teams off the system so
that subset can inject 3 STEM. And with
365
00:31:43,649 --> 00:31:49,009
that the system is faulty, jail broken and
we can perform a few cleanup steps. But
366
00:31:49,009 --> 00:31:52,750
yeah, basically the end user has
jailebroken system. Then as a little
367
00:31:52,750 --> 00:31:58,240
side note while we are testing all the
demons, we got killed by jetsam a lot. So
368
00:31:58,240 --> 00:32:02,769
basically jetsam is the kernel
extension from Apple. That is therefore
369
00:32:02,769 --> 00:32:08,349
memory management. And they basically want
to make sure the user mode application
370
00:32:08,349 --> 00:32:12,909
doesn't use too much memory because they
don't have that much on iPhone. And on all
371
00:32:12,909 --> 00:32:19,019
the iPhones, actually. So there is this
list and jetsam, it jetsam seems easier to
372
00:32:19,019 --> 00:32:24,909
use than process uses more than read and
should use. It would just kill it. So we
373
00:32:24,909 --> 00:32:29,500
changed the values in the plist under
LaunchDaemons to actually allow the
374
00:32:29,500 --> 00:32:33,820
LaunchDaemons to use more memory. But
the weird thing about this is that this
375
00:32:33,820 --> 00:32:39,479
actually got us accepted by jetsam and we
had normal crashes while Apple actually
376
00:32:39,479 --> 00:32:46,719
tried to mitigate that beforehand. So
because jailbreak is always modify those
377
00:32:46,719 --> 00:32:50,359
configuration files on the LaunchDaemons,
they start to move all of them into a
378
00:32:50,359 --> 00:32:54,489
dynamic library to guard them under code
signing. So the jailbreak just couldn't
379
00:32:54,489 --> 00:32:59,330
change them anymore. But when you tried to
figure out the Launchdemon at the Launch
380
00:32:59,330 --> 00:33:06,031
Demons, we dumped the dylib and ahm
there was also plist embedded for
381
00:33:06,031 --> 00:33:12,429
Jetsam, but Apple was still using those
files on disk. So I really want to look
382
00:33:12,429 --> 00:33:16,299
further into this because it seems like
Apple isn't always ignoring those
383
00:33:16,299 --> 00:33:22,409
configurations files on disk. And then
thanks to the whole team. Siguza, Sparkey,
384
00:33:22,409 --> 00:33:27,739
and Stek for bouncing ideas back and
forth and writing the many part of the
385
00:33:27,739 --> 00:33:35,299
jailbreak. Then for Pod2g, Synacktiv for
the kernel bugs. And basically also a big
386
00:33:35,299 --> 00:33:39,519
thanks to Saurik for substrate and the
whole jailbreaking framework and for
387
00:33:39,519 --> 00:33:43,240
Swaggo, parrorgeek and Samg_is_a_Ninja
for testing a few things and keeping
388
00:33:43,240 --> 00:33:49,359
motivated. And for Jonathan Levin for his
books basically because he bought a few
389
00:33:49,359 --> 00:33:54,720
awesome books about IOS and that got me
into it two years ago. And yeah. And in
390
00:33:54,720 --> 00:33:59,919
the future, I think exploiting kernel
vulnerability with other cache functions
391
00:33:59,919 --> 00:34:05,400
and owning ROP really is a pain and that
probably won't do it again. Because he's
392
00:34:05,400 --> 00:34:12,770
spent most of that. But yeah, the other
big problem now is that with a 12 so the
393
00:34:12,770 --> 00:34:18,850
new iPhones pack. So point authentication
kills most of these types of exploits
394
00:34:18,850 --> 00:34:23,419
because the problem there is that you
would now need an ASLA bypass and the pack
395
00:34:23,419 --> 00:34:30,130
bypass to get into return oriented
programing. And it's pretty unlikely to
396
00:34:30,130 --> 00:34:36,690
basically have both. And because Pegg
bypasses are really rare and yet I only
397
00:34:36,690 --> 00:34:43,380
know about this one is a LA bypass. So you
would have to get pretty lucky. Also un-
398
00:34:43,380 --> 00:34:48,460
tethering gets progressively harder. Apple
just fixed another good idea ahead in iOS
399
00:34:48,460 --> 00:34:55,640
13.1. Basically the idea was to use printf
with the format string format modify
400
00:34:55,640 --> 00:35:01,170
'%n' to get a Turing complete
machine because printf, this modifier
401
00:35:01,170 --> 00:35:08,170
is basic Turing complete and then you
start to develop a pack bypass basically
402
00:35:08,170 --> 00:35:14,130
and get them to ROP. But now we're in IS
13.1. I think Apple actually removed the
403
00:35:14,130 --> 00:35:19,830
'%n' modifier, so you can no
longer do this. And yeah. So this idea is
404
00:35:19,830 --> 00:35:24,730
also gone. And yeah. In the end, I was
able to complete my pipe dream, so I guess
405
00:35:24,730 --> 00:35:31,160
I will need a new one. So watch out, Apple
and that spice. Are there any questions?
406
00:35:31,160 --> 00:35:41,090
Applause
407
00:35:41,090 --> 00:35:45,400
Herald: Thank you, littlelailo for is
fantastic work. I suppose we're going to
408
00:35:45,400 --> 00:35:49,790
hear more from you in the future.
Littlelailo: Maybe.
409
00:35:49,790 --> 00:35:54,940
Herald: Are there questions here in
this audience. No one who wants to hire
410
00:35:54,940 --> 00:36:01,650
this guy now right away. No one. No one.
Can you describe to me what change
411
00:36:01,650 --> 00:36:09,190
actually do times in these, you know, all
the ASICs? Oh, yeah. Oh, yes. versions.
412
00:36:09,190 --> 00:36:11,500
Littlelailo: Well what they change to
make.
413
00:36:11,500 --> 00:36:17,030
Herald: Yeah. What. Plus, you know, I told
you like I started the tethering challenge
414
00:36:17,030 --> 00:36:20,360
actually at 5.1.
Littlelailo: Well, they added a lot new
415
00:36:20,360 --> 00:36:25,930
mitigations and also obviously pitched a
few bugs like for example, those ASLR
416
00:36:25,930 --> 00:36:31,620
bypasses that posterity used in Corona
got patched. And this one also now got
417
00:36:31,620 --> 00:36:37,660
patched by accident. But yeah, I mean like
some bugs are still there. For example,
418
00:36:37,660 --> 00:36:42,120
the Bug in racoon and the conflict pass.
The bug is still an all day. But yeah, I
419
00:36:42,120 --> 00:36:47,840
don't really care about it. And the kernel
bugs got patched by Apple. But for
420
00:36:47,840 --> 00:36:52,590
example, this synthetic one, they also
also patched wrong by accident. And now it
421
00:36:52,590 --> 00:36:55,800
always leaked the strike. But I think they
also fixed that now.
422
00:36:55,800 --> 00:36:59,740
Herald: Your team, you you're mentioning
your team. You're working not on
423
00:36:59,740 --> 00:37:01,740
your own, of course.
Littlelailo: No.
424
00:37:01,740 --> 00:37:05,820
Herald: And how would you restructured?
How are the roles divided? How was...
425
00:37:05,820 --> 00:37:10,740
Littlelailo: Well, we are just like four
people. So and we have this group chat and
426
00:37:10,740 --> 00:37:14,860
then we are just hanging out there and
bouncing ideas back and forth and maybe
427
00:37:14,860 --> 00:37:17,640
working on some stuff.
Herald: A close contact with the Apple
428
00:37:17,640 --> 00:37:22,280
developers.
Littlelailo: No, not at all.
429
00:37:22,280 --> 00:37:25,870
Herald: More.
Littlelailo: I mean, I reported one bug to
430
00:37:25,870 --> 00:37:31,890
their bounty once or like actually says to
them that their bounty and that one got
431
00:37:31,890 --> 00:37:40,770
fixed and it was all fine. But yeah, for
now, I don't report bugs at the moment.
432
00:37:40,770 --> 00:37:44,020
Herald: If you have time, you've time left
now actually, you're looking for a new
433
00:37:44,020 --> 00:37:46,560
project doesn't it?
Littlelailo: Yeah. Yeah. And I might
434
00:37:46,560 --> 00:37:50,290
report some of those bugs in the meantime
but I mean with the presentation they know
435
00:37:50,290 --> 00:37:54,430
about them though so they might fix them.
Herald: They will be listening now and at
436
00:37:54,430 --> 00:37:57,220
least probably I hope.
Littlelailo: Yes.
437
00:37:57,220 --> 00:38:02,460
Herald: Is there anyone who has really,
you where sitting on a question here. None
438
00:38:02,460 --> 00:38:10,360
of you? It's already noon. You know, noon
passed, so could be that none of you. You
439
00:38:10,360 --> 00:38:15,260
can ask them something, maybe someone
asked them something, maybe they can help
440
00:38:15,260 --> 00:38:18,490
you out with certain challenges that are
there.
441
00:38:18,490 --> 00:38:23,660
Littlelailo: Well, I don't really have a
question either. Laughter I have my own
442
00:38:23,660 --> 00:38:29,760
research project now. Well, like, I do
stuff at the moment and look at other
443
00:38:29,760 --> 00:38:34,880
things. For example, to the bootrom
exploit came out now. And so I started
444
00:38:34,880 --> 00:38:40,600
developing on the chick team with them.
And that's what I currently do, basically.
445
00:38:40,600 --> 00:38:45,450
Herald: You're great, man. Littlelailo,
thank you. Giving him a warm applause!
446
00:38:45,450 --> 00:38:48,380
Applause
447
00:38:48,380 --> 00:38:51,936
36c3 Postroll music
448
00:38:51,936 --> 00:39:15,000
Subtitles created by c3subtitles.de
in the year 2020. Join, and help us!