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