1
00:00:00,000 --> 00:00:18,450
36C3 preroll music
2
00:00:18,450 --> 00:00:25,160
Herald Angel: On my left, I have Omer
Gull, and Omer Gull is gonna tell us - A
3
00:00:25,160 --> 00:00:33,092
SELECT code_execution FROM * USING SQLite.
Omer, Omer Gull, that's your talk, your stage, have fun!
4
00:00:33,092 --> 00:00:42,190
Omer Gull: Thank you. Thank you. Hello,
everyone. Welcome to my talk, SELECT code
5
00:00:42,190 --> 00:00:49,110
execution from just about anything using
SQLite, where we will gain code execution
6
00:00:49,110 --> 00:00:54,440
using malicious SQLite databases. So my
name is Omer Gull. I'm a vulnerability
7
00:00:54,440 --> 00:00:59,559
researcher from Tel Aviv. I've been
working in Check Point Research for the
8
00:00:59,559 --> 00:01:05,960
past three years, and I've recently moved
on to a new startup called Hunters.AI.
9
00:01:05,960 --> 00:01:11,409
Our agenda for today: So we'll start with a
little motivation and the backstory for
10
00:01:11,409 --> 00:01:18,139
this research. Then we'll have a brief
SQLite introduction, and we'll examine the
11
00:01:18,139 --> 00:01:22,759
attack surface given to a malicious
database. Then we will discuss some
12
00:01:22,759 --> 00:01:29,359
previous work done in the field of SQLite
exploitation and think about exploiting
13
00:01:29,359 --> 00:01:36,229
memory corruption bugs, using nothing but
pure SQL. We'll then demonstrate our own
14
00:01:36,229 --> 00:01:41,450
innovative technique, called "Query
Oriented Programing", or QOP, and take it
15
00:01:41,450 --> 00:01:47,929
for a spin in a couple of demos. We'll
wrap things up with some future work
16
00:01:47,929 --> 00:01:54,200
possibilities and some conclusion. So the
motivation for this research is quite
17
00:01:54,200 --> 00:02:00,649
obvious. SQLite is one of the most
deployed pieces of software out there.
18
00:02:00,649 --> 00:02:08,005
Whether it's PHP 5, PHP 7, Android, iOS,
Mac OS, it is now built into Windows 10.
19
00:02:08,005 --> 00:02:14,380
It's in Firefox and Chrome. This list
could continue forever. Yet querying an
20
00:02:14,380 --> 00:02:20,310
SQLite database is considered safe.
Hopefully, by the end of this talk, you
21
00:02:20,310 --> 00:02:27,290
will realize why this is not necessarily
the case. So, it all began with password
22
00:02:27,290 --> 00:02:32,020
stealers, which is pretty strange, and
there are many, many password stealers in
23
00:02:32,020 --> 00:02:37,680
the wild, but the story is usually the
same. First of all, a computer gets
24
00:02:37,680 --> 00:02:43,170
infected. Then some malware collects the
storage credentials, as they are
25
00:02:43,170 --> 00:02:48,510
maintained by various clients. Now, some
of these clients actually store your
26
00:02:48,510 --> 00:02:55,090
secrets within SQLite databases. So the
malware just ships these SQLite databases
27
00:02:55,090 --> 00:03:01,760
to its C2 server, where the secrets are
extracted and stored within a collective
28
00:03:01,760 --> 00:03:07,740
database with the rest of the loot. So,
one day, my colleague and I, Omri, we were
29
00:03:07,740 --> 00:03:13,210
looking at the leaked sources of a very
well known password stealers. Then we
30
00:03:13,210 --> 00:03:17,930
thought to ourself: "These guys are just
harvesting a bunch of our databases and
31
00:03:17,930 --> 00:03:24,700
parse them in their own backend. Can we
actually leverage the load and query of an
32
00:03:24,700 --> 00:03:30,360
untrusted database to our advantage?" And
if we could, this could have much bigger
33
00:03:30,360 --> 00:03:37,300
implications, just because SQLite is used
in countless scenarios. And so began the
34
00:03:37,300 --> 00:03:46,320
longest CTF challenge of my life so far.
So, SQLite. Unlike most SQL databases,
35
00:03:46,320 --> 00:03:52,740
SQLite does not have that client server
architecture. Instead, it simply reads and
36
00:03:52,740 --> 00:03:58,630
write files directly to the file system.
So, you have one complete database, with
37
00:03:58,630 --> 00:04:03,340
multiple tables, and indices, and
triggers, and views, and everything is
38
00:04:03,340 --> 00:04:09,660
contained within the single file. So let's
examine the attack surface given to a
39
00:04:09,660 --> 00:04:15,240
potentially malicious SQLite database. So
again, this is a snippet of code, of a
40
00:04:15,240 --> 00:04:21,400
very well known password stealer, and we
have two main points of interest here:
41
00:04:21,400 --> 00:04:26,430
First of all, we have sqlite3_open, where
our potentially malicious database is
42
00:04:26,430 --> 00:04:32,179
loaded, and some parsing is going on. And,
obviously, we have the query itself,
43
00:04:32,179 --> 00:04:36,950
right? The SELECT statement. Now, do note
that we have no control over that
44
00:04:36,950 --> 00:04:41,020
statement, right. It is hardcoded within
our target. It tries to extract the
45
00:04:41,020 --> 00:04:47,160
secrets out of our database. Yet we do
control the content, so we might have some
46
00:04:47,160 --> 00:04:52,319
effect on what's going on there, right.
So, starting with the first point, the
47
00:04:52,319 --> 00:04:58,099
sqlite3_open. This is just a bunch of
setup and configuration code. Then we move
48
00:04:58,099 --> 00:05:03,110
on to really straightforward header
parsing, and the header itself is not that
49
00:05:03,110 --> 00:05:10,420
long, just 100 bytes. And thirdly, it was
already fuzzed to death by AFL. So it's
50
00:05:10,420 --> 00:05:17,229
probably not a very promising path to
pursue. But the SEL- the sqlite3_query
51
00:05:17,229 --> 00:05:22,449
might be a bit more interesting, because
using SQLite author's words, "The SELECT
52
00:05:22,449 --> 00:05:29,160
statement is the most complicated command
in the SQL language". Now, you might be
53
00:05:29,160 --> 00:05:36,310
aware that behind the scenes, SQLite is a
virtual machine. So every query must first
54
00:05:36,310 --> 00:05:42,259
be compiled to some proprietary bytecode.
And this is also known as the preparation
55
00:05:42,259 --> 00:05:48,140
step. So sqlite3_prepare would walk and
expand the query. So, for example, every
56
00:05:48,140 --> 00:05:56,079
time you select an asterisk, it simply
rewrite this asterisk as all column names.
57
00:05:56,079 --> 00:06:02,059
So, sqlite3LocateTable will actually
verified that all the relevant objects
58
00:06:02,059 --> 00:06:07,289
that you are querying actually exist, and
will locate them in memory. Where does it
59
00:06:07,289 --> 00:06:13,589
locate them? So, every SQLite database has
a table called sqlite_master, and this is
60
00:06:13,589 --> 00:06:20,139
actually the schema that is defining the
database. And this is its structure. So,
61
00:06:20,139 --> 00:06:25,569
for every object in the database, you have
an entry, so its type, like whether it's a
62
00:06:25,569 --> 00:06:32,120
table or view, and its name, and at the
very bottom you can see something called
63
00:06:32,120 --> 00:06:40,569
SQL. And SQL is actually the DDL that is
describing the object. And DDL stands for
64
00:06:40,569 --> 00:06:46,509
data definition language, and you can sort
of look at it like header files in C. So,
65
00:06:46,509 --> 00:06:51,759
they are used to define the structures,
and names, and types of the objects within
66
00:06:51,759 --> 00:06:57,750
the database. Furthermore, they appear in
plaintext within the file. So, let me show
67
00:06:57,750 --> 00:07:02,949
you an example. Here I opened the SQLite
interpreter, I create a table, and I
68
00:07:02,949 --> 00:07:08,360
insert some values into it. Then I quit
the interpreter, and now I hex dump the
69
00:07:08,360 --> 00:07:15,169
file that was created. And you can see,
highlighted in yellow, the DDL statement
70
00:07:15,169 --> 00:07:20,044
that is part of the master schema. And at
the very bottom, you can also see the
71
00:07:20,044 --> 00:07:25,900
values. So, let's go back to query
preparation. We have sqlite3LocateTable
72
00:07:25,900 --> 00:07:31,110
that attempts to find the structure that
is describing the table that we are
73
00:07:31,110 --> 00:07:36,639
interested in querying. So it goes on and
reads the schema available in
74
00:07:36,639 --> 00:07:41,119
sqlite_master that we just described. And
if it's the first time that it is doing
75
00:07:41,119 --> 00:07:47,639
so, it has some callback function for
every of these DDL statements. The
76
00:07:47,639 --> 00:07:53,169
callback function would actually validate
the DDL, and then it will go on and build
77
00:07:53,169 --> 00:07:58,189
the internal structures of the object in
question. So then we thought about the
78
00:07:58,189 --> 00:08:06,219
concept of DDL patching. What if I simply
replace the SQL query within the DDL? So
79
00:08:06,219 --> 00:08:10,599
it turns out that there is a slight
problem with it. And this is the callback
80
00:08:10,599 --> 00:08:16,469
function that I mentioned earlier, and as
you can tell, the DDL is first verified to
81
00:08:16,469 --> 00:08:23,210
begin with "CREATE ". And only if it does
then we continue with the preparation. So,
82
00:08:23,210 --> 00:08:28,969
this is definitely a constraint, right?
Our DDL must begin with "CREATE ". Yet it
83
00:08:28,969 --> 00:08:35,030
does leave some room for flexibility,
because judging by SQLite documentation,
84
00:08:35,030 --> 00:08:40,740
many things can be created. We can create
indexes, and tables, and triggers, and
85
00:08:40,740 --> 00:08:46,560
views, and something we still don't quite
understand, called virtual tables. So,
86
00:08:46,560 --> 00:08:53,280
then we thought about "CREATE VIEW",
because view is simply a pre-packaged
87
00:08:53,280 --> 00:08:59,760
SELECT statement, and views are queried
very similarly to tables. So, selecting a
88
00:08:59,760 --> 00:09:04,836
column out of a table is semantically
equivalent to selecting a column out of a
89
00:09:04,836 --> 00:09:10,712
view. Then when we thought about the
concept of query hijacking. We are going
90
00:09:10,712 --> 00:09:16,700
to patch sqlite_master DDL with views
instead of tables. Now our patched views
91
00:09:16,700 --> 00:09:22,680
can actually have any SELECT subquery that
we wish. And now with this subquery I can
92
00:09:22,680 --> 00:09:26,640
suddenly interact with the SQLite
interpreter. And this is a huge step
93
00:09:26,640 --> 00:09:31,790
forward! We just turned an uncontrollable
query to something that we have some
94
00:09:31,790 --> 00:09:38,110
control over. So let me show you query
hijacking by example. So let's say that
95
00:09:38,110 --> 00:09:43,710
some original database had a single table,
and this is the DDL that is defining it.
96
00:09:43,710 --> 00:09:49,130
So it's called "dummy" and it has two
columns. So, obviously any target software
97
00:09:49,130 --> 00:09:53,390
would try to query it in the following
way: It would just try to select these
98
00:09:53,390 --> 00:09:58,314
columns out of the table, right. Yet the
following view can actually hijack this
99
00:09:58,314 --> 00:10:03,280
query. I create a view, it has just the
same name, and just the same amount of
100
00:10:03,280 --> 00:10:08,220
columns, and each column is named just the
same way, and you can see that now every
101
00:10:08,220 --> 00:10:13,800
column can have any sub query that I wish,
highlighted in blue at the bottom. So
102
00:10:13,800 --> 00:10:18,570
again, let me show you a practical example
of it. Here, I created a view called
103
00:10:18,570 --> 00:10:23,900
"dummy" with cola and colb, and the first
column is utilizing the sqlite_version()
104
00:10:23,900 --> 00:10:28,340
function, and that's a built in function
that simply returns the SQLite version,
105
00:10:28,340 --> 00:10:35,420
obviously. The second column is utilizing
SQLite's own implementation of printf.
106
00:10:35,420 --> 00:10:40,030
That's right, they have all these really
surprising features and capabilities. So,
107
00:10:40,030 --> 00:10:46,150
let's see that from the supposedly - from
the target side. So, anyone trying to
108
00:10:46,150 --> 00:10:51,890
select out of these column, is suddenly
executing our functions. So, at the left
109
00:10:51,890 --> 00:10:57,180
you can see the SQLite version, and on the
right you can see the printf that was
110
00:10:57,180 --> 00:11:02,120
executed on the target side. So again,
this is a huge step forward. We just
111
00:11:02,120 --> 00:11:08,760
gained some control over that query,
right. And the question is, what can we do
112
00:11:08,760 --> 00:11:15,440
with this control? Does SQLite have any
system commands? Can maybe - maybe we can
113
00:11:15,440 --> 00:11:23,360
read and write to some other files on the
file system. So, this was a good point to
114
00:11:23,360 --> 00:11:28,380
stop and look at some previous work done
in the field, because obviously, we are
115
00:11:28,380 --> 00:11:34,533
not the first to notice SQLite's huge
potential, in terms of exploitation. A
116
00:11:34,533 --> 00:11:39,171
reasonable place to start is SQLite
injection, because this is sort of a
117
00:11:39,171 --> 00:11:45,540
similar scenario, right? Someone malicious
has some control on an SQL query. So,
118
00:11:45,540 --> 00:11:51,550
there are a couple of known tricks in SQL
injection with SQLite. The first one has
119
00:11:51,550 --> 00:11:56,450
something to do with attaching another
database, and then creating a table, and
120
00:11:56,450 --> 00:12:01,390
inserting some strings into it. And
because, as I mentioned earlier, every -
121
00:12:01,390 --> 00:12:06,920
every database is just a file, so this is
somewhat of an arbitrary file, right, on
122
00:12:06,920 --> 00:12:11,490
the file system. Yet we do have this
constraint, if you remember, that we can't
123
00:12:11,490 --> 00:12:17,730
ATTACH, because our DDL must begin with
"CREATE". Another cool trick is abusing
124
00:12:17,730 --> 00:12:23,740
the load extension function. And here you
can see how you can potentially load a
125
00:12:23,740 --> 00:12:28,160
remote DLL. In this case, the
meterpreter.dll, but obviously this very
126
00:12:28,160 --> 00:12:35,104
dangerous function is disabled by default.
So again, no go. What about memory
127
00:12:35,104 --> 00:12:42,290
corruption in SQLite, because SQLite is
really complex and it's all written in C.
128
00:12:42,290 --> 00:12:48,200
So in his amazing blog post "Finding Bugs
in SQLite, the easy way", Michal Zalewski,
129
00:12:48,200 --> 00:12:54,870
the author of AFL, described how he found
22 bugs in just under 30 minutes of
130
00:12:54,870 --> 00:13:01,790
fuzzing. And actually, since then, since
that was version 3.8.10, that was in 2015,
131
00:13:01,790 --> 00:13:06,840
SQLite actually started using AFL as an
integral part of the remarkable test
132
00:13:06,840 --> 00:13:11,690
suite. Yet these memory corruption bugs
all proved to be really difficult to
133
00:13:11,690 --> 00:13:16,610
exploit without some convenient
environment. Yet, the security research
134
00:13:16,610 --> 00:13:25,300
community soon found the perfect target,
and it was called WebSQL. So, WebSQL is
135
00:13:25,300 --> 00:13:30,240
essentially an API for storing data in
databases, and it is queried from
136
00:13:30,240 --> 00:13:36,240
JavaScript and it has an SQLite backend.
Also, it is available in Chrome and
137
00:13:36,240 --> 00:13:41,990
Safari. So here you can see a very simple
example of how to interact with WebSQL
138
00:13:41,990 --> 00:13:51,100
from JavaScript. But in other words, what
I'm hearing here is that we have some
139
00:13:51,100 --> 00:13:56,240
untrusted input to SQLite and it is
reachable from any website on the Internet
140
00:13:56,240 --> 00:14:02,350
in two of the world's most popular
browsers. And suddenly these bugs, these
141
00:14:02,350 --> 00:14:07,040
memory corruptions can now be leveraged
with the knowledge and - with the
142
00:14:07,040 --> 00:14:10,762
knowledge and comfort of JavaScript
exploitation, right. The JavaScript
143
00:14:10,762 --> 00:14:16,200
interpreter exploitation that we got, we
got pretty good over the years. So there
144
00:14:16,200 --> 00:14:20,420
have been really several really impressive
research that were published regarding
145
00:14:20,420 --> 00:14:28,610
WebSQL from really low hanging fruits like
CVE-2015-7036, that was an untrusted
146
00:14:28,610 --> 00:14:35,190
pointer dereference in the fts3_tokenizer(),
to some more complex exploit as presented
147
00:14:35,190 --> 00:14:40,840
in Blackhat 2017 by the awesome Chaitin
team, that found a type confusion in the
148
00:14:40,840 --> 00:14:46,480
FTS optimizer, to the very recent Magellan
bugs found and exploited by Tencent, that
149
00:14:46,480 --> 00:14:52,350
found an integer overflow in the FTS
segment reader. And if you are paying even
150
00:14:52,350 --> 00:14:58,080
a tiny bit of attention by now, you must
see an interesting pattern arises. All
151
00:14:58,080 --> 00:15:04,760
these vulnerable functions start with FTS.
So what is FTS? I have never heard of it.
152
00:15:04,760 --> 00:15:11,580
And actually googling it just left me more
confused. After some time, I came to the
153
00:15:11,580 --> 00:15:17,560
realization that FTS stands for "full text
search", and it is something called a
154
00:15:17,560 --> 00:15:22,840
virtual table module and it allows for
some really cool textual search on a set
155
00:15:22,840 --> 00:15:28,260
of documents. Or like the SQLite authors
described it, It's "like Google for your
156
00:15:28,260 --> 00:15:33,700
SQlite databases". So virtual tables allow
for some pretty cool functionality in
157
00:15:33,700 --> 00:15:39,410
SQLite, whether it's this free text search
or a virtual table module called RTREE,
158
00:15:39,410 --> 00:15:44,750
that does some really clever geographical
indexing, or a virtual table called CSV,
159
00:15:44,750 --> 00:15:50,060
that lets you treat your database as a CSV
file. And these virtual tables are
160
00:15:50,060 --> 00:15:55,970
actually queried just like regular tables.
Yet behind the scenes, some dark magic
161
00:15:55,970 --> 00:16:02,350
happens. And after every query, there is
some callback function that is invoked and
162
00:16:02,350 --> 00:16:07,370
it works on something called shadow
tables. Now, shadow tables would be best
163
00:16:07,370 --> 00:16:13,800
explained by example. So let's say that I
create a virtual table using that FTS
164
00:16:13,800 --> 00:16:19,910
virtual table module and I insert a string
into it. Now, obviously, to allow for some
165
00:16:19,910 --> 00:16:23,980
efficient search, I need to have some
metadata, right? I need to have some
166
00:16:23,980 --> 00:16:28,650
offsets or indexes or tokens or stuff like
that. So - and obviously they're all text,
167
00:16:28,650 --> 00:16:35,310
right? So that one virtual table is
actually, it's raw text, and metadata is
168
00:16:35,310 --> 00:16:40,620
stored among three shadow tables. So the
raw text would go to vt_content and the
169
00:16:40,620 --> 00:16:46,050
metadata would go to vt_segments and
vt_segdir. And in time, these shadow
170
00:16:46,050 --> 00:16:51,740
tables actually have interfaces passing
information between them, right. Because
171
00:16:51,740 --> 00:16:55,680
the metadata is storing all these
pointers, so you need to pass them between
172
00:16:55,680 --> 00:17:01,500
each other. And these interfaces proved to
be really, really trusting in their
173
00:17:01,500 --> 00:17:09,589
nature. And it makes them a really fertile
ground for bug hunting. So let me show you
174
00:17:09,589 --> 00:17:15,819
a bug that I found in the RTREE virtual
table module. So, RTREE virtual table
175
00:17:15,819 --> 00:17:20,589
module is available now in MacOS and iOS,
and it's really cool because now it's also
176
00:17:20,589 --> 00:17:24,890
built into Windows 10. And as I've
mentioned, it does some really clever
177
00:17:24,890 --> 00:17:31,400
geographical indexing. Now, the DDL is
supposed to be the following. Any RTREE
178
00:17:31,400 --> 00:17:37,020
virtual table is supposed to begin with
"id", that needs to be an integer. Then
179
00:17:37,020 --> 00:17:41,970
you have some X and Y coordinates. So
obviously every RTREE interface would
180
00:17:41,970 --> 00:17:48,250
expect "id" to be an integer. But if I
create a virtual table and I insert into
181
00:17:48,250 --> 00:17:53,970
"id" something that is definitely not an
integer, then I use one of these RTREE
182
00:17:53,970 --> 00:17:59,560
interfaces, rtreenode at the very bottom,
you see that we got this crash, this out-
183
00:17:59,560 --> 00:18:08,590
of-bounds read on the heap. And this
example is a crash in Windows 10. So
184
00:18:08,590 --> 00:18:15,040
that's pretty good. We have established
that virtual table has bugs. And now,
185
00:18:15,040 --> 00:18:21,260
using query hijacking technique, we can
suddenly trigger these bugs on our target,
186
00:18:21,260 --> 00:18:26,435
which is a C2 of the password stealer, and
will cause it to segfault. And this is
187
00:18:26,435 --> 00:18:32,120
nice, but actually gaining flow control
over our target requires us to have some
188
00:18:32,120 --> 00:18:37,480
form of scripting, right? We want to
bypass ASLR and do all these crazy things.
189
00:18:37,480 --> 00:18:42,390
Yet we don't have JavaScript, we don't
have JavaScript arrays and variables and,
190
00:18:42,390 --> 00:18:48,320
like, logic statements, like if and and
loops and stuff like that. However, we do
191
00:18:48,320 --> 00:18:54,580
vaguely recall hearing somewhere that SQL
is turing complete. So we decided to put
192
00:18:54,580 --> 00:19:00,780
it to the test from exploitation
perspective, and we started creating our
193
00:19:00,780 --> 00:19:06,580
own primitive wish list for exploitation.
So if it would create a full exploit
194
00:19:06,580 --> 00:19:11,080
exploiting memory corruption bugs with
nothing but SQL, what capabilities do we
195
00:19:11,080 --> 00:19:16,160
want? So, obviously, to bypass ASLR and
these kind of things, we want to leak some
196
00:19:16,160 --> 00:19:21,040
memory. We need to have an info leak. And
if you've done any pwning in your past,
197
00:19:21,040 --> 00:19:27,190
you must be familiar with really common
tasks like unpacking 64-bit pointers and
198
00:19:27,190 --> 00:19:31,190
doing some pointer arithmetics, right?
Because we had an info leak, we converted
199
00:19:31,190 --> 00:19:35,700
- we read this pointer, and it's a little
endian and so we need to flip it, and now
200
00:19:35,700 --> 00:19:40,030
we want to calculate, let's say where's
the base of libsqlite so we can find some
201
00:19:40,030 --> 00:19:45,650
more functions maybe. So we need some
pointer arithmetics. Obviously, after
202
00:19:45,650 --> 00:19:50,720
reading pointers and manipulating them, we
want to pack them again and write them
203
00:19:50,720 --> 00:19:57,710
somewhere. Obviously, writing a single
pointer is never enough. We want to create
204
00:19:57,710 --> 00:20:03,140
fake objects in memory, like more complex
objects than this one pointer. And
205
00:20:03,140 --> 00:20:08,090
finally, we would like to heap spray
because this might be really useful. So,
206
00:20:08,090 --> 00:20:13,230
the question remains, can all this
exploitation be done with nothing but SQL?
207
00:20:13,230 --> 00:20:19,020
So, the answer is "yes, it is". And I
proudly present to you Query Oriented
208
00:20:19,020 --> 00:20:25,860
Programing, or QOP. And to demonstrate
QOP, we are going to exploit the unfixed
209
00:20:25,860 --> 00:20:37,360
CVE-2015-7036. And you might ask yourself
"What? How come a four year old bug is
210
00:20:37,360 --> 00:20:44,390
still unfixed?" And this is a great point
to our argument. This CVE was only ever
211
00:20:44,390 --> 00:20:50,450
considered dangerous in the context of
untrusted WebSQL. So it was mitigated
212
00:20:50,450 --> 00:20:55,210
accordingly, right. It is blacklisted
unless SQLite is compiled with is certain
213
00:20:55,210 --> 00:20:59,910
flag. So, obviously browsers are not
compiled with this flag anymore. But let
214
00:20:59,910 --> 00:21:04,740
me show you who is compiled with this
flag. So, we have PHP 5 and PHP 7, in
215
00:21:04,740 --> 00:21:09,340
charge on most of the Internet, and iOS
and MacOS and probably so many other
216
00:21:09,340 --> 00:21:15,260
targets that we just didn't have the time
to go over. So, let's explain this
217
00:21:15,260 --> 00:21:20,780
vulnerability a little bit. I've mentioned
that it's in the FTS tokenizer. So, a
218
00:21:20,780 --> 00:21:26,830
tokenizer is just a set of rules to
extract terms from documents or queries.
219
00:21:26,830 --> 00:21:32,679
And the default tokanizer, that is named
"simple", just split the strings by
220
00:21:32,679 --> 00:21:38,820
whitespaces. However, if you like, you can
register your own custom tokenizer. You
221
00:21:38,820 --> 00:21:43,890
can just pass a C function and you
actually register this custom tokenizer
222
00:21:43,890 --> 00:21:50,020
with the function fts3_tokenizer() in an
SQL query. This is a bit where it's all
223
00:21:50,020 --> 00:21:55,930
repeated slowly. You pass a row pointer
to a C function in an SQL query. This is
224
00:21:55,930 --> 00:22:01,390
absolutely insane. To be honest, after
studying this for quite a while, I still
225
00:22:01,390 --> 00:22:06,021
don't understand how to use this feature
outside of my exploit.
226
00:22:06,021 --> 00:22:15,654
audience laughing
clapping
227
00:22:15,654 --> 00:22:17,640
So fts3_tokenizer()
228
00:22:17,640 --> 00:22:22,800
is actually an overloaded function, and if
you call it with one argument that is the
229
00:22:22,800 --> 00:22:28,230
name of a tokenizer, you get back the
address of that tokenizer, and to make it
230
00:22:28,230 --> 00:22:34,760
a bit more human readable, or somewhat
human, we'll use the hex decoder. And you
231
00:22:34,760 --> 00:22:40,210
can now see that we actually got an info
leak to libsqlite3. Now, because it's
232
00:22:40,210 --> 00:22:43,390
little endian, so it's the other way
around, so we need to reverse it, but this
233
00:22:43,390 --> 00:22:48,230
is already pretty cool. If you call
fts3_tokenizer() with two arguments, the
234
00:22:48,230 --> 00:22:53,162
first one being a name of a tokenizer, and
the second one, again, is a row pointer,
235
00:22:53,162 --> 00:22:58,426
this is absolutely insane, you rewrite the
address of that tokenizer. So now,
236
00:22:58,426 --> 00:23:05,300
whenever someone will try to use a virtual
table, so it will instantiate our default
237
00:23:05,300 --> 00:23:10,870
tokenizer, right. It will crash and burn.
And this is pretty amazing. Let's have a
238
00:23:10,870 --> 00:23:17,110
short recap. So, we've established that
SQLite is a wonderful one-shot for many
239
00:23:17,110 --> 00:23:21,540
targets, right? It's absolutely
everywhere. And it is a complex machine
240
00:23:21,540 --> 00:23:26,720
that is written in C. Now, with query
hijacking, we can start triggering these
241
00:23:26,720 --> 00:23:32,640
bugs, and we aim to write a full exploit,
implementing all necessary primitives
242
00:23:32,640 --> 00:23:40,140
using SQL queries. Our exploitation game
plan is as follows: We will leak some
243
00:23:40,140 --> 00:23:45,990
pointers, and then we'll calculate some
function addresses. We'll then create a
244
00:23:45,990 --> 00:23:51,650
fake tokenizer object with some pointer to
system(). We will override the default
245
00:23:51,650 --> 00:23:57,770
tokenizer and trigger our malicious
tokenizer. Then something will happen, and
246
00:23:57,770 --> 00:24:02,690
obviously by the end of the process we
should be able to profit somehow, right?
247
00:24:02,690 --> 00:24:08,620
So, starting with memory leak, an info
leak to libsqlite. So, you already know
248
00:24:08,620 --> 00:24:13,299
how to do it, right? We've seen
fts3_tokenizer(), but we still have a tiny
249
00:24:13,299 --> 00:24:19,290
problem of the little-endian pointer. So
we need to flip it. Now, surely we can use
250
00:24:19,290 --> 00:24:24,600
the SUBSTR function and read this pointer
two characters at a time in a reverse
251
00:24:24,600 --> 00:24:30,180
fashion, and then simply concatenate
everything throughout the pointer. So, we
252
00:24:30,180 --> 00:24:35,420
get a SELECT query that looks the
following, but now we have our pointer.
253
00:24:35,420 --> 00:24:39,810
This is great. What about an info leak to
the heap? We want to know where the heap
254
00:24:39,810 --> 00:24:44,590
is located. So, to do that trick, I'm
going to do something pretty similar to
255
00:24:44,590 --> 00:24:49,480
the RTREE bug that we've found. So, again,
I'm going to confuse some shadow table
256
00:24:49,480 --> 00:24:57,740
interface. So, we created a virtual table
and inserted some values into it. And now
257
00:24:57,740 --> 00:25:02,190
we're about to confuse the match
interface. So, the match interface does
258
00:25:02,190 --> 00:25:06,960
many things, but behind the scenes, it
just finds - it serves the pointer in
259
00:25:06,960 --> 00:25:11,020
memory to where the text is located,
right. It's this metadata, cool things
260
00:25:11,020 --> 00:25:16,030
that virtual table has. So we're going to
confuse it, and instead of passing it to
261
00:25:16,030 --> 00:25:21,191
another virtual table interface, we'll
simply pass it to the hex decoder, so we
262
00:25:21,191 --> 00:25:25,670
will decode this raw pointer. And you can
see that, again in little-endian, but now
263
00:25:25,670 --> 00:25:32,799
we have a link to the heap. We can cross
that off the list. And before we go on to
264
00:25:32,799 --> 00:25:39,320
unpacking this pointer, we have a very
basic problem. How do we even save these
265
00:25:39,320 --> 00:25:44,620
things? Because unlike browser WebSQL, we
don't have JavaScript variables or arrays
266
00:25:44,620 --> 00:25:49,690
to use and then abuse them later, but we
need to create some complex logic, right?
267
00:25:49,690 --> 00:25:54,910
We need to calculate the function address
and create things in memory, but how can
268
00:25:54,910 --> 00:25:58,780
we do it? Obviously, with SQLite, when you
want to save some values, you need to have
269
00:25:58,780 --> 00:26:05,220
insert statements, but we can only create
tables and views and index and triggers.
270
00:26:05,220 --> 00:26:10,520
Then we thought about chaining this view
together to use them sort of like a
271
00:26:10,520 --> 00:26:16,370
pseudo-variable. So again, let me show you
an example. Here, I create a view, it's
272
00:26:16,370 --> 00:26:20,929
called "little-endian leak", right? And
again, I abuse the fts3_tokenizer()
273
00:26:20,929 --> 00:26:25,530
function. Now I create another view on top
of it, and this one is called "leak", and
274
00:26:25,530 --> 00:26:30,240
it's flipping it using the SUBSTR trick
that you know from before. But notice how
275
00:26:30,240 --> 00:26:34,360
I referred to the first view, I referred
to "little-endian leak". So again, I do it
276
00:26:34,360 --> 00:26:39,781
throughout the pointer, and eventually
what I have is a pseudo-variable that's
277
00:26:39,781 --> 00:26:46,710
called "leak". And when I select from it,
I get the expected result. So now we can
278
00:26:46,710 --> 00:26:51,059
really move forward. Now we can start
building some more complex things based on
279
00:26:51,059 --> 00:26:57,190
this logic. And now we can go to unpacking
the pointers. So, we want to calculate a
280
00:26:57,190 --> 00:27:02,610
base of an image, for example, or maybe
find the beginning of the heap. So first
281
00:27:02,610 --> 00:27:09,160
of all, we want to convert our pointers to
integers. So, again, we're going to start
282
00:27:09,160 --> 00:27:14,740
and read these pointers one character at a
time and in reverse fashion using SUBSTR.
283
00:27:14,740 --> 00:27:20,690
And to get the value of this hex
character, we're going to use INSTR, that
284
00:27:20,690 --> 00:27:26,110
is just like strchar, and using the
following string we'll get the value of
285
00:27:26,110 --> 00:27:31,450
the hex character. Now, because it is one-
based, you have on the right the minus
286
00:27:31,450 --> 00:27:39,970
one. Then I need to have some shifting,
like, dark magic, and then I go and just
287
00:27:39,970 --> 00:27:44,860
concatenate everything throughout the
pointer. So the result is this monster
288
00:27:44,860 --> 00:27:50,179
query. But eventually, when all of this is
done, I get an integer that is the
289
00:27:50,179 --> 00:27:56,880
unpacked version of our initial leak. So I
successfully unpacked this pointer and we
290
00:27:56,880 --> 00:28:02,169
now have integers at hand, so we can cross
that off the list as well. We know how to
291
00:28:02,169 --> 00:28:08,140
convert pointers to integers. Now, pointer
arithmetics, right, because we want to
292
00:28:08,140 --> 00:28:13,190
have the addresses of some functions in
memory and actually, with integer, this is
293
00:28:13,190 --> 00:28:19,059
super simple. All we need to do is use
some more sub-queries. So, on the left you
294
00:28:19,059 --> 00:28:22,490
can see that I'm referring to the, now,
pseudo-variables that we have, the
295
00:28:22,490 --> 00:28:28,760
unpacked leak, and on the right I can
either have, like, subtract a silly
296
00:28:28,760 --> 00:28:32,570
constant like I did here, or I can
actually use another pseudo-variable to
297
00:28:32,570 --> 00:28:39,870
make it a bit more dynamic, can make some
a bit more reliable. So, eventually, what
298
00:28:39,870 --> 00:28:47,490
I'm ending up with is the libsqlite base
in an integer form. So, we've read some
299
00:28:47,490 --> 00:28:53,990
pointers and we manipulated them. Now it's
a good time to write them back. And
300
00:28:53,990 --> 00:29:00,510
obviously we're all used to "char" being
the exact opposite of "hex". And you can
301
00:29:00,510 --> 00:29:05,700
see that it works fairly well on most of
the values, but bigger integers were
302
00:29:05,700 --> 00:29:10,980
actually translated to their two-byte
code-points. So this was a huge obstacle
303
00:29:10,980 --> 00:29:20,180
for us. So, after bashing our head against
the documentation for quite a while, we
304
00:29:20,180 --> 00:29:25,370
suddenly had the strangest epiphany. We
realized that our exploit is actually a
305
00:29:25,370 --> 00:29:30,650
database. And if I want any conversion to
take place, I can simply create, ahead of
306
00:29:30,650 --> 00:29:37,780
time, this key-value map and simply query
it to translate whatever value I want to
307
00:29:37,780 --> 00:29:43,530
another value with sub-queries. So this is
the python function that I've used and you
308
00:29:43,530 --> 00:29:48,490
can see that there's a very simple for
loop going from 0 to FF and just inserting
309
00:29:48,490 --> 00:29:54,520
values to a table called "hex_map" with
its key-map value. And now our conversions
310
00:29:54,520 --> 00:30:00,610
are using sub-queries. So again, let me
show you by example. You can see that I'm
311
00:30:00,610 --> 00:30:06,810
selecting "val" from hex map, this key-
value map, where "int" is equal to, and
312
00:30:06,810 --> 00:30:11,371
then I go and then doing some more like
shifting and modulo dark magic, but
313
00:30:11,371 --> 00:30:18,230
eventually, what I'm ending up with is a
packed version of our libsqlite base. Now
314
00:30:18,230 --> 00:30:22,450
it's, we have a packed little-endian
pointer, so we can cross that off the list
315
00:30:22,450 --> 00:30:30,001
as well. As I've mentioned, writing a
single pointer is definitely useful, but
316
00:30:30,001 --> 00:30:35,280
it's not enough. We want to be faking
complete objects, right? All the cool kids
317
00:30:35,280 --> 00:30:40,130
are doing it and it's a pretty powerful
primitive. And if you actually recall, we
318
00:30:40,130 --> 00:30:45,970
have to do it because fts3_tokenizer()
requires us to assign a tokenizer module.
319
00:30:45,970 --> 00:30:50,510
Now, what is a tokenizer module? How does
it look? So, this is the beginning of its
320
00:30:50,510 --> 00:30:54,740
structure and there is an "iVersion",
that's an integer at the beginning, we
321
00:30:54,740 --> 00:31:00,360
don't really care about it, but following
it are three function pointers. We have
322
00:31:00,360 --> 00:31:04,840
"xCreate", which is the constructor of the
tokenizer, and "xDestroy", which is the
323
00:31:04,840 --> 00:31:10,530
destructor. We need to have both of them
valid so we don't crash during our
324
00:31:10,530 --> 00:31:14,340
exploitation. The third function pointer
is really interesting, because this is
325
00:31:14,340 --> 00:31:18,360
what actually tokenizes the string. So we
have a function pointer that we are
326
00:31:18,360 --> 00:31:23,550
passing a controllable string into. This
would be a perfect place to put our system
327
00:31:23,550 --> 00:31:33,000
gadget, right. So by now, I've used a fair
share of my SQL knowledge, right. But I do
328
00:31:33,000 --> 00:31:37,919
have one more trick up my sleeve and
that's JOIN queries, right? Because I
329
00:31:37,919 --> 00:31:43,730
learned about it at a time in the past. So
we're now going to create a fake tokenizer
330
00:31:43,730 --> 00:31:48,169
view and we're going to concatenate a
bunch of "A"'s and then, using a JOIN
331
00:31:48,169 --> 00:31:53,320
query, we'll concatenate it with a pointer
to simple_create and a pointer to
332
00:31:53,320 --> 00:31:58,039
simple_destroy and then a bunch of "B"'s.
Now let's verify it from a low-level
333
00:31:58,039 --> 00:32:02,860
debugger and you can actually see that at
some place in memory, we have a bunch of
334
00:32:02,860 --> 00:32:06,990
"A"'s followed by a pointer to
simple_create, followed by a pointer to
335
00:32:06,990 --> 00:32:14,280
simple_destroy, and a bunch of "B"'s. So,
we're almost done. But we need one more
336
00:32:14,280 --> 00:32:20,200
primitive for this exploit. And this is
because we already have our malicious
337
00:32:20,200 --> 00:32:24,700
tokenizer, and we know where the heap is
located, but we are not quite sure where
338
00:32:24,700 --> 00:32:31,140
our tokenizer is. So this is a great time
for some heap spraying, right. And ideally
339
00:32:31,140 --> 00:32:36,660
this would be some repetitive form of our
fake object primitive. So we've thought
340
00:32:36,660 --> 00:32:45,360
about repeat, but sadly SQLite did not
implement it like mySQL. So, like anyone
341
00:32:45,360 --> 00:32:51,480
else, we went to Stack Overflow, and we
found this really elegant solution. So
342
00:32:51,480 --> 00:32:59,030
we're going to use the zeroblob function
that simply returns a blob of N zeros. And
343
00:32:59,030 --> 00:33:03,630
then we will replace each of that zeros
with our fake tokenizer. And we're going
344
00:33:03,630 --> 00:33:07,640
to do it ten thousand times, as you can
see above. Again, let's verifiy it with a
345
00:33:07,640 --> 00:33:12,620
debugger. So, you see a bunch of "A"'s and
it's kind of hard to see, because these
346
00:33:12,620 --> 00:33:17,049
are really bad colors, but we also got
perfect consistency, because these
347
00:33:17,049 --> 00:33:24,820
structures repeat themselves every 20 hex
bytes. So we created a pretty good heap
348
00:33:24,820 --> 00:33:30,631
spraying capabilities and we are done with
our exploitation primitive wish list, so
349
00:33:30,631 --> 00:33:37,710
we can go back to our initial target.
Again, this is the code snippet of a very
350
00:33:37,710 --> 00:33:43,200
well known password stealer. And at the
bottom, you can see that it's trying to
351
00:33:43,200 --> 00:33:49,090
SELECT to extract the secrets by selecting
a column called "BodyRich" from a table
352
00:33:49,090 --> 00:33:55,330
called "Notes". So, we're going to prepare
a little surprise for him, right? We're
353
00:33:55,330 --> 00:33:59,049
going to create a view that is called
"Notes". And it has three sub-queries in a
354
00:33:59,049 --> 00:34:04,289
column called "BodyRich". And each of
these sub-queries is actually a QOP chain
355
00:34:04,289 --> 00:34:09,020
on its own. So if you remember my
exploitation game plan, we're going to
356
00:34:09,020 --> 00:34:14,500
start with heap spray, and then we will
override the default tokenizer, and then
357
00:34:14,500 --> 00:34:19,179
we will trigger our malicious tokenizer.
And you might ask yourself, what is
358
00:34:19,179 --> 00:34:25,160
heap_spray? Obviously, heap_spray is a QOP
chain that utilizes our heap spraying
359
00:34:25,160 --> 00:34:33,109
capabilities, right. We are spraying ten
thousand instances of our fake tokenizer,
360
00:34:33,109 --> 00:34:37,690
that is a JOIN query of a bunch of "A"'s
and then some pointers like
361
00:34:37,690 --> 00:34:43,720
p64_simple_create. And the party goes on,
because p64_ simple_create is actually
362
00:34:43,720 --> 00:34:52,399
derived from u64_simple_create, right,
with our pointer-packing capabilities. And
363
00:34:52,399 --> 00:34:56,790
this is just turtles all the way down,
because you have u64_simple_create, that
364
00:34:56,790 --> 00:35:04,440
is derived from libsqlite_base plus some
constant. And this goes back to the
365
00:35:04,440 --> 00:35:09,620
unpacked leak version, right, minus some
constant. So again, we're using our
366
00:35:09,620 --> 00:35:16,410
pointer arithmetics capabilities. We can
continue with u64_leak being derived from
367
00:35:16,410 --> 00:35:23,470
the almost initial leak. And we'll wrap up
by showing how the leak is actually
368
00:35:23,470 --> 00:35:29,410
derived from the initial vulnerability
using fts3_tokenizer. And this was just
369
00:35:29,410 --> 00:35:35,040
one out of three QOP chains that we used
in this exploit. And by now, every time
370
00:35:35,040 --> 00:35:40,490
that I described this exploit, this is how
I must look. And to be honest, this is how
371
00:35:40,490 --> 00:35:44,660
I feel. But luckily for you guys, you
don't have to look and feel like me
372
00:35:44,660 --> 00:35:50,340
because we created QOP.py, and it is
available on Checkpoint Research GitHub.
373
00:35:50,340 --> 00:35:56,650
And suddenly these crazy long chains can
now be created with four easy lines of
374
00:35:56,650 --> 00:36:01,290
python. And it feels like pwntools if you're
familiar with it, so you can go ahead and
375
00:36:01,290 --> 00:36:08,640
play with it and not look crazy on stage.
So, we'll go to our first demo. We'll own
376
00:36:08,640 --> 00:36:15,740
a password stealer backend running the
latest PHP 7. So obviously that's a model
377
00:36:15,740 --> 00:36:20,480
that we created with the leaked sources
and you can see all the infected victims,
378
00:36:20,480 --> 00:36:30,340
right. Cool. Now we'll try to go to our
webshell, to p.php. Obviously it still
379
00:36:30,340 --> 00:36:35,770
does not exist, we get a 404. Moving to
the attacker's computer. So, we see that
380
00:36:35,770 --> 00:36:42,060
we have two scripts here. First, we're
going to use QOP.py, that will generate a
381
00:36:42,060 --> 00:36:47,700
malicious database. Let's see, the
database was created. Now we're going to
382
00:36:47,700 --> 00:36:52,609
emulate an infection. We're going to send
our malicious database to the C2 server as
383
00:36:52,609 --> 00:36:56,950
if we were infected by a password stealer.
And because this process takes a bit of
384
00:36:56,950 --> 00:37:01,490
time, we can look at all the cool DDL
statements, right. So you see that we
385
00:37:01,490 --> 00:37:06,619
started with some bin leak and heap leak
and then we unpacked them. And at the very
386
00:37:06,619 --> 00:37:10,800
bottom, you can see that our end gadget is
echoing the simplest webshell to p.php,
387
00:37:10,800 --> 00:37:19,310
right. And this is the same page that we
just tried to reach. So hopefully, yeah -
388
00:37:19,310 --> 00:37:27,140
great, it's done. Now we go back to the
password stealer backend. We go to p.php
389
00:37:27,140 --> 00:37:35,210
and we got 200. Now, let's execute some
code on it. whoami. www-data. And
390
00:37:35,210 --> 00:37:44,220
obviously we need to go for /etc/password.
Yay.
391
00:37:44,220 --> 00:37:55,410
applause
So, what just happened is that we've shown
392
00:37:55,410 --> 00:38:02,109
that, given just the query to our
malicious a database, we can execute code
393
00:38:02,109 --> 00:38:07,920
on the querying process. Now, given the
fact that SQLite is so popular, this
394
00:38:07,920 --> 00:38:13,320
really opens up the door to a wide range
of attacks. Let's explore another use case
395
00:38:13,320 --> 00:38:21,060
that is completely different. And our next
target is going to be iOS persistency. So,
396
00:38:21,060 --> 00:38:28,090
iOS uses SQLite extensively, and
persistency is really hard to achieve,
397
00:38:28,090 --> 00:38:34,570
because all executable files must be
signed. Yet, SQLite databases are not
398
00:38:34,570 --> 00:38:40,440
signed, right, they're data-only. There is
no need to sign them. And iOS and MacOS
399
00:38:40,440 --> 00:38:44,320
are both compiled with
ENABLE_FTS3_TOKENIZER. That's the
400
00:38:44,320 --> 00:38:50,770
dangerous compile-time flag. So, my plan
is to regain code execution after reboot
401
00:38:50,770 --> 00:38:56,599
by replacing an arbitrary SQLite DB. And
to do this, I'm going to target that
402
00:38:56,599 --> 00:39:02,810
contacts database, and its name is
"AddressBook.sqlite". So these are two
403
00:39:02,810 --> 00:39:09,080
tables in the original database. They have
no significant meaning, right. Just for
404
00:39:09,080 --> 00:39:15,050
example. And I'm going to create malicious
contacts DB, and I'm going to start with
405
00:39:15,050 --> 00:39:19,900
two malicious DDL statements that you're
already familiar by now. First of all,
406
00:39:19,900 --> 00:39:25,770
we'll override the default organizer
"simple" to a bunch of "A"'s. Then, our
407
00:39:25,770 --> 00:39:30,911
second DDL statement would actually
instantiate this malicious trigger, so it
408
00:39:30,911 --> 00:39:34,599
will actually crash the program, right,
because every time you create a virtual
409
00:39:34,599 --> 00:39:40,000
table module, someone is trying to go to
the constructor of the tokenizer. So then
410
00:39:40,000 --> 00:39:45,290
it will crash. Now, what I'm doing next is
I'm going to go over each and every of the
411
00:39:45,290 --> 00:39:51,100
original table and rewrite them using our
query hijacking technique, right. So,
412
00:39:51,100 --> 00:39:56,359
instead of the columns that it expected,
we are going to redirect the execution to
413
00:39:56,359 --> 00:40:00,160
the override statement and the crash
statement. So, we did it for one table, we
414
00:40:00,160 --> 00:40:07,710
also do it for the others. Now we reboot
and voila, we get the following CVE and
415
00:40:07,710 --> 00:40:12,200
secure boots was bypassed. And if you pay
close attention, this is really cool,
416
00:40:12,200 --> 00:40:19,420
because we see that the crash happened at
0x414141...49. And this is exactly what we
417
00:40:19,420 --> 00:40:24,470
expected to happen, right, because this is
where our constructor should be, at an
418
00:40:24,470 --> 00:40:30,930
offset of eight after the first integer of
the version. But actually, there is more.
419
00:40:30,930 --> 00:40:35,710
We get a bonus here. Because the contacts
DB is actually used by many, many
420
00:40:35,710 --> 00:40:41,020
different processes. So Contacts and
Facetime and Springboard and WhatsApp and
421
00:40:41,020 --> 00:40:47,040
Telegram and XPCProxy and so many others.
And a lot of these processes are way more
422
00:40:47,040 --> 00:40:51,300
privileged than others. And we've
established that we can now execute code
423
00:40:51,300 --> 00:40:56,560
on the process that queries our malicious
database. So we also got a privilege
424
00:40:56,560 --> 00:41:01,260
escalation in this process, right. And
this is really cool. And there's nothing
425
00:41:01,260 --> 00:41:06,000
special about the contacts database.
Actually, any shared database can be used.
426
00:41:06,000 --> 00:41:11,820
All we need is something to be writeable
by a weak user and then being queried by a
427
00:41:11,820 --> 00:41:16,970
stronger user, right. And obviously all
these techniques and bugs were reported to
428
00:41:16,970 --> 00:41:20,790
Apple and they're all fixed. And these are
the CVEs if you want to go and read about
429
00:41:20,790 --> 00:41:27,030
it later. Now, to wrap things up, if
you'll take anything away from this talk,
430
00:41:27,030 --> 00:41:33,723
I don't want it to be the crazy SQL
gymnastics or a bunch of CVE numbers. I
431
00:41:33,723 --> 00:41:38,770
want it to be the following. Querying it
database might not be safe, whether if
432
00:41:38,770 --> 00:41:44,660
it's across reboots or between users or
processes, querying a database might not
433
00:41:44,660 --> 00:41:50,810
be safe with query hijacking. And now,
with query hijacking and query oriented
434
00:41:50,810 --> 00:41:55,330
programing, these memory corruptions that
we can trigger can actually be reliably
435
00:41:55,330 --> 00:42:00,170
exploited with nothing but SQL. We don't
need JavaScript anymore. We don't need
436
00:42:00,170 --> 00:42:05,880
WebSQL. And we truly think that this is
just the tip of the iceberg. So far,
437
00:42:05,880 --> 00:42:11,570
SQLite, super popular, yet it was only
assessed from the very narrow lands of
438
00:42:11,570 --> 00:42:18,220
WebSQL, and as much as browser pwning is
exciting, SQLite has so much more
439
00:42:18,220 --> 00:42:24,590
potential. So we do have some thoughts
about possible future work with this.
440
00:42:24,590 --> 00:42:29,530
Obviously, something really cool to do
would be expanding our primitives to some
441
00:42:29,530 --> 00:42:35,608
stronger primitives, right. We want to
gain things like absolute read and write.
442
00:42:35,608 --> 00:42:43,510
And my sketchy POC exploit was pretty
silly because it had many constants in it,
443
00:42:43,510 --> 00:42:49,080
like you've seen, but actually if you used
the internal function of SQLite, like, if
444
00:42:49,080 --> 00:42:53,590
during the exploitation you use functions
like sqlite3_version(), you ask the
445
00:42:53,590 --> 00:42:57,560
interpreter, what version are you, what
compile options where you compiled with,
446
00:42:57,560 --> 00:43:03,530
you can dynamically build these QOP chains
as you go and actually target the specific
447
00:43:03,530 --> 00:43:08,280
target environment that you are
exploiting. Like, actually utilizing the
448
00:43:08,280 --> 00:43:12,090
fact that our exploit is a database, we
can create this really cool exploit
449
00:43:12,090 --> 00:43:17,100
polyglot, and we think that these
techniques can be used to privilege
450
00:43:17,100 --> 00:43:23,200
escalate so many situations, because the
developers never had it in mind that now,
451
00:43:23,200 --> 00:43:28,240
we can take any database that is writeable
by a weak user and queried by a strong
452
00:43:28,240 --> 00:43:36,020
user, and suddenly we can try to privilege
our escalation. Another cool thing to do
453
00:43:36,020 --> 00:43:40,330
would be to note that many of the
primitives that I've shown you are not
454
00:43:40,330 --> 00:43:44,710
exclusive to SQLite, right?
The pointer packing and unpacking and
455
00:43:44,710 --> 00:43:49,740
heap spraying, and all these things are
not exclusive to SQLite. So it would be
456
00:43:49,740 --> 00:43:53,580
really interesting to take these
primitives and see if we can go ahead and
457
00:43:53,580 --> 00:44:00,070
exploit other memory corruption bugs in
different database engines.
458
00:44:00,070 --> 00:44:02,421
Thank you very much.
459
00:44:02,421 --> 00:44:09,430
Applause
460
00:44:09,430 --> 00:44:13,543
Herald Angel: Omer Gull, thank you very
much. That gives us a lot of time for
461
00:44:13,543 --> 00:44:18,412
questions. So we do have three microphones
here in the hall: Number one, Number two and
462
00:44:18,412 --> 00:44:23,680
Number three, if you have questions,
please line up. Do we have some questions
463
00:44:23,680 --> 00:44:31,140
from the net already? No. All right. Then
we're gonna start with microphone number
464
00:44:31,140 --> 00:44:34,140
two.
Microphone two: Yeah. So the question is
465
00:44:34,140 --> 00:44:42,520
regarding the hijacking of the CREATE
something. So you mentioned that at the
466
00:44:42,520 --> 00:44:48,590
beginning of the research was assuming
that CREATE was the first order of
467
00:44:48,590 --> 00:44:54,720
checking and then a space following the
CREATE word and then it could create all
468
00:44:54,720 --> 00:44:59,880
of other things. Now, my question is, if
that was changed following your report,
469
00:44:59,880 --> 00:45:06,910
because this seems like a way to expose
larger attack surface then. Well, most of
470
00:45:06,910 --> 00:45:10,800
the other bugs. So I just wonder if they
changed. And I mean, what basically what
471
00:45:10,800 --> 00:45:14,190
was the mitigation if and if that was all
of it?
472
00:45:14,190 --> 00:45:18,280
Omer Gull: Yeah. So the escalate people,
we're really more concerned with specific
473
00:45:18,280 --> 00:45:23,359
bugs and not exploitation techniques. And
this is really sad because we all know
474
00:45:23,359 --> 00:45:27,270
that you can kill bugs, but exploitation
techniques is what sticks. So no, they
475
00:45:27,270 --> 00:45:34,390
didn't change this verification. And
actually this validation of create space
476
00:45:34,390 --> 00:45:38,740
was actually added not so long ago. Before
that, you can have any DDL statement
477
00:45:38,740 --> 00:45:42,550
that you want. So the situation is not
really good over there.
478
00:45:42,550 --> 00:45:46,331
Microphone two: Good for them and good
luck in the future. And that was the
479
00:45:46,331 --> 00:45:49,061
question.
Herald Angel: All right. We head over to
480
00:45:49,061 --> 00:45:52,250
microphone one, please.
Microphone one: Did you, maybe by
481
00:45:52,250 --> 00:45:56,339
accident, attack a server which was used
for password stealing stealing?
482
00:45:56,339 --> 00:46:00,223
Omer Gull: No, obviously, I would never do
that. I would never attack anyone. This is
483
00:46:00,223 --> 00:46:04,170
just in our lab on POC. Right.
Microphone one: Thank you.
484
00:46:04,170 --> 00:46:08,130
Omer Gull: Your passwords are safe with
the Stealers.
485
00:46:08,130 --> 00:46:09,820
laughter
486
00:46:09,820 --> 00:46:12,140
Herald Angel: Right. Nobody is queueing
anymore. Do we have questions from the
487
00:46:12,140 --> 00:46:16,130
net? Nothing over there. Well, here we go.
Omer Gull: Thank you.
488
00:46:16,130 --> 00:46:18,383
Herald Angel: Omer Gull, thank you very much.
489
00:46:18,383 --> 00:46:20,786
applause
490
00:46:20,786 --> 00:46:24,982
36c3 outro music
491
00:46:24,982 --> 00:46:47,000
subtitles created by c3subtitles.de
in the year 2019. Join, and help us!