WEBVTT
00:00:00.000 --> 00:00:18.450
36C3 preroll music
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
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!
00:00:33.092 --> 00:00:42.190
Omer Gull: Thank you. Thank you. Hello,
everyone. Welcome to my talk, SELECT code
00:00:42.190 --> 00:00:49.110
execution from just about anything using
SQLite, where we will gain code execution
00:00:49.110 --> 00:00:54.440
using malicious SQLite databases. So my
name is Omer Gull. I'm a vulnerability
00:00:54.440 --> 00:00:59.559
researcher from Tel Aviv. I've been
working in Check Point Research for the
00:00:59.559 --> 00:01:05.960
past three years, and I've recently moved
on to a new startup called Hunters.AI.
00:01:05.960 --> 00:01:11.409
Our agenda for today: So we'll start with a
little motivation and the backstory for
00:01:11.409 --> 00:01:18.139
this research. Then we'll have a brief
SQLite introduction, and we'll examine the
00:01:18.139 --> 00:01:22.759
attack surface given to a malicious
database. Then we will discuss some
00:01:22.759 --> 00:01:29.359
previous work done in the field of SQLite
exploitation and think about exploiting
00:01:29.359 --> 00:01:36.229
memory corruption bugs, using nothing but
pure SQL. We'll then demonstrate our own
00:01:36.229 --> 00:01:41.450
innovative technique, called "Query
Oriented Programing", or QOP, and take it
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
00:01:47.929 --> 00:01:54.200
possibilities and some conclusion. So the
motivation for this research is quite
00:01:54.200 --> 00:02:00.649
obvious. SQLite is one of the most
deployed pieces of software out there.
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.
00:02:08.005 --> 00:02:14.380
It's in Firefox and Chrome. This list
could continue forever. Yet querying an
00:02:14.380 --> 00:02:20.310
SQLite database is considered safe.
Hopefully, by the end of this talk, you
00:02:20.310 --> 00:02:27.290
will realize why this is not necessarily
the case. So, it all began with password
00:02:27.290 --> 00:02:32.020
stealers, which is pretty strange, and
there are many, many password stealers in
00:02:32.020 --> 00:02:37.680
the wild, but the story is usually the
same. First of all, a computer gets
00:02:37.680 --> 00:02:43.170
infected. Then some malware collects the
storage credentials, as they are
00:02:43.170 --> 00:02:48.510
maintained by various clients. Now, some
of these clients actually store your
00:02:48.510 --> 00:02:55.090
secrets within SQLite databases. So the
malware just ships these SQLite databases
00:02:55.090 --> 00:03:01.760
to its C2 server, where the secrets are
extracted and stored within a collective
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
00:03:07.740 --> 00:03:13.210
looking at the leaked sources of a very
well known password stealers. Then we
00:03:13.210 --> 00:03:17.930
thought to ourself: "These guys are just
harvesting a bunch of our databases and
00:03:17.930 --> 00:03:24.700
parse them in their own backend. Can we
actually leverage the load and query of an
00:03:24.700 --> 00:03:30.360
untrusted database to our advantage?" And
if we could, this could have much bigger
00:03:30.360 --> 00:03:37.300
implications, just because SQLite is used
in countless scenarios. And so began the
00:03:37.300 --> 00:03:46.320
longest CTF challenge of my life so far.
So, SQLite. Unlike most SQL databases,
00:03:46.320 --> 00:03:52.740
SQLite does not have that client server
architecture. Instead, it simply reads and
00:03:52.740 --> 00:03:58.630
write files directly to the file system.
So, you have one complete database, with
00:03:58.630 --> 00:04:03.340
multiple tables, and indices, and
triggers, and views, and everything is
00:04:03.340 --> 00:04:09.660
contained within the single file. So let's
examine the attack surface given to a
00:04:09.660 --> 00:04:15.240
potentially malicious SQLite database. So
again, this is a snippet of code, of a
00:04:15.240 --> 00:04:21.400
very well known password stealer, and we
have two main points of interest here:
00:04:21.400 --> 00:04:26.430
First of all, we have sqlite3_open, where
our potentially malicious database is
00:04:26.430 --> 00:04:32.179
loaded, and some parsing is going on. And,
obviously, we have the query itself,
00:04:32.179 --> 00:04:36.950
right? The SELECT statement. Now, do note
that we have no control over that
00:04:36.950 --> 00:04:41.020
statement, right. It is hardcoded within
our target. It tries to extract the
00:04:41.020 --> 00:04:47.160
secrets out of our database. Yet we do
control the content, so we might have some
00:04:47.160 --> 00:04:52.319
effect on what's going on there, right.
So, starting with the first point, the
00:04:52.319 --> 00:04:58.099
sqlite3_open. This is just a bunch of
setup and configuration code. Then we move
00:04:58.099 --> 00:05:03.110
on to really straightforward header
parsing, and the header itself is not that
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
00:05:10.420 --> 00:05:17.229
probably not a very promising path to
pursue. But the SEL- the sqlite3_query
00:05:17.229 --> 00:05:22.449
might be a bit more interesting, because
using SQLite author's words, "The SELECT
00:05:22.449 --> 00:05:29.160
statement is the most complicated command
in the SQL language". Now, you might be
00:05:29.160 --> 00:05:36.310
aware that behind the scenes, SQLite is a
virtual machine. So every query must first
00:05:36.310 --> 00:05:42.259
be compiled to some proprietary bytecode.
And this is also known as the preparation
00:05:42.259 --> 00:05:48.140
step. So sqlite3_prepare would walk and
expand the query. So, for example, every
00:05:48.140 --> 00:05:56.079
time you select an asterisk, it simply
rewrite this asterisk as all column names.
00:05:56.079 --> 00:06:02.059
So, sqlite3LocateTable will actually
verified that all the relevant objects
00:06:02.059 --> 00:06:07.289
that you are querying actually exist, and
will locate them in memory. Where does it
00:06:07.289 --> 00:06:13.589
locate them? So, every SQLite database has
a table called sqlite_master, and this is
00:06:13.589 --> 00:06:20.139
actually the schema that is defining the
database. And this is its structure. So,
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
00:06:25.569 --> 00:06:32.120
table or view, and its name, and at the
very bottom you can see something called
00:06:32.120 --> 00:06:40.569
SQL. And SQL is actually the DDL that is
describing the object. And DDL stands for
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,
00:06:46.509 --> 00:06:51.759
they are used to define the structures,
and names, and types of the objects within
00:06:51.759 --> 00:06:57.750
the database. Furthermore, they appear in
plaintext within the file. So, let me show
00:06:57.750 --> 00:07:02.949
you an example. Here I opened the SQLite
interpreter, I create a table, and I
00:07:02.949 --> 00:07:08.360
insert some values into it. Then I quit
the interpreter, and now I hex dump the
00:07:08.360 --> 00:07:15.169
file that was created. And you can see,
highlighted in yellow, the DDL statement
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
00:07:20.044 --> 00:07:25.900
values. So, let's go back to query
preparation. We have sqlite3LocateTable
00:07:25.900 --> 00:07:31.110
that attempts to find the structure that
is describing the table that we are
00:07:31.110 --> 00:07:36.639
interested in querying. So it goes on and
reads the schema available in
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
00:07:41.119 --> 00:07:47.639
so, it has some callback function for
every of these DDL statements. The
00:07:47.639 --> 00:07:53.169
callback function would actually validate
the DDL, and then it will go on and build
00:07:53.169 --> 00:07:58.189
the internal structures of the object in
question. So then we thought about the
00:07:58.189 --> 00:08:06.219
concept of DDL patching. What if I simply
replace the SQL query within the DDL? So
00:08:06.219 --> 00:08:10.599
it turns out that there is a slight
problem with it. And this is the callback
00:08:10.599 --> 00:08:16.469
function that I mentioned earlier, and as
you can tell, the DDL is first verified to
00:08:16.469 --> 00:08:23.210
begin with "CREATE ". And only if it does
then we continue with the preparation. So,
00:08:23.210 --> 00:08:28.969
this is definitely a constraint, right?
Our DDL must begin with "CREATE ". Yet it
00:08:28.969 --> 00:08:35.030
does leave some room for flexibility,
because judging by SQLite documentation,
00:08:35.030 --> 00:08:40.740
many things can be created. We can create
indexes, and tables, and triggers, and
00:08:40.740 --> 00:08:46.560
views, and something we still don't quite
understand, called virtual tables. So,
00:08:46.560 --> 00:08:53.280
then we thought about "CREATE VIEW",
because view is simply a pre-packaged
00:08:53.280 --> 00:08:59.760
SELECT statement, and views are queried
very similarly to tables. So, selecting a
00:08:59.760 --> 00:09:04.836
column out of a table is semantically
equivalent to selecting a column out of a
00:09:04.836 --> 00:09:10.712
view. Then when we thought about the
concept of query hijacking. We are going
00:09:10.712 --> 00:09:16.700
to patch sqlite_master DDL with views
instead of tables. Now our patched views
00:09:16.700 --> 00:09:22.680
can actually have any SELECT subquery that
we wish. And now with this subquery I can
00:09:22.680 --> 00:09:26.640
suddenly interact with the SQLite
interpreter. And this is a huge step
00:09:26.640 --> 00:09:31.790
forward! We just turned an uncontrollable
query to something that we have some
00:09:31.790 --> 00:09:38.110
control over. So let me show you query
hijacking by example. So let's say that
00:09:38.110 --> 00:09:43.710
some original database had a single table,
and this is the DDL that is defining it.
00:09:43.710 --> 00:09:49.130
So it's called "dummy" and it has two
columns. So, obviously any target software
00:09:49.130 --> 00:09:53.390
would try to query it in the following
way: It would just try to select these
00:09:53.390 --> 00:09:58.314
columns out of the table, right. Yet the
following view can actually hijack this
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
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
00:10:08.220 --> 00:10:13.800
column can have any sub query that I wish,
highlighted in blue at the bottom. So
00:10:13.800 --> 00:10:18.570
again, let me show you a practical example
of it. Here, I created a view called
00:10:18.570 --> 00:10:23.900
"dummy" with cola and colb, and the first
column is utilizing the sqlite_version()
00:10:23.900 --> 00:10:28.340
function, and that's a built in function
that simply returns the SQLite version,
00:10:28.340 --> 00:10:35.420
obviously. The second column is utilizing
SQLite's own implementation of printf.
00:10:35.420 --> 00:10:40.030
That's right, they have all these really
surprising features and capabilities. So,
00:10:40.030 --> 00:10:46.150
let's see that from the supposedly - from
the target side. So, anyone trying to
00:10:46.150 --> 00:10:51.890
select out of these column, is suddenly
executing our functions. So, at the left
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
00:10:57.180 --> 00:11:02.120
executed on the target side. So again,
this is a huge step forward. We just
00:11:02.120 --> 00:11:08.760
gained some control over that query,
right. And the question is, what can we do
00:11:08.760 --> 00:11:15.440
with this control? Does SQLite have any
system commands? Can maybe - maybe we can
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
00:11:23.360 --> 00:11:28.380
stop and look at some previous work done
in the field, because obviously, we are
00:11:28.380 --> 00:11:34.533
not the first to notice SQLite's huge
potential, in terms of exploitation. A
00:11:34.533 --> 00:11:39.171
reasonable place to start is SQLite
injection, because this is sort of a
00:11:39.171 --> 00:11:45.540
similar scenario, right? Someone malicious
has some control on an SQL query. So,
00:11:45.540 --> 00:11:51.550
there are a couple of known tricks in SQL
injection with SQLite. The first one has
00:11:51.550 --> 00:11:56.450
something to do with attaching another
database, and then creating a table, and
00:11:56.450 --> 00:12:01.390
inserting some strings into it. And
because, as I mentioned earlier, every -
00:12:01.390 --> 00:12:06.920
every database is just a file, so this is
somewhat of an arbitrary file, right, on
00:12:06.920 --> 00:12:11.490
the file system. Yet we do have this
constraint, if you remember, that we can't
00:12:11.490 --> 00:12:17.730
ATTACH, because our DDL must begin with
"CREATE". Another cool trick is abusing
00:12:17.730 --> 00:12:23.740
the load extension function. And here you
can see how you can potentially load a
00:12:23.740 --> 00:12:28.160
remote DLL. In this case, the
meterpreter.dll, but obviously this very
00:12:28.160 --> 00:12:35.104
dangerous function is disabled by default.
So again, no go. What about memory
00:12:35.104 --> 00:12:42.290
corruption in SQLite, because SQLite is
really complex and it's all written in C.
00:12:42.290 --> 00:12:48.200
So in his amazing blog post "Finding Bugs
in SQLite, the easy way", Michal Zalewski,
00:12:48.200 --> 00:12:54.870
the author of AFL, described how he found
22 bugs in just under 30 minutes of
00:12:54.870 --> 00:13:01.790
fuzzing. And actually, since then, since
that was version 3.8.10, that was in 2015,
00:13:01.790 --> 00:13:06.840
SQLite actually started using AFL as an
integral part of the remarkable test
00:13:06.840 --> 00:13:11.690
suite. Yet these memory corruption bugs
all proved to be really difficult to
00:13:11.690 --> 00:13:16.610
exploit without some convenient
environment. Yet, the security research
00:13:16.610 --> 00:13:25.300
community soon found the perfect target,
and it was called WebSQL. So, WebSQL is
00:13:25.300 --> 00:13:30.240
essentially an API for storing data in
databases, and it is queried from
00:13:30.240 --> 00:13:36.240
JavaScript and it has an SQLite backend.
Also, it is available in Chrome and
00:13:36.240 --> 00:13:41.990
Safari. So here you can see a very simple
example of how to interact with WebSQL
00:13:41.990 --> 00:13:51.100
from JavaScript. But in other words, what
I'm hearing here is that we have some
00:13:51.100 --> 00:13:56.240
untrusted input to SQLite and it is
reachable from any website on the Internet
00:13:56.240 --> 00:14:02.350
in two of the world's most popular
browsers. And suddenly these bugs, these
00:14:02.350 --> 00:14:07.040
memory corruptions can now be leveraged
with the knowledge and - with the
00:14:07.040 --> 00:14:10.762
knowledge and comfort of JavaScript
exploitation, right. The JavaScript
00:14:10.762 --> 00:14:16.200
interpreter exploitation that we got, we
got pretty good over the years. So there
00:14:16.200 --> 00:14:20.420
have been really several really impressive
research that were published regarding
00:14:20.420 --> 00:14:28.610
WebSQL from really low hanging fruits like
CVE-2015-7036, that was an untrusted
00:14:28.610 --> 00:14:35.190
pointer dereference in the fts3_tokenizer(),
to some more complex exploit as presented
00:14:35.190 --> 00:14:40.840
in Blackhat 2017 by the awesome Chaitin
team, that found a type confusion in the
00:14:40.840 --> 00:14:46.480
FTS optimizer, to the very recent Magellan
bugs found and exploited by Tencent, that
00:14:46.480 --> 00:14:52.350
found an integer overflow in the FTS
segment reader. And if you are paying even
00:14:52.350 --> 00:14:58.080
a tiny bit of attention by now, you must
see an interesting pattern arises. All
00:14:58.080 --> 00:15:04.760
these vulnerable functions start with FTS.
So what is FTS? I have never heard of it.
00:15:04.760 --> 00:15:11.580
And actually googling it just left me more
confused. After some time, I came to the
00:15:11.580 --> 00:15:17.560
realization that FTS stands for "full text
search", and it is something called a
00:15:17.560 --> 00:15:22.840
virtual table module and it allows for
some really cool textual search on a set
00:15:22.840 --> 00:15:28.260
of documents. Or like the SQLite authors
described it, It's "like Google for your
00:15:28.260 --> 00:15:33.700
SQlite databases". So virtual tables allow
for some pretty cool functionality in
00:15:33.700 --> 00:15:39.410
SQLite, whether it's this free text search
or a virtual table module called RTREE,
00:15:39.410 --> 00:15:44.750
that does some really clever geographical
indexing, or a virtual table called CSV,
00:15:44.750 --> 00:15:50.060
that lets you treat your database as a CSV
file. And these virtual tables are
00:15:50.060 --> 00:15:55.970
actually queried just like regular tables.
Yet behind the scenes, some dark magic
00:15:55.970 --> 00:16:02.350
happens. And after every query, there is
some callback function that is invoked and
00:16:02.350 --> 00:16:07.370
it works on something called shadow
tables. Now, shadow tables would be best
00:16:07.370 --> 00:16:13.800
explained by example. So let's say that I
create a virtual table using that FTS
00:16:13.800 --> 00:16:19.910
virtual table module and I insert a string
into it. Now, obviously, to allow for some
00:16:19.910 --> 00:16:23.980
efficient search, I need to have some
metadata, right? I need to have some
00:16:23.980 --> 00:16:28.650
offsets or indexes or tokens or stuff like
that. So - and obviously they're all text,
00:16:28.650 --> 00:16:35.310
right? So that one virtual table is
actually, it's raw text, and metadata is
00:16:35.310 --> 00:16:40.620
stored among three shadow tables. So the
raw text would go to vt_content and the
00:16:40.620 --> 00:16:46.050
metadata would go to vt_segments and
vt_segdir. And in time, these shadow
00:16:46.050 --> 00:16:51.740
tables actually have interfaces passing
information between them, right. Because
00:16:51.740 --> 00:16:55.680
the metadata is storing all these
pointers, so you need to pass them between
00:16:55.680 --> 00:17:01.500
each other. And these interfaces proved to
be really, really trusting in their
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
00:17:09.589 --> 00:17:15.819
a bug that I found in the RTREE virtual
table module. So, RTREE virtual table
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
00:17:20.589 --> 00:17:24.890
built into Windows 10. And as I've
mentioned, it does some really clever
00:17:24.890 --> 00:17:31.400
geographical indexing. Now, the DDL is
supposed to be the following. Any RTREE
00:17:31.400 --> 00:17:37.020
virtual table is supposed to begin with
"id", that needs to be an integer. Then
00:17:37.020 --> 00:17:41.970
you have some X and Y coordinates. So
obviously every RTREE interface would
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
00:17:48.250 --> 00:17:53.970
"id" something that is definitely not an
integer, then I use one of these RTREE
00:17:53.970 --> 00:17:59.560
interfaces, rtreenode at the very bottom,
you see that we got this crash, this out-
00:17:59.560 --> 00:18:08.590
of-bounds read on the heap. And this
example is a crash in Windows 10. So
00:18:08.590 --> 00:18:15.040
that's pretty good. We have established
that virtual table has bugs. And now,
00:18:15.040 --> 00:18:21.260
using query hijacking technique, we can
suddenly trigger these bugs on our target,
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
00:18:26.435 --> 00:18:32.120
nice, but actually gaining flow control
over our target requires us to have some
00:18:32.120 --> 00:18:37.480
form of scripting, right? We want to
bypass ASLR and do all these crazy things.
00:18:37.480 --> 00:18:42.390
Yet we don't have JavaScript, we don't
have JavaScript arrays and variables and,
00:18:42.390 --> 00:18:48.320
like, logic statements, like if and and
loops and stuff like that. However, we do
00:18:48.320 --> 00:18:54.580
vaguely recall hearing somewhere that SQL
is turing complete. So we decided to put
00:18:54.580 --> 00:19:00.780
it to the test from exploitation
perspective, and we started creating our
00:19:00.780 --> 00:19:06.580
own primitive wish list for exploitation.
So if it would create a full exploit
00:19:06.580 --> 00:19:11.080
exploiting memory corruption bugs with
nothing but SQL, what capabilities do we
00:19:11.080 --> 00:19:16.160
want? So, obviously, to bypass ASLR and
these kind of things, we want to leak some
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,
00:19:21.040 --> 00:19:27.190
you must be familiar with really common
tasks like unpacking 64-bit pointers and
00:19:27.190 --> 00:19:31.190
doing some pointer arithmetics, right?
Because we had an info leak, we converted
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
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
00:19:40.030 --> 00:19:45.650
more functions maybe. So we need some
pointer arithmetics. Obviously, after
00:19:45.650 --> 00:19:50.720
reading pointers and manipulating them, we
want to pack them again and write them
00:19:50.720 --> 00:19:57.710
somewhere. Obviously, writing a single
pointer is never enough. We want to create
00:19:57.710 --> 00:20:03.140
fake objects in memory, like more complex
objects than this one pointer. And
00:20:03.140 --> 00:20:08.090
finally, we would like to heap spray
because this might be really useful. So,
00:20:08.090 --> 00:20:13.230
the question remains, can all this
exploitation be done with nothing but SQL?
00:20:13.230 --> 00:20:19.020
So, the answer is "yes, it is". And I
proudly present to you Query Oriented
00:20:19.020 --> 00:20:25.860
Programing, or QOP. And to demonstrate
QOP, we are going to exploit the unfixed
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
00:20:37.360 --> 00:20:44.390
still unfixed?" And this is a great point
to our argument. This CVE was only ever
00:20:44.390 --> 00:20:50.450
considered dangerous in the context of
untrusted WebSQL. So it was mitigated
00:20:50.450 --> 00:20:55.210
accordingly, right. It is blacklisted
unless SQLite is compiled with is certain
00:20:55.210 --> 00:20:59.910
flag. So, obviously browsers are not
compiled with this flag anymore. But let
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
00:21:04.740 --> 00:21:09.340
charge on most of the Internet, and iOS
and MacOS and probably so many other
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
00:21:15.260 --> 00:21:20.780
vulnerability a little bit. I've mentioned
that it's in the FTS tokenizer. So, a
00:21:20.780 --> 00:21:26.830
tokenizer is just a set of rules to
extract terms from documents or queries.
00:21:26.830 --> 00:21:32.679
And the default tokanizer, that is named
"simple", just split the strings by
00:21:32.679 --> 00:21:38.820
whitespaces. However, if you like, you can
register your own custom tokenizer. You
00:21:38.820 --> 00:21:43.890
can just pass a C function and you
actually register this custom tokenizer
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
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
00:21:55.930 --> 00:22:01.390
absolutely insane. To be honest, after
studying this for quite a while, I still
00:22:01.390 --> 00:22:06.021
don't understand how to use this feature
outside of my exploit.
00:22:06.021 --> 00:22:15.654
audience laughing
clapping
00:22:15.654 --> 00:22:17.640
So fts3_tokenizer()
00:22:17.640 --> 00:22:22.800
is actually an overloaded function, and if
you call it with one argument that is the
00:22:22.800 --> 00:22:28.230
name of a tokenizer, you get back the
address of that tokenizer, and to make it
00:22:28.230 --> 00:22:34.760
a bit more human readable, or somewhat
human, we'll use the hex decoder. And you
00:22:34.760 --> 00:22:40.210
can now see that we actually got an info
leak to libsqlite3. Now, because it's
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
00:22:43.390 --> 00:22:48.230
is already pretty cool. If you call
fts3_tokenizer() with two arguments, the
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,
00:22:53.162 --> 00:22:58.426
this is absolutely insane, you rewrite the
address of that tokenizer. So now,
00:22:58.426 --> 00:23:05.300
whenever someone will try to use a virtual
table, so it will instantiate our default
00:23:05.300 --> 00:23:10.870
tokenizer, right. It will crash and burn.
And this is pretty amazing. Let's have a
00:23:10.870 --> 00:23:17.110
short recap. So, we've established that
SQLite is a wonderful one-shot for many
00:23:17.110 --> 00:23:21.540
targets, right? It's absolutely
everywhere. And it is a complex machine
00:23:21.540 --> 00:23:26.720
that is written in C. Now, with query
hijacking, we can start triggering these
00:23:26.720 --> 00:23:32.640
bugs, and we aim to write a full exploit,
implementing all necessary primitives
00:23:32.640 --> 00:23:40.140
using SQL queries. Our exploitation game
plan is as follows: We will leak some
00:23:40.140 --> 00:23:45.990
pointers, and then we'll calculate some
function addresses. We'll then create a
00:23:45.990 --> 00:23:51.650
fake tokenizer object with some pointer to
system(). We will override the default
00:23:51.650 --> 00:23:57.770
tokenizer and trigger our malicious
tokenizer. Then something will happen, and
00:23:57.770 --> 00:24:02.690
obviously by the end of the process we
should be able to profit somehow, right?
00:24:02.690 --> 00:24:08.620
So, starting with memory leak, an info
leak to libsqlite. So, you already know
00:24:08.620 --> 00:24:13.299
how to do it, right? We've seen
fts3_tokenizer(), but we still have a tiny
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
00:24:19.290 --> 00:24:24.600
the SUBSTR function and read this pointer
two characters at a time in a reverse
00:24:24.600 --> 00:24:30.180
fashion, and then simply concatenate
everything throughout the pointer. So, we
00:24:30.180 --> 00:24:35.420
get a SELECT query that looks the
following, but now we have our pointer.
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
00:24:39.810 --> 00:24:44.590
is located. So, to do that trick, I'm
going to do something pretty similar to
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
00:24:49.480 --> 00:24:57.740
interface. So, we created a virtual table
and inserted some values into it. And now
00:24:57.740 --> 00:25:02.190
we're about to confuse the match
interface. So, the match interface does
00:25:02.190 --> 00:25:06.960
many things, but behind the scenes, it
just finds - it serves the pointer in
00:25:06.960 --> 00:25:11.020
memory to where the text is located,
right. It's this metadata, cool things
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
00:25:16.030 --> 00:25:21.191
another virtual table interface, we'll
simply pass it to the hex decoder, so we
00:25:21.191 --> 00:25:25.670
will decode this raw pointer. And you can
see that, again in little-endian, but now
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
00:25:32.799 --> 00:25:39.320
unpacking this pointer, we have a very
basic problem. How do we even save these
00:25:39.320 --> 00:25:44.620
things? Because unlike browser WebSQL, we
don't have JavaScript variables or arrays
00:25:44.620 --> 00:25:49.690
to use and then abuse them later, but we
need to create some complex logic, right?
00:25:49.690 --> 00:25:54.910
We need to calculate the function address
and create things in memory, but how can
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
00:25:58.780 --> 00:26:05.220
insert statements, but we can only create
tables and views and index and triggers.
00:26:05.220 --> 00:26:10.520
Then we thought about chaining this view
together to use them sort of like a
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
00:26:16.370 --> 00:26:20.929
called "little-endian leak", right? And
again, I abuse the fts3_tokenizer()
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
00:26:25.530 --> 00:26:30.240
it's flipping it using the SUBSTR trick
that you know from before. But notice how
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
00:26:34.360 --> 00:26:39.781
throughout the pointer, and eventually
what I have is a pseudo-variable that's
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
00:26:46.710 --> 00:26:51.059
really move forward. Now we can start
building some more complex things based on
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
00:26:57.190 --> 00:27:02.610
base of an image, for example, or maybe
find the beginning of the heap. So first
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
00:27:09.160 --> 00:27:14.740
and read these pointers one character at a
time and in reverse fashion using SUBSTR.
00:27:14.740 --> 00:27:20.690
And to get the value of this hex
character, we're going to use INSTR, that
00:27:20.690 --> 00:27:26.110
is just like strchar, and using the
following string we'll get the value of
00:27:26.110 --> 00:27:31.450
the hex character. Now, because it is one-
based, you have on the right the minus
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
00:27:39.970 --> 00:27:44.860
concatenate everything throughout the
pointer. So the result is this monster
00:27:44.860 --> 00:27:50.179
query. But eventually, when all of this is
done, I get an integer that is the
00:27:50.179 --> 00:27:56.880
unpacked version of our initial leak. So I
successfully unpacked this pointer and we
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
00:28:02.169 --> 00:28:08.140
convert pointers to integers. Now, pointer
arithmetics, right, because we want to
00:28:08.140 --> 00:28:13.190
have the addresses of some functions in
memory and actually, with integer, this is
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
00:28:19.059 --> 00:28:22.490
can see that I'm referring to the, now,
pseudo-variables that we have, the
00:28:22.490 --> 00:28:28.760
unpacked leak, and on the right I can
either have, like, subtract a silly
00:28:28.760 --> 00:28:32.570
constant like I did here, or I can
actually use another pseudo-variable to
00:28:32.570 --> 00:28:39.870
make it a bit more dynamic, can make some
a bit more reliable. So, eventually, what
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
00:28:47.490 --> 00:28:53.990
pointers and we manipulated them. Now it's
a good time to write them back. And
00:28:53.990 --> 00:29:00.510
obviously we're all used to "char" being
the exact opposite of "hex". And you can
00:29:00.510 --> 00:29:05.700
see that it works fairly well on most of
the values, but bigger integers were
00:29:05.700 --> 00:29:10.980
actually translated to their two-byte
code-points. So this was a huge obstacle
00:29:10.980 --> 00:29:20.180
for us. So, after bashing our head against
the documentation for quite a while, we
00:29:20.180 --> 00:29:25.370
suddenly had the strangest epiphany. We
realized that our exploit is actually a
00:29:25.370 --> 00:29:30.650
database. And if I want any conversion to
take place, I can simply create, ahead of
00:29:30.650 --> 00:29:37.780
time, this key-value map and simply query
it to translate whatever value I want to
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
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
00:29:48.490 --> 00:29:54.520
values to a table called "hex_map" with
its key-map value. And now our conversions
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
00:30:00.610 --> 00:30:06.810
selecting "val" from hex map, this key-
value map, where "int" is equal to, and
00:30:06.810 --> 00:30:11.371
then I go and then doing some more like
shifting and modulo dark magic, but
00:30:11.371 --> 00:30:18.230
eventually, what I'm ending up with is a
packed version of our libsqlite base. Now
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
00:30:22.450 --> 00:30:30.001
as well. As I've mentioned, writing a
single pointer is definitely useful, but
00:30:30.001 --> 00:30:35.280
it's not enough. We want to be faking
complete objects, right? All the cool kids
00:30:35.280 --> 00:30:40.130
are doing it and it's a pretty powerful
primitive. And if you actually recall, we
00:30:40.130 --> 00:30:45.970
have to do it because fts3_tokenizer()
requires us to assign a tokenizer module.
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
00:30:50.510 --> 00:30:54.740
structure and there is an "iVersion",
that's an integer at the beginning, we
00:30:54.740 --> 00:31:00.360
don't really care about it, but following
it are three function pointers. We have
00:31:00.360 --> 00:31:04.840
"xCreate", which is the constructor of the
tokenizer, and "xDestroy", which is the
00:31:04.840 --> 00:31:10.530
destructor. We need to have both of them
valid so we don't crash during our
00:31:10.530 --> 00:31:14.340
exploitation. The third function pointer
is really interesting, because this is
00:31:14.340 --> 00:31:18.360
what actually tokenizes the string. So we
have a function pointer that we are
00:31:18.360 --> 00:31:23.550
passing a controllable string into. This
would be a perfect place to put our system
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
00:31:33.000 --> 00:31:37.919
have one more trick up my sleeve and
that's JOIN queries, right? Because I
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
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
00:31:48.169 --> 00:31:53.320
query, we'll concatenate it with a pointer
to simple_create and a pointer to
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
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
00:32:02.860 --> 00:32:06.990
"A"'s followed by a pointer to
simple_create, followed by a pointer to
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
00:32:14.280 --> 00:32:20.200
primitive for this exploit. And this is
because we already have our malicious
00:32:20.200 --> 00:32:24.700
tokenizer, and we know where the heap is
located, but we are not quite sure where
00:32:24.700 --> 00:32:31.140
our tokenizer is. So this is a great time
for some heap spraying, right. And ideally
00:32:31.140 --> 00:32:36.660
this would be some repetitive form of our
fake object primitive. So we've thought
00:32:36.660 --> 00:32:45.360
about repeat, but sadly SQLite did not
implement it like mySQL. So, like anyone
00:32:45.360 --> 00:32:51.480
else, we went to Stack Overflow, and we
found this really elegant solution. So
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
00:32:59.030 --> 00:33:03.630
then we will replace each of that zeros
with our fake tokenizer. And we're going
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
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
00:33:12.620 --> 00:33:17.049
are really bad colors, but we also got
perfect consistency, because these
00:33:17.049 --> 00:33:24.820
structures repeat themselves every 20 hex
bytes. So we created a pretty good heap
00:33:24.820 --> 00:33:30.631
spraying capabilities and we are done with
our exploitation primitive wish list, so
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
00:33:37.710 --> 00:33:43.200
well known password stealer. And at the
bottom, you can see that it's trying to
00:33:43.200 --> 00:33:49.090
SELECT to extract the secrets by selecting
a column called "BodyRich" from a table
00:33:49.090 --> 00:33:55.330
called "Notes". So, we're going to prepare
a little surprise for him, right? We're
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
00:33:59.049 --> 00:34:04.289
column called "BodyRich". And each of
these sub-queries is actually a QOP chain
00:34:04.289 --> 00:34:09.020
on its own. So if you remember my
exploitation game plan, we're going to
00:34:09.020 --> 00:34:14.500
start with heap spray, and then we will
override the default tokenizer, and then
00:34:14.500 --> 00:34:19.179
we will trigger our malicious tokenizer.
And you might ask yourself, what is
00:34:19.179 --> 00:34:25.160
heap_spray? Obviously, heap_spray is a QOP
chain that utilizes our heap spraying
00:34:25.160 --> 00:34:33.109
capabilities, right. We are spraying ten
thousand instances of our fake tokenizer,
00:34:33.109 --> 00:34:37.690
that is a JOIN query of a bunch of "A"'s
and then some pointers like
00:34:37.690 --> 00:34:43.720
p64_simple_create. And the party goes on,
because p64_ simple_create is actually
00:34:43.720 --> 00:34:52.399
derived from u64_simple_create, right,
with our pointer-packing capabilities. And
00:34:52.399 --> 00:34:56.790
this is just turtles all the way down,
because you have u64_simple_create, that
00:34:56.790 --> 00:35:04.440
is derived from libsqlite_base plus some
constant. And this goes back to the
00:35:04.440 --> 00:35:09.620
unpacked leak version, right, minus some
constant. So again, we're using our
00:35:09.620 --> 00:35:16.410
pointer arithmetics capabilities. We can
continue with u64_leak being derived from
00:35:16.410 --> 00:35:23.470
the almost initial leak. And we'll wrap up
by showing how the leak is actually
00:35:23.470 --> 00:35:29.410
derived from the initial vulnerability
using fts3_tokenizer. And this was just
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
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
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
00:35:44.660 --> 00:35:50.340
because we created QOP.py, and it is
available on Checkpoint Research GitHub.
00:35:50.340 --> 00:35:56.650
And suddenly these crazy long chains can
now be created with four easy lines of
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
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
00:36:08.640 --> 00:36:15.740
a password stealer backend running the
latest PHP 7. So obviously that's a model
00:36:15.740 --> 00:36:20.480
that we created with the leaked sources
and you can see all the infected victims,
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
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
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
00:36:42.060 --> 00:36:47.700
malicious database. Let's see, the
database was created. Now we're going to
00:36:47.700 --> 00:36:52.609
emulate an infection. We're going to send
our malicious database to the C2 server as
00:36:52.609 --> 00:36:56.950
if we were infected by a password stealer.
And because this process takes a bit of
00:36:56.950 --> 00:37:01.490
time, we can look at all the cool DDL
statements, right. So you see that we
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
00:37:06.619 --> 00:37:10.800
bottom, you can see that our end gadget is
echoing the simplest webshell to p.php,
00:37:10.800 --> 00:37:19.310
right. And this is the same page that we
just tried to reach. So hopefully, yeah -
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
00:37:27.140 --> 00:37:35.210
and we got 200. Now, let's execute some
code on it. whoami. www-data. And
00:37:35.210 --> 00:37:44.220
obviously we need to go for /etc/password.
Yay.
00:37:44.220 --> 00:37:55.410
applause
So, what just happened is that we've shown
00:37:55.410 --> 00:38:02.109
that, given just the query to our
malicious a database, we can execute code
00:38:02.109 --> 00:38:07.920
on the querying process. Now, given the
fact that SQLite is so popular, this
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
00:38:13.320 --> 00:38:21.060
that is completely different. And our next
target is going to be iOS persistency. So,
00:38:21.060 --> 00:38:28.090
iOS uses SQLite extensively, and
persistency is really hard to achieve,
00:38:28.090 --> 00:38:34.570
because all executable files must be
signed. Yet, SQLite databases are not
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
00:38:40.440 --> 00:38:44.320
are both compiled with
ENABLE_FTS3_TOKENIZER. That's the
00:38:44.320 --> 00:38:50.770
dangerous compile-time flag. So, my plan
is to regain code execution after reboot
00:38:50.770 --> 00:38:56.599
by replacing an arbitrary SQLite DB. And
to do this, I'm going to target that
00:38:56.599 --> 00:39:02.810
contacts database, and its name is
"AddressBook.sqlite". So these are two
00:39:02.810 --> 00:39:09.080
tables in the original database. They have
no significant meaning, right. Just for
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
00:39:15.050 --> 00:39:19.900
two malicious DDL statements that you're
already familiar by now. First of all,
00:39:19.900 --> 00:39:25.770
we'll override the default organizer
"simple" to a bunch of "A"'s. Then, our
00:39:25.770 --> 00:39:30.911
second DDL statement would actually
instantiate this malicious trigger, so it
00:39:30.911 --> 00:39:34.599
will actually crash the program, right,
because every time you create a virtual
00:39:34.599 --> 00:39:40.000
table module, someone is trying to go to
the constructor of the tokenizer. So then
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
00:39:45.290 --> 00:39:51.100
original table and rewrite them using our
query hijacking technique, right. So,
00:39:51.100 --> 00:39:56.359
instead of the columns that it expected,
we are going to redirect the execution to
00:39:56.359 --> 00:40:00.160
the override statement and the crash
statement. So, we did it for one table, we
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
00:40:07.710 --> 00:40:12.200
secure boots was bypassed. And if you pay
close attention, this is really cool,
00:40:12.200 --> 00:40:19.420
because we see that the crash happened at
0x414141...49. And this is exactly what we
00:40:19.420 --> 00:40:24.470
expected to happen, right, because this is
where our constructor should be, at an
00:40:24.470 --> 00:40:30.930
offset of eight after the first integer of
the version. But actually, there is more.
00:40:30.930 --> 00:40:35.710
We get a bonus here. Because the contacts
DB is actually used by many, many
00:40:35.710 --> 00:40:41.020
different processes. So Contacts and
Facetime and Springboard and WhatsApp and
00:40:41.020 --> 00:40:47.040
Telegram and XPCProxy and so many others.
And a lot of these processes are way more
00:40:47.040 --> 00:40:51.300
privileged than others. And we've
established that we can now execute code
00:40:51.300 --> 00:40:56.560
on the process that queries our malicious
database. So we also got a privilege
00:40:56.560 --> 00:41:01.260
escalation in this process, right. And
this is really cool. And there's nothing
00:41:01.260 --> 00:41:06.000
special about the contacts database.
Actually, any shared database can be used.
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
00:41:11.820 --> 00:41:16.970
stronger user, right. And obviously all
these techniques and bugs were reported to
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
00:41:20.790 --> 00:41:27.030
it later. Now, to wrap things up, if
you'll take anything away from this talk,
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
00:41:33.723 --> 00:41:38.770
want it to be the following. Querying it
database might not be safe, whether if
00:41:38.770 --> 00:41:44.660
it's across reboots or between users or
processes, querying a database might not
00:41:44.660 --> 00:41:50.810
be safe with query hijacking. And now,
with query hijacking and query oriented
00:41:50.810 --> 00:41:55.330
programing, these memory corruptions that
we can trigger can actually be reliably
00:41:55.330 --> 00:42:00.170
exploited with nothing but SQL. We don't
need JavaScript anymore. We don't need
00:42:00.170 --> 00:42:05.880
WebSQL. And we truly think that this is
just the tip of the iceberg. So far,
00:42:05.880 --> 00:42:11.570
SQLite, super popular, yet it was only
assessed from the very narrow lands of
00:42:11.570 --> 00:42:18.220
WebSQL, and as much as browser pwning is
exciting, SQLite has so much more
00:42:18.220 --> 00:42:24.590
potential. So we do have some thoughts
about possible future work with this.
00:42:24.590 --> 00:42:29.530
Obviously, something really cool to do
would be expanding our primitives to some
00:42:29.530 --> 00:42:35.608
stronger primitives, right. We want to
gain things like absolute read and write.
00:42:35.608 --> 00:42:43.510
And my sketchy POC exploit was pretty
silly because it had many constants in it,
00:42:43.510 --> 00:42:49.080
like you've seen, but actually if you used
the internal function of SQLite, like, if
00:42:49.080 --> 00:42:53.590
during the exploitation you use functions
like sqlite3_version(), you ask the
00:42:53.590 --> 00:42:57.560
interpreter, what version are you, what
compile options where you compiled with,
00:42:57.560 --> 00:43:03.530
you can dynamically build these QOP chains
as you go and actually target the specific
00:43:03.530 --> 00:43:08.280
target environment that you are
exploiting. Like, actually utilizing the
00:43:08.280 --> 00:43:12.090
fact that our exploit is a database, we
can create this really cool exploit
00:43:12.090 --> 00:43:17.100
polyglot, and we think that these
techniques can be used to privilege
00:43:17.100 --> 00:43:23.200
escalate so many situations, because the
developers never had it in mind that now,
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
00:43:28.240 --> 00:43:36.020
user, and suddenly we can try to privilege
our escalation. Another cool thing to do
00:43:36.020 --> 00:43:40.330
would be to note that many of the
primitives that I've shown you are not
00:43:40.330 --> 00:43:44.710
exclusive to SQLite, right?
The pointer packing and unpacking and
00:43:44.710 --> 00:43:49.740
heap spraying, and all these things are
not exclusive to SQLite. So it would be
00:43:49.740 --> 00:43:53.580
really interesting to take these
primitives and see if we can go ahead and
00:43:53.580 --> 00:44:00.070
exploit other memory corruption bugs in
different database engines.
00:44:00.070 --> 00:44:02.421
Thank you very much.
00:44:02.421 --> 00:44:09.430
Applause
00:44:09.430 --> 00:44:13.543
Herald Angel: Omer Gull, thank you very
much. That gives us a lot of time for
00:44:13.543 --> 00:44:18.412
questions. So we do have three microphones
here in the hall: Number one, Number two and
00:44:18.412 --> 00:44:23.680
Number three, if you have questions,
please line up. Do we have some questions
00:44:23.680 --> 00:44:31.140
from the net already? No. All right. Then
we're gonna start with microphone number
00:44:31.140 --> 00:44:34.140
two.
Microphone two: Yeah. So the question is
00:44:34.140 --> 00:44:42.520
regarding the hijacking of the CREATE
something. So you mentioned that at the
00:44:42.520 --> 00:44:48.590
beginning of the research was assuming
that CREATE was the first order of
00:44:48.590 --> 00:44:54.720
checking and then a space following the
CREATE word and then it could create all
00:44:54.720 --> 00:44:59.880
of other things. Now, my question is, if
that was changed following your report,
00:44:59.880 --> 00:45:06.910
because this seems like a way to expose
larger attack surface then. Well, most of
00:45:06.910 --> 00:45:10.800
the other bugs. So I just wonder if they
changed. And I mean, what basically what
00:45:10.800 --> 00:45:14.190
was the mitigation if and if that was all
of it?
00:45:14.190 --> 00:45:18.280
Omer Gull: Yeah. So the escalate people,
we're really more concerned with specific
00:45:18.280 --> 00:45:23.359
bugs and not exploitation techniques. And
this is really sad because we all know
00:45:23.359 --> 00:45:27.270
that you can kill bugs, but exploitation
techniques is what sticks. So no, they
00:45:27.270 --> 00:45:34.390
didn't change this verification. And
actually this validation of create space
00:45:34.390 --> 00:45:38.740
was actually added not so long ago. Before
that, you can have any DDL statement
00:45:38.740 --> 00:45:42.550
that you want. So the situation is not
really good over there.
00:45:42.550 --> 00:45:46.331
Microphone two: Good for them and good
luck in the future. And that was the
00:45:46.331 --> 00:45:49.061
question.
Herald Angel: All right. We head over to
00:45:49.061 --> 00:45:52.250
microphone one, please.
Microphone one: Did you, maybe by
00:45:52.250 --> 00:45:56.339
accident, attack a server which was used
for password stealing stealing?
00:45:56.339 --> 00:46:00.223
Omer Gull: No, obviously, I would never do
that. I would never attack anyone. This is
00:46:00.223 --> 00:46:04.170
just in our lab on POC. Right.
Microphone one: Thank you.
00:46:04.170 --> 00:46:08.130
Omer Gull: Your passwords are safe with
the Stealers.
00:46:08.130 --> 00:46:09.820
laughter
00:46:09.820 --> 00:46:12.140
Herald Angel: Right. Nobody is queueing
anymore. Do we have questions from the
00:46:12.140 --> 00:46:16.130
net? Nothing over there. Well, here we go.
Omer Gull: Thank you.
00:46:16.130 --> 00:46:18.383
Herald Angel: Omer Gull, thank you very much.
00:46:18.383 --> 00:46:20.786
applause
00:46:20.786 --> 00:46:24.982
36c3 outro music
00:46:24.982 --> 00:46:47.000
subtitles created by c3subtitles.de
in the year 2019. Join, and help us!