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!