1 00:00:00,080 --> 00:00:02,430 The following content is provided under a Creative 2 00:00:02,430 --> 00:00:03,820 Commons license. 3 00:00:03,820 --> 00:00:06,060 Your support will help MIT OpenCourseWare 4 00:00:06,060 --> 00:00:10,150 continue to offer high quality educational resources for free. 5 00:00:10,150 --> 00:00:12,690 To make a donation, or to view additional materials 6 00:00:12,690 --> 00:00:16,600 from hundreds of MIT courses, visit MIT OpenCourseWare 7 00:00:16,600 --> 00:00:17,310 at ocw.mit.edu. 8 00:00:25,998 --> 00:00:27,780 PROFESSOR: All right, let's get started. 9 00:00:27,780 --> 00:00:33,090 So welcome to the next lecture about exploiting 10 00:00:33,090 --> 00:00:33,921 buffer overflow. 11 00:00:33,921 --> 00:00:35,420 So today, what we're going to do is, 12 00:00:35,420 --> 00:00:38,810 we're going to finish up our discussion about baggy bounds 13 00:00:38,810 --> 00:00:40,990 and then we're going to move on to a couple 14 00:00:40,990 --> 00:00:44,400 of other different techniques for protecting its buffer 15 00:00:44,400 --> 00:00:45,180 overflows. 16 00:00:45,180 --> 00:00:48,020 Then we're going to talk about the paper for today, 17 00:00:48,020 --> 00:00:51,032 which is the blind return oriented programming. 18 00:00:51,032 --> 00:00:53,240 So if you were like me when you first read that paper 19 00:00:53,240 --> 00:00:55,780 you kind of felt like you were watching like a Christopher 20 00:00:55,780 --> 00:00:56,665 Nolan movie at the beginning. 21 00:00:56,665 --> 00:00:58,350 It was kind of like mind blowing right. 22 00:00:58,350 --> 00:00:59,030 So what we're going to do is we're 23 00:00:59,030 --> 00:01:01,363 going to actually step through how some of these gadgets 24 00:01:01,363 --> 00:01:02,090 work right. 25 00:01:02,090 --> 00:01:03,548 And so hopefully by the end, you'll 26 00:01:03,548 --> 00:01:05,995 be able to understand all this sort of high tech chicanery 27 00:01:05,995 --> 00:01:08,110 that they're doing in the paper. 28 00:01:08,110 --> 00:01:09,810 So first of all, like I said, let's 29 00:01:09,810 --> 00:01:13,210 just close up with the baggy bounds discussions. 30 00:01:13,210 --> 00:01:18,480 Let's go through a very simple example here. 31 00:01:18,480 --> 00:01:26,280 So let's say that we're going to define a pointer called P. 32 00:01:26,280 --> 00:01:28,400 And let's say that we're going to give it 33 00:01:28,400 --> 00:01:30,360 allocation size of 44. 34 00:01:30,360 --> 00:01:37,960 Let's also assume that the slot size equals 16 bytes OK. 35 00:01:37,960 --> 00:01:40,630 So what's going to happen when we do this malloc up here? 36 00:01:40,630 --> 00:01:42,460 So as you know, the baggy bounds system 37 00:01:42,460 --> 00:01:46,401 is going to pad that allocation out to the next power of two, 38 00:01:46,401 --> 00:01:46,900 right. 39 00:01:46,900 --> 00:01:49,730 So even though we've only allocated 44 bytes here, 40 00:01:49,730 --> 00:01:54,130 we're actually going to allocate 64 bytes for this pointer 41 00:01:54,130 --> 00:01:56,470 up here. 42 00:01:56,470 --> 00:01:59,671 And so also note too, this is the slot size is 16. 43 00:01:59,671 --> 00:02:01,920 How many bounds tables entries are we going to create? 44 00:02:01,920 --> 00:02:04,960 Well we're going to create the allocation size, which 45 00:02:04,960 --> 00:02:08,970 in this case 64, divided by the slot size, which is 16. 46 00:02:08,970 --> 00:02:12,280 So in this case we'll create four different bounds table 47 00:02:12,280 --> 00:02:14,554 entries for this thing right here. 48 00:02:14,554 --> 00:02:15,970 Each one of those entries is going 49 00:02:15,970 --> 00:02:18,631 to be set to the log of the allocation size, which 50 00:02:18,631 --> 00:02:20,130 in this case is going to be 6 right. 51 00:02:20,130 --> 00:02:22,800 Because the allocation size is 64, OK? 52 00:02:22,800 --> 00:02:24,070 So, so far so good. 53 00:02:24,070 --> 00:02:31,180 Then we're going to define another pointer called q 54 00:02:31,180 --> 00:02:36,770 and we're going to set it equal to p plus 60. 55 00:02:36,770 --> 00:02:38,350 So what happens when we do this? 56 00:02:38,350 --> 00:02:40,350 Well note that strictly speaking, 57 00:02:40,350 --> 00:02:43,070 this access is out of bounds, right. 58 00:02:43,070 --> 00:02:45,470 Because this was only allocated 44 bytes of memory, 59 00:02:45,470 --> 00:02:47,345 but of course the way that baggy bounds works 60 00:02:47,345 --> 00:02:50,300 is that it will actually allow axises that are out of bounds, 61 00:02:50,300 --> 00:02:52,290 if they stay within that baggy bounds. 62 00:02:52,290 --> 00:02:53,879 So even though strictly speaking, 63 00:02:53,879 --> 00:02:55,920 the programmer probably shouldn't have done this, 64 00:02:55,920 --> 00:02:57,720 this is actually going to be OK, right. 65 00:02:57,720 --> 00:03:01,170 We're not going to raise any flags or anything like that. 66 00:03:01,170 --> 00:03:04,230 Now let's say that the next thing we do 67 00:03:04,230 --> 00:03:09,430 is we need to find another pointer, which is going to be 68 00:03:09,430 --> 00:03:14,340 set equal to q plus 16 right. 69 00:03:14,340 --> 00:03:21,290 Now this is actually going to cause an error, right. 70 00:03:21,290 --> 00:03:31,660 Because now q is at an offset of 60 plus 16, which equals 76. 71 00:03:31,660 --> 00:03:34,720 So this is actually 12 bytes away from the end 72 00:03:34,720 --> 00:03:36,380 of that baggy bounds. 73 00:03:36,380 --> 00:03:36,980 OK? 74 00:03:36,980 --> 00:03:39,964 And that's actually greater than half a slot away. 75 00:03:39,964 --> 00:03:42,380 All right, so if you remember the baggy bounds system will 76 00:03:42,380 --> 00:03:44,690 actually throw a hard synchronous error if you 77 00:03:44,690 --> 00:03:47,630 get beyond 1/2 a slot from the edge of that baggy bounds. 78 00:03:47,630 --> 00:03:49,630 So this will actually cause the program to fail. 79 00:03:49,630 --> 00:03:51,210 This will actually make it stop. 80 00:03:51,210 --> 00:03:54,020 Now let's imagine that we didn't have this line of code 81 00:03:54,020 --> 00:03:55,140 in the program, OK. 82 00:03:55,140 --> 00:03:57,610 So we had these two, but we don't have this one. 83 00:03:57,610 --> 00:04:00,290 So what if we instead of doing this line, 84 00:04:00,290 --> 00:04:02,230 did something that looks like this. 85 00:04:02,230 --> 00:04:06,790 We declare another pointer, let's call it s, 86 00:04:06,790 --> 00:04:11,700 and we set it equal to q plus 8. 87 00:04:11,700 --> 00:04:14,580 Now in this case, the pointer is going 88 00:04:14,580 --> 00:04:22,480 to be at 60 plus 8, which equals 68 bytes away from p, right. 89 00:04:22,480 --> 00:04:25,680 So this is only four bytes beyond that baggy bound. 90 00:04:25,680 --> 00:04:28,280 So this will not actually cause an error. 91 00:04:28,280 --> 00:04:30,740 Even though it is strictly speaking, out of bounds. 92 00:04:30,740 --> 00:04:33,060 What we will do here though, is set that high order 93 00:04:33,060 --> 00:04:34,950 bit on the pointer, right. 94 00:04:34,950 --> 00:04:36,610 So that if anyone subsequently tries 95 00:04:36,610 --> 00:04:38,390 to dereference this thing, it's going 96 00:04:38,390 --> 00:04:41,770 to cause a hard fault at that point. 97 00:04:41,770 --> 00:04:44,350 And then let's say, the final thing that we do 98 00:04:44,350 --> 00:04:51,250 is we declare another pointer t, which 99 00:04:51,250 --> 00:04:56,599 is going to equal s minus 32. 100 00:04:56,599 --> 00:04:58,390 So what happens here is that essentially we 101 00:04:58,390 --> 00:05:02,280 brought this pointer t, it is now back in bounds, right. 102 00:05:02,280 --> 00:05:06,510 So what that means is that even though this guy was out 103 00:05:06,510 --> 00:05:09,210 of bounds, now we sort of going back to the original allocated 104 00:05:09,210 --> 00:05:11,290 region, that we originally created up here. 105 00:05:11,290 --> 00:05:14,946 So as a result, t will not have that high order bit step 106 00:05:14,946 --> 00:05:17,320 and so you can dereference T and everything will be fine. 107 00:05:17,320 --> 00:05:18,490 So does this all make sense? 108 00:05:18,490 --> 00:05:20,073 This should be fairly straightforward. 109 00:05:20,073 --> 00:05:22,207 AUDIENCE: [INAUDIBLE] the difference 110 00:05:22,207 --> 00:05:25,920 between r and s, how would you know that r is-- 111 00:05:25,920 --> 00:05:31,365 or how does the program know that r is 1/2 the [INAUDIBLE]. 112 00:05:31,365 --> 00:05:34,830 PROFESSOR: So note that, like up here, 113 00:05:34,830 --> 00:05:39,308 when we create r you can basically interpose, 114 00:05:39,308 --> 00:05:40,861 we get an instrumented code that's 115 00:05:40,861 --> 00:05:44,570 going to be working at all of these pointer operations. 116 00:05:44,570 --> 00:05:48,528 So basically we can tell is that we know where P is going to be. 117 00:05:48,528 --> 00:05:51,276 I'm sorry, we know where q is going to be. 118 00:05:51,276 --> 00:05:57,935 And we know that q is within those baggy bounds. 119 00:05:57,935 --> 00:05:59,907 And so when we do this operation here, 120 00:05:59,907 --> 00:06:01,890 the instrumentation of baggy bounds 121 00:06:01,890 --> 00:06:03,528 adds and we're able to say, aha, well I 122 00:06:03,528 --> 00:06:05,444 know where that source formula is coming from. 123 00:06:05,444 --> 00:06:07,760 And then if you look at this offset here, 124 00:06:07,760 --> 00:06:11,273 you determine it's more than a 1/2 slot away from slot side. 125 00:06:11,273 --> 00:06:12,772 So basically what you think about is 126 00:06:12,772 --> 00:06:14,117 that as we're doing these pointer operations, 127 00:06:14,117 --> 00:06:16,317 and looking and saying is how are you going out of bounds, 128 00:06:16,317 --> 00:06:18,029 have you gone out of bounds, yes or no. 129 00:06:18,029 --> 00:06:20,362 At some point you're going to have some operation that's 130 00:06:20,362 --> 00:06:23,342 going to involve a pointer that is either in bounds 131 00:06:23,342 --> 00:06:25,758 within the baggy bounds and then some thing over here that 132 00:06:25,758 --> 00:06:27,398 makes it go out of bounds. 133 00:06:27,398 --> 00:06:29,366 So at that moment, right when that happens, 134 00:06:29,366 --> 00:06:30,760 that's how we know that something chicanerous has 135 00:06:30,760 --> 00:06:31,260 arisen. 136 00:06:36,760 --> 00:06:39,420 All right so, hopefully that should all make sense. 137 00:06:39,420 --> 00:06:41,480 And so this is very briefly a review 138 00:06:41,480 --> 00:06:44,311 of the homework question. 139 00:06:44,311 --> 00:06:46,894 So hopefully you can understand this and our homework question 140 00:06:46,894 --> 00:06:48,394 should be pretty easy to understand. 141 00:06:48,394 --> 00:06:56,740 So we have a character pointer the malloc had 256 bytes to it, 142 00:06:56,740 --> 00:06:59,427 Then we declare a character pointer 143 00:06:59,427 --> 00:07:06,420 q, that is equal to that pointer plus 256 144 00:07:06,420 --> 00:07:11,340 and then we essentially try to dereference this pointer. 145 00:07:11,340 --> 00:07:12,670 So what's going to happen? 146 00:07:12,670 --> 00:07:15,870 Well note that this is an exact power too, right. 147 00:07:15,870 --> 00:07:18,790 So there's not actually any bagginess in the bounds, right. 148 00:07:18,790 --> 00:07:23,430 So when we do this right here, this makes q point to one 149 00:07:23,430 --> 00:07:26,070 pass the end of those baggy bounds. 150 00:07:26,070 --> 00:07:27,660 So just like in this example up here, 151 00:07:27,660 --> 00:07:30,930 this line is actually fine, but it will cause the high bit 152 00:07:30,930 --> 00:07:32,217 to be set in q, right. 153 00:07:32,217 --> 00:07:34,050 So when you come down here and reference it, 154 00:07:34,050 --> 00:07:35,775 then everything blows up and it's 155 00:07:35,775 --> 00:07:37,670 time to call in your insurance agent. 156 00:07:37,670 --> 00:07:40,420 So pretty straightforward? 157 00:07:40,420 --> 00:07:44,390 OK so, that's basically two examples 158 00:07:44,390 --> 00:07:46,790 that you can flavor for how baggy bounds works. 159 00:07:46,790 --> 00:07:49,465 As I mentioned in the last lecture, 160 00:07:49,465 --> 00:07:51,590 you don't actually have to instrument every pointer 161 00:07:51,590 --> 00:07:55,860 operation, if you can use static code analysis to figure out 162 00:07:55,860 --> 00:07:58,250 the particular set of pointer operations is safe. 163 00:07:58,250 --> 00:07:59,900 I'll defer further discussion of some 164 00:07:59,900 --> 00:08:01,600 of the static analysis [INAUDIBLE], 165 00:08:01,600 --> 00:08:04,133 but suffice it to say that you don't always 166 00:08:04,133 --> 00:08:08,657 have to have all this bit wise arithmetic that you 167 00:08:08,657 --> 00:08:12,086 have in some of the cases that we've examined before. 168 00:08:15,870 --> 00:08:19,272 And so another question that came up a lot in Piazza 169 00:08:19,272 --> 00:08:21,230 was, how does baggy bounds ensure compatibility 170 00:08:21,230 --> 00:08:24,830 with these preexisting, non-instrumented libraries, 171 00:08:24,830 --> 00:08:26,510 right. 172 00:08:26,510 --> 00:08:29,360 And so the Piazza idea behind how baggy bounds does that 173 00:08:29,360 --> 00:08:33,200 is, that when baggy bounds initializes the bounds tables, 174 00:08:33,200 --> 00:08:36,477 they set all the entries to be that bound of 31. 175 00:08:36,477 --> 00:08:37,938 So when we read the bounds table, 176 00:08:37,938 --> 00:08:40,510 each entry represents 2 to the power 177 00:08:40,510 --> 00:08:43,899 of that entry, the size of that particular pointer. 178 00:08:43,899 --> 00:08:45,739 So by initializing all those bounds 179 00:08:45,739 --> 00:08:49,692 of 31, what this allows us to do is automatically 180 00:08:49,692 --> 00:08:52,670 assume that each pointer from [INAUDIBLE] the code 181 00:08:52,670 --> 00:08:54,670 is going to have the largest bound possible, 2 182 00:08:54,670 --> 00:08:56,259 raised to the 31. 183 00:08:56,259 --> 00:08:58,812 So let me just give you a very simple example here 184 00:08:58,812 --> 00:09:00,770 that will hopefully make this a little clearer. 185 00:09:00,770 --> 00:09:05,060 So let's say that this over here is the memory 186 00:09:05,060 --> 00:09:09,370 space that we lose for heap. 187 00:09:12,220 --> 00:09:15,860 This is simple example, let's suppose that basically 188 00:09:15,860 --> 00:09:18,785 what this memory space [INAUDIBLE] two components. 189 00:09:18,785 --> 00:09:26,430 This is the heap, that is out by the unistrumented code. 190 00:09:31,042 --> 00:09:33,153 And then let's suppose that down here we 191 00:09:33,153 --> 00:09:40,563 have the heat that is allocated by the instrumented code. 192 00:09:44,892 --> 00:09:46,816 So what's baggy bounds going to do? 193 00:09:46,816 --> 00:09:51,041 So remember, baggy bounds has this notion of a slot size, 194 00:09:51,041 --> 00:09:51,540 right. 195 00:09:51,540 --> 00:09:53,467 So basically the slot size is 16, 196 00:09:53,467 --> 00:09:55,420 you only have entry for every sort 197 00:09:55,420 --> 00:09:57,619 of slot of size 16 over here. 198 00:09:57,619 --> 00:09:59,410 So basically the bounds table in this case, 199 00:09:59,410 --> 00:10:03,910 you can think of being set up into three 200 00:10:03,910 --> 00:10:06,080 places, sorry two places. 201 00:10:06,080 --> 00:10:12,190 So initially all of the bounds table, all the entries 202 00:10:12,190 --> 00:10:16,160 are initialized to 2 to the 30-- or sorry, to the 31. 203 00:10:16,160 --> 00:10:19,600 But then eventually as the instrument code 204 00:10:19,600 --> 00:10:23,740 runs it's actually going to use the baggy bounds 205 00:10:23,740 --> 00:10:28,960 algorithm to set these values for whatever 206 00:10:28,960 --> 00:10:33,711 should be appropriate for that particular [INAUDIBLE], right. 207 00:10:33,711 --> 00:10:35,252 So what ends happening is that if you 208 00:10:35,252 --> 00:10:39,608 did-- if instrumented code gets a pointer that comes from here, 209 00:10:39,608 --> 00:10:42,010 then those baggy bounds with each particular pointer 210 00:10:42,010 --> 00:10:45,110 will always be set to the largest possible value, 231. 211 00:10:45,110 --> 00:10:45,945 2 to the 31, right. 212 00:10:45,945 --> 00:10:47,320 Which means that it's going to be 213 00:10:47,320 --> 00:10:49,900 impossible for baggy bounds, entry of the code, 214 00:10:49,900 --> 00:10:52,052 to think that you've done an out of bound operation 215 00:10:52,052 --> 00:10:55,130 with that pointer that's coming from this uninstrumented 216 00:10:55,130 --> 00:10:57,090 library. 217 00:10:57,090 --> 00:10:59,264 So does that make sense? 218 00:10:59,264 --> 00:11:00,930 So the idea is that in instrumented code 219 00:11:00,930 --> 00:11:03,110 we're always going to be doing these comparisons 220 00:11:03,110 --> 00:11:06,720 with the pointers, but if we always set the bounds 221 00:11:06,720 --> 00:11:09,618 entries for uninstrumented pointer code 2 to the 31, 222 00:11:09,618 --> 00:11:13,000 you can never have a dereference error. 223 00:11:13,000 --> 00:11:17,560 OK so that's basically how we have this nice interoperability 224 00:11:17,560 --> 00:11:20,542 between the entry of the baggy bounds code in between 225 00:11:20,542 --> 00:11:24,320 a noninstrumented off the shelf legacy library's. 226 00:11:24,320 --> 00:11:27,010 So putting it all together, what does this all mean? 227 00:11:27,010 --> 00:11:28,830 So, we have this system here which 228 00:11:28,830 --> 00:11:31,330 is nice because it doesn't make the uninstrumented libraries 229 00:11:31,330 --> 00:11:34,828 blow up, but one problem is that we can't detect out 230 00:11:34,828 --> 00:11:37,400 of bounds pointers that were generated 231 00:11:37,400 --> 00:11:39,830 in the uninstrumented code, right. 232 00:11:39,830 --> 00:11:42,766 Because we're never going to set that high bit for example, 233 00:11:42,766 --> 00:11:44,790 if that [INAUDIBLE] pointer gets too big, 234 00:11:44,790 --> 00:11:46,590 or gets too small or anything like that. 235 00:11:46,590 --> 00:11:48,430 So we actually can't provide memory safety 236 00:11:48,430 --> 00:11:51,730 for operations that take place in uninstrumented code. 237 00:11:51,730 --> 00:11:54,770 You also can't detect when we pass an out of bounds 238 00:11:54,770 --> 00:11:58,300 pointer from instrumented code to uninstrumented code. 239 00:11:58,300 --> 00:11:59,842 Something insane could happen, right. 240 00:11:59,842 --> 00:12:01,758 Because remember if you had this out of bounds 241 00:12:01,758 --> 00:12:03,370 pulled it from the instrumented code 242 00:12:03,370 --> 00:12:05,210 it has that high bit set to 1, right. 243 00:12:05,210 --> 00:12:07,466 So it looks like it's super ginormous. 244 00:12:07,466 --> 00:12:09,924 Now we know if we just kept that code in instrumented code, 245 00:12:09,924 --> 00:12:11,507 we might clear that flag at some point 246 00:12:11,507 --> 00:12:13,340 if it comes back in bounds. 247 00:12:13,340 --> 00:12:15,391 But if we just pass this ginormous address 248 00:12:15,391 --> 00:12:17,240 to uninstrumented code, then who knows, 249 00:12:17,240 --> 00:12:20,000 it may try to dereference it, it may do something crazy. 250 00:12:20,000 --> 00:12:22,297 It may even bring that pointer back in bounds, 251 00:12:22,297 --> 00:12:23,880 but we would never have an opportunity 252 00:12:23,880 --> 00:12:25,990 to clear that high bit, right. 253 00:12:25,990 --> 00:12:27,854 So you can come up-- you still may come up 254 00:12:27,854 --> 00:12:30,040 with some inter-op issues there, even if we 255 00:12:30,040 --> 00:12:34,190 use this scheme over here. 256 00:12:34,190 --> 00:12:38,911 OK, so that's essentially how baggy bounds works on a 32-- 257 00:12:38,911 --> 00:12:39,702 you got a question? 258 00:12:39,702 --> 00:12:41,951 AUDIENCE: Yeah, so if you have a instrumented coding 259 00:12:41,951 --> 00:12:43,799 meets like allocated memory, is it 260 00:12:43,799 --> 00:12:46,460 using the same malloc that the attributing code is using, or? 261 00:12:46,460 --> 00:12:48,001 PROFESSOR: Yeah so it's a bit subtle. 262 00:12:48,001 --> 00:12:50,295 So like in this case here, it's like very stark 263 00:12:50,295 --> 00:12:53,300 what's going on, because there's just two regions, one of which 264 00:12:53,300 --> 00:12:55,294 is used by each set of things. 265 00:12:55,294 --> 00:12:57,784 So it actually depends on the if they use [INAUDIBLE] 266 00:12:57,784 --> 00:12:58,617 and stuff like that. 267 00:12:58,617 --> 00:13:01,768 You can also imagine that like in C++ [INAUDIBLE] for example, 268 00:13:01,768 --> 00:13:03,760 you can define your own allocator, right. 269 00:13:03,760 --> 00:13:06,748 So it kind of depends [INAUDIBLE]. 270 00:13:06,748 --> 00:13:10,732 AUDIENCE: [INAUDIBLE] input the same, 271 00:13:10,732 --> 00:13:13,720 how does the allocator know whether or not 272 00:13:13,720 --> 00:13:15,627 to set 31 or [INAUDIBLE]. 273 00:13:15,627 --> 00:13:17,960 PROFESSOR: Yeah so at the lower level, typically the way 274 00:13:17,960 --> 00:13:19,543 that these allocation algorithms work, 275 00:13:19,543 --> 00:13:23,139 is that you call unknown system [INAUDIBLE] or something 276 00:13:23,139 --> 00:13:24,680 like that, sort of move a pointer up. 277 00:13:24,680 --> 00:13:27,397 So you can imagine if you have multiple allocators, all trying 278 00:13:27,397 --> 00:13:29,290 to allocate memory, they each have 279 00:13:29,290 --> 00:13:32,316 their own chunk of memory they reserve for themselves 280 00:13:32,316 --> 00:13:33,460 basically, right. 281 00:13:33,460 --> 00:13:36,251 So in real life it may be more fragmented than this, 282 00:13:36,251 --> 00:13:39,730 that's essentially on a high level, how it works. 283 00:13:39,730 --> 00:13:43,130 OK so this was a baggy bounds on a 32-bit system. 284 00:13:43,130 --> 00:13:45,516 So as you all know 64-bit systems are the bees 285 00:13:45,516 --> 00:13:47,910 knees these days, so how does baggy bounds 286 00:13:47,910 --> 00:13:50,276 work on those systems? 287 00:13:50,276 --> 00:13:51,900 Well, in those systems you can actually 288 00:13:51,900 --> 00:13:55,170 get rid of the bounds table, because we can actually 289 00:13:55,170 --> 00:13:58,871 store some information about the bounds, from the pointer 290 00:13:58,871 --> 00:13:59,370 itself. 291 00:14:02,032 --> 00:14:06,514 So imagine we're going to look at a regular pointer 292 00:14:06,514 --> 00:14:09,010 in a baggy bounds system. 293 00:14:09,010 --> 00:14:11,638 So we can use it, like this. 294 00:14:15,110 --> 00:14:18,330 So we can-- if the pointer's in bounds, 295 00:14:18,330 --> 00:14:21,690 we can basically just set the first 21 bits to 0. 296 00:14:21,690 --> 00:14:24,340 We can put the size in these 5 bits here. 297 00:14:24,340 --> 00:14:27,610 And once again this is representing the log base 2 298 00:14:27,610 --> 00:14:28,770 at the size here. 299 00:14:28,770 --> 00:14:31,970 And then we have here, in the remaining 38 bits, 300 00:14:31,970 --> 00:14:33,662 just the regular address bits. 301 00:14:33,662 --> 00:14:35,370 Now the reason why this doesn't massively 302 00:14:35,370 --> 00:14:37,850 curtail the address size of the program you use, 303 00:14:37,850 --> 00:14:39,960 is that a lot of these high order bits, 304 00:14:39,960 --> 00:14:41,908 the operating system and-or the hardware, 305 00:14:41,908 --> 00:14:45,317 doesn't let a application use, for various reasons, right. 306 00:14:45,317 --> 00:14:47,180 So as it turns out, we're not dramatically 307 00:14:47,180 --> 00:14:49,268 shrinking the amount of [INAUDIBLE] application 308 00:14:49,268 --> 00:14:51,062 you use in the system. 309 00:14:51,062 --> 00:14:52,894 This is what a regular pointer looks like. 310 00:14:52,894 --> 00:14:53,810 Now what happens when we only have 311 00:14:53,810 --> 00:14:55,280 one of these out of bounds pointers? 312 00:14:55,280 --> 00:14:57,290 Well, in a 32-bit system all we can do basically 313 00:14:57,290 --> 00:14:59,570 is just set that high order bit and you just 314 00:14:59,570 --> 00:15:02,990 hope that thing never got beyond a 1/2 a slot away 315 00:15:02,990 --> 00:15:05,119 from it's base. 316 00:15:05,119 --> 00:15:08,053 But now that we have all this extra address space here, 317 00:15:08,053 --> 00:15:13,760 you can actually put the out of bounds offset directly 318 00:15:13,760 --> 00:15:14,912 in this pointer. 319 00:15:18,020 --> 00:15:20,075 So we can do something like this. 320 00:15:25,230 --> 00:15:29,300 So we can have 13 bits here for the offset, right, 321 00:15:29,300 --> 00:15:30,460 the out of bound offset. 322 00:15:30,460 --> 00:15:33,740 How far away is this out of bounds pointer, from the place 323 00:15:33,740 --> 00:15:35,050 where it should be? 324 00:15:35,050 --> 00:15:39,280 And then once again you can put the actual size 325 00:15:39,280 --> 00:15:42,240 of the referred object here. 326 00:15:42,240 --> 00:15:44,112 This will be 0 once again. 327 00:15:44,112 --> 00:15:48,740 And this will be the real address base here. 328 00:15:48,740 --> 00:15:51,430 And so this may be reminiscent to you 329 00:15:51,430 --> 00:15:53,290 of some type of fact pointer representation, 330 00:15:53,290 --> 00:15:55,190 but there's a couple of advantages 331 00:15:55,190 --> 00:15:57,800 here, now that we're moving in the 64-bit world. 332 00:15:57,800 --> 00:16:00,870 So first of all, you'll note that these tag pointers, 333 00:16:00,870 --> 00:16:04,000 these are the regular size of a regular pointer, right. 334 00:16:04,000 --> 00:16:07,860 Pointer's are still just 64-bits wide in both of these setups. 335 00:16:07,860 --> 00:16:10,180 So that's nice because that means for example, 336 00:16:10,180 --> 00:16:13,280 that means and rights to that pointer are time. 337 00:16:13,280 --> 00:16:14,905 Unlike in traditional fat finger world, 338 00:16:14,905 --> 00:16:16,779 where you actually have to use multiple words 339 00:16:16,779 --> 00:16:18,042 represent that fat pointer. 340 00:16:18,042 --> 00:16:19,125 So that's nice. 341 00:16:19,125 --> 00:16:22,570 And also note that we can trivially ask these things, 342 00:16:22,570 --> 00:16:24,300 uninstrumented code, because they 343 00:16:24,300 --> 00:16:27,312 work and are the same size as regular pointers. 344 00:16:27,312 --> 00:16:29,270 We can put these things in structs for example, 345 00:16:29,270 --> 00:16:32,080 and the size of those structs won't change. 346 00:16:32,080 --> 00:16:36,470 So this is very nice if we can work in that 64-bit world. 347 00:16:36,470 --> 00:16:39,166 So does that all make sense? 348 00:16:39,166 --> 00:16:42,798 AUDIENCE: So why are there eight 0-bits [INAUDIBLE] 349 00:16:42,798 --> 00:16:43,680 pointer there? 350 00:16:43,680 --> 00:16:47,550 Where like the 5 size bits previously weren't. 351 00:16:47,550 --> 00:16:49,590 PROFESSOR: So you're talking about down here? 352 00:16:49,590 --> 00:16:50,965 AUDIENCE: Yeah, is there a reason 353 00:16:50,965 --> 00:16:53,320 why we can't just store a [INAUDIBLE] 354 00:16:53,320 --> 00:16:54,935 if we're like six 0-bits there and had 355 00:16:54,935 --> 00:16:57,720 more bits for the offset, like why is the number 8? 356 00:16:57,720 --> 00:17:00,475 PROFESSOR: So I think so in some cases 357 00:17:00,475 --> 00:17:02,808 there are certain line issues that we have to work with. 358 00:17:02,808 --> 00:17:05,825 The [INAUDIBLE] issue is to deal with if the bits are higher. 359 00:17:05,825 --> 00:17:07,325 I don't think, in principle, there's 360 00:17:07,325 --> 00:17:08,866 any reason why you couldn't read some 361 00:17:08,866 --> 00:17:10,089 of these things [INAUDIBLE]. 362 00:17:10,089 --> 00:17:11,589 Well there may be some hard versions 363 00:17:11,589 --> 00:17:13,128 that I'm not thinking of right now, 364 00:17:13,128 --> 00:17:15,003 but [INAUDIBLE] some of these would have to 0 365 00:17:15,003 --> 00:17:17,930 or otherwise the hardware's going to cause a problem. 366 00:17:21,079 --> 00:17:23,310 Any other questions? 367 00:17:23,310 --> 00:17:26,380 OK so, next thing are you wondering 368 00:17:26,380 --> 00:17:28,550 is, can you still launch a buffer 369 00:17:28,550 --> 00:17:30,355 overflows in the baggy bounds system, 370 00:17:30,355 --> 00:17:32,480 obviously because I gave you another paper to read, 371 00:17:32,480 --> 00:17:34,220 so clearly this thing, this doesn't solve all the problems, 372 00:17:34,220 --> 00:17:34,970 right? 373 00:17:34,970 --> 00:17:36,610 So one problem you might run into 374 00:17:36,610 --> 00:17:38,735 is that if you have uninstrumented code once again, 375 00:17:38,735 --> 00:17:41,510 we can't detect any problems in uninstrumented code. 376 00:17:41,510 --> 00:17:44,550 You could also encounter memory vulnerabilities 377 00:17:44,550 --> 00:17:47,380 that come about from the dynamic memory allocation system. 378 00:17:47,380 --> 00:17:48,921 So if you can remember in the lecture 379 00:17:48,921 --> 00:17:52,990 we looked at this weird free malloc weird pointer 380 00:17:52,990 --> 00:17:54,090 thing that took place. 381 00:17:54,090 --> 00:17:55,980 Baggy bounds won't necessarily prevent you 382 00:17:55,980 --> 00:17:57,500 from some of that stuff. 383 00:17:57,500 --> 00:18:00,130 We also discussed last lecture, where 384 00:18:00,130 --> 00:18:02,654 the fact that code pointers do not have bounds 385 00:18:02,654 --> 00:18:04,260 associated with them, right. 386 00:18:04,260 --> 00:18:07,240 So now you have struct that has a buffer at the bottom, 387 00:18:07,240 --> 00:18:09,140 it has a function pointer up top, 388 00:18:09,140 --> 00:18:12,050 if you have a buffer overflow in to that function pointer, 389 00:18:12,050 --> 00:18:12,550 right. 390 00:18:12,550 --> 00:18:14,220 Let's say that buffer overflow is still 391 00:18:14,220 --> 00:18:15,280 within the baggy bounds. 392 00:18:15,280 --> 00:18:17,910 So you've overridden that function pointer. 393 00:18:17,910 --> 00:18:20,020 We would try to execute that function pointer, 394 00:18:20,020 --> 00:18:22,100 it could be pointed at something for, 395 00:18:22,100 --> 00:18:23,840 attack a control piece of memory. 396 00:18:23,840 --> 00:18:24,950 OK, and bounds won't help with that, 397 00:18:24,950 --> 00:18:26,814 because there's no bounds associate with function 398 00:18:26,814 --> 00:18:27,313 pointers. 399 00:18:30,076 --> 00:18:36,562 And so in general, what are the cost's of baggy bounds? 400 00:18:36,562 --> 00:18:38,860 So there are essentially four. 401 00:18:38,860 --> 00:18:43,120 So the first cost is space, right. 402 00:18:43,120 --> 00:18:44,495 So if you're using a fat pointer, 403 00:18:44,495 --> 00:18:47,120 obviously you've got to make pointers bigger. 404 00:18:47,120 --> 00:18:49,821 But if you're using the baggy bounds system that we just 405 00:18:49,821 --> 00:18:52,112 discussed, you've got to store the bounds table, right. 406 00:18:52,112 --> 00:18:55,600 And so the bounds table has that slot size 407 00:18:55,600 --> 00:18:58,090 which allows you to control how big that bounds table is, 408 00:18:58,090 --> 00:19:02,140 but still you may end up using [INAUDIBLE] memory for that. 409 00:19:02,140 --> 00:19:08,370 You've also got the CPU overhead of doing all of the pointer 410 00:19:08,370 --> 00:19:09,800 instrumentation, right. 411 00:19:09,800 --> 00:19:13,420 So for every, or close to every pointer thing that you do, 412 00:19:13,420 --> 00:19:16,880 you got to check these bounds using those shift operations 413 00:19:16,880 --> 00:19:18,040 and things like that. 414 00:19:18,040 --> 00:19:21,140 So that's going to slow your program down. 415 00:19:21,140 --> 00:19:26,890 There's also this problem with false alarms, right. 416 00:19:26,890 --> 00:19:29,624 So as we discussed, it may be the case 417 00:19:29,624 --> 00:19:31,540 that a program generates out of bound pointers 418 00:19:31,540 --> 00:19:33,360 but never tries to dereference it, right. 419 00:19:33,360 --> 00:19:35,520 Strictly speaking that's not an issue. 420 00:19:35,520 --> 00:19:37,560 The baggy bounds will flag the creation 421 00:19:37,560 --> 00:19:39,250 of those out of bounds pointers, if they 422 00:19:39,250 --> 00:19:42,660 get beyond a 1/2 a slot size, at least in the 32-bit solution, 423 00:19:42,660 --> 00:19:43,160 right. 424 00:19:43,160 --> 00:19:45,460 And so what you'll see with a lot of security tools, 425 00:19:45,460 --> 00:19:48,362 is that false alarms really reduce the likelihood 426 00:19:48,362 --> 00:19:50,320 that people are going to use your tools, right. 427 00:19:50,320 --> 00:19:52,330 Because in practice we would all hope 428 00:19:52,330 --> 00:19:54,547 that we care about security, but actually 429 00:19:54,547 --> 00:19:55,630 what do people care about? 430 00:19:55,630 --> 00:19:57,720 They want to be able to upload their silly Facebook photos 431 00:19:57,720 --> 00:19:59,070 and life things, and they want to be 432 00:19:59,070 --> 00:20:01,130 able to make things go fast and stuff like that. 433 00:20:01,130 --> 00:20:03,160 So you really want your security tools 434 00:20:03,160 --> 00:20:07,240 to probably have less coverage of finding bugs, 435 00:20:07,240 --> 00:20:09,520 but actually have 0 false alarms. 436 00:20:09,520 --> 00:20:12,230 As opposed to catching all types of security vulnerabilities, 437 00:20:12,230 --> 00:20:14,020 but then maybe having some false alarms 438 00:20:14,020 --> 00:20:16,790 that are going to irritate developers, or irritate users. 439 00:20:16,790 --> 00:20:19,040 And the other costs that you have for this is finally, 440 00:20:19,040 --> 00:20:25,770 is that you need compiler support, right. 441 00:20:25,770 --> 00:20:27,640 Which can actually end up being nontrivial, 442 00:20:27,640 --> 00:20:28,570 because you have to go in there, you 443 00:20:28,570 --> 00:20:30,360 have to add all the instrumentation, 444 00:20:30,360 --> 00:20:32,610 crawl the pointer checks, and so on ans so forth. 445 00:20:32,610 --> 00:20:35,330 So those are basically the cost of these bounds checking 446 00:20:35,330 --> 00:20:37,000 approaches. 447 00:20:37,000 --> 00:20:42,120 So that concludes the discussion of baggy bounds. 448 00:20:42,120 --> 00:20:45,010 And so now we can actually think about a two other mitigation 449 00:20:45,010 --> 00:20:46,570 strategies for buffer overflows. 450 00:20:46,570 --> 00:20:49,600 They're actually much simpler to explain and understand. 451 00:20:49,600 --> 00:20:55,090 So one of these approaches is called a non-executable memory. 452 00:21:00,570 --> 00:21:04,600 And the basic idea is that the paging hardware 453 00:21:04,600 --> 00:21:08,830 is going to specify 3-bits for each page 454 00:21:08,830 --> 00:21:12,064 that you have in memory, read, write and execute, right. 455 00:21:12,064 --> 00:21:13,980 Can the program read that memory, write to it, 456 00:21:13,980 --> 00:21:14,720 execute it. 457 00:21:14,720 --> 00:21:16,380 The first 2-bits are old, they've 458 00:21:16,380 --> 00:21:18,600 been around for a while, that last bit is actually 459 00:21:18,600 --> 00:21:19,764 a fairly new construction. 460 00:21:19,764 --> 00:21:21,430 And so the idea is that you can actually 461 00:21:21,430 --> 00:21:24,790 make the stack non-executable, right. 462 00:21:24,790 --> 00:21:26,960 So if you make the stack non-executable 463 00:21:26,960 --> 00:21:29,110 that means that the adversary can't run code 464 00:21:29,110 --> 00:21:31,440 just by pointing-- by creating that shell code 465 00:21:31,440 --> 00:21:34,840 and then sort of jumping to someplace in that buffer. 466 00:21:34,840 --> 00:21:39,470 And so what a lot of systems do, is they actually specify 467 00:21:39,470 --> 00:21:43,190 a policy like this. 468 00:21:43,190 --> 00:21:46,690 So right exclusive or x, which means that if you have 469 00:21:46,690 --> 00:21:49,730 a particular page, you can either write to it, 470 00:21:49,730 --> 00:21:52,070 or you can treat it as executable code, 471 00:21:52,070 --> 00:21:53,542 but you cannot do both. 472 00:21:53,542 --> 00:21:55,000 OK and so that once again, is going 473 00:21:55,000 --> 00:21:56,450 to prevent the attacker from just 474 00:21:56,450 --> 00:21:58,250 putting executable code in the stack 475 00:21:58,250 --> 00:22:00,380 and then going straight to it. 476 00:22:00,380 --> 00:22:02,890 So this is-- should be pretty straightforward, right. 477 00:22:02,890 --> 00:22:06,850 So we've removed, at the hardware level, this attack 478 00:22:06,850 --> 00:22:09,920 vector of the attacker putting executable code in the stack. 479 00:22:09,920 --> 00:22:11,210 So what's nice about this? 480 00:22:11,210 --> 00:22:14,670 Well potentially this works without any changes 481 00:22:14,670 --> 00:22:16,190 to the application, right. 482 00:22:16,190 --> 00:22:18,610 This is all taken place at the hardware level 483 00:22:18,610 --> 00:22:20,660 and at the OS level, with the OS just 484 00:22:20,660 --> 00:22:23,350 making sure the pages are protected with these bits, OK. 485 00:22:23,350 --> 00:22:24,725 So that's very, very nuts, right. 486 00:22:24,725 --> 00:22:27,183 Because you don;t have to worry about this compiler support 487 00:22:27,183 --> 00:22:28,210 issue we had over here. 488 00:22:28,210 --> 00:22:30,250 The other nice thing is that, as I mentioned 489 00:22:30,250 --> 00:22:32,210 in the last lecture, the hardware's 490 00:22:32,210 --> 00:22:35,320 always watching you, even though the OS is not, right. 491 00:22:35,320 --> 00:22:37,520 So these bits being said over here, 492 00:22:37,520 --> 00:22:40,060 you know they're looked at and verified 493 00:22:40,060 --> 00:22:42,415 for correctness at every memory reference 494 00:22:42,415 --> 00:22:43,850 that you make by the code. 495 00:22:43,850 --> 00:22:46,930 That's a very nice aspect of this too. 496 00:22:46,930 --> 00:22:49,460 Now one disadvantage of this system 497 00:22:49,460 --> 00:22:52,260 though, is that it makes it harder for an application 498 00:22:52,260 --> 00:22:56,990 to dynamically generate code, in benign or benevolent cases. 499 00:22:56,990 --> 00:22:59,880 And the best example of that is, the just-in-time 500 00:22:59,880 --> 00:23:02,480 compilers that we discussed from last lecture, right. 501 00:23:02,480 --> 00:23:04,150 So how is it that you can go to a web 502 00:23:04,150 --> 00:23:06,100 page and your JavaScript code executes fast. 503 00:23:06,100 --> 00:23:07,650 It downloads that JavaScript source, 504 00:23:07,650 --> 00:23:09,826 it initially probably starts just interpreting it, 505 00:23:09,826 --> 00:23:11,200 but then at some point it's going 506 00:23:11,200 --> 00:23:12,999 to find some hot path, some hot loop 507 00:23:12,999 --> 00:23:14,790 and then it's going to dynamically generate 508 00:23:14,790 --> 00:23:17,884 x86 machine code and execute that directly, right. 509 00:23:17,884 --> 00:23:20,550 But to get that to work you have to be able to dynamically write 510 00:23:20,550 --> 00:23:23,400 code to a page. 511 00:23:23,400 --> 00:23:25,990 So there's some ways you can get around this for example, 512 00:23:25,990 --> 00:23:28,620 you could imagine that the just-in-time compiler initially 513 00:23:28,620 --> 00:23:31,580 sets the write bit and then it removes the write bit, 514 00:23:31,580 --> 00:23:32,950 then it sets the execute bits. 515 00:23:32,950 --> 00:23:34,770 There are some ways that you can get around that, 516 00:23:34,770 --> 00:23:36,603 but it can be a little bit tricky sometimes. 517 00:23:36,603 --> 00:23:39,227 On a higher level, that's how non-executable memory works, 518 00:23:39,227 --> 00:23:40,310 pretty easy to understand. 519 00:23:40,310 --> 00:23:44,158 AUDIENCE: What is the definition of like executable 520 00:23:44,158 --> 00:23:44,772 instructions? 521 00:23:44,772 --> 00:23:46,563 So if you change the attenuator [INAUDIBLE] 522 00:23:46,563 --> 00:23:47,525 it's not considered a executable instruction. 523 00:23:47,525 --> 00:23:49,410 PROFESSOR: Well basically no. 524 00:23:49,410 --> 00:23:53,220 Can you set like the instruction pointer register to that value. 525 00:23:53,220 --> 00:23:56,240 In other words, can you-- if you have a bunch of memory pages, 526 00:23:56,240 --> 00:23:58,580 can you actually set EIP there and actually start 527 00:23:58,580 --> 00:23:59,979 executing code from that page. 528 00:23:59,979 --> 00:24:00,520 AUDIENCE: Ah. 529 00:24:03,520 --> 00:24:07,480 PROFESSOR: OK, so that is nonexecutable memory. 530 00:24:07,480 --> 00:24:09,710 And so another technique you might 531 00:24:09,710 --> 00:24:12,990 imagine for protecting against a buffer overflows 532 00:24:12,990 --> 00:24:19,845 is using a randomized addresses or address spaces. 533 00:24:26,410 --> 00:24:30,270 And so the observation here is, that a lot 534 00:24:30,270 --> 00:24:35,080 of the attacks that we've discussed so far 535 00:24:35,080 --> 00:24:39,590 use hard coded addresses, right. 536 00:24:39,590 --> 00:24:42,140 And so if you think about a lot of the attacks 537 00:24:42,140 --> 00:24:44,610 you've been working on in your lab, how does that work? 538 00:24:44,610 --> 00:24:47,140 You open up the program in GDB, you find out 539 00:24:47,140 --> 00:24:49,840 the location of some things, you may create some shell code 540 00:24:49,840 --> 00:24:52,700 that actually has some hard coded addresses in there, 541 00:24:52,700 --> 00:24:53,200 right. 542 00:24:53,200 --> 00:24:55,390 So the idea behind the randomized address base 543 00:24:55,390 --> 00:24:55,890 is simple. 544 00:24:55,890 --> 00:25:03,160 Basically you want to make it difficult for the attacker 545 00:25:03,160 --> 00:25:04,205 to guess addresses. 546 00:25:08,084 --> 00:25:09,500 So there's a couple different ways 547 00:25:09,500 --> 00:25:11,230 you could think about doing this, right. 548 00:25:11,230 --> 00:25:13,530 So one idea is that you can imagine having 549 00:25:13,530 --> 00:25:15,260 stack randomization, right. 550 00:25:15,260 --> 00:25:17,850 So imagine that from here to here, 551 00:25:17,850 --> 00:25:20,370 this is the entire virtual memory space of the program, 552 00:25:20,370 --> 00:25:20,870 right. 553 00:25:20,870 --> 00:25:22,870 As we described this stuff to you so far, 554 00:25:22,870 --> 00:25:24,690 basically the stack always starts 555 00:25:24,690 --> 00:25:27,270 with this particular place up here, always goes down, 556 00:25:27,270 --> 00:25:30,360 right, and the program codes down here and the heap always 557 00:25:30,360 --> 00:25:31,470 goes up here. 558 00:25:31,470 --> 00:25:35,030 And all these seg-- all of these segments, the stack, the heap, 559 00:25:35,030 --> 00:25:38,350 and the program code, they all start at a well known location. 560 00:25:38,350 --> 00:25:40,950 So imagine for example, like if my lecture notes here 561 00:25:40,950 --> 00:25:41,695 are the stack. 562 00:25:41,695 --> 00:25:44,070 You can imagine instead of the stack always starting here 563 00:25:44,070 --> 00:25:46,780 at this known location, maybe you start it here, 564 00:25:46,780 --> 00:25:47,947 maybe you start it here. 565 00:25:47,947 --> 00:25:49,280 Somewhere else like that, right. 566 00:25:49,280 --> 00:25:51,900 Similarly you can imagine that maybe the program code which 567 00:25:51,900 --> 00:25:53,760 used to always start down here, maybe we 568 00:25:53,760 --> 00:25:56,616 start it up here, or down here, or something like that, right. 569 00:25:56,616 --> 00:25:58,490 So the idea now is that if you, the attacker, 570 00:25:58,490 --> 00:26:01,075 control one of these binary's, you can look in GDB 571 00:26:01,075 --> 00:26:02,867 and figure out where all these offsets are, 572 00:26:02,867 --> 00:26:05,075 but they're not actually going to help you figure out 573 00:26:05,075 --> 00:26:07,190 where those offsets are in the real code that's 574 00:26:07,190 --> 00:26:09,190 running on the server, right. 575 00:26:09,190 --> 00:26:12,320 So that's the basic idea behind these randomized address spaces 576 00:26:12,320 --> 00:26:13,510 there. 577 00:26:13,510 --> 00:26:15,312 And so this takes advantage of the fact 578 00:26:15,312 --> 00:26:17,020 that a lot of the code that you generate, 579 00:26:17,020 --> 00:26:19,740 doesn't have to be loaded into a specific place in memory, 580 00:26:19,740 --> 00:26:20,240 right. 581 00:26:20,240 --> 00:26:22,698 So unless you're writing like a device driver, or something 582 00:26:22,698 --> 00:26:25,350 like, that maybe is interacting with some hardware that 583 00:26:25,350 --> 00:26:29,670 requires this particular address to be 584 00:26:29,670 --> 00:26:32,370 belong in this particular buffer so it can copy information in. 585 00:26:32,370 --> 00:26:34,562 If you're not doing stuff like that then typically 586 00:26:34,562 --> 00:26:36,020 your codes going to be relocatable. 587 00:26:36,020 --> 00:26:40,000 So this approach will work very nicely with that kind of stuff. 588 00:26:40,000 --> 00:26:43,740 So once again the question is, can you exploit this? 589 00:26:43,740 --> 00:26:45,196 Obviously the answer is still yes. 590 00:26:45,196 --> 00:26:47,070 There's a couple different ways you can do it 591 00:26:47,070 --> 00:26:50,460 as we'll discuss later today in the [INAUDIBLE] paper, 592 00:26:50,460 --> 00:26:53,779 the attacker can actually extract randomness, right. 593 00:26:53,779 --> 00:26:55,570 And so in general that's how you defeat all 594 00:26:55,570 --> 00:26:56,850 these randomized approaches. 595 00:26:56,850 --> 00:26:58,857 You make them unrandom, by either finding out 596 00:26:58,857 --> 00:27:00,690 the random seed that the attacker was doing, 597 00:27:00,690 --> 00:27:03,740 or by somehow leveraging the fact that the attacker leaks 598 00:27:03,740 --> 00:27:07,040 information about the randomized locations of these things. 599 00:27:10,520 --> 00:27:12,020 And another thing that's interesting 600 00:27:12,020 --> 00:27:15,250 is that for a lot of the attacks we've discussed so far, 601 00:27:15,250 --> 00:27:18,060 we've basically been using these sort of hard coded addresses, 602 00:27:18,060 --> 00:27:21,300 but note that the attacker may not necessarily 603 00:27:21,300 --> 00:27:23,740 care about jumping to a specific address. 604 00:27:23,740 --> 00:27:26,160 Or there's this attack called a heap attack, which 605 00:27:26,160 --> 00:27:29,260 is actually pretty hilarious if you're a bad person, I suppose. 606 00:27:29,260 --> 00:27:32,050 So the way that this heap attack works 607 00:27:32,050 --> 00:27:34,160 is, that the attacker essentially 608 00:27:34,160 --> 00:27:37,280 just starts dynamically allocating a ton of shell code 609 00:27:37,280 --> 00:27:39,341 and just stuffs it randomly in memory, right. 610 00:27:39,341 --> 00:27:41,007 This is particularly effective if you're 611 00:27:41,007 --> 00:27:44,870 using like a dynamically high level language like JavaScript 612 00:27:44,870 --> 00:27:45,490 let's say. 613 00:27:45,490 --> 00:27:46,910 So the tag reader is sitting in a tight loop 614 00:27:46,910 --> 00:27:49,201 and just generate a bunch of shell code strings, right. 615 00:27:49,201 --> 00:27:51,750 And you just fill the heap with all these shell code 616 00:27:51,750 --> 00:27:53,140 strings, right. 617 00:27:53,140 --> 00:27:55,820 Now the attacker maybe cannot figure out where the exact 618 00:27:55,820 --> 00:27:58,340 location is of each of the shell code strings, 619 00:27:58,340 --> 00:28:02,330 but if you've allocated 10s of megabytes of shell code strings 620 00:28:02,330 --> 00:28:04,160 and then just do a random jump, right. 621 00:28:04,160 --> 00:28:06,800 If you could somehow control one of these ret pointers, 622 00:28:06,800 --> 00:28:09,914 then hey, maybe you'll land in shell code, right. 623 00:28:09,914 --> 00:28:11,330 And one trick you can actually use 624 00:28:11,330 --> 00:28:14,200 is this thing called NOP sleds, which is also pretty hilarious. 625 00:28:14,200 --> 00:28:18,590 So imagine that if you have a shell code string, then 626 00:28:18,590 --> 00:28:20,640 it may not work out if you jump to a random place 627 00:28:20,640 --> 00:28:22,720 in that shell code string, because it may not 628 00:28:22,720 --> 00:28:24,330 set the attack up correctly. 629 00:28:24,330 --> 00:28:27,250 But maybe this stuff that your spewing to the heap, 630 00:28:27,250 --> 00:28:30,876 is basically just a ton of NOPs and then at the very, very end 631 00:28:30,876 --> 00:28:32,240 you have the shell code, right. 632 00:28:32,240 --> 00:28:33,910 This is actually quite clever right, 633 00:28:33,910 --> 00:28:36,690 because this means that now you can actually goof up 634 00:28:36,690 --> 00:28:38,182 the exact place where you jump. 635 00:28:38,182 --> 00:28:39,890 If you jump into another one of these NOP 636 00:28:39,890 --> 00:28:42,431 things just go boom, boom, boom, boom, boom, boom, boom, then 637 00:28:42,431 --> 00:28:43,920 you hit the shell code, right. 638 00:28:43,920 --> 00:28:46,110 So it's like these are the people that you probably 639 00:28:46,110 --> 00:28:47,090 see on the team. 640 00:28:47,090 --> 00:28:49,048 They're inventing these types of things, right. 641 00:28:49,048 --> 00:28:49,980 This is a problem. 642 00:28:49,980 --> 00:28:51,956 So that's another way to get around some 643 00:28:51,956 --> 00:28:53,330 of this randomization stuff, just 644 00:28:53,330 --> 00:28:55,850 by making your codes randomization resilient, 645 00:28:55,850 --> 00:28:58,880 if that makes sense. 646 00:28:58,880 --> 00:29:01,493 OK so that's basically a discussion of some 647 00:29:01,493 --> 00:29:03,120 of the types of randomness you can use. 648 00:29:03,120 --> 00:29:05,400 There's also some wacky ideas that people have had too. 649 00:29:05,400 --> 00:29:06,340 So now you know that when you want 650 00:29:06,340 --> 00:29:08,020 to make a system call for example, 651 00:29:08,020 --> 00:29:11,275 you use this syscall libc function 652 00:29:11,275 --> 00:29:13,157 and you basically pass any unique number that 653 00:29:13,157 --> 00:29:15,490 represents the system call that you want to make, right. 654 00:29:15,490 --> 00:29:19,150 So maybe four is seven and maybe sleep is eight, or something 655 00:29:19,150 --> 00:29:20,950 like that, right. 656 00:29:20,950 --> 00:29:23,280 So what that means is that if the attacker can somehow 657 00:29:23,280 --> 00:29:26,730 figure out the address of that syscall instruction 658 00:29:26,730 --> 00:29:29,420 and jump to it somehow, he or she can actually just supply 659 00:29:29,420 --> 00:29:32,972 the system call number that they want to invoke directly, right. 660 00:29:32,972 --> 00:29:35,180 So you could imagine that each time the program runs, 661 00:29:35,180 --> 00:29:39,290 you actually create a dynamic assignment of syscall numbers 662 00:29:39,290 --> 00:29:40,951 to actual syscalls, right. 663 00:29:40,951 --> 00:29:42,950 To make it harder for the attacker to get stuff. 664 00:29:42,950 --> 00:29:45,250 There's even some very avant garde proposals 665 00:29:45,250 --> 00:29:48,300 to change the hardware such that the hardware actually 666 00:29:48,300 --> 00:29:51,870 contains an xor key, that is used to dynamically xor 667 00:29:51,870 --> 00:29:53,130 instructions, right. 668 00:29:53,130 --> 00:29:55,500 Imagine every time you compile the program, all 669 00:29:55,500 --> 00:29:58,570 of the instruction codes that's the xor of some key, right. 670 00:29:58,570 --> 00:30:00,590 That key is put into that hardware register 671 00:30:00,590 --> 00:30:02,370 when you initially load the program 672 00:30:02,370 --> 00:30:04,450 and then whenever you execute an instruction, 673 00:30:04,450 --> 00:30:06,620 the hardware automatically xor's it, 674 00:30:06,620 --> 00:30:08,980 before you continue executing that instruction, right. 675 00:30:08,980 --> 00:30:10,771 So what's nice about that is, that now even 676 00:30:10,771 --> 00:30:12,700 if the attacker can generate the shell code, 677 00:30:12,700 --> 00:30:14,450 the attacker doesn't know that key, right. 678 00:30:14,450 --> 00:30:16,074 So it's very difficult for the attacker 679 00:30:16,074 --> 00:30:18,020 to figure out what exactly to put into memory. 680 00:30:18,020 --> 00:30:19,520 AUDIENCE: But if he can get the code 681 00:30:19,520 --> 00:30:23,219 and he also instructions he can xor it back 682 00:30:23,219 --> 00:30:24,510 to the instruction [INAUDIBLE]. 683 00:30:24,510 --> 00:30:25,140 PROFESSOR;Oh yeah. 684 00:30:25,140 --> 00:30:26,810 This is always a canonical problem, right. 685 00:30:26,810 --> 00:30:28,360 So it's like what if someone does this? 686 00:30:28,360 --> 00:30:29,377 So that's exactly right. 687 00:30:29,377 --> 00:30:31,960 So this is somewhat similar to what happens in the BROP attack 688 00:30:31,960 --> 00:30:35,290 where, essentially we've sort of randomized where locations are, 689 00:30:35,290 --> 00:30:37,270 but the attacker can do probes, right. 690 00:30:37,270 --> 00:30:38,760 And figure out what's going on. 691 00:30:38,760 --> 00:30:41,610 So you can imagine too that for example, if the attacker knows 692 00:30:41,610 --> 00:30:44,410 some sub-sequence of code that he's expects 693 00:30:44,410 --> 00:30:46,220 to be in the binary, you could imagine 694 00:30:46,220 --> 00:30:49,047 just sort of trying to xor the binary with that known code, 695 00:30:49,047 --> 00:30:50,130 trying to extract the key. 696 00:30:50,130 --> 00:30:51,630 And there's a lot evil in the world, 697 00:30:51,630 --> 00:30:53,890 so you're exactly correct about that. 698 00:30:53,890 --> 00:30:55,720 OK so that's essentially the discussion 699 00:30:55,720 --> 00:31:00,310 of all the randomization attacks that I want to discuss today. 700 00:31:00,310 --> 00:31:02,150 So one thing to talk about before we 701 00:31:02,150 --> 00:31:04,370 get to some of the return oriented programming stuff, 702 00:31:04,370 --> 00:31:06,370 is you might wonder which ones of these defenses 703 00:31:06,370 --> 00:31:08,440 are actually used in practice. 704 00:31:08,440 --> 00:31:12,420 And so as it turns out, both GCC and Visual Studio, 705 00:31:12,420 --> 00:31:15,640 they both enable stack canaries by default, right. 706 00:31:15,640 --> 00:31:19,900 So that's very popular, that's a very well known community. 707 00:31:19,900 --> 00:31:21,820 If you look Linux and Windows they 708 00:31:21,820 --> 00:31:24,071 can also do things like non-executable memory. 709 00:31:24,071 --> 00:31:26,570 They can also do things like randomize the address space, so 710 00:31:26,570 --> 00:31:27,950 that's also [INAUDIBLE]. 711 00:31:27,950 --> 00:31:30,247 The baggy bounds stuff however, is not as popular. 712 00:31:30,247 --> 00:31:31,955 And that's because of some of these costs 713 00:31:31,955 --> 00:31:33,621 that we talked about over here, in terms 714 00:31:33,621 --> 00:31:36,925 of memory overhead, CPU, the false alarms, and so on ans 715 00:31:36,925 --> 00:31:38,560 so forth. 716 00:31:38,560 --> 00:31:41,810 So that's basically a survey of the state of the art, 717 00:31:41,810 --> 00:31:45,970 in trying to prevent these buffer overflows. 718 00:31:45,970 --> 00:31:50,311 So now we're going to talk about this return oriented programing 719 00:31:50,311 --> 00:31:50,810 stuff. 720 00:31:53,900 --> 00:31:56,050 So what I'm described to you so far today in terms 721 00:31:56,050 --> 00:31:58,260 of the address space randomization and the data 722 00:31:58,260 --> 00:32:01,264 execution prevention, that's the-- the 723 00:32:01,264 --> 00:32:03,180 read, write and execute that I just described. 724 00:32:03,180 --> 00:32:05,662 Those things are actually very, very powerful, right. 725 00:32:05,662 --> 00:32:07,620 Because the randomization prevents the attacker 726 00:32:07,620 --> 00:32:10,036 from actually understanding where our hard coded addresses 727 00:32:10,036 --> 00:32:10,580 are. 728 00:32:10,580 --> 00:32:11,980 And the data execution prevention 729 00:32:11,980 --> 00:32:15,198 says, even if you can put shell code into the stack, 730 00:32:15,198 --> 00:32:16,823 then the attacker can't just jump to it 731 00:32:16,823 --> 00:32:18,160 and execute it, right. 732 00:32:18,160 --> 00:32:19,560 So at its space, that seems like, 733 00:32:19,560 --> 00:32:21,226 man you've really made a lot of progress 734 00:32:21,226 --> 00:32:25,469 for stopping these attackers, but of course there 735 00:32:25,469 --> 00:32:28,010 are these hackers out there who spend all their time thinking 736 00:32:28,010 --> 00:32:29,560 about how to ruin our lives. 737 00:32:29,560 --> 00:32:33,030 So what's the insight behind return oriented programming? 738 00:32:33,030 --> 00:32:35,830 The insight is that, what if instead of the attacker 739 00:32:35,830 --> 00:32:39,660 being able to generate just new code at attack time, what 740 00:32:39,660 --> 00:32:42,430 if the attacker could string together preexisting 741 00:32:42,430 --> 00:32:47,050 pieces of code and then string them together in deviant ways, 742 00:32:47,050 --> 00:32:47,550 right? 743 00:32:47,550 --> 00:32:50,281 And we know that the program contains a ton of code already, 744 00:32:50,281 --> 00:32:50,780 right. 745 00:32:50,780 --> 00:32:53,508 So hopefully, or unhopefully, depending on which side of this 746 00:32:53,508 --> 00:32:54,450 you're on. 747 00:32:54,450 --> 00:32:56,900 If you can find enough interesting code snippets, 748 00:32:56,900 --> 00:32:59,800 you can string them together to basically form 749 00:32:59,800 --> 00:33:01,630 like this Turing complete language, where 750 00:33:01,630 --> 00:33:03,540 the attacker can essentially do whatever the attacker wants 751 00:33:03,540 --> 00:33:04,140 to do. 752 00:33:04,140 --> 00:33:07,240 So that's the insight behind return oriented programming. 753 00:33:07,240 --> 00:33:08,980 So understand how this works. 754 00:33:08,980 --> 00:33:11,600 Let's look at a very simple example that will initially 755 00:33:11,600 --> 00:33:14,800 start off very familiar, right. 756 00:33:14,800 --> 00:33:19,210 But then it's very quickly going to descend into madness. 757 00:33:19,210 --> 00:33:23,560 So let's say that we have the following program. 758 00:33:23,560 --> 00:33:29,810 So we have some program-- sorry, some function and conveniently 759 00:33:29,810 --> 00:33:33,770 for the attacker, it has this nice function here called 760 00:33:33,770 --> 00:33:36,300 run shell. 761 00:33:36,300 --> 00:33:38,790 So this is just going to call system, 762 00:33:38,790 --> 00:33:45,830 it's going to execute bin slash bash and then be done. 763 00:33:45,830 --> 00:33:51,280 And then we've got the canonical buffer overflow process 764 00:33:51,280 --> 00:33:56,040 or sorry, function down here, basically this thing 765 00:33:56,040 --> 00:34:01,940 is going to declare a buffer, and then it's 766 00:34:01,940 --> 00:34:07,370 going to use one of these unsafe functions 767 00:34:07,370 --> 00:34:12,870 to fill in bytes in the buffer. 768 00:34:12,870 --> 00:34:17,210 OK so, we know that this can be overflowing OK, 769 00:34:17,210 --> 00:34:18,510 this is old news. 770 00:34:18,510 --> 00:34:22,969 Now what's interesting is that we have this function up here, 771 00:34:22,969 --> 00:34:26,110 run shell, but it doesn't quite seem 772 00:34:26,110 --> 00:34:29,900 to be accessed in some direct way based on this buffer 773 00:34:29,900 --> 00:34:30,400 overflow. 774 00:34:30,400 --> 00:34:35,540 So how can the attacker invoke this run shell command here? 775 00:34:35,540 --> 00:34:38,550 Well the attack may do a couple things. 776 00:34:38,550 --> 00:34:42,920 So first of all, the attacker can disassemble the program, 777 00:34:42,920 --> 00:34:46,699 run GDB, find out the address of this thing in the executable, 778 00:34:46,699 --> 00:34:47,199 right. 779 00:34:47,199 --> 00:34:48,900 So you all should be very familiar with doing those kinds 780 00:34:48,900 --> 00:34:50,209 of things through the lab. 781 00:34:50,209 --> 00:34:52,000 That's the first thing the attacker can do. 782 00:34:52,000 --> 00:34:54,480 And then during the buffer overflow, 783 00:34:54,480 --> 00:34:57,410 the attacker can essentially take that address, 784 00:34:57,410 --> 00:35:00,360 put it in the buffer overflow that's generated 785 00:35:00,360 --> 00:35:04,450 and make sure that the function returns to run shell. 786 00:35:04,450 --> 00:35:09,370 So just to make that clear, let's draw that over here. 787 00:35:09,370 --> 00:35:14,060 So, you have a setup that looks something 788 00:35:14,060 --> 00:35:20,541 like this at the bottom, we have the buffer, 789 00:35:20,541 --> 00:35:21,540 that's being overflowed. 790 00:35:26,340 --> 00:35:36,590 And then up here, we have the save the break pointer, 791 00:35:36,590 --> 00:35:44,395 up here we have the return address, for process message. 792 00:35:48,990 --> 00:35:54,850 So remember that the new stack pointer will be here initially, 793 00:35:54,850 --> 00:35:57,350 when we start executing the function. 794 00:35:57,350 --> 00:36:07,710 This is the new break pointer, this 795 00:36:07,710 --> 00:36:10,740 is what the stack pointer used to be. 796 00:36:13,980 --> 00:36:19,390 And then we've got some break pointer up here, 797 00:36:19,390 --> 00:36:20,430 for the previous frame. 798 00:36:25,390 --> 00:36:27,940 OK, so this should look pretty familiar. 799 00:36:27,940 --> 00:36:29,790 So basically, in the attack, like I said, 800 00:36:29,790 --> 00:36:31,830 we've used GDB to figure out what 801 00:36:31,830 --> 00:36:33,220 the address is of run shell. 802 00:36:33,220 --> 00:36:37,360 So in the buffer overflow, we can essentially just 803 00:36:37,360 --> 00:36:44,140 put the address of run shell right here, right. 804 00:36:44,140 --> 00:36:46,390 So this is a actually pretty straightforward extension 805 00:36:46,390 --> 00:36:48,240 of what we already know how to do, right. 806 00:36:48,240 --> 00:36:50,270 So basically it's saying, if we conveniently 807 00:36:50,270 --> 00:36:52,337 have a command that runs a shell, 808 00:36:52,337 --> 00:36:54,170 if we can disassemble the binary, figure out 809 00:36:54,170 --> 00:36:57,010 where that address is, we can just put that in this overflow 810 00:36:57,010 --> 00:36:58,422 array that we have here. 811 00:36:58,422 --> 00:37:00,130 So that should be pretty straightforward. 812 00:37:00,130 --> 00:37:02,700 Does that make sense? 813 00:37:02,700 --> 00:37:03,490 OK. 814 00:37:03,490 --> 00:37:07,390 So, this was a very childish example, 815 00:37:07,390 --> 00:37:09,690 because the programmer for some crazy reason 816 00:37:09,690 --> 00:37:12,030 has put this low hanging fruit here. 817 00:37:12,030 --> 00:37:14,670 So as an attacker this is like Christmas coming early, right. 818 00:37:14,670 --> 00:37:17,620 Now it may not be the case that you have something 819 00:37:17,620 --> 00:37:19,420 as delightful as this. 820 00:37:19,420 --> 00:37:25,400 So what you could have instead, is something like this. 821 00:37:25,400 --> 00:37:29,840 So let's say that instead of this thing being called 822 00:37:29,840 --> 00:37:33,810 run shell, we call it run boring and then 823 00:37:33,810 --> 00:37:41,880 maybe this thing just executes bin slash OS let's say. 824 00:37:41,880 --> 00:37:47,480 But let's say that everything is not completely lost, 825 00:37:47,480 --> 00:37:51,730 because we actually have a string up here 826 00:37:51,730 --> 00:37:56,365 that conveniently gives us the path of that. 827 00:38:04,700 --> 00:38:08,810 So what's interesting about this is, that we can disassemble 828 00:38:08,810 --> 00:38:11,570 the program, find the location of run boring, 829 00:38:11,570 --> 00:38:13,380 but as an attacker, who wants to run an OS? 830 00:38:13,380 --> 00:38:15,860 Right, that's no fun But we do actually 831 00:38:15,860 --> 00:38:21,910 have a string in memory that points to the path of the shell 832 00:38:21,910 --> 00:38:24,660 and actually we also know something interesting too. 833 00:38:24,660 --> 00:38:27,440 Which is that even though the program isn't calling system 834 00:38:27,440 --> 00:38:30,830 with the argument that we want, it is calling system somehow. 835 00:38:30,830 --> 00:38:32,700 So we know that system must be getting 836 00:38:32,700 --> 00:38:35,860 linked into this program somehow, right. 837 00:38:35,860 --> 00:38:38,630 So we can actually leverage those two things, 838 00:38:38,630 --> 00:38:42,700 to actually call system with this argument here. 839 00:38:42,700 --> 00:38:45,610 So the first thing that we do, is we can go into GDB 840 00:38:45,610 --> 00:38:48,460 and we can actually figure out where 841 00:38:48,460 --> 00:38:52,634 this thing is located in the process binary image, right. 842 00:38:52,634 --> 00:38:55,050 So you just go to GDB, just type in basically print system 843 00:38:55,050 --> 00:38:56,070 and I'll give you some information 844 00:38:56,070 --> 00:38:57,335 about the offset of that OK. 845 00:38:57,335 --> 00:38:58,710 So that's pretty straightforward. 846 00:38:58,710 --> 00:39:00,989 You can also do the same thing with bash path. 847 00:39:00,989 --> 00:39:02,530 Right, you just use GDB to figure out 848 00:39:02,530 --> 00:39:03,500 where this thing lives. 849 00:39:03,500 --> 00:39:05,125 It's statically declared string, right. 850 00:39:05,125 --> 00:39:07,140 So you'd be able to find out where that lives. 851 00:39:07,140 --> 00:39:09,357 And so once you've done that, now you 852 00:39:09,357 --> 00:39:11,440 got to do something a little bit different, right. 853 00:39:11,440 --> 00:39:14,510 Because now we actually have to figure out somehow, 854 00:39:14,510 --> 00:39:18,160 how to invoke system with an argument of our choosing, 855 00:39:18,160 --> 00:39:18,660 right. 856 00:39:18,660 --> 00:39:21,750 And so the way that we do that is by essentially faking 857 00:39:21,750 --> 00:39:24,730 a calling frame for system. 858 00:39:24,730 --> 00:39:26,490 OK, so remember that a frame is the thing 859 00:39:26,490 --> 00:39:28,240 that the compiler and the hardware 860 00:39:28,240 --> 00:39:31,361 work together to use to implement the call stack, 861 00:39:31,361 --> 00:39:31,860 right. 862 00:39:31,860 --> 00:39:35,450 So here's basically what we want to do. 863 00:39:38,630 --> 00:39:50,710 We want to set up something like this on the stack, right. 864 00:39:50,710 --> 00:39:53,630 So basically we're going to fake what 865 00:39:53,630 --> 00:39:58,700 system would expect to be on the stack, 866 00:39:58,700 --> 00:40:01,480 but right before it actually executes its code. 867 00:40:05,800 --> 00:40:07,860 So up here we had the argument of the system, 868 00:40:07,860 --> 00:40:10,580 this is the string that we actually want to execute. 869 00:40:10,580 --> 00:40:19,160 And then down here, this is where system should return to, 870 00:40:19,160 --> 00:40:19,790 when it's done. 871 00:40:23,530 --> 00:40:27,690 Right, so this is what system expects the stack to look like, 872 00:40:27,690 --> 00:40:29,067 right before it starts execution. 873 00:40:29,067 --> 00:40:31,650 It's going to say this is where I should go when I'm finished, 874 00:40:31,650 --> 00:40:34,180 this is the thing I should consume as my argument, right. 875 00:40:34,180 --> 00:40:35,380 In the past we've been assuming that there 876 00:40:35,380 --> 00:40:36,670 were no arguments when you pass the functions, 877 00:40:36,670 --> 00:40:38,420 but now this is a little bit different, right. 878 00:40:38,420 --> 00:40:39,878 So basically we just have to ensure 879 00:40:39,878 --> 00:40:44,280 that this thing is in that overflow code that we create, 880 00:40:44,280 --> 00:40:44,780 right. 881 00:40:44,780 --> 00:40:47,280 We just have to make sure this fake calling 882 00:40:47,280 --> 00:40:50,280 frame is in that array. 883 00:40:50,280 --> 00:40:53,640 So basically the way this will work 884 00:40:53,640 --> 00:40:55,615 is, we will do the following. 885 00:40:59,810 --> 00:41:02,640 So once again remember the overflow goes up here. 886 00:41:02,640 --> 00:41:08,590 So first, we're going to put the address of system here. 887 00:41:15,370 --> 00:41:20,781 And then here, we're going to put just some junk return 888 00:41:20,781 --> 00:41:21,280 address. 889 00:41:24,622 --> 00:41:26,080 Right, this is where system's going 890 00:41:26,080 --> 00:41:27,414 to return after it's finished. 891 00:41:27,414 --> 00:41:28,830 For the purposes of the discussion 892 00:41:28,830 --> 00:41:30,246 now, we don't care what this does, 893 00:41:30,246 --> 00:41:33,020 we'll just make this be just some random set of bytes. 894 00:41:33,020 --> 00:41:36,060 And then up here, we're actually going 895 00:41:36,060 --> 00:41:46,674 to put the address of bash path, right. 896 00:41:46,674 --> 00:41:48,090 So what's going to happen now when 897 00:41:48,090 --> 00:41:49,620 we do this buffer in overflow? 898 00:41:49,620 --> 00:41:52,690 So what's going to happen is that, process message is going 899 00:41:52,690 --> 00:41:54,740 to finish, it's going to say, OK hey, 900 00:41:54,740 --> 00:41:56,750 here's where I should return to, right. 901 00:41:56,750 --> 00:42:00,070 And then it's going to pop the stack, right, 902 00:42:00,070 --> 00:42:03,140 and now the system code is executing, right. 903 00:42:03,140 --> 00:42:06,610 The system code now sees that fake call frame 904 00:42:06,610 --> 00:42:08,190 that we created, right. 905 00:42:08,190 --> 00:42:10,310 As far as system is concerned, nothing chicanerous 906 00:42:10,310 --> 00:42:11,750 has taken place, right. 907 00:42:11,750 --> 00:42:13,840 System will say, aha here's the argument 908 00:42:13,840 --> 00:42:16,950 that I want to execute, it's bin slash bash, 909 00:42:16,950 --> 00:42:19,460 it's going to execute it and voila, the attacker 910 00:42:19,460 --> 00:42:22,550 has a shell, right. 911 00:42:22,550 --> 00:42:23,550 So does this make sense? 912 00:42:23,550 --> 00:42:25,300 So basically what we've done is, we've now 913 00:42:25,300 --> 00:42:27,610 taken advantage of knowledge of the calling convention, 914 00:42:27,610 --> 00:42:30,610 for the platform to create fake stack frames, 915 00:42:30,610 --> 00:42:32,110 or fake calling frames I should say. 916 00:42:32,110 --> 00:42:34,680 And using those fake calling frames, 917 00:42:34,680 --> 00:42:38,575 we can actually execute any function that is already linked 918 00:42:38,575 --> 00:42:42,330 and defined in the application. 919 00:42:42,330 --> 00:42:45,150 Does that make sense? 920 00:42:45,150 --> 00:42:52,050 OK so, another question you might have is, 921 00:42:52,050 --> 00:42:57,111 what if this string wasn't actually in the program? 922 00:42:57,111 --> 00:42:59,110 Now to be clear, this string is almost certainly 923 00:42:59,110 --> 00:43:00,192 in the program. 924 00:43:00,192 --> 00:43:01,900 So that's one funny thing about security, 925 00:43:01,900 --> 00:43:04,285 there's just all kinds of fun strings that are laying around, 926 00:43:04,285 --> 00:43:05,400 you can just go to town all day long. 927 00:43:05,400 --> 00:43:07,610 Well let's suppose we live in bizarro world 928 00:43:07,610 --> 00:43:09,550 and like this string is not in the program. 929 00:43:09,550 --> 00:43:11,220 So does anyone have any ideas about what 930 00:43:11,220 --> 00:43:13,387 we could do to get that string to be in the program? 931 00:43:13,387 --> 00:43:15,511 AUDIENCE: We can put the string on the [INAUDIBLE]. 932 00:43:15,511 --> 00:43:17,450 PROFESSOR; Yes exactly, don't trust that man. 933 00:43:17,450 --> 00:43:18,783 That's what you can do, exactly. 934 00:43:18,783 --> 00:43:23,060 So, what you can do is actually for here, 935 00:43:23,060 --> 00:43:29,990 have the address of bash path, actually point here, right. 936 00:43:29,990 --> 00:43:35,890 And then you'd put-- up here you would put slash B-I-N 937 00:43:35,890 --> 00:43:41,860 slash P-A-T slash 0. 938 00:43:41,860 --> 00:43:43,470 So that's how you can get around-- I 939 00:43:43,470 --> 00:43:45,720 think I got that math right, because each one of these 940 00:43:45,720 --> 00:43:48,360 is 4 bytes. 941 00:43:48,360 --> 00:43:51,710 But anyway, so you have the pointer go up here and then 942 00:43:51,710 --> 00:43:52,730 boom, you're done. 943 00:43:52,730 --> 00:43:55,890 So now you can actually conjure up arguments 944 00:43:55,890 --> 00:43:58,130 just by putting them in the shell code. 945 00:44:00,690 --> 00:44:02,370 Pretty horrifying. 946 00:44:02,370 --> 00:44:07,301 So this is all building up towards the full BROP attack, 947 00:44:07,301 --> 00:44:07,800 right. 948 00:44:07,800 --> 00:44:09,380 But before you can mention the full BROP attack, 949 00:44:09,380 --> 00:44:10,921 you've got to understand how you just 950 00:44:10,921 --> 00:44:13,560 chain together these preexisting things in the code. 951 00:44:16,950 --> 00:44:20,300 So one thing to note is that when I'm setting up this return 952 00:44:20,300 --> 00:44:23,170 address here, I just said, eh just put some junk here, 953 00:44:23,170 --> 00:44:25,740 it doesn't really matter, we just want to get a shell. 954 00:44:25,740 --> 00:44:28,770 But if you're the attacker, you could actually 955 00:44:28,770 --> 00:44:30,420 set this return address to something 956 00:44:30,420 --> 00:44:32,500 that's actually useful, right. 957 00:44:32,500 --> 00:44:35,970 And if you did that, you could actually string together 958 00:44:35,970 --> 00:44:39,810 several functions, several function indications in a row, 959 00:44:39,810 --> 00:44:40,310 right. 960 00:44:40,310 --> 00:44:42,590 That's actually very, very powerful, right. 961 00:44:42,590 --> 00:44:44,830 Because in particular, if we literally just 962 00:44:44,830 --> 00:44:47,364 set this return address to jump, I 963 00:44:47,364 --> 00:44:49,030 mean it may be that when we ret from it, 964 00:44:49,030 --> 00:44:51,410 like the program crashes on it, maybe we don't want that, 965 00:44:51,410 --> 00:44:51,740 right. 966 00:44:51,740 --> 00:44:53,865 So can actually start chaining some of these things 967 00:44:53,865 --> 00:44:55,980 to do interesting stuff. 968 00:44:55,980 --> 00:45:01,370 So let's say that our goal is that we want to call system 969 00:45:01,370 --> 00:45:03,309 an arbitrary number of times. 970 00:45:03,309 --> 00:45:04,850 We don't just want to do it one time, 971 00:45:04,850 --> 00:45:06,766 we're going to it a arbitrary number of times. 972 00:45:06,766 --> 00:45:08,037 So how can we do that? 973 00:45:08,037 --> 00:45:10,120 Well, we're going to use two pieces of information 974 00:45:10,120 --> 00:45:11,460 that we already know how to get, right. 975 00:45:11,460 --> 00:45:13,820 We already know how to get the address of system, right. 976 00:45:13,820 --> 00:45:16,090 We just look in GDB and find it. 977 00:45:16,090 --> 00:45:20,180 We also know how to find the address of that string, 978 00:45:20,180 --> 00:45:21,960 bin flash bash. 979 00:45:21,960 --> 00:45:25,490 Now to actually make this attack work using multiple calls 980 00:45:25,490 --> 00:45:28,310 to system, we're going to have to use gadgets, right. 981 00:45:28,310 --> 00:45:29,820 This is getting us closer to what's 982 00:45:29,820 --> 00:45:31,470 taking place in the BROP paper. 983 00:45:34,210 --> 00:45:37,660 So what we need to do now, is find the address 984 00:45:37,660 --> 00:45:41,670 of these two Op codes. 985 00:45:48,070 --> 00:45:51,490 Right, so what is this, so this is pop in EAX, so what does 986 00:45:51,490 --> 00:45:52,110 this do? 987 00:45:52,110 --> 00:45:58,050 This just takes the top of the stack 988 00:45:58,050 --> 00:46:01,810 and then it puts it into the EAX register. 989 00:46:01,810 --> 00:46:03,910 And what is the ret instruction going to do? 990 00:46:03,910 --> 00:46:07,980 It just pops the top of the stack 991 00:46:07,980 --> 00:46:15,340 and then puts it into EIP, instruction pointer. 992 00:46:15,340 --> 00:46:18,060 OK, so this is what's known as a gadget, right. 993 00:46:18,060 --> 00:46:21,030 This is like a small set of assembly instructions 994 00:46:21,030 --> 00:46:24,790 that the attacker can use to build these larger more 995 00:46:24,790 --> 00:46:25,890 grandiose attacks. 996 00:46:25,890 --> 00:46:30,410 OK, So how can we find this gadget, right. 997 00:46:30,410 --> 00:46:33,140 There's actually like some off the shelf tools 998 00:46:33,140 --> 00:46:35,010 that hackers use to find these things, 999 00:46:35,010 --> 00:46:36,776 it's not hard to get the binary, right. 1000 00:46:36,776 --> 00:46:38,150 Essentially just do a [INAUDIBLE] 1001 00:46:38,150 --> 00:46:39,570 for these types of things, right. 1002 00:46:39,570 --> 00:46:43,070 So it's just as easy to find one of these gadgets, 1003 00:46:43,070 --> 00:46:45,024 assuming that you've got a copy of the binary 1004 00:46:45,024 --> 00:46:46,940 and we're not worried about randomization yet. 1005 00:46:46,940 --> 00:46:48,600 It's very easy to find these things. 1006 00:46:48,600 --> 00:46:50,377 Just like it's very easy to find the address of system and stuff 1007 00:46:50,377 --> 00:46:51,420 like that. 1008 00:46:51,420 --> 00:46:54,220 So if we've got one of these gadgets, 1009 00:46:54,220 --> 00:46:56,020 what can we use this gadget to do? 1010 00:46:56,020 --> 00:46:58,560 Well of course the answer is evil. 1011 00:46:58,560 --> 00:47:02,925 So, what we can do is the following. 1012 00:47:05,480 --> 00:47:09,410 Let's say that we changed the stack 1013 00:47:09,410 --> 00:47:11,660 so that it looks like this. 1014 00:47:19,500 --> 00:47:22,470 So the exploit goes this way. 1015 00:47:22,470 --> 00:47:26,360 And so let's say, we do this. 1016 00:47:26,360 --> 00:47:28,310 So the first thing we're going to put here 1017 00:47:28,310 --> 00:47:30,190 is the address of system. 1018 00:47:32,960 --> 00:47:35,380 And the thing we're going to put up here, 1019 00:47:35,380 --> 00:47:41,160 is the address of the pop ret gadget. 1020 00:47:45,750 --> 00:47:58,180 Then up here, we're going to put the address of bash path 1021 00:47:58,180 --> 00:48:00,080 and then we're going to repeat this pattern. 1022 00:48:00,080 --> 00:48:10,620 So we're going to put the address of system, 1023 00:48:10,620 --> 00:48:19,890 the address of the pop ret gadget, 1024 00:48:19,890 --> 00:48:24,290 and then the address of bash path. 1025 00:48:29,880 --> 00:48:31,960 OK, so what's going to happen here now? 1026 00:48:31,960 --> 00:48:33,745 Now this is going to be a bit tricky, 1027 00:48:33,745 --> 00:48:35,120 and these lecture notes are going 1028 00:48:35,120 --> 00:48:36,490 to be up on the web, so you may just 1029 00:48:36,490 --> 00:48:38,060 want to listen to what's happening, 1030 00:48:38,060 --> 00:48:40,310 but this-- when I first understood this, this 1031 00:48:40,310 --> 00:48:42,850 was like understanding that Santa Claus wasn't real right. 1032 00:48:42,850 --> 00:48:44,870 So what will happen is-- and by the way, 1033 00:48:44,870 --> 00:48:47,411 Santa Claus isn't real, I hope I didn't ruin it for everyone. 1034 00:48:47,411 --> 00:48:48,530 So what's going to happen? 1035 00:48:48,530 --> 00:48:50,760 So [INAUDIBLE] is what puts this in memory. 1036 00:48:50,760 --> 00:48:52,837 So we're going to start here, OK. 1037 00:48:52,837 --> 00:48:53,920 So what's going to happen? 1038 00:48:53,920 --> 00:48:57,075 We're going to return to system, the ret instruction 1039 00:48:57,075 --> 00:48:59,530 is going to pop an entry off the stack, now 1040 00:48:59,530 --> 00:49:02,130 the top of the stack pointers here. 1041 00:49:02,130 --> 00:49:06,510 OK, so system is going to find its argument here, 1042 00:49:06,510 --> 00:49:08,110 it's going to execute the shell. 1043 00:49:08,110 --> 00:49:11,490 Then it's going to finish and return to whatever's 1044 00:49:11,490 --> 00:49:13,070 here, which is the pop gadget. 1045 00:49:13,070 --> 00:49:15,840 In executing that return, we change 1046 00:49:15,840 --> 00:49:17,770 the top of the stack pointer to be here. 1047 00:49:17,770 --> 00:49:20,770 OK, now we are in the pop ret gadget. 1048 00:49:20,770 --> 00:49:23,190 OK, so what is that pop ret gadget going to do? 1049 00:49:23,190 --> 00:49:26,700 It's going to pop what's on the stack, which is this, OK. 1050 00:49:26,700 --> 00:49:29,699 So now the top of the stack is here. 1051 00:49:29,699 --> 00:49:31,240 Then we're now in the ret instruction 1052 00:49:31,240 --> 00:49:32,730 from the pop ret gadget. 1053 00:49:32,730 --> 00:49:33,730 What's this going to do? 1054 00:49:33,730 --> 00:49:37,060 Aha, it's going to call system again, right. 1055 00:49:37,060 --> 00:49:41,400 So once again the ret is going to pop this off this stack, 1056 00:49:41,400 --> 00:49:42,690 we are now in system. 1057 00:49:42,690 --> 00:49:44,644 Top of the stack is here, system is 1058 00:49:44,644 --> 00:49:46,810 going-- this will trigger calling frame, the system. 1059 00:49:46,810 --> 00:49:49,466 System takes the bash path argument here. 1060 00:49:49,466 --> 00:49:52,681 OK, and then it is going to ret, right. 1061 00:49:52,681 --> 00:49:53,980 Where's it going to ret to? 1062 00:49:53,980 --> 00:49:55,740 The pop ret gadget again. 1063 00:49:55,740 --> 00:49:57,977 So the ret pops the stack, we are 1064 00:49:57,977 --> 00:50:00,850 now in the pop ret gadget, the ret gadget-- sorry, 1065 00:50:00,850 --> 00:50:05,460 the pop ret gadget is going to pop this, so on and so forth. 1066 00:50:05,460 --> 00:50:06,050 OK? 1067 00:50:06,050 --> 00:50:08,760 So clearly we can chain this sequence 1068 00:50:08,760 --> 00:50:12,350 to execute an arbitrary number of things, right. 1069 00:50:12,350 --> 00:50:15,380 And so this in essence is starting 1070 00:50:15,380 --> 00:50:18,420 to get to the core of what return oriented programming is. 1071 00:50:18,420 --> 00:50:23,060 Note that we have not executed anything in the stack, right. 1072 00:50:23,060 --> 00:50:26,890 This is what has allowed us to get beyond those data execution 1073 00:50:26,890 --> 00:50:28,150 prevention bits, right. 1074 00:50:28,150 --> 00:50:29,690 Nothing's been executed here. 1075 00:50:29,690 --> 00:50:33,150 We're just sort of jumping to things in unexpected ways 1076 00:50:33,150 --> 00:50:35,300 to do what we want to do. 1077 00:50:35,300 --> 00:50:39,350 OK so this is actually very, very, very, clever. 1078 00:50:39,350 --> 00:50:41,620 And so what's interesting is that at a high level 1079 00:50:41,620 --> 00:50:44,990 you can think about us, we've now defined this new model 1080 00:50:44,990 --> 00:50:46,180 for computation, right. 1081 00:50:46,180 --> 00:50:48,450 So in a traditional, non-malicious program, 1082 00:50:48,450 --> 00:50:50,072 you have the instruction pointer that 1083 00:50:50,072 --> 00:50:52,030 points to some linear sequence of instructions. 1084 00:50:52,030 --> 00:50:53,910 And you increment the instruction pointer 1085 00:50:53,910 --> 00:50:56,030 to figure out what's the next thing to do. 1086 00:50:56,030 --> 00:50:58,720 In essence, what return oriented programing does is, 1087 00:50:58,720 --> 00:51:02,720 it uses the stack pointer as the instruction pointer. 1088 00:51:02,720 --> 00:51:05,540 Right, so as we move the stack pointer, 1089 00:51:05,540 --> 00:51:09,230 we're pointing to like other blocks of code 1090 00:51:09,230 --> 00:51:10,720 that we're going to execute. 1091 00:51:10,720 --> 00:51:12,180 And then at the end of the gadget, 1092 00:51:12,180 --> 00:51:14,010 you return back to the stack pointer 1093 00:51:14,010 --> 00:51:16,218 which is then going to tell us the next block of code 1094 00:51:16,218 --> 00:51:17,550 to execute. 1095 00:51:17,550 --> 00:51:19,340 OK so that does that make sense? 1096 00:51:26,220 --> 00:51:29,785 So that's basically how you can avoid the data execution 1097 00:51:29,785 --> 00:51:30,570 prevention stuff. 1098 00:51:30,570 --> 00:51:32,190 That's how you can get around having 1099 00:51:32,190 --> 00:51:36,170 this no execute bit on pages. 1100 00:51:36,170 --> 00:51:38,120 So the next thing that we might want to do 1101 00:51:38,120 --> 00:51:39,710 is defeat stack canaries. 1102 00:51:39,710 --> 00:51:42,740 So if you remember, this canary was this value 1103 00:51:42,740 --> 00:51:45,510 that we were going to place on the stack, right. 1104 00:51:45,510 --> 00:51:48,620 So you can imagine the canary would 1105 00:51:48,620 --> 00:51:50,640 go right here for example, or right here, 1106 00:51:50,640 --> 00:51:53,500 and it would prevent someone from overriding the return 1107 00:51:53,500 --> 00:51:56,370 address, without also overwriting the canary. 1108 00:51:56,370 --> 00:52:00,350 With the intuition being that before the system actually 1109 00:52:00,350 --> 00:52:02,330 jumps to the ret address, it can check 1110 00:52:02,330 --> 00:52:04,890 to see if the canary has been changed 1111 00:52:04,890 --> 00:52:07,380 in a way that's incorrect. 1112 00:52:07,380 --> 00:52:09,850 So that's how the canary works, but can we 1113 00:52:09,850 --> 00:52:11,060 get around the canary? 1114 00:52:11,060 --> 00:52:13,250 Can we guess the canary somehow? 1115 00:52:13,250 --> 00:52:17,950 Well we can actually, if we make a few assumptions 1116 00:52:17,950 --> 00:52:22,110 about how the system works. 1117 00:52:22,110 --> 00:52:31,650 So, how do we defeat those canaries? 1118 00:52:36,160 --> 00:52:46,730 So the first thing that we want to assume is, that the server, 1119 00:52:46,730 --> 00:52:48,720 it has to have a buffer overflow vulnerability. 1120 00:52:53,420 --> 00:52:58,140 The second thing that we're going to assume, 1121 00:52:58,140 --> 00:53:07,300 is that the server is going to crash and respond, just 1122 00:53:07,300 --> 00:53:13,355 restart, if we set the canary value to a bad one. 1123 00:53:19,600 --> 00:53:22,060 And the third thing that we're going to assume 1124 00:53:22,060 --> 00:53:37,600 is that, after the restart, that the canary and any address 1125 00:53:37,600 --> 00:53:42,695 space randomization that you're doing, is not rerandomized. 1126 00:53:49,184 --> 00:53:50,850 Right, so what that means is that, we're 1127 00:53:50,850 --> 00:53:53,520 going to assume that if we can somehow crash the server, then 1128 00:53:53,520 --> 00:53:55,520 when the server restarts, it's going to have 1129 00:53:55,520 --> 00:53:57,030 the same value for the canary. 1130 00:53:57,030 --> 00:54:00,520 And it's going to have the same locations for all the quote 1131 00:54:00,520 --> 00:54:04,030 unquote "randomized" stack, heap and code information 1132 00:54:04,030 --> 00:54:05,140 that it has. 1133 00:54:05,140 --> 00:54:08,622 So you might wonder why would this be the case? 1134 00:54:08,622 --> 00:54:10,580 Why would it be that when the server comes back 1135 00:54:10,580 --> 00:54:12,390 it doesn't have new locations for things? 1136 00:54:12,390 --> 00:54:14,020 The reason is because a lot of servers 1137 00:54:14,020 --> 00:54:17,950 are written to use fork, to create new processes. 1138 00:54:17,950 --> 00:54:20,260 And if you remember, fork actually 1139 00:54:20,260 --> 00:54:23,580 inherits-- the child inherits the address 1140 00:54:23,580 --> 00:54:27,161 space of the address space layout right of the parent, 1141 00:54:27,161 --> 00:54:27,660 right. 1142 00:54:27,660 --> 00:54:30,890 This is copy on write pages that change stuff as the child 1143 00:54:30,890 --> 00:54:33,510 updates things, but if you use fork here, 1144 00:54:33,510 --> 00:54:35,730 instead of execing a whole new process, 1145 00:54:35,730 --> 00:54:39,680 any time that parent server process forms new children, 1146 00:54:39,680 --> 00:54:42,090 those children will have the same values of the canary 1147 00:54:42,090 --> 00:54:43,370 in the address base, OK. 1148 00:54:43,370 --> 00:54:44,995 So these are the assumptions that we're 1149 00:54:44,995 --> 00:54:49,000 going to make to try to defeat these canaries here. 1150 00:54:49,000 --> 00:54:51,490 So how can we defeat the canary? 1151 00:54:51,490 --> 00:54:54,680 Well the attack is actually fairly straightforward. 1152 00:54:54,680 --> 00:54:58,270 So imagine that the stack is going up this way, right. 1153 00:54:58,270 --> 00:55:00,440 Imagine you got the buffer overflow here, 1154 00:55:00,440 --> 00:55:02,720 then imagine that the canary is up here, right. 1155 00:55:02,720 --> 00:55:05,860 And the canary actually has multiple bytes, right. 1156 00:55:05,860 --> 00:55:07,850 So what you can actually do is, you 1157 00:55:07,850 --> 00:55:12,280 can probe those bytes one by one and start guessing values 1158 00:55:12,280 --> 00:55:13,740 of what those bytes are, right. 1159 00:55:13,740 --> 00:55:20,940 So let's say that-- so the canary looks like this. 1160 00:55:20,940 --> 00:55:24,640 Here's the overflowing buffer, and you want 1161 00:55:24,640 --> 00:55:26,200 to guess what these bytes are. 1162 00:55:26,200 --> 00:55:28,290 So the first thing that you guess 1163 00:55:28,290 --> 00:55:31,066 is you take your overflow, just to this first byte 1164 00:55:31,066 --> 00:55:34,910 of the canary and you say, hey, is that byte 0? 1165 00:55:34,910 --> 00:55:36,806 You write a 0 there, with your overflow. 1166 00:55:36,806 --> 00:55:38,556 You're either correct or you're incorrect. 1167 00:55:38,556 --> 00:55:43,000 If you are incorrect, then the server's going to crash, right. 1168 00:55:43,000 --> 00:55:45,560 If you are correct you say, aha I actually 1169 00:55:45,560 --> 00:55:48,020 know the first byte of the canary now, right. 1170 00:55:48,020 --> 00:55:49,400 Then you start guessing here. 1171 00:55:49,400 --> 00:55:51,710 You say, are you 0? 1172 00:55:51,710 --> 00:55:53,300 Probably not, it's going to crash. 1173 00:55:53,300 --> 00:55:54,180 Are you one? 1174 00:55:54,180 --> 00:55:55,930 And maybe not, it's going to crash. 1175 00:55:55,930 --> 00:55:56,670 Are you two? 1176 00:55:56,670 --> 00:55:58,930 Aha, it doesn't crash, right. 1177 00:55:58,930 --> 00:56:01,730 So now you've actually found the value of that second canary 1178 00:56:01,730 --> 00:56:02,530 byte, right. 1179 00:56:02,530 --> 00:56:04,770 As you can imagine, you step up this way, 1180 00:56:04,770 --> 00:56:07,849 and you eventually find all the values for the canary. 1181 00:56:07,849 --> 00:56:09,890 So once again we're taking advantage of the fact, 1182 00:56:09,890 --> 00:56:12,580 that crashes are a signal to you, the attacker, 1183 00:56:12,580 --> 00:56:15,935 that you've actually done something wrong, right. 1184 00:56:15,935 --> 00:56:17,810 And the server is staying up, in other words, 1185 00:56:17,810 --> 00:56:19,830 that socket connection's staying open, is 1186 00:56:19,830 --> 00:56:21,579 a signal to you, the attacker, that you've 1187 00:56:21,579 --> 00:56:22,774 done something right. 1188 00:56:22,774 --> 00:56:24,940 AUDIENCE: Maybe I mentioned something basic here 1189 00:56:24,940 --> 00:56:27,610 like why do you-- if you know how long the canary is, 1190 00:56:27,610 --> 00:56:28,818 can you just infect directly? 1191 00:56:28,818 --> 00:56:31,632 Skip that buffer and overflow those-- 1192 00:56:31,632 --> 00:56:33,508 the one path there the canary? 1193 00:56:33,508 --> 00:56:37,460 So like [INAUDIBLE] say you can like [INAUDIBLE] the canary-- 1194 00:56:37,460 --> 00:56:39,620 PROFESSOR: Yeah, yeah you can't-- so that's right 1195 00:56:39,620 --> 00:56:41,890 if you-- so if you in fact know the exact location 1196 00:56:41,890 --> 00:56:42,801 of the canary, right. 1197 00:56:42,801 --> 00:56:44,300 That can sometimes allow you to skip 1198 00:56:44,300 --> 00:56:45,420 some of these attacks totally. 1199 00:56:45,420 --> 00:56:46,480 Because then you can just directly 1200 00:56:46,480 --> 00:56:48,340 write to the return address, let's say, 1201 00:56:48,340 --> 00:56:51,180 as opposed to doing some of this buffer overflow nonsense. 1202 00:56:51,180 --> 00:56:53,430 But in general, if there's some level of randomization 1203 00:56:53,430 --> 00:56:56,050 here, if you don't quite know where the stack is for example, 1204 00:56:56,050 --> 00:56:57,810 then it's tricky to do that, right. 1205 00:56:57,810 --> 00:56:59,685 So basically the way that the attack proceeds 1206 00:56:59,685 --> 00:57:01,800 is that you don't quite know what's happening, 1207 00:57:01,800 --> 00:57:06,710 and so you just very slowly creep your way up memory, 1208 00:57:06,710 --> 00:57:09,184 down the stack, to figure out where these things are. 1209 00:57:09,184 --> 00:57:11,112 AUDIENCE: Can the server instead of 1210 00:57:11,112 --> 00:57:13,522 crashing when it finds strong canaries, 1211 00:57:13,522 --> 00:57:15,932 keep the socket open and [INAUDIBLE] deprocess 1212 00:57:15,932 --> 00:57:18,149 and [INAUDIBLE]? 1213 00:57:18,149 --> 00:57:20,440 PROFESSOR: Yeah, so we'll discuss at the end of lecture 1214 00:57:20,440 --> 00:57:22,630 some of the defenses you can have against this, 1215 00:57:22,630 --> 00:57:25,790 but one very, abstractly speaking civil defense, 1216 00:57:25,790 --> 00:57:28,220 is that when the program crashes, 1217 00:57:28,220 --> 00:57:30,222 you catch the segfault using a signal handler, 1218 00:57:30,222 --> 00:57:31,930 do not deduce you're own code by the way. 1219 00:57:31,930 --> 00:57:33,055 But you can do this, right. 1220 00:57:33,055 --> 00:57:35,250 You catch that segfault and then the signal handler 1221 00:57:35,250 --> 00:57:37,247 just keeps that process alive for a bit 1222 00:57:37,247 --> 00:57:39,330 and that will trick the attack into thinking that, 1223 00:57:39,330 --> 00:57:45,570 oh I won't get that signal back, in other words. 1224 00:57:45,570 --> 00:57:48,000 OK so that's basically how you can 1225 00:57:48,000 --> 00:57:49,710 guess the value for the canary. 1226 00:57:49,710 --> 00:57:51,700 And note that you can actually use this attack 1227 00:57:51,700 --> 00:57:54,285 to sort of figure out arbitrary values that 1228 00:57:54,285 --> 00:57:56,020 are low in the stack, right. 1229 00:57:56,020 --> 00:57:58,790 Just by iteratively guessing for each byte what it is, 1230 00:57:58,790 --> 00:58:00,490 and then using that crash indication 1231 00:58:00,490 --> 00:58:04,960 as a signal of whether you're guess was correct or not. 1232 00:58:04,960 --> 00:58:07,820 So that's basically how you can defeat 1233 00:58:07,820 --> 00:58:09,460 these randomized canaries, assuming 1234 00:58:09,460 --> 00:58:14,000 that after the server restarts, those things are not changed. 1235 00:58:14,000 --> 00:58:15,575 And so we've also shown how you can 1236 00:58:15,575 --> 00:58:17,800 use the gadgets to string together 1237 00:58:17,800 --> 00:58:19,460 these more elaborate attacks. 1238 00:58:19,460 --> 00:58:21,730 So what we're going to look at next 1239 00:58:21,730 --> 00:58:25,770 is a way that you can use all these techniques to defeat 1240 00:58:25,770 --> 00:58:29,300 data execution prevention, address-based randomization 1241 00:58:29,300 --> 00:58:32,674 and canaries on a production system. 1242 00:58:32,674 --> 00:58:34,090 Now what we're going to do now is, 1243 00:58:34,090 --> 00:58:35,800 we're actually going to start looking 1244 00:58:35,800 --> 00:58:38,870 at 64-bit architectures instead of 32-bit architectures. 1245 00:58:38,870 --> 00:58:41,330 As it turns out for randomization purposes, 1246 00:58:41,330 --> 00:58:43,750 64-bit architectures actually give you 1247 00:58:43,750 --> 00:58:47,280 a lot more randomness to protect yourself against the attacker. 1248 00:58:47,280 --> 00:58:49,260 So looking at attacks is much more interesting 1249 00:58:49,260 --> 00:58:50,850 on those systems. 1250 00:58:50,850 --> 00:58:52,800 So that's also the type of architecture that's 1251 00:58:52,800 --> 00:58:54,690 discussed in the BROP paper. 1252 00:58:54,690 --> 00:58:56,245 They talk about 64-bit machines. 1253 00:58:56,245 --> 00:58:57,620 So from now on, assume that we're 1254 00:58:57,620 --> 00:58:59,950 going to talk about the 64-bit architectures. 1255 00:58:59,950 --> 00:59:01,640 For the purposes of this discussion, 1256 00:59:01,640 --> 00:59:03,740 the only difference between a 32-bit machine 1257 00:59:03,740 --> 00:59:07,360 and a 64-bit machine, is that on a 32-bit machine, 1258 00:59:07,360 --> 00:59:10,500 the arguments are passed on the stack, right. 1259 00:59:10,500 --> 00:59:14,620 So here for example, this is like a 32-bit machine 1260 00:59:14,620 --> 00:59:16,480 we were assuming, so for example, bash path 1261 00:59:16,480 --> 00:59:17,570 will pass on the stack. 1262 00:59:17,570 --> 00:59:19,810 On a 64-bit machine, the arguments 1263 00:59:19,810 --> 00:59:22,350 are passed in registers instead. 1264 00:59:22,350 --> 00:59:24,570 OK so like when a function starts execution, 1265 00:59:24,570 --> 00:59:26,195 it's going to look in certain registers 1266 00:59:26,195 --> 00:59:28,320 to find where the arguments are. 1267 00:59:28,320 --> 00:59:29,040 OK, make sense? 1268 00:59:29,040 --> 00:59:30,250 All right. 1269 00:59:30,250 --> 00:59:33,950 So start up here. 1270 00:59:41,400 --> 00:59:45,210 All right, so now we get to the point of today's paper. 1271 00:59:45,210 --> 00:59:48,200 Which is the blind return oriented programming. 1272 00:59:48,200 --> 00:59:51,380 So what's the first thing you want to do, 1273 00:59:51,380 --> 00:59:54,970 if you want to engage in BROP for fun or profit? 1274 00:59:54,970 --> 00:59:57,080 So the first thing you have to do 1275 00:59:57,080 --> 01:00:01,170 is, you have to find what they call a stop gadget. 1276 01:00:06,970 --> 01:00:10,270 Now a stop gadget-- and remember that when we say gadget, 1277 01:00:10,270 --> 01:00:13,510 we essentially mean, return addresses, right. 1278 01:00:13,510 --> 01:00:15,630 A gadget is identified by the return address, 1279 01:00:15,630 --> 01:00:18,280 by the start address of that sequence of instructions 1280 01:00:18,280 --> 01:00:19,660 that we want to jump to, right. 1281 01:00:19,660 --> 01:00:21,030 So what is a stop gadget? 1282 01:00:21,030 --> 01:00:24,350 So a stop gadget is essentially a return address 1283 01:00:24,350 --> 01:00:27,580 to someplace in the code, but if you jump to it, 1284 01:00:27,580 --> 01:00:29,340 you're going to pause the program, 1285 01:00:29,340 --> 01:00:31,890 but you're not going to crash it. 1286 01:00:31,890 --> 01:00:35,070 OK, so that's why it's called a stop gadget. 1287 01:00:35,070 --> 01:00:37,510 Now what might that stop gadget be? 1288 01:00:37,510 --> 01:00:40,660 You might jump to someplace in the code that then calls 1289 01:00:40,660 --> 01:00:43,562 via the sleep system call for example, or does pause, 1290 01:00:43,562 --> 01:00:44,520 or something like that. 1291 01:00:44,520 --> 01:00:46,997 Or maybe somehow the program gets stuck in an infinite loop 1292 01:00:46,997 --> 01:00:48,080 if you jump to that place. 1293 01:00:48,080 --> 01:00:50,061 Doesn't really matter why the stop's happening, 1294 01:00:50,061 --> 01:00:52,185 but you could imagine several scenarios which would 1295 01:00:52,185 --> 01:00:53,760 cause that stop to take place. 1296 01:00:53,760 --> 01:00:55,330 So why is this useful? 1297 01:00:55,330 --> 01:00:57,554 Well once the attacker has managed 1298 01:00:57,554 --> 01:00:59,720 to defeat the canaries using that iterative guessing 1299 01:00:59,720 --> 01:01:02,080 technique I showed you, he can start 1300 01:01:02,080 --> 01:01:05,850 to overwrite this return address and start probing 1301 01:01:05,850 --> 01:01:07,900 for these stop gadgets, right. 1302 01:01:07,900 --> 01:01:09,950 And so note that most of the random 1303 01:01:09,950 --> 01:01:12,110 addresses you might put there, they'll 1304 01:01:12,110 --> 01:01:13,654 probably crash the server, right. 1305 01:01:13,654 --> 01:01:15,820 Once again, that's the message to you, the attacker, 1306 01:01:15,820 --> 01:01:18,601 that's an indication that what you found is not a stop gadget, 1307 01:01:18,601 --> 01:01:19,100 right. 1308 01:01:19,100 --> 01:01:21,016 Because when the server crashes your sockets-- 1309 01:01:21,016 --> 01:01:22,420 your socket connection is closed. 1310 01:01:22,420 --> 01:01:23,653 You as an attacker know, OK that must not 1311 01:01:23,653 --> 01:01:24,660 have been a stop gadget. 1312 01:01:24,660 --> 01:01:27,201 Where if you guess something and then you-- that socket still 1313 01:01:27,201 --> 01:01:28,720 stays open for awhile, you think, 1314 01:01:28,720 --> 01:01:31,620 aha I found that stop gadget. 1315 01:01:31,620 --> 01:01:33,890 So that's the basic idea behind step one. 1316 01:01:33,890 --> 01:01:36,220 You got to find that stop gadget. 1317 01:01:36,220 --> 01:01:42,590 Now step two, is that you want to find 1318 01:01:42,590 --> 01:01:46,560 gadgets that pop stack entries. 1319 01:01:57,500 --> 01:02:02,220 And so you basically have to use this sequence of carefully 1320 01:02:02,220 --> 01:02:03,910 crafted instructions to figure out 1321 01:02:03,910 --> 01:02:08,040 when we've got one of these stack gadgets. 1322 01:02:08,040 --> 01:02:10,530 So this sequence is going to consist 1323 01:02:10,530 --> 01:02:18,450 of a probe address, a stop address, and a crash address. 1324 01:02:18,450 --> 01:02:20,489 So the probe address is the thing 1325 01:02:20,489 --> 01:02:22,030 that we're going to put in the stack. 1326 01:02:22,030 --> 01:02:32,036 This is going to be the address of a potential stack popping 1327 01:02:32,036 --> 01:02:32,535 gadget. 1328 01:02:36,760 --> 01:02:41,410 This stop gadget is going to be what we found in step one. 1329 01:02:41,410 --> 01:02:46,876 So this is an address of the stop gadget. 1330 01:02:49,550 --> 01:02:51,780 And then the crash gadget is just 1331 01:02:51,780 --> 01:02:56,683 going to be the address of nonexecutable code. 1332 01:03:02,295 --> 01:03:03,920 So for example, you could just set this 1333 01:03:03,920 --> 01:03:06,957 to, just the address zero, right. 1334 01:03:06,957 --> 01:03:09,415 If you do a ret to this and then try to execute code there, 1335 01:03:09,415 --> 01:03:11,250 this is going to crash your program. 1336 01:03:11,250 --> 01:03:14,830 So we can basically use these types of addresses 1337 01:03:14,830 --> 01:03:17,360 to find out where these stack popping gadgets are. 1338 01:03:17,360 --> 01:03:20,870 So here's a simple example. 1339 01:03:20,870 --> 01:03:24,640 So let's write this over here. 1340 01:03:24,640 --> 01:03:31,730 So let's say we have these two different examples of a probe, 1341 01:03:31,730 --> 01:03:36,600 a trap, and then a stop, right. 1342 01:03:36,600 --> 01:03:40,290 So let's assume that we have down here, 1343 01:03:40,290 --> 01:03:44,380 we're going to probe at some address, 1344 01:03:44,380 --> 01:03:46,130 doesn't really matter, starts with a four, 1345 01:03:46,130 --> 01:03:46,921 ends with an eight. 1346 01:03:46,921 --> 01:03:47,840 That doesn't matter. 1347 01:03:47,840 --> 01:03:50,230 Over here, let's say that we look at the address 1348 01:03:50,230 --> 01:03:54,220 that, let's say starts in a four ends in a C. 1349 01:03:54,220 --> 01:03:56,520 So we're saying, we're hypothesizing, 1350 01:03:56,520 --> 01:03:59,270 that maybe one of these two addresses 1351 01:03:59,270 --> 01:04:02,190 is going to be one of these stack popping gadgets. 1352 01:04:02,190 --> 01:04:05,100 And then let's say that the trap up here, 1353 01:04:05,100 --> 01:04:10,790 like I said this is just going to be address zero, 1354 01:04:10,790 --> 01:04:14,540 and then let's assume that we found some preexisting stop 1355 01:04:14,540 --> 01:04:19,380 gadget, some addresses start the [INAUDIBLE] doesn't really 1356 01:04:19,380 --> 01:04:19,910 matter. 1357 01:04:19,910 --> 01:04:24,720 And remember this stop gadget, like maybe this address, 1358 01:04:24,720 --> 01:04:29,650 points to code that does something like sleep 10, 1359 01:04:29,650 --> 01:04:31,370 or something like that, right. 1360 01:04:31,370 --> 01:04:33,720 So when I say that we're going to test these sequences, 1361 01:04:33,720 --> 01:04:35,920 this is the stuff that we're going to push onto the stack, 1362 01:04:35,920 --> 01:04:36,460 right. 1363 01:04:36,460 --> 01:04:40,386 So similar to over there, when we were pushing these gadgets 1364 01:04:40,386 --> 01:04:41,760 onto the stack, this is the stuff 1365 01:04:41,760 --> 01:04:42,885 that we're going to push onto the stack, 1366 01:04:42,885 --> 01:04:45,150 and we're going to see what happens, right. 1367 01:04:45,150 --> 01:04:51,800 Now let's say that, this code here, points 1368 01:04:51,800 --> 01:04:53,750 to the following sequence. 1369 01:04:53,750 --> 01:04:58,880 We're going to pop some register, let's say racks, 1370 01:04:58,880 --> 01:05:03,340 and then we're going to return. 1371 01:05:03,340 --> 01:05:05,210 So what's going to happen here? 1372 01:05:05,210 --> 01:05:10,560 Well so when the system jumps this address, 1373 01:05:10,560 --> 01:05:13,440 the stack pointer's going to move here, OK. 1374 01:05:13,440 --> 01:05:15,380 Now we're in the middle of this gadget, right. 1375 01:05:15,380 --> 01:05:16,630 What's the gadget going to do? 1376 01:05:16,630 --> 01:05:18,450 It's going to pop racks, OK. 1377 01:05:18,450 --> 01:05:20,582 Top of stack pointer's now here, and it's 1378 01:05:20,582 --> 01:05:22,915 going to return to whatever's the top of the stack which 1379 01:05:22,915 --> 01:05:24,880 is the stop gap, right. 1380 01:05:24,880 --> 01:05:29,240 So in this case this gadget gets us to here, 1381 01:05:29,240 --> 01:05:31,358 and the attacker can tell that this 1382 01:05:31,358 --> 01:05:34,720 is-- this probe address belong to one of these pop stacking 1383 01:05:34,720 --> 01:05:35,820 things, right. 1384 01:05:35,820 --> 01:05:38,400 Because the client connection stays open. 1385 01:05:38,400 --> 01:05:41,400 Now let's say that this gadget here, 1386 01:05:41,400 --> 01:05:48,580 pointed to something like the following. 1387 01:05:48,580 --> 01:05:52,760 Maybe it just does like an xor, for example. 1388 01:05:52,760 --> 01:05:58,000 So it's just going to xor some registers and then it's 1389 01:05:58,000 --> 01:06:00,540 going to ret. 1390 01:06:00,540 --> 01:06:02,930 So what happens if we try to jump to this gadget? 1391 01:06:02,930 --> 01:06:06,170 Right, note that this does not pop anything off the stack, OK. 1392 01:06:06,170 --> 01:06:07,920 It just changes the contents of registers. 1393 01:06:07,920 --> 01:06:09,160 So what's going to happen? 1394 01:06:09,160 --> 01:06:11,690 So we're going to be here, we're going 1395 01:06:11,690 --> 01:06:13,630 to jump to the address of this gadget, 1396 01:06:13,630 --> 01:06:15,830 stack pointer goes here, OK. 1397 01:06:15,830 --> 01:06:18,210 We're going to xor these two things, right. 1398 01:06:18,210 --> 01:06:19,932 Stack pointer's not going to change. 1399 01:06:19,932 --> 01:06:22,390 Then we're going to return to whatever the top of the stack 1400 01:06:22,390 --> 01:06:23,550 is, which is 0, 0. 1401 01:06:23,550 --> 01:06:25,370 This is going to crash. 1402 01:06:25,370 --> 01:06:28,420 OK, the client connection to the server is going to close, 1403 01:06:28,420 --> 01:06:31,245 and as a result, the attacker knows that this is not 1404 01:06:31,245 --> 01:06:34,210 a stack popping gadget. 1405 01:06:34,210 --> 01:06:35,990 So does that all make sense? 1406 01:06:35,990 --> 01:06:38,850 And so you can also imagine that you can-- 1407 01:06:38,850 --> 01:06:42,609 by coming with more baroque series of traps 1408 01:06:42,609 --> 01:06:44,150 and stop gadgets and stuff like that, 1409 01:06:44,150 --> 01:06:46,510 you can find things that for example, pop two things 1410 01:06:46,510 --> 01:06:47,879 off the stack, right. 1411 01:06:47,879 --> 01:06:50,170 You can just put another one of these trap instructions 1412 01:06:50,170 --> 01:06:51,110 there, right. 1413 01:06:51,110 --> 01:06:53,166 And so then unless the-- unless this gadget 1414 01:06:53,166 --> 01:06:54,540 pops two things off, you're going 1415 01:06:54,540 --> 01:06:56,831 to end up in one of these traps and your code execution 1416 01:06:56,831 --> 01:06:58,250 is going to blow up, right. 1417 01:06:58,250 --> 01:07:02,090 And so in the paper they discuss like this thing called the BROP 1418 01:07:02,090 --> 01:07:03,950 gadget, which is sort of like hilariously 1419 01:07:03,950 --> 01:07:06,300 complex if you're not used to returning to programming. 1420 01:07:06,300 --> 01:07:08,297 What I'll show you today is you can actually 1421 01:07:08,297 --> 01:07:09,880 just use these very simple pop gadgets 1422 01:07:09,880 --> 01:07:10,963 to launch the same attack. 1423 01:07:10,963 --> 01:07:12,690 Then hopefully after you understand this, 1424 01:07:12,690 --> 01:07:14,696 the BROP gadget will make more sense. 1425 01:07:14,696 --> 01:07:16,570 But does everyone understand how we can probe 1426 01:07:16,570 --> 01:07:19,180 for these little gadgets here? 1427 01:07:19,180 --> 01:07:20,120 OK. 1428 01:07:20,120 --> 01:07:26,220 So, once you've got these gadgets, what do you know? 1429 01:07:26,220 --> 01:07:28,720 Well you found the location of code snippets that 1430 01:07:28,720 --> 01:07:31,080 allow you to pop stuff up, one thing off the stack. 1431 01:07:31,080 --> 01:07:32,820 Precisely one thing off the stack, 1432 01:07:32,820 --> 01:07:35,990 but you don't actually know into what register 1433 01:07:35,990 --> 01:07:37,990 they're popping it into. 1434 01:07:37,990 --> 01:07:40,440 You just know that they're getting popped off, right. 1435 01:07:40,440 --> 01:07:42,394 And you actually need to know what 1436 01:07:42,394 --> 01:07:44,060 register these gadgets are popping stuff 1437 01:07:44,060 --> 01:07:47,370 into, because remember, on a 64-bit architecture, 1438 01:07:47,370 --> 01:07:50,840 the registers control where the arguments are to this function 1439 01:07:50,840 --> 01:07:52,480 that you want to invoke, right. 1440 01:07:52,480 --> 01:07:54,170 So the ultimate goal to keep in mind, 1441 01:07:54,170 --> 01:07:56,419 is that we want to be able to create some gadgets that 1442 01:07:56,419 --> 01:07:58,920 allow us to pop values that we put on the stack 1443 01:07:58,920 --> 01:08:00,754 into certain registers, and eventually we're 1444 01:08:00,754 --> 01:08:02,794 going to call a system call that's going to allow 1445 01:08:02,794 --> 01:08:03,850 us to do something evil. 1446 01:08:03,850 --> 01:08:05,870 OK, so the next thing that we need to do 1447 01:08:05,870 --> 01:08:14,670 is determine which registers-- so determine which 1448 01:08:14,670 --> 01:08:19,025 registers the pop gadgets use. 1449 01:08:26,319 --> 01:08:28,870 So how are we going to do that? 1450 01:08:28,870 --> 01:08:32,160 Well basically we can take advantage of the pause system 1451 01:08:32,160 --> 01:08:32,840 call. 1452 01:08:32,840 --> 01:08:37,580 OK, so the pause system call, it takes no arguments, right. 1453 01:08:37,580 --> 01:08:40,970 And that means that it ignores everything in the registers. 1454 01:08:40,970 --> 01:08:41,930 OK. 1455 01:08:41,930 --> 01:08:45,129 And essentially, to find the pause instruction what 1456 01:08:45,129 --> 01:08:49,760 we can do is, we can chain all of these pop gadgets 1457 01:08:49,760 --> 01:08:52,490 in such a way, that we put all of them on the stack, 1458 01:08:52,490 --> 01:08:55,229 in between each one of them we put the syscall number 1459 01:08:55,229 --> 01:08:57,739 for pause, and then we see if we can actually 1460 01:08:57,739 --> 01:08:59,269 get the program to hang. 1461 01:08:59,269 --> 01:09:01,060 Let me give you a concrete example of that. 1462 01:09:01,060 --> 01:09:05,050 So we'll do something like this. 1463 01:09:09,390 --> 01:09:13,850 So here for the return address, we'll put the following. 1464 01:09:24,290 --> 01:09:28,750 So let's say we have one gadget that pops RDI register, 1465 01:09:28,750 --> 01:09:30,899 then does a ret. 1466 01:09:30,899 --> 01:09:40,090 And then up here we'll put the syscall number for pause. 1467 01:09:40,090 --> 01:09:45,810 And then let's say that we have another gadget that we found, 1468 01:09:45,810 --> 01:09:50,600 that does a pop into a different register, let's say RSI. 1469 01:09:53,960 --> 01:09:58,670 And then we'll put the system call number for pause 1470 01:09:58,670 --> 01:09:59,460 up here again. 1471 01:10:02,124 --> 01:10:05,640 And we do this for all the gadgets that we've found 1472 01:10:05,640 --> 01:10:15,947 and then eventually we put the guest address for pause, 1473 01:10:15,947 --> 01:10:17,280 or sorry for syscall, excuse me. 1474 01:10:25,370 --> 01:10:28,510 Once again, remember how you invoke these system calls. 1475 01:10:28,510 --> 01:10:32,990 So you basically have to put the number of the system call 1476 01:10:32,990 --> 01:10:36,560 into the RAX register, then you invoke this libc function 1477 01:10:36,560 --> 01:10:39,855 syscall which is then going to execute the requested system 1478 01:10:39,855 --> 01:10:40,784 call, OK. 1479 01:10:40,784 --> 01:10:42,950 So what's going to happen when we execute this code? 1480 01:10:42,950 --> 01:10:46,120 Right, so we're going to come here, 1481 01:10:46,120 --> 01:10:48,580 we're going to jump to the address of this gadget, 1482 01:10:48,580 --> 01:10:50,840 and note that as an attacker, all that we know 1483 01:10:50,840 --> 01:10:53,610 is that this gadget here pops something off the stack. 1484 01:10:53,610 --> 01:10:55,680 We don't know what the register is yet, right. 1485 01:10:55,680 --> 01:10:57,080 Put it here just to make the [INAUDIBLE], 1486 01:10:57,080 --> 01:10:58,788 but the attacker doesn't know yet, right. 1487 01:10:58,788 --> 01:11:01,560 So if you jump-- or sorry the-- we jump 1488 01:11:01,560 --> 01:11:03,664 to the gadget, the stack corners now here, 1489 01:11:03,664 --> 01:11:04,580 what's it going to do? 1490 01:11:04,580 --> 01:11:07,720 It's going to pop this syscall number for pause, 1491 01:11:07,720 --> 01:11:09,870 into some register the attacker doesn't know, 1492 01:11:09,870 --> 01:11:14,006 and then we're going to continue to go up this chain and so 1493 01:11:14,006 --> 01:11:14,700 on and so forth. 1494 01:11:14,700 --> 01:11:17,470 And what you'll see is that each one of these gadgets, one 1495 01:11:17,470 --> 01:11:20,430 of them hopefully will pop the system call 1496 01:11:20,430 --> 01:11:23,500 number into the appropriate RAX register. 1497 01:11:23,500 --> 01:11:25,980 So that by the time we get up to here, 1498 01:11:25,980 --> 01:11:28,320 I mean we basically polluted all the registers, 1499 01:11:28,320 --> 01:11:31,090 with the system call number, but hopefully just one of them 1500 01:11:31,090 --> 01:11:32,460 has to be correct, right. 1501 01:11:32,460 --> 01:11:35,510 Because if one of our gadgets does this, then by the time 1502 01:11:35,510 --> 01:11:37,610 we ret to here, we'll get a pause. 1503 01:11:37,610 --> 01:11:42,310 Once again, that pause acts as a signal to the attacker, OK. 1504 01:11:42,310 --> 01:11:44,980 Because if this guest address was wrong, 1505 01:11:44,980 --> 01:11:47,710 then probably the program's going to crash, right. 1506 01:11:47,710 --> 01:11:51,540 So what does this phase of the attack let us do? 1507 01:11:51,540 --> 01:11:54,300 Well we still don't know which gadgets 1508 01:11:54,300 --> 01:11:56,860 pop into which registers, but we know that one of them 1509 01:11:56,860 --> 01:11:59,600 is popped into RAX, which is the one we want to control. 1510 01:11:59,600 --> 01:12:03,690 And for sure we know the address of syscall, right. 1511 01:12:03,690 --> 01:12:06,790 Because we were able to induce the pause, right. 1512 01:12:06,790 --> 01:12:09,330 So once we've done that, right. 1513 01:12:09,330 --> 01:12:12,000 Once we know for sure where this thing is, 1514 01:12:12,000 --> 01:12:14,200 the address for syscall, then we can actually just 1515 01:12:14,200 --> 01:12:16,299 try the gadgets one by one, right. 1516 01:12:16,299 --> 01:12:18,090 And see which one of them is actually going 1517 01:12:18,090 --> 01:12:19,474 to induce the pause, right. 1518 01:12:19,474 --> 01:12:21,640 So in other words, cut all the middleman here, let's 1519 01:12:21,640 --> 01:12:24,760 have a stack it looks like this, and then you just immediately 1520 01:12:24,760 --> 01:12:25,590 jump to syscall. 1521 01:12:25,590 --> 01:12:27,790 Did that cause the pause or did it crash? 1522 01:12:27,790 --> 01:12:29,680 If it crashed, OK we know this gadget, 1523 01:12:29,680 --> 01:12:31,200 it pops to RDI for example. 1524 01:12:31,200 --> 01:12:32,700 OK, get rid of that one, right. 1525 01:12:32,700 --> 01:12:34,769 Try the next gadget, right. 1526 01:12:34,769 --> 01:12:37,310 Put the guest address-- put the, well it's not guest anymore, 1527 01:12:37,310 --> 01:12:39,270 put the real address for syscall up here. 1528 01:12:39,270 --> 01:12:41,011 Were we able to pause the program? 1529 01:12:41,011 --> 01:12:41,510 Yes? 1530 01:12:41,510 --> 01:12:47,420 Aha, so we know that pop gadget must pop into RAX. 1531 01:12:47,420 --> 01:12:49,836 So does that make sense? 1532 01:12:49,836 --> 01:12:53,280 AUDIENCE: So the way to guess the address for system call 1533 01:12:53,280 --> 01:12:54,756 is just blind transfer? 1534 01:12:54,756 --> 01:12:57,020 PROFESSOR: Yeah, so there-- so in the paper, 1535 01:12:57,020 --> 01:12:58,929 they go into some optimizations about how 1536 01:12:58,929 --> 01:13:00,970 you can work in a PLT and all that kind of stuff. 1537 01:13:00,970 --> 01:13:03,530 Like I said, I think it's easier to ignore that for a second, 1538 01:13:03,530 --> 01:13:04,690 and just look toward the simpler thing 1539 01:13:04,690 --> 01:13:07,200 first, but yeah in a simple attack that I'm describing, 1540 01:13:07,200 --> 01:13:08,790 yeah you just put some address up here 1541 01:13:08,790 --> 01:13:11,272 and you just see if you pause. 1542 01:13:14,070 --> 01:13:17,800 So does that all make sense? 1543 01:13:17,800 --> 01:13:22,370 OK so at the end of this we actually know 1544 01:13:22,370 --> 01:13:23,810 the location of syscall. 1545 01:13:23,810 --> 01:13:27,460 We know the location of the instruction 1546 01:13:27,460 --> 01:13:29,730 that does the pop into RAX. 1547 01:13:29,730 --> 01:13:32,230 Now you can imagine that we also need gadgets that pop 1548 01:13:32,230 --> 01:13:34,300 into some other registers too. 1549 01:13:34,300 --> 01:13:36,830 Suffice to say, you can do similar tests, right. 1550 01:13:36,830 --> 01:13:39,780 So instead of like pushing a system call number for pause, 1551 01:13:39,780 --> 01:13:41,280 push it for some other command that 1552 01:13:41,280 --> 01:13:46,890 now takes in all arguments in RAX and RDI for example, right. 1553 01:13:46,890 --> 01:13:48,280 Do the same type of test, right. 1554 01:13:48,280 --> 01:13:49,950 So basically you can leverage the fact 1555 01:13:49,950 --> 01:13:52,080 that for any particular set of registers 1556 01:13:52,080 --> 01:13:54,750 that you want to be able to control, 1557 01:13:54,750 --> 01:13:56,690 there's some system call that will give you 1558 01:13:56,690 --> 01:13:59,070 a signal as an attacker, that allow you to figure out 1559 01:13:59,070 --> 01:14:00,942 whether you successfully broke it or not. 1560 01:14:00,942 --> 01:14:02,400 Right, so at the end of this phase, 1561 01:14:02,400 --> 01:14:05,580 you basically have the address of syscall 1562 01:14:05,580 --> 01:14:07,770 and the address of a bunch of gadgets 1563 01:14:07,770 --> 01:14:11,130 which allow you to pop into arbitrary registers. 1564 01:14:11,130 --> 01:14:16,900 OK and so now let's see so, step 4 1565 01:14:16,900 --> 01:14:19,895 is going to be to invoke write. 1566 01:14:28,970 --> 01:14:35,924 Step 4 is invoke the write system call. 1567 01:14:38,710 --> 01:14:44,200 So to invoke write, we need to have the following gadgets. 1568 01:14:44,200 --> 01:14:48,770 You need to be able to pop RDI. 1569 01:14:48,770 --> 01:14:51,400 We need to be able to pop RSI. 1570 01:14:54,310 --> 01:15:06,490 We need to be able to pop RDX, pop racks, and then invoke 1571 01:15:06,490 --> 01:15:09,140 syscall, right. 1572 01:15:09,140 --> 01:15:11,000 So as it turns out, what are these registers 1573 01:15:11,000 --> 01:15:12,950 being used for by system call? 1574 01:15:12,950 --> 01:15:17,900 So this is the socket, or more generally, the file descriptor 1575 01:15:17,900 --> 01:15:20,650 that you're going to pass into write. 1576 01:15:20,650 --> 01:15:23,190 This is the buffer. 1577 01:15:23,190 --> 01:15:25,080 This is the length of that buffer. 1578 01:15:27,680 --> 01:15:30,150 This is the syscall number. 1579 01:15:33,970 --> 01:15:35,910 And it is called syscall. 1580 01:15:35,910 --> 01:15:39,150 Right, so if we found all these gadgets, 1581 01:15:39,150 --> 01:15:42,480 then we can actually now control the values 1582 01:15:42,480 --> 01:15:44,310 that are put into those arguments, that 1583 01:15:44,310 --> 01:15:46,435 put in those registers, because we just pushed them 1584 01:15:46,435 --> 01:15:47,440 on the stack, right. 1585 01:15:47,440 --> 01:15:49,670 And so for example, what's the socket going to be? 1586 01:15:49,670 --> 01:15:51,560 For once you're going to have to do a little guessing here, 1587 01:15:51,560 --> 01:15:52,060 right. 1588 01:15:52,060 --> 01:15:54,280 can take advantage of the fact that Linux restricts 1589 01:15:54,280 --> 01:15:56,960 the number of simultaneous open file connections, 1590 01:15:56,960 --> 01:15:59,050 for a file that's going to be 2024. 1591 01:15:59,050 --> 01:16:01,650 And also it's supposed to be the lowest one available. 1592 01:16:01,650 --> 01:16:03,858 So we do a little bit of guessing here and figure out 1593 01:16:03,858 --> 01:16:05,690 what that socket is, put it in there. 1594 01:16:05,690 --> 01:16:07,190 Now interestingly, what are we going 1595 01:16:07,190 --> 01:16:08,920 to pass into the buff pointer? 1596 01:16:08,920 --> 01:16:10,870 Right, we're actually going to use the text 1597 01:16:10,870 --> 01:16:12,720 segment of the program. 1598 01:16:12,720 --> 01:16:15,800 We're actually going to pass in that the pointer to somewhere 1599 01:16:15,800 --> 01:16:17,540 in the code of the program. 1600 01:16:17,540 --> 01:16:19,410 So what's that going to allow us to do? 1601 01:16:19,410 --> 01:16:23,170 That's going to allows us to read the binary, out of memory, 1602 01:16:23,170 --> 01:16:26,750 using the right call to the client socket. 1603 01:16:26,750 --> 01:16:29,740 So that the attacker can then take that binary, 1604 01:16:29,740 --> 01:16:31,820 analyze it offline, right. 1605 01:16:31,820 --> 01:16:33,670 Just use GDB, or whatever, to figure out 1606 01:16:33,670 --> 01:16:35,080 where everything is located. 1607 01:16:35,080 --> 01:16:38,280 The attacker knows that now, every time the server crashes, 1608 01:16:38,280 --> 01:16:41,300 it's going to have the same randomized set of things in it. 1609 01:16:41,300 --> 01:16:43,950 So now, once the attacker can find out addresses and offsets 1610 01:16:43,950 --> 01:16:46,350 for stuff, now the attacker can directly 1611 01:16:46,350 --> 01:16:47,850 attack those gadgets, right. 1612 01:16:47,850 --> 01:16:49,720 Directly attack other vulnerabilities, 1613 01:16:49,720 --> 01:16:52,330 figure out how to open up a shell, so on and so forth. 1614 01:16:52,330 --> 01:16:53,850 So in other words, at the point you 1615 01:16:53,850 --> 01:16:57,880 exfiltrated the binary to the attacker, you basically lost. 1616 01:16:57,880 --> 01:17:02,454 Right, so this is essentially how the BROP attack works. 1617 01:17:02,454 --> 01:17:03,870 Like I said, in the paper, there's 1618 01:17:03,870 --> 01:17:05,882 a bunch of optimization, but really you 1619 01:17:05,882 --> 01:17:07,840 need to understand this stuff, the basic stuff, 1620 01:17:07,840 --> 01:17:10,020 before that optimization will start to make sense. 1621 01:17:10,020 --> 01:17:11,670 And so we can talk about the optimization with me offline 1622 01:17:11,670 --> 01:17:13,205 if you want, or after class. 1623 01:17:13,205 --> 01:17:14,580 But to suffice it to say, this is 1624 01:17:14,580 --> 01:17:17,270 the basics of how you launch that BROP attack. 1625 01:17:17,270 --> 01:17:20,490 You've got to find the stop gadget, 1626 01:17:20,490 --> 01:17:23,230 find those gadgets that pop stack entries. 1627 01:17:23,230 --> 01:17:25,260 Figure out which of those registers 1628 01:17:25,260 --> 01:17:27,440 those gadgets pop into, and find out 1629 01:17:27,440 --> 01:17:30,330 how to figure out where syscall is, and then invoke 1630 01:17:30,330 --> 01:17:33,560 write by accumulating all that knowledge. 1631 01:17:33,560 --> 01:17:35,729 So very quickly, how do you defend against BROP? 1632 01:17:35,729 --> 01:17:37,270 Well the most obvious thing is you've 1633 01:17:37,270 --> 01:17:39,270 got to rerandomize, right. 1634 01:17:39,270 --> 01:17:41,810 So the fact that crashed servers do not 1635 01:17:41,810 --> 01:17:44,490 respawn, rerandomize versions of themselves, 1636 01:17:44,490 --> 01:17:48,000 that allows the crash to act as a signal that let's 1637 01:17:48,000 --> 01:17:49,990 the attacker test various hypotheses 1638 01:17:49,990 --> 01:17:52,010 about how the programs working. 1639 01:17:52,010 --> 01:17:54,990 So one simple defense is to make sure 1640 01:17:54,990 --> 01:17:58,850 that you do exec when you spawn your process, instead of fork, 1641 01:17:58,850 --> 01:17:59,350 right. 1642 01:17:59,350 --> 01:18:01,990 Because when you exec the process, you create totally new 1643 01:18:01,990 --> 01:18:04,676 randomized layout space, at least on Linux, right. 1644 01:18:04,676 --> 01:18:07,050 So on Linux, when you compile with this PIE, the Position 1645 01:18:07,050 --> 01:18:09,970 Independent Executable flag, you only 1646 01:18:09,970 --> 01:18:12,420 get that randomized address space 1647 01:18:12,420 --> 01:18:14,950 that's new if you use exec. 1648 01:18:14,950 --> 01:18:17,730 So another event you can use is just use Windows, 1649 01:18:17,730 --> 01:18:20,350 because Windows basically does not 1650 01:18:20,350 --> 01:18:22,240 have a fork equivalent, right. 1651 01:18:22,240 --> 01:18:23,890 So hooray for us. 1652 01:18:23,890 --> 01:18:26,560 So that means that on Windows, whenever 1653 01:18:26,560 --> 01:18:28,400 you spawn that new server, it's always 1654 01:18:28,400 --> 01:18:31,950 going to have a new randomized address space. 1655 01:18:31,950 --> 01:18:34,440 I think someone over here mentioned something like, 1656 01:18:34,440 --> 01:18:36,020 what would happen if for example, 1657 01:18:36,020 --> 01:18:38,340 when the server crashed, it didn't actually 1658 01:18:38,340 --> 01:18:40,230 close the connection? 1659 01:18:40,230 --> 01:18:41,770 Right, so you can imagine one thing 1660 01:18:41,770 --> 01:18:45,360 that when a crash takes place, we somehow catch that fault 1661 01:18:45,360 --> 01:18:48,050 and then we keep that connection open for a little while 1662 01:18:48,050 --> 01:18:51,310 to confuse the attacker and remove that signal, 1663 01:18:51,310 --> 01:18:52,540 that something's gone amiss. 1664 01:18:52,540 --> 01:18:54,690 So that's something you definitely do. 1665 01:18:54,690 --> 01:18:57,720 What's hilarious about that is, that now your BROP attack 1666 01:18:57,720 --> 01:19:00,980 turns into a denial of service attack. 1667 01:19:00,980 --> 01:19:03,280 Because now you just got all the potential zombie 1668 01:19:03,280 --> 01:19:05,660 processes that are sitting around, they segfaulted. 1669 01:19:05,660 --> 01:19:07,380 They're useless in society, but you 1670 01:19:07,380 --> 01:19:09,421 can't let them go, because otherwise you're going 1671 01:19:09,421 --> 01:19:10,905 to delete this information. 1672 01:19:10,905 --> 01:19:12,530 Another thing you might think about to, 1673 01:19:12,530 --> 01:19:14,155 is you could do bounds checking, right. 1674 01:19:14,155 --> 01:19:16,040 We just talked a bunch about that, right. 1675 01:19:16,040 --> 01:19:19,312 But in the paper, they casually dismiss this 1676 01:19:19,312 --> 01:19:20,770 as saying it has up to 2x overhead, 1677 01:19:20,770 --> 01:19:24,870 so nobody's going to do that, but you could in fact do that. 1678 01:19:24,870 --> 01:19:27,100 So that's basically how BROP works. 1679 01:19:27,100 --> 01:19:29,670 As for the homework question, the homework 1680 01:19:29,670 --> 01:19:32,140 questions a bit subtle, because the homework question says, 1681 01:19:32,140 --> 01:19:36,610 what if you use a hash of the current time, right? 1682 01:19:36,610 --> 01:19:39,060 Get time of day when you restarted the program. 1683 01:19:39,060 --> 01:19:42,950 Is that sufficient to prevent this type of attack? 1684 01:19:42,950 --> 01:19:46,780 Well note that, hashing does not magically 1685 01:19:46,780 --> 01:19:50,010 provide you bits of entropy if the input to the hash 1686 01:19:50,010 --> 01:19:51,890 is easily guessable, right. 1687 01:19:51,890 --> 01:19:54,860 If I know that you're only going to hash one or two things, 1688 01:19:54,860 --> 01:19:58,160 it doesn't matter if I have like some a jillion bit hash. 1689 01:19:58,160 --> 01:19:58,930 Doesn't matter. 1690 01:19:58,930 --> 01:20:01,580 So I can just guess one of those two values and see what is. 1691 01:20:01,580 --> 01:20:03,580 So the thing to note is that get time of day, 1692 01:20:03,580 --> 01:20:06,110 actually has much less entropy than you might think. 1693 01:20:06,110 --> 01:20:09,070 Particularly because the attacker can actually 1694 01:20:09,070 --> 01:20:12,690 check what time he or she is launching the attack, right. 1695 01:20:12,690 --> 01:20:15,150 So that's going to actually remove a bunch of entropy 1696 01:20:15,150 --> 01:20:17,170 from that calculation, right. 1697 01:20:17,170 --> 01:20:18,750 So there's some subtleties there. 1698 01:20:18,750 --> 01:20:21,860 What's the server skew in terms of clock or the client 1699 01:20:21,860 --> 01:20:22,900 and so on and so forth. 1700 01:20:22,900 --> 01:20:26,600 The long story short, using a guessable base value, 1701 01:20:26,600 --> 01:20:28,830 even with guessable just inside of a range, 1702 01:20:28,830 --> 01:20:30,661 is super useful for the attacker, right. 1703 01:20:30,661 --> 01:20:32,035 Particularly because the attack-- 1704 01:20:32,035 --> 01:20:35,680 we can start subverting a bunch of servers in parallel 1705 01:20:35,680 --> 01:20:37,960 and know that all of them should have 1706 01:20:37,960 --> 01:20:39,320 fairly similar values, right. 1707 01:20:39,320 --> 01:20:41,440 This is a high order of bits, right. 1708 01:20:41,440 --> 01:20:42,890 So long story short, the answer is 1709 01:20:42,890 --> 01:20:47,730 that, it's literally better than nothing to randomize, 1710 01:20:47,730 --> 01:20:50,390 if you use get time of day, but it doesn't actually provide you 1711 01:20:50,390 --> 01:20:51,870 as much security as you think. 1712 01:20:51,870 --> 01:20:53,953 And the other lesson too is, that just because you 1713 01:20:53,953 --> 01:20:55,640 hash something right, that doesn't 1714 01:20:55,640 --> 01:20:59,052 matter if you're not actually using that hash in a smart way. 1715 01:20:59,052 --> 01:21:00,036 You have a question? 1716 01:21:00,036 --> 01:21:03,480 AUDIENCE: Oh, still when I did the calculations that some 1717 01:21:03,480 --> 01:21:09,604 [INAUDIBLE] it seems like maybe to be 1718 01:21:09,604 --> 01:21:13,712 able to get the offset that the [INAUDIBLE] 1719 01:21:13,712 --> 01:21:17,616 your [INAUDIBLE] start the process 1720 01:21:17,616 --> 01:21:19,249 to within like 48 milliseconds? 1721 01:21:19,249 --> 01:21:21,040 PROFESSOR: Yes and getting the timing right 1722 01:21:21,040 --> 01:21:22,780 depends on a bunch of different things, right. 1723 01:21:22,780 --> 01:21:24,000 But you could take advantage of the fact 1724 01:21:24,000 --> 01:21:26,166 that the attacker can open up a bunch of connections 1725 01:21:26,166 --> 01:21:27,640 in parallel, and leverage the fact 1726 01:21:27,640 --> 01:21:29,640 that even if the initial guess a little bit off, 1727 01:21:29,640 --> 01:21:31,900 you can still launch multiple guesses on what 1728 01:21:31,900 --> 01:21:34,209 should be very similar canary values, 1729 01:21:34,209 --> 01:21:35,500 and do that attack in parallel. 1730 01:21:35,500 --> 01:21:37,650 But you're right, there's tricky time and issues.