>>Hello everyone. Uh- welcome to
my talk called ‘Select Code
Execution from Just About Anything Using SQL Lite’ where
we will gain code execution
using malicious SQL lite databases. So, quick who am i.
My name is uh- Omer Gull. I’m a
vulnerability researcher from Tel Aviv. I’ve been working in
check point research for the
past three years. This is where I’ve done this research and I’ve
recently moved onto a new
startup called Hunters AI. So, the uh- agenda for today, we’ll
start with a little motivation
and uh backstory for this research. We’ll then talk a
little bit about SQL lite
internals. Uh- we will examine attack surface available to a
malicious database and discuss
some previous uh- work done in the field of SQL lite
exploitation. We will then move
onto memory corruptions and uh- the possibility of exploiting
them using nothing but SQL
queries and demonstrate our innovative technique called
Query Oriented Programming, or
QOP. That’s a registered trademark. Eh- we’ll take it for
a spin in a couple of demos and
discuss some possible future work and conclusion. So, let’s
get started. The motivation for
this research is quite obvious. SQL lite is one of the most
deployed pieces of software in
the world. Whether it is PHP five, seven, Android, iOS,
MacOS, it is now built into
Windows 10. It is practically everywhere. Yet, querying a
database uh- is considered safe.
And hopefully by the end of this talk you realize why this is not
necessarily the case. So, it all
actually started with password stealers, and, it’s a pretty
popular type of malware. And
there are several uh- types uh- in this field but the story is
usually all the same. First of
all, a computer gets infected. Then the malware collects the
stored credentials as they are
maintained by various clients. Some of these clients actually
store your secrets within SQL
lite databases. Uh- so the malware just ships those
databases to its C2 server where
they are all parsed uh- and your secrets are stored in a
collective database with the
rest of the loot. So it all actually began when my colleague
and I, Omriher were looking at
the leaked sources of a very known password stealer. Then we
thought to ourselves, these guys
are just harvesting a bunch of our DBs and parse them in their
own backend. Can we actually
leverage the load and query of an untrusted database to our
advantage. Uh- if we could this
might actually have much bigger implications just because SQL
lite is so popular and used in
countless scenarios. And so began the longest CTF challenge
of my life. So uh- a couple of
words about SQL lite. So, unlike most database engines, it
doesn’t have that client server
architecture. Instead it just uh- reads and writes directly to
the file system to files. So you
have a complete database with multiple tables and indices and
triggers and views, and
everything is contained within a single file. So let’s examine
for a second, the attack surface
available to a malicious database. Uh- again this is the
leaked sources of a very uh-
known password stealer and we have two main points of interest
here. The first one is SQL lite
open, where our potentially malicious database is about to
be uh- loaded and initially
parsed. And the second point is obviously the query itself. Now,
you notice that is
uncontrollable to us, right? It is hard coded within our target,
yet we have some control over
the database so we should uh- it should be beneficial to us to
learn this process. So let’s
break the attack surface in two. First of all, the SQL lite open.
So, actually it’s a bunch of
setup and configuration codes, a bunch of loaded, uh- a bunch of
modules are uh- loaded, and then
we move onto straight forward header parsing. And, actually
the header is not that long. It
is only 100 bytes long and it was already fuzzed to death by
AFL. So probably, this is not a
very promising path to pursue. The second part of our surface,
uh- the query itself, and it
might be a bit more interesting because using SQL lite authors’
words, the select statement is
the most complicated command in the AQL language. And, actually,
uh- SQL lite is a wonderful
virtual machine. So every query, uh- is first compiled to some
bytecode. And this is also known
as the preparation step. Uh- So SQL lite prepare would actually
walk and expand your query so
for example, everytime you write an asterisk, it goes uh- behind
your back, replace this asterisk
with all the column names. Uh so, SQL lite locate table
actually verifies that all the
relevant objects do exists, and locates them uh- in memory. So
where does this object exist.
Uh- every SQL lite uh- database has an SQL lite master table
that defines the schema for the
database. And, this is it’s structure. You can see that it
is actually a table. And uh-
every entry there has that type of the object, so like a table
or a view, and its name and
roots page, because if you recall everything is contained
within this file, and a field
called SQL. And SQL is actually the DDL describing the object.
So, DDL stands for data
definition language and you can sort of look at it like uh- your
header files in C. So they are
used to define the structures and the names and the types that
are used within the database.
Furthermore, also appear in plain text within the file. So,
let me show you an example.
Here, I create a very simple database. I create a table and
then I insert a couple of
strings into it. Then I quit the SQL lite interpreter and I hex
dump the file. And you can
actually see the DDL in text, the DDL of SQL lite master in
plaintext within this file. Uh-
so let’s go back to query preparation for a second. So we
have SQL lite locate table uh-
that attempts to find the structures describing the tables
that we are interested in
querying. Uh- so it reads the available in SQL lite master.
And if it’s the first time that
it is doing so, it has a callback function for every DDL
statement. This callback uh-
actually validates uh- the DDL is indeed valid and it builds
the internal data structures of
the object. So, then we thought about- what- what about DDL
patching. Can we simply replace
the SQL query within the DDL. And, turns out that- this is uh-
the callback function that I
mentioned, and you see that the DDL is verified to begin with
create space and only then it
moves onto preparation. So that’s actually a constraint.
Our DDL must begin with create.
However uh- it does leave some room for flexibility because uh-
to judge by the recommendation,
actually many things can be created in SQL lite. So you can
create an index and a table and
a trigger and a view, and something we still don’t
understand called virtual table.
And then, create a view gave us an interesting idea. Because
views are simply prepackaged
select statements, right? And they are queried similarly to a
table. So selecting a column
from a table is semantically equivalent to selecting a column
from a view, right? Uh, so we
move onto the concept of query hijacking. We are going to patch
SQL lite maser DDL with a view
instead of a table. And our patched view can actually have
any select that we wish. And now
using our select subquery, we can actually interact with the
AQL lite interpreter. And this
is a huge step forward right? Because the query was
uncontrollable by us at first,
but now we have some control over it. Let me show you an
example. So let’s say that the
original database had just a single table. And it’s called
dummy and it has two columns
inside it. The target software uh- would actually uh query it
uh the following way. It would
just select those two columns out of the table. Right? But the
following view can actually
hijack this query so if we create a view that it’s called
dummy, it has uh- the exact
number of columns inside, and the same name, and every column
can have any subquery that we
wish inside it. So again, let me show you in a practical example.
Here I create uh- a database.
And inside it I create a view with two columns. Every column
is actually a function. So the
first column would call the SQL lite version function that
simply returns the SQL lite
version in use. And the second column will utilize SQL lite’s
own implementation of print f.
That’s right they have their own implementation of print f, they
must be insane. So now, when the
target software actually queries uh- this- uh- what it thinks to
be a table but is actually a
view, we can actually see our two functions executing and
again, we just gain some control
over the query and this is a huge step forward. But then the
question is what do we do with
this control, what primitives does SQL lite have? Okay, do we
have any system commands? Can we
write to other files on the system, maybe read some more
files? Uh so this is uh- a
really good point to uh- look back at previous research done
in the field because we are
definitely not the first one to notice SQL lites uh- huge
potential in terms of
exploitation, right? So a reasonable place to start is SQL
injections, right? And there are
a couple of known SQL injection tricks in SQL lite. The first
one has something to do with
attaching another database and creating a table and then
inserting a string into it uh-
so you are able to write your own webshell. And this is all
very nice but we can’t do it
because if you recall, you can’t start any statement with attach.
Our DDL must begin with create.
So it’s not a very uh- uh- useful trick for us. Another
common thing to do in SQL
injection uh- is loading a remote extension like here in
this example you can see it
actually loads the meterpreter DLL, however it is also disabled
by default so again, no go with
this trick. Let’s talk about memory corruptions for a second
because SQL lite is such a
complex piece of software and it- everything is written in C.
Uh so, in his amazing blog post,
“Finding bugs in SQL lite the easy way” Michael Zalewski, uh-
the author of AFL, described how
he found 22 bugs in just under 30 minutes of fuzzing and this
is pretty amazing. And
interestingly, since then, there was uh- version three eight ten
that was 2015. SQL lite actually
started using AFL as part of their remarkable test suite. Yet
these memory corruption all
proved to be really difficult to exploit without a convenient
environment, right? But the
security research community soon found the perfect target, and it
was web SQL. So, web SQL is
essentially a webpage API for storing data in databases. It is
queried from javascript using
SQL and it has an SQL lite backend and it is available in
Chrome and Safari. Here we see
an example of how to uh- query SQL to SQL lite using
javascript. It’s very straight
forward. But, in other words, what I’m hearing here, is that
we have untrusted inputs into
SQL lite available uh- reachable from any website on the internet
in two of the world’s most
popular browsers. Uh- and now, every memory corruption bug
could could actually be
leveraged with the comfort and knowledge of javascript
exploitation. So there have been
uh- several impressive researchers that uh- were
published about web SQL from
very low hanging fruits like CVE 2015 70 36, that was an
untrusted pointer dereference in
FTS tokenizer. Uh to more complex exploits presented at
Blackhat 2017 by the awesome
Chaitin team that was a type confusion in the FTS optimizer.
Uh to the recent Magellan bugs
that were just uh- presented by the tencent team. That was an
integer overflow in uh FTS
segment reader. And if you guys are paying even a tiny bit of
attention here, you might see an
interesting pattern arises, right? All these functions start
with FTS. So, what is FTS? I’ve
never heard of it and Googling just even left me more confused.
Well, after some time, I came to
the realization that FTS actually stands for full text
search and it is something
called a virtual table module and it allows for textual
searches on a set of documents.
Again, using SQL lite’s author’s words, it’s just like google for
your SQL lite database. So
that’s pretty cool. And a virtual table actually allows
for plenty of core functionality
in SQL lite so we have FTS that we just described. There is also
R TREE, a virtual table that
allows for some uh- clever geographical indexing, or the
CSV virtual table that lets you
treat your database as you would a CSV file. And actually, all
these virtual tables are queried
just like regular tables, but behind the scenes, some dark
magic happens. Because every
query invokes a callback method on something called shadow
tables. So, shadow tables. Uh-
for example, let’s look at a virtual table that is created
using FTS virtual table module.
Right. So we create a table and we insert a string into it. Now,
obviously to allow for some
efficient search, we need to have some metadata right? We
need to have some indexing or
pointers or toke- or some tokens or stuff like that. So obviously
we have some- we have the raw
text and some metadata, but this one virtual table is actually
comprised from three shadow
tables. So the raw text would go a shadow table called content,
and the metadata would go to the
seg dir and segments. And, actually each of these shadow
tables, uh- they pass
information between them. They have all those interfaces and
those interfaces, and given that
they have uh- such trusting nature, are really fertile
ground for bugs. Uh- many of the
bugs in SQL lite are uh uh- presented there so uh- it’s a
really good thing to look at if
you’re hunting for bugs. And let me show you an example of a bug
that I found in one of the
interfaces of the R TREE virtual table. Uh- so again, R TREE is a
virtual table module and it is
available in MacOS, iOS, and now also built into Windows 10. And
it’s used for some geographical
indexing. I’m not entirely sure what that means but the
structure should be the
following. A table should begin with ID, that is supposedly an
integer and then you have a
bunch of coordinates, the like X and Ys. Uh- so R TREE interfaces
would obviously expect ID to be
an integer but if we create a virtual table using the R TREE
module, and we’ll insert uh- a
value, where ID is definitely not an integer, but it’s a
string, and then we use the uh-
R TREE node, that is one of the R TREE interfaces, we get the
following CVE. That’s an out of
bounds read, uh, and it’s really cool because this bug is now
available in iOS and MacOS and
as you can see here, also in Windows 10. So, let’s go back to
exploitability for a second. We
realize that virtual tables do have bugs, right? And, using our
method of query hijacking, we
can actually trigger them at the C2 and cause it to segfault. But
gaining flow control requires
some form of scripting right? Because segfaulting is not
enough. We write- we want to uh
write a complete exploit. We want to bypass ASLR, we want to
have some logic. However, we
don’t have the javascript interpreter so we don’t have any
variables or arrays to use like
you would in web SQL exploitation. However we do
vaguely recall hearing somewhere
that SQL is turing complete. So, we decided to put it to the test
in terms of exploitation. And we
started writing our own wishlist for exploitation primitives. So
Obviously we need to leak some
memories, right? We want to bypass the ALSR. Uh- we’ll have
to do some common tests like
unpacking 64 bit pointers to integers, and then do some
arithmetics with them right? We
want to calculate where functions are or where the heap
is located. After all you want
to pack those integers back to little endian 64 bit pointers
and maybe we also want to fake
some objects in memories. This is a really uh- uh- powerful
primitive that’s uh- really
helpful in many vulnerabilities. And uh- we want to know how to
heap spray. Uh because why not?
It might be really really useful. So the question remains
can all these primitives be
achieved with nothing but SQL. And the question is, yes it it.
So I proudly present to you
something we call the query oriented programming. And to- to
explain it we will uh exploit
the unfixed CVE 2015 70 36. And you might ask yourself, what?
How come a four year old bug is
still unfixed? But this is exactly our point. It was only
considered vulnerable from uh-
the context of the untrusted web SQL so it was mitigated
accordingly. It’s just not
available in web SQL anymore. However, so it- it was
blacklisted actually, unless you
compile SQL lite with a certain flag. Uh- but these platforms
are still vulnerable. So we
have: PHP 5, and PHP 7, and iOS and MacOS, all still vulnerable
to this CVE. So let’s describe
the vulnerability a little bit. So, we said it has something to
do with the tokenizer. So a
tokenizer is a set of rules for extracting terms from a document
or a query. And the default is
called simple just splits those strings by whitespaces. However,
if oyu like, you can register
custom tokenizer using the FTS tokenizer function in an SQL
query. I will repeat it slowly.
You can actually register uh- a function using an SQL query. You
are about to pass uh- a raw
pointer to an SQL query. This is absolutely insane. Actually I
have no idea how to really use
this functionality other than in my exploit.>>[laughter]>>So,
FTS tokenizer is actually an
overloaded function and if you call it with one argument, so
simple, again this is the name
of the default tokenizer, it actually spits back the address
of this tokenizer. So, to make
it a bit more readable, we’ll use the hex decoder and we can
see that we actually got a
pointer to lib SQL lite but it’s the other way around because
little endianity. And uh- if you
call it with two arguments, so the first one is the tokenizer
name, the other one is a raw
pointer, uh- you actually override the address of this uh-
uh- tokenizer. So everyone
trying to use this tokenizer, everyone instantiating a virtual
table will try to uh- initialize
it and will then crash and burn with segmentation fault uh- at
the order it’s given to it. So a
little recap, uh we established that SQL lite is a wonderful one
shot for many targets. One good
bug in SQL lite is one good bug in so many platforms. And we
realized that is a complex
machine written in C, and using query hijacking, we can now
actually start triggering bugs.
And we aim to write a full exploit uh- uh- implementing all
necessary exploitation
primitives uh- with nothing but SQL queries. So, our
exploitation game plan is as
follows. We are going to leak some pointers and then we’ll
calculate some function
addresses. Uh- we’ll create our own fake tokenizer with some
pointers to assist them to allow
us to actually execute code. We will override the default
tokenizer and trigger it, right?
And then something will happen, and I know you think is going to
come up next. But we’re not
going to profit, we are going to grab your grandma’s Yahoo
password because this is what’s
available in password stealers. So, starting with the memory
leak. Uh- we- first of all uh-
we need to gain a leak to lib SQL lite, right? Uh- so we
already know how to do it,
right? The FTS tokenizer just give us the address. But, we
have a slight problem because
it’s in little endian so we need to flip it. So, surely we can
read the pointer in a reverse
fashion, two characters at a time, and concatenate everything
together. So, our leak would
eventually uh be the following query and we actually now have a
leak to lib SQL lite. This is
really really cool. Another thing that is going to be useful
to us is a leak to the heap,
right? So, I’m going to do something pretty similar to the
R TREE bugs that I’ve shown you.
I’m going to confuse a virtual table interface. So again I’m
creating a virtual table. And
I’m inserting a sting into it. And then I will confuse the
match interface and it is
usually passing a pointer but instead of uh- passing it to
some other interface that is
expecting this pointer, I will simply pass it to the hex
decoder again. So now we read
this uh pointer. And it is indeed a pointer to the heap,
again, in uh- little endian, but
using the trick above, we should be fine in flipping it. So, we
can cross that off the list. We
know how to leak memory, now it’s time to unpack some
pointers. Uh, but before we do
that, we actually have a slight problem because unlike uh-
browser uh- web SQL
exploitation, we don’t have any javascript variables or arrays
to use, and this is a big
problem because we need to create some logic. We want to
calculate things, we want to
store things, and naturally storing things in SQL lite uh-
requires you to have some
insert. Uh- but we can’t use insert, right? We have to begin
with create and we can only
create tables and views and indexes and triggers. So then we
thought about chasing uh- uh-
chaining a couple of views together and use them sort of,
as pseudo variables. Again, let
me show you an example. We create a view called little
endian leak, uh- and we use the
vulnerability as mentioned in the earlier slide. Now we create
another view, leak, and notice
how it refers to the first view, right? It selecting from little
endian leak. Again, we are doing
the trick from before. And now we’re actually uh- we actually
remain with a pseudo variable
called leak that is actually all these chains together so we have
one pseudo variable that
contains all the calculations from before. And again, this is
a huge step forward because we
want to create some logic. Uh- our exploit should bypass ASLR
and those kind of things we need
to be able to store things and this would really help us. So,
unpacking 64 bit pointers. Uh-
to calculate the base of an image or the heap, we have to
convert our pointers to
integers. And this can be done using the following query. So,
again we start with sub str,
reading one character in a reverse fashion. Then we take
this character and we use it in
str. In str is just like str char, and we get the value of
this hex character. Because it
is one based, you have the minus one on the side, and then you
have some multiplication and
shifting dark voodoo, and you simply return it for every
character in the pointer
resulting in this monster query. But eventually, we actually
unpacked uh- the pointer and now
we have the integer value. So again, we can cross that off the
list as well. Moving to pointer
arithmetics, and it is actually really really easy right now
when we have uh- integers at
hand right? All we have to is, in one sub query, we use our
pseudo variables, and the other
one can have any constant then, we wish, and now we now where
lib SQL lite is located. So, uh-
packing 64 bit pointers because we read some pointers and we
manipulated them. Now would be a
good time to write them somewhere. Uh- so we thought
char is going to be really
useful here because we are used to char being the reverse of
hex, right? And it actually
works fairly well on some values, but on higher values
this was a problem because they
were translated back to their uh- two byte code points uh- in
unicode. And this was a huge
obstacle for us. And we actually uh- uh- had a really big problem
with this and after bashing our
head against the documentation for about a week, we suddenly
had the strangest epiphany: that
our exploit is actually a database, and if I want any
conversion to happen at all, I
can simply cre- uh- prepare a key value table in advanced
while I’m generating this
database and then use some sub queries. Uh- so this is the
python function that is actually
generating this hex map key value table and you can see that
it’s a very simple four loop
from zero to FF, just inserting all the values that I wish. And
now our conversion use sub
queries that are selecting from this hex map so you see how the
view is referring to hex map and
again, we have some uh- shifting and moderate dark magic and we
can catenate everything together
resulting in this query. So, now we also know how to pack 64 bit
pointers, we are moving forward.
Let’s talk about faking objects in memory. Because writing a
single pointer is definitely
useful but it’s not enough, right? Uh- we all want to fake
objects in memory, it’s a really
powerful primitive, and if you recall, uh- FTS tokenizer
actually requires us to assign a
tokenizer module, so we need to fake one. And a tokenizer module
is the following struct. Uh- we
don’t really care about most of it. Uh- it starts with an
integer and then it has three
function pointer. First of all we have the create, which is the
constructor. Then we have the
destroyer which is the destructor. Obviously we want
both of them to be valid because
we don’t want to crash during our exploitation. The third
function pointer, uh- open,
actually tokenizes a string. So it gets a string as an argument.
This would be a really good
place to put our system functions so we can execute code
as we wish. So, I’ve used most
of my SQL knowledge by know but I still have one more trick up
my sleeve. I remember join
queries. So, we are going to fake an object using the
following join query, right? We
can see that we started- we created a view called fake
tokenizer and it’s concatenating
a bunch of As, and then uh- a packed version of the simple
create address, and then another
packed pointer, and then a bunch of Bs with a join query. So
actually if we verify it from a
debugger, we can actually see that it works pretty good. That
memory section begins with a
bunch of As and then we have two pointers and then we have a
bunch of Bs. So we have
successfully faked an object in memory using nothing but SQL
queries so far. Uh- so for our
final primitive, we want to do some heap spray. Uh- because now
we have our malicious tokenizer,
right? And using our leaks, we also know where the heap is but
we are not entirely sure where
our tokenizer is between- uh- it is inside the heap. So it’s time
for some spraying. And ideally
that would be some repetitive form of our fake object
primitive, right? Uh- so repeat
sounded like a really good option to us. Uh- sadly SQL lite
did not implement it for us so
we had to do it by ourself. Stack overflow for the win. We
found this really elegant
solution. So the following query, uh- it uses the zero blob
function that returns a blob
consisting of N bytes. Uh- they are all zeros, right? And then
we’ll use the replace function.
We are going to replace each and every o- of those null bytes
with our fake tokenizer. So,
again the colors here are pretty bad, but, verifying it with pwn
dbg, uh- we actually see that we
got perfect consistency. Our fake tokenizer is repeating
itself every twenty bytes. So
this is perfect. And it looks like Christmas came early
because we can go onto pwning
shit. So, again our target is the following code, right? We
have the password stealer, and
it selects a column called body rich from a table called notes,
right? So we are going to create
a view that is called notes and it will have three sub queries
inside. We are going to start
with a sub query called uh- a heap spray and then will
override the simple tokenizer,
and then will trigger our malicious tokenizer. And you
might ask yourself, what is a
heap spray? Well, heap spray is obviously a QOP chain. It’s
another view called heap spray
that utilizes our heap spray crazy capabilities. We start
with a bunch of As and then we
can catenate one of the pointers that we are interested in; P 64
simple create, for example.
Needless to say that P 64 simple create is another view, right,
that actually refers, it’s a
packed version of U 64 simple create. The party goes on
because U 64 simple create
actually goes back to U 64 lib SQL lite that utilizes uh- some
of our pointer arithmetics
capabilities, right? And everything is derived from our
initial leak, the U 64 leak. But
it actually turtles all the way down. U 64 leak refers to leak,
right? And our unpacking
capabilities. And leak goes all the way back to our initial
vulnerability. And everytime I
describe this QOP chain, this is how I must look, right? I must
look insane. But luckily for you
guys, you don’t have to look like me. Because we created QOP
dot Pi. And QOP dot Pi is a
really useful python library generating these crazy long
statements, right? In something
in- like the start of pwn tools. So creazing uh- creating the
pass chain is actually on this
like four lines of python. Uh- and it’s going to be available
in our github right after this
presentation. So, now that we have everything in order, let’s
show our first demo for today
where we will own a password stealer backend that is uh-
running the latest PHP 7. So,
this is our module uh- this is our uh- panel. Obviously it’s
just a model that we setup from
the leaked sources. And you can see of those uh- all those uh-
victims that are infected. And
we are trying to go p dot php where our webshell should be.
Obviously it’s still not there
because we have yet to exploit it. Moving onto the attacker’s
computer, we see that we have
two scripts. The first, qop dot py will actually generate, our
malicious database. And we see
uh- using LS that a database was indeed created. Now we are going
to emulate an infection, right?
So we are going to send this SQL lite database to the C two
server as if we were infected
and as a bunch of passwords that is interested in. And this
process takes a bit of time so
we can look at all the crazy statements above. We started
with the leaks, and then we
unpacked them, and- and packed them again and manipulated, and
you see that at the bottom, our
payload is actually creating P dot PHP with the simplest
webshell. So after our exploit
uh- will run successfully, it will go to that page. Now that
it is finished we go to P dot
PHP again, and we see 200, the page do exist. So now we can
actually execute some code on
the backend. Who am I, www dot data. And obviously type in etc
password, and we got it. Yeah.
>>[Applause]>>So, actually, if you think of it, what we just
demonstrated is that anyone
querying our malicious database can actually be exploited. And
this can be a lot of fun. And
given the fact that SQL lite is so popular, it opens up uh- the
door to wide range of attacks.
Uh- let’s explore another really interesting use case. Uh so this
is iOS persistency. iOS uses SQL
lite extensively. It is everywhere, right? And
persistency is really hard to
achieve on iOS because all executable files must be signed.
Uh- SQL lite database, being
data only are not signed. Right? There’s no need to sign them.
Uh- and iOS and MacOS are both
compiled with the enable FTS uh- tokenizer compile time flag. So
we plan on regaining code
execution after the reboot by replacing any SQL lite DB,
right? So, as our target, we
chose the context db. So this is the name of the context, it’s
address book SQL lite db. And
these are a couple of tables inside it, there’s nothing
really special about those
tables, they’re just here as an example. We will replace the db
with our malicious db. Alright,
that will start with two DDL statements, and you guys are
already familiar with them. The
first one will override the simple tokenizer with a bunch of
As. The second one will actually
trigger it, right? It will start an FTS virtual table uh- try to
construct our malicious
tokenizer. Uh- and now what we are going to do is that we are
going to go over each and every
one of the original tables, and using query hijacking, we are
going to rewrite them as views,
redirecting the execution to our malicious DDL statements. So you
see we select from override and
then we select from crash. And then we go and we do it for the
second ta- second table as well.
And we reboot, and secure boot was actually bypassed and we got
the following CVE. And this is
really interesting because you can see that the crashing
address is 41, 41, 41, 49, and
this is exactly as we expected, right? This is where the
constructor X create should be.
But that’s actually not everything. Uh- because the
context DB within your iPhone is
actually used and shared by many many different processes. So
whether it’s the contacts app,
or Facetime, Springboard, WhatsApp, Telegram, XPC proxy,
many many process, some of them
are more privileged than others. And we’ve actually established
the fact that we can execute
code on the querying process. So this actually means that we got
privilege escalation using our
tricks, right? And actually there is nothing special about
context DB. Any shared database
can be used to achieve our goals. Uh- all these methods and
techniques were reported to
Apple and they gained those CVEs if you want to go and read about
it later. So, if you’ll take
anything away from this research, I don’t want it to be
the crazy SQL gymnastics, or I
don’t want it to be a bunch of CVE numbers. I want it to be the
following. Querying a database
might not be safe. Whether it is across reboots or shared between
processes, or shared between
users, querying a database might not be safe. And with QOP,
actually these memory
corruptions can now be reliably exploited using nothing but SQL.
Uh- and we really think that
this is just the tip of the iceberg. So far, SQL lite was
only examined through the very
narrow lense of web S- webSQL. And while browser pointing is
really exciting, SQL lite has so
much more potential from exploitation uh- perspective. So
we really uh- want to see where
the community will take this research to. And we do have a
couple of ideas of our own. So,
obviously, something really cool to do in future work would be to
expand our primitives and gain
something powerful as absolute read or write. And second, uh-
our exploit was actually uh- a
really sketchy POC right? It had a bunch of hard coded constants
inside. But you can actually
make it really really clever. Because if you think that your
eploit is actually a database,
you can choose the right QOP chain for you, uh- based on the
results of functions like SQL
lite uh- version or compile option- like getting the compile
option views. Uh- so you can
dynamically create your QOP chain, uh- to be exact to the
target that you are exploiting.
Obviously we think that uh- these techniques can be used to
privilege escalate almost
everything. All we have to do is find a database that is writable
by a weak user and queried by a
more powerful user so it’s also interesting to look at other
platforms than iOS or MacOS. And
something- uh- another thing that is really interesting is
that many of the primitives that
we have shown are not exclusive to SQL lite. You can actually
port many of them, like the
packing and unpacking, you can port them to other database
engines so this would be also a
really cool path to pursue, to see how these techniques work in
other database engines. And
that’s it, thank you so much.>>[Applause]