WEBVTT

00:00:00.080 --> 00:00:02.430
The following content is
provided under a Creative

00:00:02.430 --> 00:00:03.820
Commons license.

00:00:03.820 --> 00:00:06.060
Your support will help
MIT OpenCourseWare

00:00:06.060 --> 00:00:10.150
continue to offer high quality
educational resources for free.

00:00:10.150 --> 00:00:12.690
To make a donation, or to
view additional materials

00:00:12.690 --> 00:00:16.600
from hundreds of MIT courses,
visit MIT OpenCourseWare

00:00:16.600 --> 00:00:17.310
at ocw.mit.edu.

00:00:25.998 --> 00:00:27.780
PROFESSOR: All right,
let's get started.

00:00:27.780 --> 00:00:33.090
So welcome to the next
lecture about exploiting

00:00:33.090 --> 00:00:33.921
buffer overflow.

00:00:33.921 --> 00:00:35.420
So today, what we're
going to do is,

00:00:35.420 --> 00:00:38.810
we're going to finish up our
discussion about baggy bounds

00:00:38.810 --> 00:00:40.990
and then we're going
to move on to a couple

00:00:40.990 --> 00:00:44.400
of other different techniques
for protecting its buffer

00:00:44.400 --> 00:00:45.180
overflows.

00:00:45.180 --> 00:00:48.020
Then we're going to talk
about the paper for today,

00:00:48.020 --> 00:00:51.032
which is the blind return
oriented programming.

00:00:51.032 --> 00:00:53.240
So if you were like me when
you first read that paper

00:00:53.240 --> 00:00:55.780
you kind of felt like you were
watching like a Christopher

00:00:55.780 --> 00:00:56.665
Nolan movie at the beginning.

00:00:56.665 --> 00:00:58.350
It was kind of like
mind blowing right.

00:00:58.350 --> 00:00:59.030
So what we're going
to do is we're

00:00:59.030 --> 00:01:01.363
going to actually step through
how some of these gadgets

00:01:01.363 --> 00:01:02.090
work right.

00:01:02.090 --> 00:01:03.548
And so hopefully
by the end, you'll

00:01:03.548 --> 00:01:05.995
be able to understand all this
sort of high tech chicanery

00:01:05.995 --> 00:01:08.110
that they're doing in the paper.

00:01:08.110 --> 00:01:09.810
So first of all,
like I said, let's

00:01:09.810 --> 00:01:13.210
just close up with the
baggy bounds discussions.

00:01:13.210 --> 00:01:18.480
Let's go through a very
simple example here.

00:01:18.480 --> 00:01:26.280
So let's say that we're going
to define a pointer called P.

00:01:26.280 --> 00:01:28.400
And let's say that
we're going to give it

00:01:28.400 --> 00:01:30.360
allocation size of 44.

00:01:30.360 --> 00:01:37.960
Let's also assume that the
slot size equals 16 bytes OK.

00:01:37.960 --> 00:01:40.630
So what's going to happen when
we do this malloc up here?

00:01:40.630 --> 00:01:42.460
So as you know, the
baggy bounds system

00:01:42.460 --> 00:01:46.401
is going to pad that allocation
out to the next power of two,

00:01:46.401 --> 00:01:46.900
right.

00:01:46.900 --> 00:01:49.730
So even though we've only
allocated 44 bytes here,

00:01:49.730 --> 00:01:54.130
we're actually going to allocate
64 bytes for this pointer

00:01:54.130 --> 00:01:56.470
up here.

00:01:56.470 --> 00:01:59.671
And so also note too, this
is the slot size is 16.

00:01:59.671 --> 00:02:01.920
How many bounds tables entries
are we going to create?

00:02:01.920 --> 00:02:04.960
Well we're going to create
the allocation size, which

00:02:04.960 --> 00:02:08.970
in this case 64, divided by
the slot size, which is 16.

00:02:08.970 --> 00:02:12.280
So in this case we'll create
four different bounds table

00:02:12.280 --> 00:02:14.554
entries for this
thing right here.

00:02:14.554 --> 00:02:15.970
Each one of those
entries is going

00:02:15.970 --> 00:02:18.631
to be set to the log of
the allocation size, which

00:02:18.631 --> 00:02:20.130
in this case is
going to be 6 right.

00:02:20.130 --> 00:02:22.800
Because the allocation
size is 64, OK?

00:02:22.800 --> 00:02:24.070
So, so far so good.

00:02:24.070 --> 00:02:31.180
Then we're going to define
another pointer called q

00:02:31.180 --> 00:02:36.770
and we're going to set
it equal to p plus 60.

00:02:36.770 --> 00:02:38.350
So what happens when we do this?

00:02:38.350 --> 00:02:40.350
Well note that
strictly speaking,

00:02:40.350 --> 00:02:43.070
this access is out
of bounds, right.

00:02:43.070 --> 00:02:45.470
Because this was only
allocated 44 bytes of memory,

00:02:45.470 --> 00:02:47.345
but of course the way
that baggy bounds works

00:02:47.345 --> 00:02:50.300
is that it will actually allow
axises that are out of bounds,

00:02:50.300 --> 00:02:52.290
if they stay within
that baggy bounds.

00:02:52.290 --> 00:02:53.879
So even though
strictly speaking,

00:02:53.879 --> 00:02:55.920
the programmer probably
shouldn't have done this,

00:02:55.920 --> 00:02:57.720
this is actually
going to be OK, right.

00:02:57.720 --> 00:03:01.170
We're not going to raise any
flags or anything like that.

00:03:01.170 --> 00:03:04.230
Now let's say that
the next thing we do

00:03:04.230 --> 00:03:09.430
is we need to find another
pointer, which is going to be

00:03:09.430 --> 00:03:14.340
set equal to q plus 16 right.

00:03:14.340 --> 00:03:21.290
Now this is actually going
to cause an error, right.

00:03:21.290 --> 00:03:31.660
Because now q is at an offset
of 60 plus 16, which equals 76.

00:03:31.660 --> 00:03:34.720
So this is actually 12
bytes away from the end

00:03:34.720 --> 00:03:36.380
of that baggy bounds.

00:03:36.380 --> 00:03:36.980
OK?

00:03:36.980 --> 00:03:39.964
And that's actually greater
than half a slot away.

00:03:39.964 --> 00:03:42.380
All right, so if you remember
the baggy bounds system will

00:03:42.380 --> 00:03:44.690
actually throw a hard
synchronous error if you

00:03:44.690 --> 00:03:47.630
get beyond 1/2 a slot from
the edge of that baggy bounds.

00:03:47.630 --> 00:03:49.630
So this will actually
cause the program to fail.

00:03:49.630 --> 00:03:51.210
This will actually make it stop.

00:03:51.210 --> 00:03:54.020
Now let's imagine that we
didn't have this line of code

00:03:54.020 --> 00:03:55.140
in the program, OK.

00:03:55.140 --> 00:03:57.610
So we had these two, but
we don't have this one.

00:03:57.610 --> 00:04:00.290
So what if we instead
of doing this line,

00:04:00.290 --> 00:04:02.230
did something that
looks like this.

00:04:02.230 --> 00:04:06.790
We declare another
pointer, let's call it s,

00:04:06.790 --> 00:04:11.700
and we set it equal to q plus 8.

00:04:11.700 --> 00:04:14.580
Now in this case,
the pointer is going

00:04:14.580 --> 00:04:22.480
to be at 60 plus 8, which equals
68 bytes away from p, right.

00:04:22.480 --> 00:04:25.680
So this is only four bytes
beyond that baggy bound.

00:04:25.680 --> 00:04:28.280
So this will not
actually cause an error.

00:04:28.280 --> 00:04:30.740
Even though it is strictly
speaking, out of bounds.

00:04:30.740 --> 00:04:33.060
What we will do here though,
is set that high order

00:04:33.060 --> 00:04:34.950
bit on the pointer, right.

00:04:34.950 --> 00:04:36.610
So that if anyone
subsequently tries

00:04:36.610 --> 00:04:38.390
to dereference this
thing, it's going

00:04:38.390 --> 00:04:41.770
to cause a hard
fault at that point.

00:04:41.770 --> 00:04:44.350
And then let's say, the
final thing that we do

00:04:44.350 --> 00:04:51.250
is we declare another
pointer t, which

00:04:51.250 --> 00:04:56.599
is going to equal s minus 32.

00:04:56.599 --> 00:04:58.390
So what happens here
is that essentially we

00:04:58.390 --> 00:05:02.280
brought this pointer t, it
is now back in bounds, right.

00:05:02.280 --> 00:05:06.510
So what that means is that
even though this guy was out

00:05:06.510 --> 00:05:09.210
of bounds, now we sort of going
back to the original allocated

00:05:09.210 --> 00:05:11.290
region, that we originally
created up here.

00:05:11.290 --> 00:05:14.946
So as a result, t will not
have that high order bit step

00:05:14.946 --> 00:05:17.320
and so you can dereference T
and everything will be fine.

00:05:17.320 --> 00:05:18.490
So does this all make sense?

00:05:18.490 --> 00:05:20.073
This should be fairly
straightforward.

00:05:20.073 --> 00:05:22.207
AUDIENCE: [INAUDIBLE]
the difference

00:05:22.207 --> 00:05:25.920
between r and s, how
would you know that r is--

00:05:25.920 --> 00:05:31.365
or how does the program know
that r is 1/2 the [INAUDIBLE].

00:05:31.365 --> 00:05:34.830
PROFESSOR: So note
that, like up here,

00:05:34.830 --> 00:05:39.308
when we create r you
can basically interpose,

00:05:39.308 --> 00:05:40.861
we get an instrumented
code that's

00:05:40.861 --> 00:05:44.570
going to be working at all
of these pointer operations.

00:05:44.570 --> 00:05:48.528
So basically we can tell is that
we know where P is going to be.

00:05:48.528 --> 00:05:51.276
I'm sorry, we know
where q is going to be.

00:05:51.276 --> 00:05:57.935
And we know that q is
within those baggy bounds.

00:05:57.935 --> 00:05:59.907
And so when we do
this operation here,

00:05:59.907 --> 00:06:01.890
the instrumentation
of baggy bounds

00:06:01.890 --> 00:06:03.528
adds and we're able
to say, aha, well I

00:06:03.528 --> 00:06:05.444
know where that source
formula is coming from.

00:06:05.444 --> 00:06:07.760
And then if you look
at this offset here,

00:06:07.760 --> 00:06:11.273
you determine it's more than a
1/2 slot away from slot side.

00:06:11.273 --> 00:06:12.772
So basically what
you think about is

00:06:12.772 --> 00:06:14.117
that as we're doing
these pointer operations,

00:06:14.117 --> 00:06:16.317
and looking and saying is how
are you going out of bounds,

00:06:16.317 --> 00:06:18.029
have you gone out of
bounds, yes or no.

00:06:18.029 --> 00:06:20.362
At some point you're going
to have some operation that's

00:06:20.362 --> 00:06:23.342
going to involve a pointer
that is either in bounds

00:06:23.342 --> 00:06:25.758
within the baggy bounds and
then some thing over here that

00:06:25.758 --> 00:06:27.398
makes it go out of bounds.

00:06:27.398 --> 00:06:29.366
So at that moment,
right when that happens,

00:06:29.366 --> 00:06:30.760
that's how we know that
something chicanerous has

00:06:30.760 --> 00:06:31.260
arisen.

00:06:36.760 --> 00:06:39.420
All right so, hopefully
that should all make sense.

00:06:39.420 --> 00:06:41.480
And so this is very
briefly a review

00:06:41.480 --> 00:06:44.311
of the homework question.

00:06:44.311 --> 00:06:46.894
So hopefully you can understand
this and our homework question

00:06:46.894 --> 00:06:48.394
should be pretty
easy to understand.

00:06:48.394 --> 00:06:56.740
So we have a character pointer
the malloc had 256 bytes to it,

00:06:56.740 --> 00:06:59.427
Then we declare a
character pointer

00:06:59.427 --> 00:07:06.420
q, that is equal to
that pointer plus 256

00:07:06.420 --> 00:07:11.340
and then we essentially try
to dereference this pointer.

00:07:11.340 --> 00:07:12.670
So what's going to happen?

00:07:12.670 --> 00:07:15.870
Well note that this is an
exact power too, right.

00:07:15.870 --> 00:07:18.790
So there's not actually any
bagginess in the bounds, right.

00:07:18.790 --> 00:07:23.430
So when we do this right here,
this makes q point to one

00:07:23.430 --> 00:07:26.070
pass the end of
those baggy bounds.

00:07:26.070 --> 00:07:27.660
So just like in this
example up here,

00:07:27.660 --> 00:07:30.930
this line is actually fine,
but it will cause the high bit

00:07:30.930 --> 00:07:32.217
to be set in q, right.

00:07:32.217 --> 00:07:34.050
So when you come down
here and reference it,

00:07:34.050 --> 00:07:35.775
then everything
blows up and it's

00:07:35.775 --> 00:07:37.670
time to call in your
insurance agent.

00:07:37.670 --> 00:07:40.420
So pretty straightforward?

00:07:40.420 --> 00:07:44.390
OK so, that's
basically two examples

00:07:44.390 --> 00:07:46.790
that you can flavor for
how baggy bounds works.

00:07:46.790 --> 00:07:49.465
As I mentioned in
the last lecture,

00:07:49.465 --> 00:07:51.590
you don't actually have to
instrument every pointer

00:07:51.590 --> 00:07:55.860
operation, if you can use static
code analysis to figure out

00:07:55.860 --> 00:07:58.250
the particular set of
pointer operations is safe.

00:07:58.250 --> 00:07:59.900
I'll defer further
discussion of some

00:07:59.900 --> 00:08:01.600
of the static
analysis [INAUDIBLE],

00:08:01.600 --> 00:08:04.133
but suffice it to say
that you don't always

00:08:04.133 --> 00:08:08.657
have to have all this bit
wise arithmetic that you

00:08:08.657 --> 00:08:12.086
have in some of the cases
that we've examined before.

00:08:15.870 --> 00:08:19.272
And so another question
that came up a lot in Piazza

00:08:19.272 --> 00:08:21.230
was, how does baggy bounds
ensure compatibility

00:08:21.230 --> 00:08:24.830
with these preexisting,
non-instrumented libraries,

00:08:24.830 --> 00:08:26.510
right.

00:08:26.510 --> 00:08:29.360
And so the Piazza idea behind
how baggy bounds does that

00:08:29.360 --> 00:08:33.200
is, that when baggy bounds
initializes the bounds tables,

00:08:33.200 --> 00:08:36.477
they set all the entries
to be that bound of 31.

00:08:36.477 --> 00:08:37.938
So when we read
the bounds table,

00:08:37.938 --> 00:08:40.510
each entry represents
2 to the power

00:08:40.510 --> 00:08:43.899
of that entry, the size of
that particular pointer.

00:08:43.899 --> 00:08:45.739
So by initializing
all those bounds

00:08:45.739 --> 00:08:49.692
of 31, what this allows
us to do is automatically

00:08:49.692 --> 00:08:52.670
assume that each pointer
from [INAUDIBLE] the code

00:08:52.670 --> 00:08:54.670
is going to have the
largest bound possible, 2

00:08:54.670 --> 00:08:56.259
raised to the 31.

00:08:56.259 --> 00:08:58.812
So let me just give you a
very simple example here

00:08:58.812 --> 00:09:00.770
that will hopefully make
this a little clearer.

00:09:00.770 --> 00:09:05.060
So let's say that this
over here is the memory

00:09:05.060 --> 00:09:09.370
space that we lose for heap.

00:09:12.220 --> 00:09:15.860
This is simple example,
let's suppose that basically

00:09:15.860 --> 00:09:18.785
what this memory space
[INAUDIBLE] two components.

00:09:18.785 --> 00:09:26.430
This is the heap, that is out
by the unistrumented code.

00:09:31.042 --> 00:09:33.153
And then let's suppose
that down here we

00:09:33.153 --> 00:09:40.563
have the heat that is allocated
by the instrumented code.

00:09:44.892 --> 00:09:46.816
So what's baggy
bounds going to do?

00:09:46.816 --> 00:09:51.041
So remember, baggy bounds has
this notion of a slot size,

00:09:51.041 --> 00:09:51.540
right.

00:09:51.540 --> 00:09:53.467
So basically the
slot size is 16,

00:09:53.467 --> 00:09:55.420
you only have entry
for every sort

00:09:55.420 --> 00:09:57.619
of slot of size 16 over here.

00:09:57.619 --> 00:09:59.410
So basically the bounds
table in this case,

00:09:59.410 --> 00:10:03.910
you can think of being
set up into three

00:10:03.910 --> 00:10:06.080
places, sorry two places.

00:10:06.080 --> 00:10:12.190
So initially all of the
bounds table, all the entries

00:10:12.190 --> 00:10:16.160
are initialized to 2 to the
30-- or sorry, to the 31.

00:10:16.160 --> 00:10:19.600
But then eventually
as the instrument code

00:10:19.600 --> 00:10:23.740
runs it's actually going
to use the baggy bounds

00:10:23.740 --> 00:10:28.960
algorithm to set these
values for whatever

00:10:28.960 --> 00:10:33.711
should be appropriate for that
particular [INAUDIBLE], right.

00:10:33.711 --> 00:10:35.252
So what ends happening
is that if you

00:10:35.252 --> 00:10:39.608
did-- if instrumented code gets
a pointer that comes from here,

00:10:39.608 --> 00:10:42.010
then those baggy bounds
with each particular pointer

00:10:42.010 --> 00:10:45.110
will always be set to the
largest possible value, 231.

00:10:45.110 --> 00:10:45.945
2 to the 31, right.

00:10:45.945 --> 00:10:47.320
Which means that
it's going to be

00:10:47.320 --> 00:10:49.900
impossible for baggy
bounds, entry of the code,

00:10:49.900 --> 00:10:52.052
to think that you've done
an out of bound operation

00:10:52.052 --> 00:10:55.130
with that pointer that's
coming from this uninstrumented

00:10:55.130 --> 00:10:57.090
library.

00:10:57.090 --> 00:10:59.264
So does that make sense?

00:10:59.264 --> 00:11:00.930
So the idea is that
in instrumented code

00:11:00.930 --> 00:11:03.110
we're always going to be
doing these comparisons

00:11:03.110 --> 00:11:06.720
with the pointers, but if
we always set the bounds

00:11:06.720 --> 00:11:09.618
entries for uninstrumented
pointer code 2 to the 31,

00:11:09.618 --> 00:11:13.000
you can never have
a dereference error.

00:11:13.000 --> 00:11:17.560
OK so that's basically how we
have this nice interoperability

00:11:17.560 --> 00:11:20.542
between the entry of the
baggy bounds code in between

00:11:20.542 --> 00:11:24.320
a noninstrumented off the
shelf legacy library's.

00:11:24.320 --> 00:11:27.010
So putting it all together,
what does this all mean?

00:11:27.010 --> 00:11:28.830
So, we have this
system here which

00:11:28.830 --> 00:11:31.330
is nice because it doesn't make
the uninstrumented libraries

00:11:31.330 --> 00:11:34.828
blow up, but one problem
is that we can't detect out

00:11:34.828 --> 00:11:37.400
of bounds pointers
that were generated

00:11:37.400 --> 00:11:39.830
in the uninstrumented
code, right.

00:11:39.830 --> 00:11:42.766
Because we're never going to
set that high bit for example,

00:11:42.766 --> 00:11:44.790
if that [INAUDIBLE]
pointer gets too big,

00:11:44.790 --> 00:11:46.590
or gets too small or
anything like that.

00:11:46.590 --> 00:11:48.430
So we actually can't
provide memory safety

00:11:48.430 --> 00:11:51.730
for operations that take
place in uninstrumented code.

00:11:51.730 --> 00:11:54.770
You also can't detect when
we pass an out of bounds

00:11:54.770 --> 00:11:58.300
pointer from instrumented
code to uninstrumented code.

00:11:58.300 --> 00:11:59.842
Something insane
could happen, right.

00:11:59.842 --> 00:12:01.758
Because remember if you
had this out of bounds

00:12:01.758 --> 00:12:03.370
pulled it from the
instrumented code

00:12:03.370 --> 00:12:05.210
it has that high
bit set to 1, right.

00:12:05.210 --> 00:12:07.466
So it looks like
it's super ginormous.

00:12:07.466 --> 00:12:09.924
Now we know if we just kept
that code in instrumented code,

00:12:09.924 --> 00:12:11.507
we might clear that
flag at some point

00:12:11.507 --> 00:12:13.340
if it comes back in bounds.

00:12:13.340 --> 00:12:15.391
But if we just pass
this ginormous address

00:12:15.391 --> 00:12:17.240
to uninstrumented
code, then who knows,

00:12:17.240 --> 00:12:20.000
it may try to dereference it,
it may do something crazy.

00:12:20.000 --> 00:12:22.297
It may even bring that
pointer back in bounds,

00:12:22.297 --> 00:12:23.880
but we would never
have an opportunity

00:12:23.880 --> 00:12:25.990
to clear that high bit, right.

00:12:25.990 --> 00:12:27.854
So you can come up--
you still may come up

00:12:27.854 --> 00:12:30.040
with some inter-op
issues there, even if we

00:12:30.040 --> 00:12:34.190
use this scheme over here.

00:12:34.190 --> 00:12:38.911
OK, so that's essentially how
baggy bounds works on a 32--

00:12:38.911 --> 00:12:39.702
you got a question?

00:12:39.702 --> 00:12:41.951
AUDIENCE: Yeah, so if you
have a instrumented coding

00:12:41.951 --> 00:12:43.799
meets like allocated
memory, is it

00:12:43.799 --> 00:12:46.460
using the same malloc that the
attributing code is using, or?

00:12:46.460 --> 00:12:48.001
PROFESSOR: Yeah so
it's a bit subtle.

00:12:48.001 --> 00:12:50.295
So like in this case
here, it's like very stark

00:12:50.295 --> 00:12:53.300
what's going on, because there's
just two regions, one of which

00:12:53.300 --> 00:12:55.294
is used by each set of things.

00:12:55.294 --> 00:12:57.784
So it actually depends on
the if they use [INAUDIBLE]

00:12:57.784 --> 00:12:58.617
and stuff like that.

00:12:58.617 --> 00:13:01.768
You can also imagine that like
in C++ [INAUDIBLE] for example,

00:13:01.768 --> 00:13:03.760
you can define your
own allocator, right.

00:13:03.760 --> 00:13:06.748
So it kind of
depends [INAUDIBLE].

00:13:06.748 --> 00:13:10.732
AUDIENCE: [INAUDIBLE]
input the same,

00:13:10.732 --> 00:13:13.720
how does the allocator
know whether or not

00:13:13.720 --> 00:13:15.627
to set 31 or [INAUDIBLE].

00:13:15.627 --> 00:13:17.960
PROFESSOR: Yeah so at the
lower level, typically the way

00:13:17.960 --> 00:13:19.543
that these allocation
algorithms work,

00:13:19.543 --> 00:13:23.139
is that you call unknown
system [INAUDIBLE] or something

00:13:23.139 --> 00:13:24.680
like that, sort of
move a pointer up.

00:13:24.680 --> 00:13:27.397
So you can imagine if you have
multiple allocators, all trying

00:13:27.397 --> 00:13:29.290
to allocate memory,
they each have

00:13:29.290 --> 00:13:32.316
their own chunk of memory
they reserve for themselves

00:13:32.316 --> 00:13:33.460
basically, right.

00:13:33.460 --> 00:13:36.251
So in real life it may be
more fragmented than this,

00:13:36.251 --> 00:13:39.730
that's essentially on a
high level, how it works.

00:13:39.730 --> 00:13:43.130
OK so this was a baggy
bounds on a 32-bit system.

00:13:43.130 --> 00:13:45.516
So as you all know 64-bit
systems are the bees

00:13:45.516 --> 00:13:47.910
knees these days, so
how does baggy bounds

00:13:47.910 --> 00:13:50.276
work on those systems?

00:13:50.276 --> 00:13:51.900
Well, in those systems
you can actually

00:13:51.900 --> 00:13:55.170
get rid of the bounds table,
because we can actually

00:13:55.170 --> 00:13:58.871
store some information about
the bounds, from the pointer

00:13:58.871 --> 00:13:59.370
itself.

00:14:02.032 --> 00:14:06.514
So imagine we're going to
look at a regular pointer

00:14:06.514 --> 00:14:09.010
in a baggy bounds system.

00:14:09.010 --> 00:14:11.638
So we can use it, like this.

00:14:15.110 --> 00:14:18.330
So we can-- if the
pointer's in bounds,

00:14:18.330 --> 00:14:21.690
we can basically just set
the first 21 bits to 0.

00:14:21.690 --> 00:14:24.340
We can put the size
in these 5 bits here.

00:14:24.340 --> 00:14:27.610
And once again this is
representing the log base 2

00:14:27.610 --> 00:14:28.770
at the size here.

00:14:28.770 --> 00:14:31.970
And then we have here,
in the remaining 38 bits,

00:14:31.970 --> 00:14:33.662
just the regular address bits.

00:14:33.662 --> 00:14:35.370
Now the reason why
this doesn't massively

00:14:35.370 --> 00:14:37.850
curtail the address size
of the program you use,

00:14:37.850 --> 00:14:39.960
is that a lot of
these high order bits,

00:14:39.960 --> 00:14:41.908
the operating system
and-or the hardware,

00:14:41.908 --> 00:14:45.317
doesn't let a application use,
for various reasons, right.

00:14:45.317 --> 00:14:47.180
So as it turns out,
we're not dramatically

00:14:47.180 --> 00:14:49.268
shrinking the amount of
[INAUDIBLE] application

00:14:49.268 --> 00:14:51.062
you use in the system.

00:14:51.062 --> 00:14:52.894
This is what a regular
pointer looks like.

00:14:52.894 --> 00:14:53.810
Now what happens
when we only have

00:14:53.810 --> 00:14:55.280
one of these out
of bounds pointers?

00:14:55.280 --> 00:14:57.290
Well, in a 32-bit system
all we can do basically

00:14:57.290 --> 00:14:59.570
is just set that high
order bit and you just

00:14:59.570 --> 00:15:02.990
hope that thing never got
beyond a 1/2 a slot away

00:15:02.990 --> 00:15:05.119
from it's base.

00:15:05.119 --> 00:15:08.053
But now that we have all this
extra address space here,

00:15:08.053 --> 00:15:13.760
you can actually put the out
of bounds offset directly

00:15:13.760 --> 00:15:14.912
in this pointer.

00:15:18.020 --> 00:15:20.075
So we can do
something like this.

00:15:25.230 --> 00:15:29.300
So we can have 13 bits
here for the offset, right,

00:15:29.300 --> 00:15:30.460
the out of bound offset.

00:15:30.460 --> 00:15:33.740
How far away is this out of
bounds pointer, from the place

00:15:33.740 --> 00:15:35.050
where it should be?

00:15:35.050 --> 00:15:39.280
And then once again you
can put the actual size

00:15:39.280 --> 00:15:42.240
of the referred object here.

00:15:42.240 --> 00:15:44.112
This will be 0 once again.

00:15:44.112 --> 00:15:48.740
And this will be the
real address base here.

00:15:48.740 --> 00:15:51.430
And so this may be
reminiscent to you

00:15:51.430 --> 00:15:53.290
of some type of fact
pointer representation,

00:15:53.290 --> 00:15:55.190
but there's a
couple of advantages

00:15:55.190 --> 00:15:57.800
here, now that we're
moving in the 64-bit world.

00:15:57.800 --> 00:16:00.870
So first of all, you'll note
that these tag pointers,

00:16:00.870 --> 00:16:04.000
these are the regular size
of a regular pointer, right.

00:16:04.000 --> 00:16:07.860
Pointer's are still just 64-bits
wide in both of these setups.

00:16:07.860 --> 00:16:10.180
So that's nice because
that means for example,

00:16:10.180 --> 00:16:13.280
that means and rights to
that pointer are time.

00:16:13.280 --> 00:16:14.905
Unlike in traditional
fat finger world,

00:16:14.905 --> 00:16:16.779
where you actually have
to use multiple words

00:16:16.779 --> 00:16:18.042
represent that fat pointer.

00:16:18.042 --> 00:16:19.125
So that's nice.

00:16:19.125 --> 00:16:22.570
And also note that we can
trivially ask these things,

00:16:22.570 --> 00:16:24.300
uninstrumented
code, because they

00:16:24.300 --> 00:16:27.312
work and are the same
size as regular pointers.

00:16:27.312 --> 00:16:29.270
We can put these things
in structs for example,

00:16:29.270 --> 00:16:32.080
and the size of those
structs won't change.

00:16:32.080 --> 00:16:36.470
So this is very nice if we
can work in that 64-bit world.

00:16:36.470 --> 00:16:39.166
So does that all make sense?

00:16:39.166 --> 00:16:42.798
AUDIENCE: So why are there
eight 0-bits [INAUDIBLE]

00:16:42.798 --> 00:16:43.680
pointer there?

00:16:43.680 --> 00:16:47.550
Where like the 5 size
bits previously weren't.

00:16:47.550 --> 00:16:49.590
PROFESSOR: So you're
talking about down here?

00:16:49.590 --> 00:16:50.965
AUDIENCE: Yeah,
is there a reason

00:16:50.965 --> 00:16:53.320
why we can't just
store a [INAUDIBLE]

00:16:53.320 --> 00:16:54.935
if we're like six
0-bits there and had

00:16:54.935 --> 00:16:57.720
more bits for the offset,
like why is the number 8?

00:16:57.720 --> 00:17:00.475
PROFESSOR: So I think
so in some cases

00:17:00.475 --> 00:17:02.808
there are certain line issues
that we have to work with.

00:17:02.808 --> 00:17:05.825
The [INAUDIBLE] issue is to deal
with if the bits are higher.

00:17:05.825 --> 00:17:07.325
I don't think, in
principle, there's

00:17:07.325 --> 00:17:08.866
any reason why you
couldn't read some

00:17:08.866 --> 00:17:10.089
of these things [INAUDIBLE].

00:17:10.089 --> 00:17:11.589
Well there may be
some hard versions

00:17:11.589 --> 00:17:13.128
that I'm not thinking
of right now,

00:17:13.128 --> 00:17:15.003
but [INAUDIBLE] some of
these would have to 0

00:17:15.003 --> 00:17:17.930
or otherwise the hardware's
going to cause a problem.

00:17:21.079 --> 00:17:23.310
Any other questions?

00:17:23.310 --> 00:17:26.380
OK so, next thing
are you wondering

00:17:26.380 --> 00:17:28.550
is, can you still
launch a buffer

00:17:28.550 --> 00:17:30.355
overflows in the
baggy bounds system,

00:17:30.355 --> 00:17:32.480
obviously because I gave
you another paper to read,

00:17:32.480 --> 00:17:34.220
so clearly this thing, this
doesn't solve all the problems,

00:17:34.220 --> 00:17:34.970
right?

00:17:34.970 --> 00:17:36.610
So one problem
you might run into

00:17:36.610 --> 00:17:38.735
is that if you have
uninstrumented code once again,

00:17:38.735 --> 00:17:41.510
we can't detect any problems
in uninstrumented code.

00:17:41.510 --> 00:17:44.550
You could also encounter
memory vulnerabilities

00:17:44.550 --> 00:17:47.380
that come about from the dynamic
memory allocation system.

00:17:47.380 --> 00:17:48.921
So if you can remember
in the lecture

00:17:48.921 --> 00:17:52.990
we looked at this weird
free malloc weird pointer

00:17:52.990 --> 00:17:54.090
thing that took place.

00:17:54.090 --> 00:17:55.980
Baggy bounds won't
necessarily prevent you

00:17:55.980 --> 00:17:57.500
from some of that stuff.

00:17:57.500 --> 00:18:00.130
We also discussed
last lecture, where

00:18:00.130 --> 00:18:02.654
the fact that code
pointers do not have bounds

00:18:02.654 --> 00:18:04.260
associated with them, right.

00:18:04.260 --> 00:18:07.240
So now you have struct that
has a buffer at the bottom,

00:18:07.240 --> 00:18:09.140
it has a function
pointer up top,

00:18:09.140 --> 00:18:12.050
if you have a buffer overflow
in to that function pointer,

00:18:12.050 --> 00:18:12.550
right.

00:18:12.550 --> 00:18:14.220
Let's say that buffer
overflow is still

00:18:14.220 --> 00:18:15.280
within the baggy bounds.

00:18:15.280 --> 00:18:17.910
So you've overridden
that function pointer.

00:18:17.910 --> 00:18:20.020
We would try to execute
that function pointer,

00:18:20.020 --> 00:18:22.100
it could be pointed
at something for,

00:18:22.100 --> 00:18:23.840
attack a control
piece of memory.

00:18:23.840 --> 00:18:24.950
OK, and bounds won't
help with that,

00:18:24.950 --> 00:18:26.814
because there's no bounds
associate with function

00:18:26.814 --> 00:18:27.313
pointers.

00:18:30.076 --> 00:18:36.562
And so in general, what are
the cost's of baggy bounds?

00:18:36.562 --> 00:18:38.860
So there are essentially four.

00:18:38.860 --> 00:18:43.120
So the first cost
is space, right.

00:18:43.120 --> 00:18:44.495
So if you're using
a fat pointer,

00:18:44.495 --> 00:18:47.120
obviously you've got to
make pointers bigger.

00:18:47.120 --> 00:18:49.821
But if you're using the baggy
bounds system that we just

00:18:49.821 --> 00:18:52.112
discussed, you've got to
store the bounds table, right.

00:18:52.112 --> 00:18:55.600
And so the bounds table
has that slot size

00:18:55.600 --> 00:18:58.090
which allows you to control
how big that bounds table is,

00:18:58.090 --> 00:19:02.140
but still you may end up using
[INAUDIBLE] memory for that.

00:19:02.140 --> 00:19:08.370
You've also got the CPU overhead
of doing all of the pointer

00:19:08.370 --> 00:19:09.800
instrumentation, right.

00:19:09.800 --> 00:19:13.420
So for every, or close to every
pointer thing that you do,

00:19:13.420 --> 00:19:16.880
you got to check these bounds
using those shift operations

00:19:16.880 --> 00:19:18.040
and things like that.

00:19:18.040 --> 00:19:21.140
So that's going to
slow your program down.

00:19:21.140 --> 00:19:26.890
There's also this problem
with false alarms, right.

00:19:26.890 --> 00:19:29.624
So as we discussed,
it may be the case

00:19:29.624 --> 00:19:31.540
that a program generates
out of bound pointers

00:19:31.540 --> 00:19:33.360
but never tries to
dereference it, right.

00:19:33.360 --> 00:19:35.520
Strictly speaking
that's not an issue.

00:19:35.520 --> 00:19:37.560
The baggy bounds will
flag the creation

00:19:37.560 --> 00:19:39.250
of those out of bounds
pointers, if they

00:19:39.250 --> 00:19:42.660
get beyond a 1/2 a slot size,
at least in the 32-bit solution,

00:19:42.660 --> 00:19:43.160
right.

00:19:43.160 --> 00:19:45.460
And so what you'll see with
a lot of security tools,

00:19:45.460 --> 00:19:48.362
is that false alarms really
reduce the likelihood

00:19:48.362 --> 00:19:50.320
that people are going to
use your tools, right.

00:19:50.320 --> 00:19:52.330
Because in practice
we would all hope

00:19:52.330 --> 00:19:54.547
that we care about
security, but actually

00:19:54.547 --> 00:19:55.630
what do people care about?

00:19:55.630 --> 00:19:57.720
They want to be able to upload
their silly Facebook photos

00:19:57.720 --> 00:19:59.070
and life things,
and they want to be

00:19:59.070 --> 00:20:01.130
able to make things go
fast and stuff like that.

00:20:01.130 --> 00:20:03.160
So you really want
your security tools

00:20:03.160 --> 00:20:07.240
to probably have less
coverage of finding bugs,

00:20:07.240 --> 00:20:09.520
but actually have
0 false alarms.

00:20:09.520 --> 00:20:12.230
As opposed to catching all types
of security vulnerabilities,

00:20:12.230 --> 00:20:14.020
but then maybe having
some false alarms

00:20:14.020 --> 00:20:16.790
that are going to irritate
developers, or irritate users.

00:20:16.790 --> 00:20:19.040
And the other costs that you
have for this is finally,

00:20:19.040 --> 00:20:25.770
is that you need
compiler support, right.

00:20:25.770 --> 00:20:27.640
Which can actually end
up being nontrivial,

00:20:27.640 --> 00:20:28.570
because you have
to go in there, you

00:20:28.570 --> 00:20:30.360
have to add all the
instrumentation,

00:20:30.360 --> 00:20:32.610
crawl the pointer checks,
and so on ans so forth.

00:20:32.610 --> 00:20:35.330
So those are basically the
cost of these bounds checking

00:20:35.330 --> 00:20:37.000
approaches.

00:20:37.000 --> 00:20:42.120
So that concludes the
discussion of baggy bounds.

00:20:42.120 --> 00:20:45.010
And so now we can actually think
about a two other mitigation

00:20:45.010 --> 00:20:46.570
strategies for buffer overflows.

00:20:46.570 --> 00:20:49.600
They're actually much simpler
to explain and understand.

00:20:49.600 --> 00:20:55.090
So one of these approaches is
called a non-executable memory.

00:21:00.570 --> 00:21:04.600
And the basic idea is
that the paging hardware

00:21:04.600 --> 00:21:08.830
is going to specify
3-bits for each page

00:21:08.830 --> 00:21:12.064
that you have in memory, read,
write and execute, right.

00:21:12.064 --> 00:21:13.980
Can the program read
that memory, write to it,

00:21:13.980 --> 00:21:14.720
execute it.

00:21:14.720 --> 00:21:16.380
The first 2-bits
are old, they've

00:21:16.380 --> 00:21:18.600
been around for a while,
that last bit is actually

00:21:18.600 --> 00:21:19.764
a fairly new construction.

00:21:19.764 --> 00:21:21.430
And so the idea is
that you can actually

00:21:21.430 --> 00:21:24.790
make the stack
non-executable, right.

00:21:24.790 --> 00:21:26.960
So if you make the
stack non-executable

00:21:26.960 --> 00:21:29.110
that means that the
adversary can't run code

00:21:29.110 --> 00:21:31.440
just by pointing-- by
creating that shell code

00:21:31.440 --> 00:21:34.840
and then sort of jumping to
someplace in that buffer.

00:21:34.840 --> 00:21:39.470
And so what a lot of systems
do, is they actually specify

00:21:39.470 --> 00:21:43.190
a policy like this.

00:21:43.190 --> 00:21:46.690
So right exclusive or x,
which means that if you have

00:21:46.690 --> 00:21:49.730
a particular page, you
can either write to it,

00:21:49.730 --> 00:21:52.070
or you can treat it
as executable code,

00:21:52.070 --> 00:21:53.542
but you cannot do both.

00:21:53.542 --> 00:21:55.000
OK and so that once
again, is going

00:21:55.000 --> 00:21:56.450
to prevent the
attacker from just

00:21:56.450 --> 00:21:58.250
putting executable
code in the stack

00:21:58.250 --> 00:22:00.380
and then going straight to it.

00:22:00.380 --> 00:22:02.890
So this is-- should be pretty
straightforward, right.

00:22:02.890 --> 00:22:06.850
So we've removed, at the
hardware level, this attack

00:22:06.850 --> 00:22:09.920
vector of the attacker putting
executable code in the stack.

00:22:09.920 --> 00:22:11.210
So what's nice about this?

00:22:11.210 --> 00:22:14.670
Well potentially this
works without any changes

00:22:14.670 --> 00:22:16.190
to the application, right.

00:22:16.190 --> 00:22:18.610
This is all taken place
at the hardware level

00:22:18.610 --> 00:22:20.660
and at the OS level,
with the OS just

00:22:20.660 --> 00:22:23.350
making sure the pages are
protected with these bits, OK.

00:22:23.350 --> 00:22:24.725
So that's very,
very nuts, right.

00:22:24.725 --> 00:22:27.183
Because you don;t have to worry
about this compiler support

00:22:27.183 --> 00:22:28.210
issue we had over here.

00:22:28.210 --> 00:22:30.250
The other nice thing
is that, as I mentioned

00:22:30.250 --> 00:22:32.210
in the last lecture,
the hardware's

00:22:32.210 --> 00:22:35.320
always watching you, even
though the OS is not, right.

00:22:35.320 --> 00:22:37.520
So these bits being
said over here,

00:22:37.520 --> 00:22:40.060
you know they're
looked at and verified

00:22:40.060 --> 00:22:42.415
for correctness at
every memory reference

00:22:42.415 --> 00:22:43.850
that you make by the code.

00:22:43.850 --> 00:22:46.930
That's a very nice
aspect of this too.

00:22:46.930 --> 00:22:49.460
Now one disadvantage
of this system

00:22:49.460 --> 00:22:52.260
though, is that it makes it
harder for an application

00:22:52.260 --> 00:22:56.990
to dynamically generate code,
in benign or benevolent cases.

00:22:56.990 --> 00:22:59.880
And the best example of
that is, the just-in-time

00:22:59.880 --> 00:23:02.480
compilers that we discussed
from last lecture, right.

00:23:02.480 --> 00:23:04.150
So how is it that
you can go to a web

00:23:04.150 --> 00:23:06.100
page and your JavaScript
code executes fast.

00:23:06.100 --> 00:23:07.650
It downloads that
JavaScript source,

00:23:07.650 --> 00:23:09.826
it initially probably
starts just interpreting it,

00:23:09.826 --> 00:23:11.200
but then at some
point it's going

00:23:11.200 --> 00:23:12.999
to find some hot
path, some hot loop

00:23:12.999 --> 00:23:14.790
and then it's going to
dynamically generate

00:23:14.790 --> 00:23:17.884
x86 machine code and execute
that directly, right.

00:23:17.884 --> 00:23:20.550
But to get that to work you have
to be able to dynamically write

00:23:20.550 --> 00:23:23.400
code to a page.

00:23:23.400 --> 00:23:25.990
So there's some ways you can
get around this for example,

00:23:25.990 --> 00:23:28.620
you could imagine that the
just-in-time compiler initially

00:23:28.620 --> 00:23:31.580
sets the write bit and then
it removes the write bit,

00:23:31.580 --> 00:23:32.950
then it sets the execute bits.

00:23:32.950 --> 00:23:34.770
There are some ways that
you can get around that,

00:23:34.770 --> 00:23:36.603
but it can be a little
bit tricky sometimes.

00:23:36.603 --> 00:23:39.227
On a higher level, that's how
non-executable memory works,

00:23:39.227 --> 00:23:40.310
pretty easy to understand.

00:23:40.310 --> 00:23:44.158
AUDIENCE: What is the
definition of like executable

00:23:44.158 --> 00:23:44.772
instructions?

00:23:44.772 --> 00:23:46.563
So if you change the
attenuator [INAUDIBLE]

00:23:46.563 --> 00:23:47.525
it's not considered a
executable instruction.

00:23:47.525 --> 00:23:49.410
PROFESSOR: Well basically no.

00:23:49.410 --> 00:23:53.220
Can you set like the instruction
pointer register to that value.

00:23:53.220 --> 00:23:56.240
In other words, can you-- if you
have a bunch of memory pages,

00:23:56.240 --> 00:23:58.580
can you actually set EIP
there and actually start

00:23:58.580 --> 00:23:59.979
executing code from that page.

00:23:59.979 --> 00:24:00.520
AUDIENCE: Ah.

00:24:03.520 --> 00:24:07.480
PROFESSOR: OK, so that
is nonexecutable memory.

00:24:07.480 --> 00:24:09.710
And so another
technique you might

00:24:09.710 --> 00:24:12.990
imagine for protecting
against a buffer overflows

00:24:12.990 --> 00:24:19.845
is using a randomized
addresses or address spaces.

00:24:26.410 --> 00:24:30.270
And so the observation
here is, that a lot

00:24:30.270 --> 00:24:35.080
of the attacks that
we've discussed so far

00:24:35.080 --> 00:24:39.590
use hard coded addresses, right.

00:24:39.590 --> 00:24:42.140
And so if you think about
a lot of the attacks

00:24:42.140 --> 00:24:44.610
you've been working on in
your lab, how does that work?

00:24:44.610 --> 00:24:47.140
You open up the program
in GDB, you find out

00:24:47.140 --> 00:24:49.840
the location of some things,
you may create some shell code

00:24:49.840 --> 00:24:52.700
that actually has some hard
coded addresses in there,

00:24:52.700 --> 00:24:53.200
right.

00:24:53.200 --> 00:24:55.390
So the idea behind the
randomized address base

00:24:55.390 --> 00:24:55.890
is simple.

00:24:55.890 --> 00:25:03.160
Basically you want to make
it difficult for the attacker

00:25:03.160 --> 00:25:04.205
to guess addresses.

00:25:08.084 --> 00:25:09.500
So there's a couple
different ways

00:25:09.500 --> 00:25:11.230
you could think about
doing this, right.

00:25:11.230 --> 00:25:13.530
So one idea is that
you can imagine having

00:25:13.530 --> 00:25:15.260
stack randomization, right.

00:25:15.260 --> 00:25:17.850
So imagine that
from here to here,

00:25:17.850 --> 00:25:20.370
this is the entire virtual
memory space of the program,

00:25:20.370 --> 00:25:20.870
right.

00:25:20.870 --> 00:25:22.870
As we described this
stuff to you so far,

00:25:22.870 --> 00:25:24.690
basically the
stack always starts

00:25:24.690 --> 00:25:27.270
with this particular place
up here, always goes down,

00:25:27.270 --> 00:25:30.360
right, and the program codes
down here and the heap always

00:25:30.360 --> 00:25:31.470
goes up here.

00:25:31.470 --> 00:25:35.030
And all these seg-- all of these
segments, the stack, the heap,

00:25:35.030 --> 00:25:38.350
and the program code, they all
start at a well known location.

00:25:38.350 --> 00:25:40.950
So imagine for example, like
if my lecture notes here

00:25:40.950 --> 00:25:41.695
are the stack.

00:25:41.695 --> 00:25:44.070
You can imagine instead of
the stack always starting here

00:25:44.070 --> 00:25:46.780
at this known location,
maybe you start it here,

00:25:46.780 --> 00:25:47.947
maybe you start it here.

00:25:47.947 --> 00:25:49.280
Somewhere else like that, right.

00:25:49.280 --> 00:25:51.900
Similarly you can imagine that
maybe the program code which

00:25:51.900 --> 00:25:53.760
used to always start
down here, maybe we

00:25:53.760 --> 00:25:56.616
start it up here, or down here,
or something like that, right.

00:25:56.616 --> 00:25:58.490
So the idea now is that
if you, the attacker,

00:25:58.490 --> 00:26:01.075
control one of these
binary's, you can look in GDB

00:26:01.075 --> 00:26:02.867
and figure out where
all these offsets are,

00:26:02.867 --> 00:26:05.075
but they're not actually
going to help you figure out

00:26:05.075 --> 00:26:07.190
where those offsets are
in the real code that's

00:26:07.190 --> 00:26:09.190
running on the server, right.

00:26:09.190 --> 00:26:12.320
So that's the basic idea behind
these randomized address spaces

00:26:12.320 --> 00:26:13.510
there.

00:26:13.510 --> 00:26:15.312
And so this takes
advantage of the fact

00:26:15.312 --> 00:26:17.020
that a lot of the code
that you generate,

00:26:17.020 --> 00:26:19.740
doesn't have to be loaded into
a specific place in memory,

00:26:19.740 --> 00:26:20.240
right.

00:26:20.240 --> 00:26:22.698
So unless you're writing like
a device driver, or something

00:26:22.698 --> 00:26:25.350
like, that maybe is interacting
with some hardware that

00:26:25.350 --> 00:26:29.670
requires this
particular address to be

00:26:29.670 --> 00:26:32.370
belong in this particular buffer
so it can copy information in.

00:26:32.370 --> 00:26:34.562
If you're not doing stuff
like that then typically

00:26:34.562 --> 00:26:36.020
your codes going
to be relocatable.

00:26:36.020 --> 00:26:40.000
So this approach will work very
nicely with that kind of stuff.

00:26:40.000 --> 00:26:43.740
So once again the question
is, can you exploit this?

00:26:43.740 --> 00:26:45.196
Obviously the
answer is still yes.

00:26:45.196 --> 00:26:47.070
There's a couple different
ways you can do it

00:26:47.070 --> 00:26:50.460
as we'll discuss later today
in the [INAUDIBLE] paper,

00:26:50.460 --> 00:26:53.779
the attacker can actually
extract randomness, right.

00:26:53.779 --> 00:26:55.570
And so in general that's
how you defeat all

00:26:55.570 --> 00:26:56.850
these randomized approaches.

00:26:56.850 --> 00:26:58.857
You make them unrandom,
by either finding out

00:26:58.857 --> 00:27:00.690
the random seed that
the attacker was doing,

00:27:00.690 --> 00:27:03.740
or by somehow leveraging the
fact that the attacker leaks

00:27:03.740 --> 00:27:07.040
information about the randomized
locations of these things.

00:27:10.520 --> 00:27:12.020
And another thing
that's interesting

00:27:12.020 --> 00:27:15.250
is that for a lot of the
attacks we've discussed so far,

00:27:15.250 --> 00:27:18.060
we've basically been using these
sort of hard coded addresses,

00:27:18.060 --> 00:27:21.300
but note that the attacker
may not necessarily

00:27:21.300 --> 00:27:23.740
care about jumping to
a specific address.

00:27:23.740 --> 00:27:26.160
Or there's this attack
called a heap attack, which

00:27:26.160 --> 00:27:29.260
is actually pretty hilarious if
you're a bad person, I suppose.

00:27:29.260 --> 00:27:32.050
So the way that this
heap attack works

00:27:32.050 --> 00:27:34.160
is, that the
attacker essentially

00:27:34.160 --> 00:27:37.280
just starts dynamically
allocating a ton of shell code

00:27:37.280 --> 00:27:39.341
and just stuffs it
randomly in memory, right.

00:27:39.341 --> 00:27:41.007
This is particularly
effective if you're

00:27:41.007 --> 00:27:44.870
using like a dynamically high
level language like JavaScript

00:27:44.870 --> 00:27:45.490
let's say.

00:27:45.490 --> 00:27:46.910
So the tag reader is
sitting in a tight loop

00:27:46.910 --> 00:27:49.201
and just generate a bunch of
shell code strings, right.

00:27:49.201 --> 00:27:51.750
And you just fill the heap
with all these shell code

00:27:51.750 --> 00:27:53.140
strings, right.

00:27:53.140 --> 00:27:55.820
Now the attacker maybe cannot
figure out where the exact

00:27:55.820 --> 00:27:58.340
location is of each of
the shell code strings,

00:27:58.340 --> 00:28:02.330
but if you've allocated 10s of
megabytes of shell code strings

00:28:02.330 --> 00:28:04.160
and then just do a
random jump, right.

00:28:04.160 --> 00:28:06.800
If you could somehow control
one of these ret pointers,

00:28:06.800 --> 00:28:09.914
then hey, maybe you'll
land in shell code, right.

00:28:09.914 --> 00:28:11.330
And one trick you
can actually use

00:28:11.330 --> 00:28:14.200
is this thing called NOP sleds,
which is also pretty hilarious.

00:28:14.200 --> 00:28:18.590
So imagine that if you have
a shell code string, then

00:28:18.590 --> 00:28:20.640
it may not work out if
you jump to a random place

00:28:20.640 --> 00:28:22.720
in that shell code
string, because it may not

00:28:22.720 --> 00:28:24.330
set the attack up correctly.

00:28:24.330 --> 00:28:27.250
But maybe this stuff that
your spewing to the heap,

00:28:27.250 --> 00:28:30.876
is basically just a ton of NOPs
and then at the very, very end

00:28:30.876 --> 00:28:32.240
you have the shell code, right.

00:28:32.240 --> 00:28:33.910
This is actually
quite clever right,

00:28:33.910 --> 00:28:36.690
because this means that now
you can actually goof up

00:28:36.690 --> 00:28:38.182
the exact place where you jump.

00:28:38.182 --> 00:28:39.890
If you jump into
another one of these NOP

00:28:39.890 --> 00:28:42.431
things just go boom, boom, boom,
boom, boom, boom, boom, then

00:28:42.431 --> 00:28:43.920
you hit the shell code, right.

00:28:43.920 --> 00:28:46.110
So it's like these are the
people that you probably

00:28:46.110 --> 00:28:47.090
see on the team.

00:28:47.090 --> 00:28:49.048
They're inventing these
types of things, right.

00:28:49.048 --> 00:28:49.980
This is a problem.

00:28:49.980 --> 00:28:51.956
So that's another way
to get around some

00:28:51.956 --> 00:28:53.330
of this randomization
stuff, just

00:28:53.330 --> 00:28:55.850
by making your codes
randomization resilient,

00:28:55.850 --> 00:28:58.880
if that makes sense.

00:28:58.880 --> 00:29:01.493
OK so that's basically
a discussion of some

00:29:01.493 --> 00:29:03.120
of the types of
randomness you can use.

00:29:03.120 --> 00:29:05.400
There's also some wacky ideas
that people have had too.

00:29:05.400 --> 00:29:06.340
So now you know
that when you want

00:29:06.340 --> 00:29:08.020
to make a system
call for example,

00:29:08.020 --> 00:29:11.275
you use this syscall
libc function

00:29:11.275 --> 00:29:13.157
and you basically pass
any unique number that

00:29:13.157 --> 00:29:15.490
represents the system call
that you want to make, right.

00:29:15.490 --> 00:29:19.150
So maybe four is seven and maybe
sleep is eight, or something

00:29:19.150 --> 00:29:20.950
like that, right.

00:29:20.950 --> 00:29:23.280
So what that means is that
if the attacker can somehow

00:29:23.280 --> 00:29:26.730
figure out the address of
that syscall instruction

00:29:26.730 --> 00:29:29.420
and jump to it somehow, he or
she can actually just supply

00:29:29.420 --> 00:29:32.972
the system call number that they
want to invoke directly, right.

00:29:32.972 --> 00:29:35.180
So you could imagine that
each time the program runs,

00:29:35.180 --> 00:29:39.290
you actually create a dynamic
assignment of syscall numbers

00:29:39.290 --> 00:29:40.951
to actual syscalls, right.

00:29:40.951 --> 00:29:42.950
To make it harder for the
attacker to get stuff.

00:29:42.950 --> 00:29:45.250
There's even some very
avant garde proposals

00:29:45.250 --> 00:29:48.300
to change the hardware such
that the hardware actually

00:29:48.300 --> 00:29:51.870
contains an xor key, that
is used to dynamically xor

00:29:51.870 --> 00:29:53.130
instructions, right.

00:29:53.130 --> 00:29:55.500
Imagine every time you
compile the program, all

00:29:55.500 --> 00:29:58.570
of the instruction codes that's
the xor of some key, right.

00:29:58.570 --> 00:30:00.590
That key is put into
that hardware register

00:30:00.590 --> 00:30:02.370
when you initially
load the program

00:30:02.370 --> 00:30:04.450
and then whenever you
execute an instruction,

00:30:04.450 --> 00:30:06.620
the hardware
automatically xor's it,

00:30:06.620 --> 00:30:08.980
before you continue executing
that instruction, right.

00:30:08.980 --> 00:30:10.771
So what's nice about
that is, that now even

00:30:10.771 --> 00:30:12.700
if the attacker can
generate the shell code,

00:30:12.700 --> 00:30:14.450
the attacker doesn't
know that key, right.

00:30:14.450 --> 00:30:16.074
So it's very difficult
for the attacker

00:30:16.074 --> 00:30:18.020
to figure out what exactly
to put into memory.

00:30:18.020 --> 00:30:19.520
AUDIENCE: But if
he can get the code

00:30:19.520 --> 00:30:23.219
and he also instructions
he can xor it back

00:30:23.219 --> 00:30:24.510
to the instruction [INAUDIBLE].

00:30:24.510 --> 00:30:25.140
PROFESSOR;Oh yeah.

00:30:25.140 --> 00:30:26.810
This is always a
canonical problem, right.

00:30:26.810 --> 00:30:28.360
So it's like what if
someone does this?

00:30:28.360 --> 00:30:29.377
So that's exactly right.

00:30:29.377 --> 00:30:31.960
So this is somewhat similar to
what happens in the BROP attack

00:30:31.960 --> 00:30:35.290
where, essentially we've sort of
randomized where locations are,

00:30:35.290 --> 00:30:37.270
but the attacker can
do probes, right.

00:30:37.270 --> 00:30:38.760
And figure out what's going on.

00:30:38.760 --> 00:30:41.610
So you can imagine too that for
example, if the attacker knows

00:30:41.610 --> 00:30:44.410
some sub-sequence of
code that he's expects

00:30:44.410 --> 00:30:46.220
to be in the binary,
you could imagine

00:30:46.220 --> 00:30:49.047
just sort of trying to xor the
binary with that known code,

00:30:49.047 --> 00:30:50.130
trying to extract the key.

00:30:50.130 --> 00:30:51.630
And there's a lot
evil in the world,

00:30:51.630 --> 00:30:53.890
so you're exactly
correct about that.

00:30:53.890 --> 00:30:55.720
OK so that's essentially
the discussion

00:30:55.720 --> 00:31:00.310
of all the randomization attacks
that I want to discuss today.

00:31:00.310 --> 00:31:02.150
So one thing to
talk about before we

00:31:02.150 --> 00:31:04.370
get to some of the return
oriented programming stuff,

00:31:04.370 --> 00:31:06.370
is you might wonder which
ones of these defenses

00:31:06.370 --> 00:31:08.440
are actually used in practice.

00:31:08.440 --> 00:31:12.420
And so as it turns out,
both GCC and Visual Studio,

00:31:12.420 --> 00:31:15.640
they both enable stack
canaries by default, right.

00:31:15.640 --> 00:31:19.900
So that's very popular, that's
a very well known community.

00:31:19.900 --> 00:31:21.820
If you look Linux
and Windows they

00:31:21.820 --> 00:31:24.071
can also do things like
non-executable memory.

00:31:24.071 --> 00:31:26.570
They can also do things like
randomize the address space, so

00:31:26.570 --> 00:31:27.950
that's also [INAUDIBLE].

00:31:27.950 --> 00:31:30.247
The baggy bounds stuff
however, is not as popular.

00:31:30.247 --> 00:31:31.955
And that's because of
some of these costs

00:31:31.955 --> 00:31:33.621
that we talked about
over here, in terms

00:31:33.621 --> 00:31:36.925
of memory overhead, CPU, the
false alarms, and so on ans

00:31:36.925 --> 00:31:38.560
so forth.

00:31:38.560 --> 00:31:41.810
So that's basically a survey
of the state of the art,

00:31:41.810 --> 00:31:45.970
in trying to prevent
these buffer overflows.

00:31:45.970 --> 00:31:50.311
So now we're going to talk about
this return oriented programing

00:31:50.311 --> 00:31:50.810
stuff.

00:31:53.900 --> 00:31:56.050
So what I'm described to
you so far today in terms

00:31:56.050 --> 00:31:58.260
of the address space
randomization and the data

00:31:58.260 --> 00:32:01.264
execution prevention,
that's the-- the

00:32:01.264 --> 00:32:03.180
read, write and execute
that I just described.

00:32:03.180 --> 00:32:05.662
Those things are actually
very, very powerful, right.

00:32:05.662 --> 00:32:07.620
Because the randomization
prevents the attacker

00:32:07.620 --> 00:32:10.036
from actually understanding
where our hard coded addresses

00:32:10.036 --> 00:32:10.580
are.

00:32:10.580 --> 00:32:11.980
And the data
execution prevention

00:32:11.980 --> 00:32:15.198
says, even if you can put
shell code into the stack,

00:32:15.198 --> 00:32:16.823
then the attacker
can't just jump to it

00:32:16.823 --> 00:32:18.160
and execute it, right.

00:32:18.160 --> 00:32:19.560
So at its space,
that seems like,

00:32:19.560 --> 00:32:21.226
man you've really
made a lot of progress

00:32:21.226 --> 00:32:25.469
for stopping these attackers,
but of course there

00:32:25.469 --> 00:32:28.010
are these hackers out there who
spend all their time thinking

00:32:28.010 --> 00:32:29.560
about how to ruin our lives.

00:32:29.560 --> 00:32:33.030
So what's the insight behind
return oriented programming?

00:32:33.030 --> 00:32:35.830
The insight is that, what
if instead of the attacker

00:32:35.830 --> 00:32:39.660
being able to generate just
new code at attack time, what

00:32:39.660 --> 00:32:42.430
if the attacker could
string together preexisting

00:32:42.430 --> 00:32:47.050
pieces of code and then string
them together in deviant ways,

00:32:47.050 --> 00:32:47.550
right?

00:32:47.550 --> 00:32:50.281
And we know that the program
contains a ton of code already,

00:32:50.281 --> 00:32:50.780
right.

00:32:50.780 --> 00:32:53.508
So hopefully, or unhopefully,
depending on which side of this

00:32:53.508 --> 00:32:54.450
you're on.

00:32:54.450 --> 00:32:56.900
If you can find enough
interesting code snippets,

00:32:56.900 --> 00:32:59.800
you can string them
together to basically form

00:32:59.800 --> 00:33:01.630
like this Turing
complete language, where

00:33:01.630 --> 00:33:03.540
the attacker can essentially
do whatever the attacker wants

00:33:03.540 --> 00:33:04.140
to do.

00:33:04.140 --> 00:33:07.240
So that's the insight behind
return oriented programming.

00:33:07.240 --> 00:33:08.980
So understand how this works.

00:33:08.980 --> 00:33:11.600
Let's look at a very simple
example that will initially

00:33:11.600 --> 00:33:14.800
start off very familiar, right.

00:33:14.800 --> 00:33:19.210
But then it's very quickly
going to descend into madness.

00:33:19.210 --> 00:33:23.560
So let's say that we have
the following program.

00:33:23.560 --> 00:33:29.810
So we have some program-- sorry,
some function and conveniently

00:33:29.810 --> 00:33:33.770
for the attacker, it has this
nice function here called

00:33:33.770 --> 00:33:36.300
run shell.

00:33:36.300 --> 00:33:38.790
So this is just
going to call system,

00:33:38.790 --> 00:33:45.830
it's going to execute bin
slash bash and then be done.

00:33:45.830 --> 00:33:51.280
And then we've got the canonical
buffer overflow process

00:33:51.280 --> 00:33:56.040
or sorry, function down
here, basically this thing

00:33:56.040 --> 00:34:01.940
is going to declare a
buffer, and then it's

00:34:01.940 --> 00:34:07.370
going to use one of
these unsafe functions

00:34:07.370 --> 00:34:12.870
to fill in bytes in the buffer.

00:34:12.870 --> 00:34:17.210
OK so, we know that this
can be overflowing OK,

00:34:17.210 --> 00:34:18.510
this is old news.

00:34:18.510 --> 00:34:22.969
Now what's interesting is that
we have this function up here,

00:34:22.969 --> 00:34:26.110
run shell, but it
doesn't quite seem

00:34:26.110 --> 00:34:29.900
to be accessed in some direct
way based on this buffer

00:34:29.900 --> 00:34:30.400
overflow.

00:34:30.400 --> 00:34:35.540
So how can the attacker invoke
this run shell command here?

00:34:35.540 --> 00:34:38.550
Well the attack may
do a couple things.

00:34:38.550 --> 00:34:42.920
So first of all, the attacker
can disassemble the program,

00:34:42.920 --> 00:34:46.699
run GDB, find out the address
of this thing in the executable,

00:34:46.699 --> 00:34:47.199
right.

00:34:47.199 --> 00:34:48.900
So you all should be very
familiar with doing those kinds

00:34:48.900 --> 00:34:50.209
of things through the lab.

00:34:50.209 --> 00:34:52.000
That's the first thing
the attacker can do.

00:34:52.000 --> 00:34:54.480
And then during the
buffer overflow,

00:34:54.480 --> 00:34:57.410
the attacker can essentially
take that address,

00:34:57.410 --> 00:35:00.360
put it in the buffer
overflow that's generated

00:35:00.360 --> 00:35:04.450
and make sure that the
function returns to run shell.

00:35:04.450 --> 00:35:09.370
So just to make that clear,
let's draw that over here.

00:35:09.370 --> 00:35:14.060
So, you have a setup
that looks something

00:35:14.060 --> 00:35:20.541
like this at the bottom,
we have the buffer,

00:35:20.541 --> 00:35:21.540
that's being overflowed.

00:35:26.340 --> 00:35:36.590
And then up here, we have
the save the break pointer,

00:35:36.590 --> 00:35:44.395
up here we have the return
address, for process message.

00:35:48.990 --> 00:35:54.850
So remember that the new stack
pointer will be here initially,

00:35:54.850 --> 00:35:57.350
when we start
executing the function.

00:35:57.350 --> 00:36:07.710
This is the new
break pointer, this

00:36:07.710 --> 00:36:10.740
is what the stack
pointer used to be.

00:36:13.980 --> 00:36:19.390
And then we've got some
break pointer up here,

00:36:19.390 --> 00:36:20.430
for the previous frame.

00:36:25.390 --> 00:36:27.940
OK, so this should
look pretty familiar.

00:36:27.940 --> 00:36:29.790
So basically, in the
attack, like I said,

00:36:29.790 --> 00:36:31.830
we've used GDB to
figure out what

00:36:31.830 --> 00:36:33.220
the address is of run shell.

00:36:33.220 --> 00:36:37.360
So in the buffer overflow,
we can essentially just

00:36:37.360 --> 00:36:44.140
put the address of run
shell right here, right.

00:36:44.140 --> 00:36:46.390
So this is a actually pretty
straightforward extension

00:36:46.390 --> 00:36:48.240
of what we already
know how to do, right.

00:36:48.240 --> 00:36:50.270
So basically it's saying,
if we conveniently

00:36:50.270 --> 00:36:52.337
have a command
that runs a shell,

00:36:52.337 --> 00:36:54.170
if we can disassemble
the binary, figure out

00:36:54.170 --> 00:36:57.010
where that address is, we can
just put that in this overflow

00:36:57.010 --> 00:36:58.422
array that we have here.

00:36:58.422 --> 00:37:00.130
So that should be
pretty straightforward.

00:37:00.130 --> 00:37:02.700
Does that make sense?

00:37:02.700 --> 00:37:03.490
OK.

00:37:03.490 --> 00:37:07.390
So, this was a very
childish example,

00:37:07.390 --> 00:37:09.690
because the programmer
for some crazy reason

00:37:09.690 --> 00:37:12.030
has put this low
hanging fruit here.

00:37:12.030 --> 00:37:14.670
So as an attacker this is like
Christmas coming early, right.

00:37:14.670 --> 00:37:17.620
Now it may not be the case
that you have something

00:37:17.620 --> 00:37:19.420
as delightful as this.

00:37:19.420 --> 00:37:25.400
So what you could have instead,
is something like this.

00:37:25.400 --> 00:37:29.840
So let's say that instead
of this thing being called

00:37:29.840 --> 00:37:33.810
run shell, we call it
run boring and then

00:37:33.810 --> 00:37:41.880
maybe this thing just executes
bin slash OS let's say.

00:37:41.880 --> 00:37:47.480
But let's say that everything
is not completely lost,

00:37:47.480 --> 00:37:51.730
because we actually
have a string up here

00:37:51.730 --> 00:37:56.365
that conveniently gives
us the path of that.

00:38:04.700 --> 00:38:08.810
So what's interesting about
this is, that we can disassemble

00:38:08.810 --> 00:38:11.570
the program, find the
location of run boring,

00:38:11.570 --> 00:38:13.380
but as an attacker,
who wants to run an OS?

00:38:13.380 --> 00:38:15.860
Right, that's no fun
But we do actually

00:38:15.860 --> 00:38:21.910
have a string in memory that
points to the path of the shell

00:38:21.910 --> 00:38:24.660
and actually we also know
something interesting too.

00:38:24.660 --> 00:38:27.440
Which is that even though the
program isn't calling system

00:38:27.440 --> 00:38:30.830
with the argument that we want,
it is calling system somehow.

00:38:30.830 --> 00:38:32.700
So we know that
system must be getting

00:38:32.700 --> 00:38:35.860
linked into this
program somehow, right.

00:38:35.860 --> 00:38:38.630
So we can actually
leverage those two things,

00:38:38.630 --> 00:38:42.700
to actually call system
with this argument here.

00:38:42.700 --> 00:38:45.610
So the first thing that we
do, is we can go into GDB

00:38:45.610 --> 00:38:48.460
and we can actually
figure out where

00:38:48.460 --> 00:38:52.634
this thing is located in the
process binary image, right.

00:38:52.634 --> 00:38:55.050
So you just go to GDB, just
type in basically print system

00:38:55.050 --> 00:38:56.070
and I'll give you
some information

00:38:56.070 --> 00:38:57.335
about the offset of that OK.

00:38:57.335 --> 00:38:58.710
So that's pretty
straightforward.

00:38:58.710 --> 00:39:00.989
You can also do the same
thing with bash path.

00:39:00.989 --> 00:39:02.530
Right, you just use
GDB to figure out

00:39:02.530 --> 00:39:03.500
where this thing lives.

00:39:03.500 --> 00:39:05.125
It's statically
declared string, right.

00:39:05.125 --> 00:39:07.140
So you'd be able to find
out where that lives.

00:39:07.140 --> 00:39:09.357
And so once you've
done that, now you

00:39:09.357 --> 00:39:11.440
got to do something a
little bit different, right.

00:39:11.440 --> 00:39:14.510
Because now we actually
have to figure out somehow,

00:39:14.510 --> 00:39:18.160
how to invoke system with
an argument of our choosing,

00:39:18.160 --> 00:39:18.660
right.

00:39:18.660 --> 00:39:21.750
And so the way that we do
that is by essentially faking

00:39:21.750 --> 00:39:24.730
a calling frame for system.

00:39:24.730 --> 00:39:26.490
OK, so remember that
a frame is the thing

00:39:26.490 --> 00:39:28.240
that the compiler
and the hardware

00:39:28.240 --> 00:39:31.361
work together to use to
implement the call stack,

00:39:31.361 --> 00:39:31.860
right.

00:39:31.860 --> 00:39:35.450
So here's basically
what we want to do.

00:39:38.630 --> 00:39:50.710
We want to set up something
like this on the stack, right.

00:39:50.710 --> 00:39:53.630
So basically we're
going to fake what

00:39:53.630 --> 00:39:58.700
system would expect
to be on the stack,

00:39:58.700 --> 00:40:01.480
but right before it
actually executes its code.

00:40:05.800 --> 00:40:07.860
So up here we had the
argument of the system,

00:40:07.860 --> 00:40:10.580
this is the string that we
actually want to execute.

00:40:10.580 --> 00:40:19.160
And then down here, this is
where system should return to,

00:40:19.160 --> 00:40:19.790
when it's done.

00:40:23.530 --> 00:40:27.690
Right, so this is what system
expects the stack to look like,

00:40:27.690 --> 00:40:29.067
right before it
starts execution.

00:40:29.067 --> 00:40:31.650
It's going to say this is where
I should go when I'm finished,

00:40:31.650 --> 00:40:34.180
this is the thing I should
consume as my argument, right.

00:40:34.180 --> 00:40:35.380
In the past we've been
assuming that there

00:40:35.380 --> 00:40:36.670
were no arguments when
you pass the functions,

00:40:36.670 --> 00:40:38.420
but now this is a little
bit different, right.

00:40:38.420 --> 00:40:39.878
So basically we
just have to ensure

00:40:39.878 --> 00:40:44.280
that this thing is in that
overflow code that we create,

00:40:44.280 --> 00:40:44.780
right.

00:40:44.780 --> 00:40:47.280
We just have to make
sure this fake calling

00:40:47.280 --> 00:40:50.280
frame is in that array.

00:40:50.280 --> 00:40:53.640
So basically the
way this will work

00:40:53.640 --> 00:40:55.615
is, we will do the following.

00:40:59.810 --> 00:41:02.640
So once again remember
the overflow goes up here.

00:41:02.640 --> 00:41:08.590
So first, we're going to put
the address of system here.

00:41:15.370 --> 00:41:20.781
And then here, we're going
to put just some junk return

00:41:20.781 --> 00:41:21.280
address.

00:41:24.622 --> 00:41:26.080
Right, this is
where system's going

00:41:26.080 --> 00:41:27.414
to return after it's finished.

00:41:27.414 --> 00:41:28.830
For the purposes
of the discussion

00:41:28.830 --> 00:41:30.246
now, we don't care
what this does,

00:41:30.246 --> 00:41:33.020
we'll just make this be just
some random set of bytes.

00:41:33.020 --> 00:41:36.060
And then up here,
we're actually going

00:41:36.060 --> 00:41:46.674
to put the address
of bash path, right.

00:41:46.674 --> 00:41:48.090
So what's going
to happen now when

00:41:48.090 --> 00:41:49.620
we do this buffer in overflow?

00:41:49.620 --> 00:41:52.690
So what's going to happen is
that, process message is going

00:41:52.690 --> 00:41:54.740
to finish, it's
going to say, OK hey,

00:41:54.740 --> 00:41:56.750
here's where I should
return to, right.

00:41:56.750 --> 00:42:00.070
And then it's going to
pop the stack, right,

00:42:00.070 --> 00:42:03.140
and now the system code
is executing, right.

00:42:03.140 --> 00:42:06.610
The system code now sees
that fake call frame

00:42:06.610 --> 00:42:08.190
that we created, right.

00:42:08.190 --> 00:42:10.310
As far as system is
concerned, nothing chicanerous

00:42:10.310 --> 00:42:11.750
has taken place, right.

00:42:11.750 --> 00:42:13.840
System will say, aha
here's the argument

00:42:13.840 --> 00:42:16.950
that I want to execute,
it's bin slash bash,

00:42:16.950 --> 00:42:19.460
it's going to execute it
and voila, the attacker

00:42:19.460 --> 00:42:22.550
has a shell, right.

00:42:22.550 --> 00:42:23.550
So does this make sense?

00:42:23.550 --> 00:42:25.300
So basically what we've
done is, we've now

00:42:25.300 --> 00:42:27.610
taken advantage of knowledge
of the calling convention,

00:42:27.610 --> 00:42:30.610
for the platform to
create fake stack frames,

00:42:30.610 --> 00:42:32.110
or fake calling
frames I should say.

00:42:32.110 --> 00:42:34.680
And using those
fake calling frames,

00:42:34.680 --> 00:42:38.575
we can actually execute any
function that is already linked

00:42:38.575 --> 00:42:42.330
and defined in the application.

00:42:42.330 --> 00:42:45.150
Does that make sense?

00:42:45.150 --> 00:42:52.050
OK so, another question
you might have is,

00:42:52.050 --> 00:42:57.111
what if this string wasn't
actually in the program?

00:42:57.111 --> 00:42:59.110
Now to be clear, this
string is almost certainly

00:42:59.110 --> 00:43:00.192
in the program.

00:43:00.192 --> 00:43:01.900
So that's one funny
thing about security,

00:43:01.900 --> 00:43:04.285
there's just all kinds of fun
strings that are laying around,

00:43:04.285 --> 00:43:05.400
you can just go to
town all day long.

00:43:05.400 --> 00:43:07.610
Well let's suppose we
live in bizarro world

00:43:07.610 --> 00:43:09.550
and like this string
is not in the program.

00:43:09.550 --> 00:43:11.220
So does anyone have
any ideas about what

00:43:11.220 --> 00:43:13.387
we could do to get that
string to be in the program?

00:43:13.387 --> 00:43:15.511
AUDIENCE: We can put the
string on the [INAUDIBLE].

00:43:15.511 --> 00:43:17.450
PROFESSOR; Yes exactly,
don't trust that man.

00:43:17.450 --> 00:43:18.783
That's what you can do, exactly.

00:43:18.783 --> 00:43:23.060
So, what you can do
is actually for here,

00:43:23.060 --> 00:43:29.990
have the address of bash path,
actually point here, right.

00:43:29.990 --> 00:43:35.890
And then you'd put-- up here
you would put slash B-I-N

00:43:35.890 --> 00:43:41.860
slash P-A-T slash 0.

00:43:41.860 --> 00:43:43.470
So that's how you
can get around-- I

00:43:43.470 --> 00:43:45.720
think I got that math right,
because each one of these

00:43:45.720 --> 00:43:48.360
is 4 bytes.

00:43:48.360 --> 00:43:51.710
But anyway, so you have the
pointer go up here and then

00:43:51.710 --> 00:43:52.730
boom, you're done.

00:43:52.730 --> 00:43:55.890
So now you can actually
conjure up arguments

00:43:55.890 --> 00:43:58.130
just by putting them
in the shell code.

00:44:00.690 --> 00:44:02.370
Pretty horrifying.

00:44:02.370 --> 00:44:07.301
So this is all building up
towards the full BROP attack,

00:44:07.301 --> 00:44:07.800
right.

00:44:07.800 --> 00:44:09.380
But before you can mention
the full BROP attack,

00:44:09.380 --> 00:44:10.921
you've got to
understand how you just

00:44:10.921 --> 00:44:13.560
chain together these
preexisting things in the code.

00:44:16.950 --> 00:44:20.300
So one thing to note is that
when I'm setting up this return

00:44:20.300 --> 00:44:23.170
address here, I just said,
eh just put some junk here,

00:44:23.170 --> 00:44:25.740
it doesn't really matter,
we just want to get a shell.

00:44:25.740 --> 00:44:28.770
But if you're the attacker,
you could actually

00:44:28.770 --> 00:44:30.420
set this return
address to something

00:44:30.420 --> 00:44:32.500
that's actually useful, right.

00:44:32.500 --> 00:44:35.970
And if you did that, you
could actually string together

00:44:35.970 --> 00:44:39.810
several functions, several
function indications in a row,

00:44:39.810 --> 00:44:40.310
right.

00:44:40.310 --> 00:44:42.590
That's actually very,
very powerful, right.

00:44:42.590 --> 00:44:44.830
Because in particular,
if we literally just

00:44:44.830 --> 00:44:47.364
set this return
address to jump, I

00:44:47.364 --> 00:44:49.030
mean it may be that
when we ret from it,

00:44:49.030 --> 00:44:51.410
like the program crashes on
it, maybe we don't want that,

00:44:51.410 --> 00:44:51.740
right.

00:44:51.740 --> 00:44:53.865
So can actually start
chaining some of these things

00:44:53.865 --> 00:44:55.980
to do interesting stuff.

00:44:55.980 --> 00:45:01.370
So let's say that our goal is
that we want to call system

00:45:01.370 --> 00:45:03.309
an arbitrary number of times.

00:45:03.309 --> 00:45:04.850
We don't just want
to do it one time,

00:45:04.850 --> 00:45:06.766
we're going to it a
arbitrary number of times.

00:45:06.766 --> 00:45:08.037
So how can we do that?

00:45:08.037 --> 00:45:10.120
Well, we're going to use
two pieces of information

00:45:10.120 --> 00:45:11.460
that we already know
how to get, right.

00:45:11.460 --> 00:45:13.820
We already know how to get
the address of system, right.

00:45:13.820 --> 00:45:16.090
We just look in GDB and find it.

00:45:16.090 --> 00:45:20.180
We also know how to find
the address of that string,

00:45:20.180 --> 00:45:21.960
bin flash bash.

00:45:21.960 --> 00:45:25.490
Now to actually make this
attack work using multiple calls

00:45:25.490 --> 00:45:28.310
to system, we're going to
have to use gadgets, right.

00:45:28.310 --> 00:45:29.820
This is getting us
closer to what's

00:45:29.820 --> 00:45:31.470
taking place in the BROP paper.

00:45:34.210 --> 00:45:37.660
So what we need to do
now, is find the address

00:45:37.660 --> 00:45:41.670
of these two Op codes.

00:45:48.070 --> 00:45:51.490
Right, so what is this, so this
is pop in EAX, so what does

00:45:51.490 --> 00:45:52.110
this do?

00:45:52.110 --> 00:45:58.050
This just takes the
top of the stack

00:45:58.050 --> 00:46:01.810
and then it puts it
into the EAX register.

00:46:01.810 --> 00:46:03.910
And what is the ret
instruction going to do?

00:46:03.910 --> 00:46:07.980
It just pops the
top of the stack

00:46:07.980 --> 00:46:15.340
and then puts it into
EIP, instruction pointer.

00:46:15.340 --> 00:46:18.060
OK, so this is what's
known as a gadget, right.

00:46:18.060 --> 00:46:21.030
This is like a small set
of assembly instructions

00:46:21.030 --> 00:46:24.790
that the attacker can use
to build these larger more

00:46:24.790 --> 00:46:25.890
grandiose attacks.

00:46:25.890 --> 00:46:30.410
OK, So how can we find
this gadget, right.

00:46:30.410 --> 00:46:33.140
There's actually like
some off the shelf tools

00:46:33.140 --> 00:46:35.010
that hackers use to
find these things,

00:46:35.010 --> 00:46:36.776
it's not hard to get
the binary, right.

00:46:36.776 --> 00:46:38.150
Essentially just
do a [INAUDIBLE]

00:46:38.150 --> 00:46:39.570
for these types
of things, right.

00:46:39.570 --> 00:46:43.070
So it's just as easy to
find one of these gadgets,

00:46:43.070 --> 00:46:45.024
assuming that you've
got a copy of the binary

00:46:45.024 --> 00:46:46.940
and we're not worried
about randomization yet.

00:46:46.940 --> 00:46:48.600
It's very easy to
find these things.

00:46:48.600 --> 00:46:50.377
Just like it's very easy to find
the address of system and stuff

00:46:50.377 --> 00:46:51.420
like that.

00:46:51.420 --> 00:46:54.220
So if we've got one
of these gadgets,

00:46:54.220 --> 00:46:56.020
what can we use
this gadget to do?

00:46:56.020 --> 00:46:58.560
Well of course the
answer is evil.

00:46:58.560 --> 00:47:02.925
So, what we can do
is the following.

00:47:05.480 --> 00:47:09.410
Let's say that we
changed the stack

00:47:09.410 --> 00:47:11.660
so that it looks like this.

00:47:19.500 --> 00:47:22.470
So the exploit goes this way.

00:47:22.470 --> 00:47:26.360
And so let's say, we do this.

00:47:26.360 --> 00:47:28.310
So the first thing
we're going to put here

00:47:28.310 --> 00:47:30.190
is the address of system.

00:47:32.960 --> 00:47:35.380
And the thing we're
going to put up here,

00:47:35.380 --> 00:47:41.160
is the address of
the pop ret gadget.

00:47:45.750 --> 00:47:58.180
Then up here, we're going to
put the address of bash path

00:47:58.180 --> 00:48:00.080
and then we're going
to repeat this pattern.

00:48:00.080 --> 00:48:10.620
So we're going to put
the address of system,

00:48:10.620 --> 00:48:19.890
the address of the
pop ret gadget,

00:48:19.890 --> 00:48:24.290
and then the address
of bash path.

00:48:29.880 --> 00:48:31.960
OK, so what's going
to happen here now?

00:48:31.960 --> 00:48:33.745
Now this is going
to be a bit tricky,

00:48:33.745 --> 00:48:35.120
and these lecture
notes are going

00:48:35.120 --> 00:48:36.490
to be up on the
web, so you may just

00:48:36.490 --> 00:48:38.060
want to listen to
what's happening,

00:48:38.060 --> 00:48:40.310
but this-- when I first
understood this, this

00:48:40.310 --> 00:48:42.850
was like understanding that
Santa Claus wasn't real right.

00:48:42.850 --> 00:48:44.870
So what will happen
is-- and by the way,

00:48:44.870 --> 00:48:47.411
Santa Claus isn't real, I hope
I didn't ruin it for everyone.

00:48:47.411 --> 00:48:48.530
So what's going to happen?

00:48:48.530 --> 00:48:50.760
So [INAUDIBLE] is what
puts this in memory.

00:48:50.760 --> 00:48:52.837
So we're going to
start here, OK.

00:48:52.837 --> 00:48:53.920
So what's going to happen?

00:48:53.920 --> 00:48:57.075
We're going to return to
system, the ret instruction

00:48:57.075 --> 00:48:59.530
is going to pop an
entry off the stack, now

00:48:59.530 --> 00:49:02.130
the top of the
stack pointers here.

00:49:02.130 --> 00:49:06.510
OK, so system is going to
find its argument here,

00:49:06.510 --> 00:49:08.110
it's going to execute the shell.

00:49:08.110 --> 00:49:11.490
Then it's going to finish
and return to whatever's

00:49:11.490 --> 00:49:13.070
here, which is the pop gadget.

00:49:13.070 --> 00:49:15.840
In executing that
return, we change

00:49:15.840 --> 00:49:17.770
the top of the stack
pointer to be here.

00:49:17.770 --> 00:49:20.770
OK, now we are in
the pop ret gadget.

00:49:20.770 --> 00:49:23.190
OK, so what is that pop
ret gadget going to do?

00:49:23.190 --> 00:49:26.700
It's going to pop what's on
the stack, which is this, OK.

00:49:26.700 --> 00:49:29.699
So now the top of
the stack is here.

00:49:29.699 --> 00:49:31.240
Then we're now in
the ret instruction

00:49:31.240 --> 00:49:32.730
from the pop ret gadget.

00:49:32.730 --> 00:49:33.730
What's this going to do?

00:49:33.730 --> 00:49:37.060
Aha, it's going to call
system again, right.

00:49:37.060 --> 00:49:41.400
So once again the ret is going
to pop this off this stack,

00:49:41.400 --> 00:49:42.690
we are now in system.

00:49:42.690 --> 00:49:44.644
Top of the stack
is here, system is

00:49:44.644 --> 00:49:46.810
going-- this will trigger
calling frame, the system.

00:49:46.810 --> 00:49:49.466
System takes the bash
path argument here.

00:49:49.466 --> 00:49:52.681
OK, and then it is
going to ret, right.

00:49:52.681 --> 00:49:53.980
Where's it going to ret to?

00:49:53.980 --> 00:49:55.740
The pop ret gadget again.

00:49:55.740 --> 00:49:57.977
So the ret pops
the stack, we are

00:49:57.977 --> 00:50:00.850
now in the pop ret gadget,
the ret gadget-- sorry,

00:50:00.850 --> 00:50:05.460
the pop ret gadget is going to
pop this, so on and so forth.

00:50:05.460 --> 00:50:06.050
OK?

00:50:06.050 --> 00:50:08.760
So clearly we can
chain this sequence

00:50:08.760 --> 00:50:12.350
to execute an arbitrary
number of things, right.

00:50:12.350 --> 00:50:15.380
And so this in
essence is starting

00:50:15.380 --> 00:50:18.420
to get to the core of what
return oriented programming is.

00:50:18.420 --> 00:50:23.060
Note that we have not executed
anything in the stack, right.

00:50:23.060 --> 00:50:26.890
This is what has allowed us to
get beyond those data execution

00:50:26.890 --> 00:50:28.150
prevention bits, right.

00:50:28.150 --> 00:50:29.690
Nothing's been executed here.

00:50:29.690 --> 00:50:33.150
We're just sort of jumping
to things in unexpected ways

00:50:33.150 --> 00:50:35.300
to do what we want to do.

00:50:35.300 --> 00:50:39.350
OK so this is actually
very, very, very, clever.

00:50:39.350 --> 00:50:41.620
And so what's interesting
is that at a high level

00:50:41.620 --> 00:50:44.990
you can think about us, we've
now defined this new model

00:50:44.990 --> 00:50:46.180
for computation, right.

00:50:46.180 --> 00:50:48.450
So in a traditional,
non-malicious program,

00:50:48.450 --> 00:50:50.072
you have the
instruction pointer that

00:50:50.072 --> 00:50:52.030
points to some linear
sequence of instructions.

00:50:52.030 --> 00:50:53.910
And you increment the
instruction pointer

00:50:53.910 --> 00:50:56.030
to figure out what's
the next thing to do.

00:50:56.030 --> 00:50:58.720
In essence, what return
oriented programing does is,

00:50:58.720 --> 00:51:02.720
it uses the stack pointer
as the instruction pointer.

00:51:02.720 --> 00:51:05.540
Right, so as we move
the stack pointer,

00:51:05.540 --> 00:51:09.230
we're pointing to like
other blocks of code

00:51:09.230 --> 00:51:10.720
that we're going to execute.

00:51:10.720 --> 00:51:12.180
And then at the
end of the gadget,

00:51:12.180 --> 00:51:14.010
you return back to
the stack pointer

00:51:14.010 --> 00:51:16.218
which is then going to tell
us the next block of code

00:51:16.218 --> 00:51:17.550
to execute.

00:51:17.550 --> 00:51:19.340
OK so that does that make sense?

00:51:26.220 --> 00:51:29.785
So that's basically how you
can avoid the data execution

00:51:29.785 --> 00:51:30.570
prevention stuff.

00:51:30.570 --> 00:51:32.190
That's how you can
get around having

00:51:32.190 --> 00:51:36.170
this no execute bit on pages.

00:51:36.170 --> 00:51:38.120
So the next thing that
we might want to do

00:51:38.120 --> 00:51:39.710
is defeat stack canaries.

00:51:39.710 --> 00:51:42.740
So if you remember, this
canary was this value

00:51:42.740 --> 00:51:45.510
that we were going to
place on the stack, right.

00:51:45.510 --> 00:51:48.620
So you can imagine
the canary would

00:51:48.620 --> 00:51:50.640
go right here for
example, or right here,

00:51:50.640 --> 00:51:53.500
and it would prevent someone
from overriding the return

00:51:53.500 --> 00:51:56.370
address, without also
overwriting the canary.

00:51:56.370 --> 00:52:00.350
With the intuition being that
before the system actually

00:52:00.350 --> 00:52:02.330
jumps to the ret
address, it can check

00:52:02.330 --> 00:52:04.890
to see if the canary
has been changed

00:52:04.890 --> 00:52:07.380
in a way that's incorrect.

00:52:07.380 --> 00:52:09.850
So that's how the
canary works, but can we

00:52:09.850 --> 00:52:11.060
get around the canary?

00:52:11.060 --> 00:52:13.250
Can we guess the canary somehow?

00:52:13.250 --> 00:52:17.950
Well we can actually, if
we make a few assumptions

00:52:17.950 --> 00:52:22.110
about how the system works.

00:52:22.110 --> 00:52:31.650
So, how do we defeat
those canaries?

00:52:36.160 --> 00:52:46.730
So the first thing that we want
to assume is, that the server,

00:52:46.730 --> 00:52:48.720
it has to have a buffer
overflow vulnerability.

00:52:53.420 --> 00:52:58.140
The second thing that
we're going to assume,

00:52:58.140 --> 00:53:07.300
is that the server is going
to crash and respond, just

00:53:07.300 --> 00:53:13.355
restart, if we set the
canary value to a bad one.

00:53:19.600 --> 00:53:22.060
And the third thing that
we're going to assume

00:53:22.060 --> 00:53:37.600
is that, after the restart,
that the canary and any address

00:53:37.600 --> 00:53:42.695
space randomization that you're
doing, is not rerandomized.

00:53:49.184 --> 00:53:50.850
Right, so what that
means is that, we're

00:53:50.850 --> 00:53:53.520
going to assume that if we can
somehow crash the server, then

00:53:53.520 --> 00:53:55.520
when the server restarts,
it's going to have

00:53:55.520 --> 00:53:57.030
the same value for the canary.

00:53:57.030 --> 00:54:00.520
And it's going to have the same
locations for all the quote

00:54:00.520 --> 00:54:04.030
unquote "randomized" stack,
heap and code information

00:54:04.030 --> 00:54:05.140
that it has.

00:54:05.140 --> 00:54:08.622
So you might wonder why
would this be the case?

00:54:08.622 --> 00:54:10.580
Why would it be that when
the server comes back

00:54:10.580 --> 00:54:12.390
it doesn't have new
locations for things?

00:54:12.390 --> 00:54:14.020
The reason is because
a lot of servers

00:54:14.020 --> 00:54:17.950
are written to use fork,
to create new processes.

00:54:17.950 --> 00:54:20.260
And if you remember,
fork actually

00:54:20.260 --> 00:54:23.580
inherits-- the child
inherits the address

00:54:23.580 --> 00:54:27.161
space of the address space
layout right of the parent,

00:54:27.161 --> 00:54:27.660
right.

00:54:27.660 --> 00:54:30.890
This is copy on write pages
that change stuff as the child

00:54:30.890 --> 00:54:33.510
updates things, but
if you use fork here,

00:54:33.510 --> 00:54:35.730
instead of execing
a whole new process,

00:54:35.730 --> 00:54:39.680
any time that parent server
process forms new children,

00:54:39.680 --> 00:54:42.090
those children will have the
same values of the canary

00:54:42.090 --> 00:54:43.370
in the address base, OK.

00:54:43.370 --> 00:54:44.995
So these are the
assumptions that we're

00:54:44.995 --> 00:54:49.000
going to make to try to
defeat these canaries here.

00:54:49.000 --> 00:54:51.490
So how can we defeat the canary?

00:54:51.490 --> 00:54:54.680
Well the attack is actually
fairly straightforward.

00:54:54.680 --> 00:54:58.270
So imagine that the stack
is going up this way, right.

00:54:58.270 --> 00:55:00.440
Imagine you got the
buffer overflow here,

00:55:00.440 --> 00:55:02.720
then imagine that the
canary is up here, right.

00:55:02.720 --> 00:55:05.860
And the canary actually
has multiple bytes, right.

00:55:05.860 --> 00:55:07.850
So what you can
actually do is, you

00:55:07.850 --> 00:55:12.280
can probe those bytes one by
one and start guessing values

00:55:12.280 --> 00:55:13.740
of what those bytes are, right.

00:55:13.740 --> 00:55:20.940
So let's say that-- so the
canary looks like this.

00:55:20.940 --> 00:55:24.640
Here's the overflowing
buffer, and you want

00:55:24.640 --> 00:55:26.200
to guess what these bytes are.

00:55:26.200 --> 00:55:28.290
So the first thing
that you guess

00:55:28.290 --> 00:55:31.066
is you take your overflow,
just to this first byte

00:55:31.066 --> 00:55:34.910
of the canary and you
say, hey, is that byte 0?

00:55:34.910 --> 00:55:36.806
You write a 0 there,
with your overflow.

00:55:36.806 --> 00:55:38.556
You're either correct
or you're incorrect.

00:55:38.556 --> 00:55:43.000
If you are incorrect, then the
server's going to crash, right.

00:55:43.000 --> 00:55:45.560
If you are correct you
say, aha I actually

00:55:45.560 --> 00:55:48.020
know the first byte of
the canary now, right.

00:55:48.020 --> 00:55:49.400
Then you start guessing here.

00:55:49.400 --> 00:55:51.710
You say, are you 0?

00:55:51.710 --> 00:55:53.300
Probably not, it's
going to crash.

00:55:53.300 --> 00:55:54.180
Are you one?

00:55:54.180 --> 00:55:55.930
And maybe not, it's
going to crash.

00:55:55.930 --> 00:55:56.670
Are you two?

00:55:56.670 --> 00:55:58.930
Aha, it doesn't crash, right.

00:55:58.930 --> 00:56:01.730
So now you've actually found
the value of that second canary

00:56:01.730 --> 00:56:02.530
byte, right.

00:56:02.530 --> 00:56:04.770
As you can imagine,
you step up this way,

00:56:04.770 --> 00:56:07.849
and you eventually find all
the values for the canary.

00:56:07.849 --> 00:56:09.890
So once again we're taking
advantage of the fact,

00:56:09.890 --> 00:56:12.580
that crashes are a signal
to you, the attacker,

00:56:12.580 --> 00:56:15.935
that you've actually done
something wrong, right.

00:56:15.935 --> 00:56:17.810
And the server is staying
up, in other words,

00:56:17.810 --> 00:56:19.830
that socket connection's
staying open, is

00:56:19.830 --> 00:56:21.579
a signal to you, the
attacker, that you've

00:56:21.579 --> 00:56:22.774
done something right.

00:56:22.774 --> 00:56:24.940
AUDIENCE: Maybe I mentioned
something basic here

00:56:24.940 --> 00:56:27.610
like why do you-- if you
know how long the canary is,

00:56:27.610 --> 00:56:28.818
can you just infect directly?

00:56:28.818 --> 00:56:31.632
Skip that buffer
and overflow those--

00:56:31.632 --> 00:56:33.508
the one path there the canary?

00:56:33.508 --> 00:56:37.460
So like [INAUDIBLE] say you can
like [INAUDIBLE] the canary--

00:56:37.460 --> 00:56:39.620
PROFESSOR: Yeah, yeah you
can't-- so that's right

00:56:39.620 --> 00:56:41.890
if you-- so if you in fact
know the exact location

00:56:41.890 --> 00:56:42.801
of the canary, right.

00:56:42.801 --> 00:56:44.300
That can sometimes
allow you to skip

00:56:44.300 --> 00:56:45.420
some of these attacks totally.

00:56:45.420 --> 00:56:46.480
Because then you
can just directly

00:56:46.480 --> 00:56:48.340
write to the return
address, let's say,

00:56:48.340 --> 00:56:51.180
as opposed to doing some of
this buffer overflow nonsense.

00:56:51.180 --> 00:56:53.430
But in general, if there's
some level of randomization

00:56:53.430 --> 00:56:56.050
here, if you don't quite know
where the stack is for example,

00:56:56.050 --> 00:56:57.810
then it's tricky
to do that, right.

00:56:57.810 --> 00:56:59.685
So basically the way
that the attack proceeds

00:56:59.685 --> 00:57:01.800
is that you don't quite
know what's happening,

00:57:01.800 --> 00:57:06.710
and so you just very slowly
creep your way up memory,

00:57:06.710 --> 00:57:09.184
down the stack, to figure
out where these things are.

00:57:09.184 --> 00:57:11.112
AUDIENCE: Can the
server instead of

00:57:11.112 --> 00:57:13.522
crashing when it
finds strong canaries,

00:57:13.522 --> 00:57:15.932
keep the socket open and
[INAUDIBLE] deprocess

00:57:15.932 --> 00:57:18.149
and [INAUDIBLE]?

00:57:18.149 --> 00:57:20.440
PROFESSOR: Yeah, so we'll
discuss at the end of lecture

00:57:20.440 --> 00:57:22.630
some of the defenses you
can have against this,

00:57:22.630 --> 00:57:25.790
but one very, abstractly
speaking civil defense,

00:57:25.790 --> 00:57:28.220
is that when the
program crashes,

00:57:28.220 --> 00:57:30.222
you catch the segfault
using a signal handler,

00:57:30.222 --> 00:57:31.930
do not deduce you're
own code by the way.

00:57:31.930 --> 00:57:33.055
But you can do this, right.

00:57:33.055 --> 00:57:35.250
You catch that segfault
and then the signal handler

00:57:35.250 --> 00:57:37.247
just keeps that
process alive for a bit

00:57:37.247 --> 00:57:39.330
and that will trick the
attack into thinking that,

00:57:39.330 --> 00:57:45.570
oh I won't get that signal
back, in other words.

00:57:45.570 --> 00:57:48.000
OK so that's
basically how you can

00:57:48.000 --> 00:57:49.710
guess the value for the canary.

00:57:49.710 --> 00:57:51.700
And note that you can
actually use this attack

00:57:51.700 --> 00:57:54.285
to sort of figure out
arbitrary values that

00:57:54.285 --> 00:57:56.020
are low in the stack, right.

00:57:56.020 --> 00:57:58.790
Just by iteratively guessing
for each byte what it is,

00:57:58.790 --> 00:58:00.490
and then using that
crash indication

00:58:00.490 --> 00:58:04.960
as a signal of whether you're
guess was correct or not.

00:58:04.960 --> 00:58:07.820
So that's basically
how you can defeat

00:58:07.820 --> 00:58:09.460
these randomized
canaries, assuming

00:58:09.460 --> 00:58:14.000
that after the server restarts,
those things are not changed.

00:58:14.000 --> 00:58:15.575
And so we've also
shown how you can

00:58:15.575 --> 00:58:17.800
use the gadgets
to string together

00:58:17.800 --> 00:58:19.460
these more elaborate attacks.

00:58:19.460 --> 00:58:21.730
So what we're going
to look at next

00:58:21.730 --> 00:58:25.770
is a way that you can use all
these techniques to defeat

00:58:25.770 --> 00:58:29.300
data execution prevention,
address-based randomization

00:58:29.300 --> 00:58:32.674
and canaries on a
production system.

00:58:32.674 --> 00:58:34.090
Now what we're
going to do now is,

00:58:34.090 --> 00:58:35.800
we're actually going
to start looking

00:58:35.800 --> 00:58:38.870
at 64-bit architectures instead
of 32-bit architectures.

00:58:38.870 --> 00:58:41.330
As it turns out for
randomization purposes,

00:58:41.330 --> 00:58:43.750
64-bit architectures
actually give you

00:58:43.750 --> 00:58:47.280
a lot more randomness to protect
yourself against the attacker.

00:58:47.280 --> 00:58:49.260
So looking at attacks
is much more interesting

00:58:49.260 --> 00:58:50.850
on those systems.

00:58:50.850 --> 00:58:52.800
So that's also the type
of architecture that's

00:58:52.800 --> 00:58:54.690
discussed in the BROP paper.

00:58:54.690 --> 00:58:56.245
They talk about 64-bit machines.

00:58:56.245 --> 00:58:57.620
So from now on,
assume that we're

00:58:57.620 --> 00:58:59.950
going to talk about the
64-bit architectures.

00:58:59.950 --> 00:59:01.640
For the purposes
of this discussion,

00:59:01.640 --> 00:59:03.740
the only difference
between a 32-bit machine

00:59:03.740 --> 00:59:07.360
and a 64-bit machine, is
that on a 32-bit machine,

00:59:07.360 --> 00:59:10.500
the arguments are passed
on the stack, right.

00:59:10.500 --> 00:59:14.620
So here for example, this
is like a 32-bit machine

00:59:14.620 --> 00:59:16.480
we were assuming, so
for example, bash path

00:59:16.480 --> 00:59:17.570
will pass on the stack.

00:59:17.570 --> 00:59:19.810
On a 64-bit machine,
the arguments

00:59:19.810 --> 00:59:22.350
are passed in registers instead.

00:59:22.350 --> 00:59:24.570
OK so like when a
function starts execution,

00:59:24.570 --> 00:59:26.195
it's going to look
in certain registers

00:59:26.195 --> 00:59:28.320
to find where the arguments are.

00:59:28.320 --> 00:59:29.040
OK, make sense?

00:59:29.040 --> 00:59:30.250
All right.

00:59:30.250 --> 00:59:33.950
So start up here.

00:59:41.400 --> 00:59:45.210
All right, so now we get to
the point of today's paper.

00:59:45.210 --> 00:59:48.200
Which is the blind return
oriented programming.

00:59:48.200 --> 00:59:51.380
So what's the first
thing you want to do,

00:59:51.380 --> 00:59:54.970
if you want to engage in
BROP for fun or profit?

00:59:54.970 --> 00:59:57.080
So the first thing
you have to do

00:59:57.080 --> 01:00:01.170
is, you have to find what
they call a stop gadget.

01:00:06.970 --> 01:00:10.270
Now a stop gadget-- and remember
that when we say gadget,

01:00:10.270 --> 01:00:13.510
we essentially mean,
return addresses, right.

01:00:13.510 --> 01:00:15.630
A gadget is identified
by the return address,

01:00:15.630 --> 01:00:18.280
by the start address of that
sequence of instructions

01:00:18.280 --> 01:00:19.660
that we want to jump to, right.

01:00:19.660 --> 01:00:21.030
So what is a stop gadget?

01:00:21.030 --> 01:00:24.350
So a stop gadget is
essentially a return address

01:00:24.350 --> 01:00:27.580
to someplace in the code,
but if you jump to it,

01:00:27.580 --> 01:00:29.340
you're going to
pause the program,

01:00:29.340 --> 01:00:31.890
but you're not
going to crash it.

01:00:31.890 --> 01:00:35.070
OK, so that's why it's
called a stop gadget.

01:00:35.070 --> 01:00:37.510
Now what might that
stop gadget be?

01:00:37.510 --> 01:00:40.660
You might jump to someplace
in the code that then calls

01:00:40.660 --> 01:00:43.562
via the sleep system call
for example, or does pause,

01:00:43.562 --> 01:00:44.520
or something like that.

01:00:44.520 --> 01:00:46.997
Or maybe somehow the program
gets stuck in an infinite loop

01:00:46.997 --> 01:00:48.080
if you jump to that place.

01:00:48.080 --> 01:00:50.061
Doesn't really matter
why the stop's happening,

01:00:50.061 --> 01:00:52.185
but you could imagine
several scenarios which would

01:00:52.185 --> 01:00:53.760
cause that stop to take place.

01:00:53.760 --> 01:00:55.330
So why is this useful?

01:00:55.330 --> 01:00:57.554
Well once the
attacker has managed

01:00:57.554 --> 01:00:59.720
to defeat the canaries using
that iterative guessing

01:00:59.720 --> 01:01:02.080
technique I showed
you, he can start

01:01:02.080 --> 01:01:05.850
to overwrite this return
address and start probing

01:01:05.850 --> 01:01:07.900
for these stop gadgets, right.

01:01:07.900 --> 01:01:09.950
And so note that
most of the random

01:01:09.950 --> 01:01:12.110
addresses you might
put there, they'll

01:01:12.110 --> 01:01:13.654
probably crash
the server, right.

01:01:13.654 --> 01:01:15.820
Once again, that's the
message to you, the attacker,

01:01:15.820 --> 01:01:18.601
that's an indication that what
you found is not a stop gadget,

01:01:18.601 --> 01:01:19.100
right.

01:01:19.100 --> 01:01:21.016
Because when the server
crashes your sockets--

01:01:21.016 --> 01:01:22.420
your socket
connection is closed.

01:01:22.420 --> 01:01:23.653
You as an attacker
know, OK that must not

01:01:23.653 --> 01:01:24.660
have been a stop gadget.

01:01:24.660 --> 01:01:27.201
Where if you guess something
and then you-- that socket still

01:01:27.201 --> 01:01:28.720
stays open for
awhile, you think,

01:01:28.720 --> 01:01:31.620
aha I found that stop gadget.

01:01:31.620 --> 01:01:33.890
So that's the basic
idea behind step one.

01:01:33.890 --> 01:01:36.220
You got to find
that stop gadget.

01:01:36.220 --> 01:01:42.590
Now step two, is
that you want to find

01:01:42.590 --> 01:01:46.560
gadgets that pop stack entries.

01:01:57.500 --> 01:02:02.220
And so you basically have to
use this sequence of carefully

01:02:02.220 --> 01:02:03.910
crafted instructions
to figure out

01:02:03.910 --> 01:02:08.040
when we've got one of
these stack gadgets.

01:02:08.040 --> 01:02:10.530
So this sequence
is going to consist

01:02:10.530 --> 01:02:18.450
of a probe address, a stop
address, and a crash address.

01:02:18.450 --> 01:02:20.489
So the probe
address is the thing

01:02:20.489 --> 01:02:22.030
that we're going to
put in the stack.

01:02:22.030 --> 01:02:32.036
This is going to be the address
of a potential stack popping

01:02:32.036 --> 01:02:32.535
gadget.

01:02:36.760 --> 01:02:41.410
This stop gadget is going to
be what we found in step one.

01:02:41.410 --> 01:02:46.876
So this is an address
of the stop gadget.

01:02:49.550 --> 01:02:51.780
And then the crash
gadget is just

01:02:51.780 --> 01:02:56.683
going to be the address
of nonexecutable code.

01:03:02.295 --> 01:03:03.920
So for example, you
could just set this

01:03:03.920 --> 01:03:06.957
to, just the
address zero, right.

01:03:06.957 --> 01:03:09.415
If you do a ret to this and
then try to execute code there,

01:03:09.415 --> 01:03:11.250
this is going to
crash your program.

01:03:11.250 --> 01:03:14.830
So we can basically use
these types of addresses

01:03:14.830 --> 01:03:17.360
to find out where these
stack popping gadgets are.

01:03:17.360 --> 01:03:20.870
So here's a simple example.

01:03:20.870 --> 01:03:24.640
So let's write this over here.

01:03:24.640 --> 01:03:31.730
So let's say we have these two
different examples of a probe,

01:03:31.730 --> 01:03:36.600
a trap, and then a stop, right.

01:03:36.600 --> 01:03:40.290
So let's assume that
we have down here,

01:03:40.290 --> 01:03:44.380
we're going to probe
at some address,

01:03:44.380 --> 01:03:46.130
doesn't really matter,
starts with a four,

01:03:46.130 --> 01:03:46.921
ends with an eight.

01:03:46.921 --> 01:03:47.840
That doesn't matter.

01:03:47.840 --> 01:03:50.230
Over here, let's say that
we look at the address

01:03:50.230 --> 01:03:54.220
that, let's say starts
in a four ends in a C.

01:03:54.220 --> 01:03:56.520
So we're saying,
we're hypothesizing,

01:03:56.520 --> 01:03:59.270
that maybe one of
these two addresses

01:03:59.270 --> 01:04:02.190
is going to be one of these
stack popping gadgets.

01:04:02.190 --> 01:04:05.100
And then let's say
that the trap up here,

01:04:05.100 --> 01:04:10.790
like I said this is just
going to be address zero,

01:04:10.790 --> 01:04:14.540
and then let's assume that we
found some preexisting stop

01:04:14.540 --> 01:04:19.380
gadget, some addresses start
the [INAUDIBLE] doesn't really

01:04:19.380 --> 01:04:19.910
matter.

01:04:19.910 --> 01:04:24.720
And remember this stop gadget,
like maybe this address,

01:04:24.720 --> 01:04:29.650
points to code that does
something like sleep 10,

01:04:29.650 --> 01:04:31.370
or something like that, right.

01:04:31.370 --> 01:04:33.720
So when I say that we're
going to test these sequences,

01:04:33.720 --> 01:04:35.920
this is the stuff that we're
going to push onto the stack,

01:04:35.920 --> 01:04:36.460
right.

01:04:36.460 --> 01:04:40.386
So similar to over there, when
we were pushing these gadgets

01:04:40.386 --> 01:04:41.760
onto the stack,
this is the stuff

01:04:41.760 --> 01:04:42.885
that we're going to
push onto the stack,

01:04:42.885 --> 01:04:45.150
and we're going to see
what happens, right.

01:04:45.150 --> 01:04:51.800
Now let's say that,
this code here, points

01:04:51.800 --> 01:04:53.750
to the following sequence.

01:04:53.750 --> 01:04:58.880
We're going to pop some
register, let's say racks,

01:04:58.880 --> 01:05:03.340
and then we're going to return.

01:05:03.340 --> 01:05:05.210
So what's going to happen here?

01:05:05.210 --> 01:05:10.560
Well so when the system
jumps this address,

01:05:10.560 --> 01:05:13.440
the stack pointer's
going to move here, OK.

01:05:13.440 --> 01:05:15.380
Now we're in the middle
of this gadget, right.

01:05:15.380 --> 01:05:16.630
What's the gadget going to do?

01:05:16.630 --> 01:05:18.450
It's going to pop racks, OK.

01:05:18.450 --> 01:05:20.582
Top of stack pointer's
now here, and it's

01:05:20.582 --> 01:05:22.915
going to return to whatever's
the top of the stack which

01:05:22.915 --> 01:05:24.880
is the stop gap, right.

01:05:24.880 --> 01:05:29.240
So in this case this
gadget gets us to here,

01:05:29.240 --> 01:05:31.358
and the attacker
can tell that this

01:05:31.358 --> 01:05:34.720
is-- this probe address belong
to one of these pop stacking

01:05:34.720 --> 01:05:35.820
things, right.

01:05:35.820 --> 01:05:38.400
Because the client
connection stays open.

01:05:38.400 --> 01:05:41.400
Now let's say that
this gadget here,

01:05:41.400 --> 01:05:48.580
pointed to something
like the following.

01:05:48.580 --> 01:05:52.760
Maybe it just does like
an xor, for example.

01:05:52.760 --> 01:05:58.000
So it's just going to xor
some registers and then it's

01:05:58.000 --> 01:06:00.540
going to ret.

01:06:00.540 --> 01:06:02.930
So what happens if we try
to jump to this gadget?

01:06:02.930 --> 01:06:06.170
Right, note that this does not
pop anything off the stack, OK.

01:06:06.170 --> 01:06:07.920
It just changes the
contents of registers.

01:06:07.920 --> 01:06:09.160
So what's going to happen?

01:06:09.160 --> 01:06:11.690
So we're going to
be here, we're going

01:06:11.690 --> 01:06:13.630
to jump to the address
of this gadget,

01:06:13.630 --> 01:06:15.830
stack pointer goes here, OK.

01:06:15.830 --> 01:06:18.210
We're going to xor
these two things, right.

01:06:18.210 --> 01:06:19.932
Stack pointer's not
going to change.

01:06:19.932 --> 01:06:22.390
Then we're going to return to
whatever the top of the stack

01:06:22.390 --> 01:06:23.550
is, which is 0, 0.

01:06:23.550 --> 01:06:25.370
This is going to crash.

01:06:25.370 --> 01:06:28.420
OK, the client connection to
the server is going to close,

01:06:28.420 --> 01:06:31.245
and as a result, the attacker
knows that this is not

01:06:31.245 --> 01:06:34.210
a stack popping gadget.

01:06:34.210 --> 01:06:35.990
So does that all make sense?

01:06:35.990 --> 01:06:38.850
And so you can also
imagine that you can--

01:06:38.850 --> 01:06:42.609
by coming with more
baroque series of traps

01:06:42.609 --> 01:06:44.150
and stop gadgets
and stuff like that,

01:06:44.150 --> 01:06:46.510
you can find things that
for example, pop two things

01:06:46.510 --> 01:06:47.879
off the stack, right.

01:06:47.879 --> 01:06:50.170
You can just put another one
of these trap instructions

01:06:50.170 --> 01:06:51.110
there, right.

01:06:51.110 --> 01:06:53.166
And so then unless
the-- unless this gadget

01:06:53.166 --> 01:06:54.540
pops two things
off, you're going

01:06:54.540 --> 01:06:56.831
to end up in one of these
traps and your code execution

01:06:56.831 --> 01:06:58.250
is going to blow up, right.

01:06:58.250 --> 01:07:02.090
And so in the paper they discuss
like this thing called the BROP

01:07:02.090 --> 01:07:03.950
gadget, which is sort
of like hilariously

01:07:03.950 --> 01:07:06.300
complex if you're not used
to returning to programming.

01:07:06.300 --> 01:07:08.297
What I'll show you today
is you can actually

01:07:08.297 --> 01:07:09.880
just use these very
simple pop gadgets

01:07:09.880 --> 01:07:10.963
to launch the same attack.

01:07:10.963 --> 01:07:12.690
Then hopefully after
you understand this,

01:07:12.690 --> 01:07:14.696
the BROP gadget will
make more sense.

01:07:14.696 --> 01:07:16.570
But does everyone
understand how we can probe

01:07:16.570 --> 01:07:19.180
for these little gadgets here?

01:07:19.180 --> 01:07:20.120
OK.

01:07:20.120 --> 01:07:26.220
So, once you've got these
gadgets, what do you know?

01:07:26.220 --> 01:07:28.720
Well you found the location
of code snippets that

01:07:28.720 --> 01:07:31.080
allow you to pop stuff up,
one thing off the stack.

01:07:31.080 --> 01:07:32.820
Precisely one thing
off the stack,

01:07:32.820 --> 01:07:35.990
but you don't actually
know into what register

01:07:35.990 --> 01:07:37.990
they're popping it into.

01:07:37.990 --> 01:07:40.440
You just know that they're
getting popped off, right.

01:07:40.440 --> 01:07:42.394
And you actually
need to know what

01:07:42.394 --> 01:07:44.060
register these gadgets
are popping stuff

01:07:44.060 --> 01:07:47.370
into, because remember,
on a 64-bit architecture,

01:07:47.370 --> 01:07:50.840
the registers control where the
arguments are to this function

01:07:50.840 --> 01:07:52.480
that you want to invoke, right.

01:07:52.480 --> 01:07:54.170
So the ultimate goal
to keep in mind,

01:07:54.170 --> 01:07:56.419
is that we want to be able
to create some gadgets that

01:07:56.419 --> 01:07:58.920
allow us to pop values
that we put on the stack

01:07:58.920 --> 01:08:00.754
into certain registers,
and eventually we're

01:08:00.754 --> 01:08:02.794
going to call a system
call that's going to allow

01:08:02.794 --> 01:08:03.850
us to do something evil.

01:08:03.850 --> 01:08:05.870
OK, so the next thing
that we need to do

01:08:05.870 --> 01:08:14.670
is determine which
registers-- so determine which

01:08:14.670 --> 01:08:19.025
registers the pop gadgets use.

01:08:26.319 --> 01:08:28.870
So how are we going to do that?

01:08:28.870 --> 01:08:32.160
Well basically we can take
advantage of the pause system

01:08:32.160 --> 01:08:32.840
call.

01:08:32.840 --> 01:08:37.580
OK, so the pause system call,
it takes no arguments, right.

01:08:37.580 --> 01:08:40.970
And that means that it ignores
everything in the registers.

01:08:40.970 --> 01:08:41.930
OK.

01:08:41.930 --> 01:08:45.129
And essentially, to find
the pause instruction what

01:08:45.129 --> 01:08:49.760
we can do is, we can chain
all of these pop gadgets

01:08:49.760 --> 01:08:52.490
in such a way, that we put
all of them on the stack,

01:08:52.490 --> 01:08:55.229
in between each one of them
we put the syscall number

01:08:55.229 --> 01:08:57.739
for pause, and then we
see if we can actually

01:08:57.739 --> 01:08:59.269
get the program to hang.

01:08:59.269 --> 01:09:01.060
Let me give you a
concrete example of that.

01:09:01.060 --> 01:09:05.050
So we'll do something like this.

01:09:09.390 --> 01:09:13.850
So here for the return address,
we'll put the following.

01:09:24.290 --> 01:09:28.750
So let's say we have one
gadget that pops RDI register,

01:09:28.750 --> 01:09:30.899
then does a ret.

01:09:30.899 --> 01:09:40.090
And then up here we'll put
the syscall number for pause.

01:09:40.090 --> 01:09:45.810
And then let's say that we have
another gadget that we found,

01:09:45.810 --> 01:09:50.600
that does a pop into a different
register, let's say RSI.

01:09:53.960 --> 01:09:58.670
And then we'll put the
system call number for pause

01:09:58.670 --> 01:09:59.460
up here again.

01:10:02.124 --> 01:10:05.640
And we do this for all the
gadgets that we've found

01:10:05.640 --> 01:10:15.947
and then eventually we put
the guest address for pause,

01:10:15.947 --> 01:10:17.280
or sorry for syscall, excuse me.

01:10:25.370 --> 01:10:28.510
Once again, remember how you
invoke these system calls.

01:10:28.510 --> 01:10:32.990
So you basically have to put
the number of the system call

01:10:32.990 --> 01:10:36.560
into the RAX register, then
you invoke this libc function

01:10:36.560 --> 01:10:39.855
syscall which is then going to
execute the requested system

01:10:39.855 --> 01:10:40.784
call, OK.

01:10:40.784 --> 01:10:42.950
So what's going to happen
when we execute this code?

01:10:42.950 --> 01:10:46.120
Right, so we're
going to come here,

01:10:46.120 --> 01:10:48.580
we're going to jump to the
address of this gadget,

01:10:48.580 --> 01:10:50.840
and note that as an
attacker, all that we know

01:10:50.840 --> 01:10:53.610
is that this gadget here
pops something off the stack.

01:10:53.610 --> 01:10:55.680
We don't know what the
register is yet, right.

01:10:55.680 --> 01:10:57.080
Put it here just to
make the [INAUDIBLE],

01:10:57.080 --> 01:10:58.788
but the attacker
doesn't know yet, right.

01:10:58.788 --> 01:11:01.560
So if you jump-- or
sorry the-- we jump

01:11:01.560 --> 01:11:03.664
to the gadget, the
stack corners now here,

01:11:03.664 --> 01:11:04.580
what's it going to do?

01:11:04.580 --> 01:11:07.720
It's going to pop this
syscall number for pause,

01:11:07.720 --> 01:11:09.870
into some register the
attacker doesn't know,

01:11:09.870 --> 01:11:14.006
and then we're going to continue
to go up this chain and so

01:11:14.006 --> 01:11:14.700
on and so forth.

01:11:14.700 --> 01:11:17.470
And what you'll see is that
each one of these gadgets, one

01:11:17.470 --> 01:11:20.430
of them hopefully will
pop the system call

01:11:20.430 --> 01:11:23.500
number into the
appropriate RAX register.

01:11:23.500 --> 01:11:25.980
So that by the time
we get up to here,

01:11:25.980 --> 01:11:28.320
I mean we basically
polluted all the registers,

01:11:28.320 --> 01:11:31.090
with the system call number,
but hopefully just one of them

01:11:31.090 --> 01:11:32.460
has to be correct, right.

01:11:32.460 --> 01:11:35.510
Because if one of our gadgets
does this, then by the time

01:11:35.510 --> 01:11:37.610
we ret to here,
we'll get a pause.

01:11:37.610 --> 01:11:42.310
Once again, that pause acts as
a signal to the attacker, OK.

01:11:42.310 --> 01:11:44.980
Because if this guest
address was wrong,

01:11:44.980 --> 01:11:47.710
then probably the program's
going to crash, right.

01:11:47.710 --> 01:11:51.540
So what does this phase
of the attack let us do?

01:11:51.540 --> 01:11:54.300
Well we still don't
know which gadgets

01:11:54.300 --> 01:11:56.860
pop into which registers,
but we know that one of them

01:11:56.860 --> 01:11:59.600
is popped into RAX, which is
the one we want to control.

01:11:59.600 --> 01:12:03.690
And for sure we know the
address of syscall, right.

01:12:03.690 --> 01:12:06.790
Because we were able to
induce the pause, right.

01:12:06.790 --> 01:12:09.330
So once we've done that, right.

01:12:09.330 --> 01:12:12.000
Once we know for sure
where this thing is,

01:12:12.000 --> 01:12:14.200
the address for syscall,
then we can actually just

01:12:14.200 --> 01:12:16.299
try the gadgets
one by one, right.

01:12:16.299 --> 01:12:18.090
And see which one of
them is actually going

01:12:18.090 --> 01:12:19.474
to induce the pause, right.

01:12:19.474 --> 01:12:21.640
So in other words, cut all
the middleman here, let's

01:12:21.640 --> 01:12:24.760
have a stack it looks like this,
and then you just immediately

01:12:24.760 --> 01:12:25.590
jump to syscall.

01:12:25.590 --> 01:12:27.790
Did that cause the
pause or did it crash?

01:12:27.790 --> 01:12:29.680
If it crashed, OK
we know this gadget,

01:12:29.680 --> 01:12:31.200
it pops to RDI for example.

01:12:31.200 --> 01:12:32.700
OK, get rid of that one, right.

01:12:32.700 --> 01:12:34.769
Try the next gadget, right.

01:12:34.769 --> 01:12:37.310
Put the guest address-- put the,
well it's not guest anymore,

01:12:37.310 --> 01:12:39.270
put the real address
for syscall up here.

01:12:39.270 --> 01:12:41.011
Were we able to
pause the program?

01:12:41.011 --> 01:12:41.510
Yes?

01:12:41.510 --> 01:12:47.420
Aha, so we know that pop
gadget must pop into RAX.

01:12:47.420 --> 01:12:49.836
So does that make sense?

01:12:49.836 --> 01:12:53.280
AUDIENCE: So the way to guess
the address for system call

01:12:53.280 --> 01:12:54.756
is just blind transfer?

01:12:54.756 --> 01:12:57.020
PROFESSOR: Yeah, so
there-- so in the paper,

01:12:57.020 --> 01:12:58.929
they go into some
optimizations about how

01:12:58.929 --> 01:13:00.970
you can work in a PLT and
all that kind of stuff.

01:13:00.970 --> 01:13:03.530
Like I said, I think it's easier
to ignore that for a second,

01:13:03.530 --> 01:13:04.690
and just look toward
the simpler thing

01:13:04.690 --> 01:13:07.200
first, but yeah in a simple
attack that I'm describing,

01:13:07.200 --> 01:13:08.790
yeah you just put
some address up here

01:13:08.790 --> 01:13:11.272
and you just see if you pause.

01:13:14.070 --> 01:13:17.800
So does that all make sense?

01:13:17.800 --> 01:13:22.370
OK so at the end of
this we actually know

01:13:22.370 --> 01:13:23.810
the location of syscall.

01:13:23.810 --> 01:13:27.460
We know the location
of the instruction

01:13:27.460 --> 01:13:29.730
that does the pop into RAX.

01:13:29.730 --> 01:13:32.230
Now you can imagine that we
also need gadgets that pop

01:13:32.230 --> 01:13:34.300
into some other registers too.

01:13:34.300 --> 01:13:36.830
Suffice to say, you can
do similar tests, right.

01:13:36.830 --> 01:13:39.780
So instead of like pushing a
system call number for pause,

01:13:39.780 --> 01:13:41.280
push it for some
other command that

01:13:41.280 --> 01:13:46.890
now takes in all arguments in
RAX and RDI for example, right.

01:13:46.890 --> 01:13:48.280
Do the same type of test, right.

01:13:48.280 --> 01:13:49.950
So basically you can
leverage the fact

01:13:49.950 --> 01:13:52.080
that for any particular
set of registers

01:13:52.080 --> 01:13:54.750
that you want to
be able to control,

01:13:54.750 --> 01:13:56.690
there's some system
call that will give you

01:13:56.690 --> 01:13:59.070
a signal as an attacker,
that allow you to figure out

01:13:59.070 --> 01:14:00.942
whether you successfully
broke it or not.

01:14:00.942 --> 01:14:02.400
Right, so at the
end of this phase,

01:14:02.400 --> 01:14:05.580
you basically have
the address of syscall

01:14:05.580 --> 01:14:07.770
and the address of
a bunch of gadgets

01:14:07.770 --> 01:14:11.130
which allow you to pop
into arbitrary registers.

01:14:11.130 --> 01:14:16.900
OK and so now let's
see so, step 4

01:14:16.900 --> 01:14:19.895
is going to be to invoke write.

01:14:28.970 --> 01:14:35.924
Step 4 is invoke the
write system call.

01:14:38.710 --> 01:14:44.200
So to invoke write, we need
to have the following gadgets.

01:14:44.200 --> 01:14:48.770
You need to be able to pop RDI.

01:14:48.770 --> 01:14:51.400
We need to be able to pop RSI.

01:14:54.310 --> 01:15:06.490
We need to be able to pop RDX,
pop racks, and then invoke

01:15:06.490 --> 01:15:09.140
syscall, right.

01:15:09.140 --> 01:15:11.000
So as it turns out,
what are these registers

01:15:11.000 --> 01:15:12.950
being used for by system call?

01:15:12.950 --> 01:15:17.900
So this is the socket, or more
generally, the file descriptor

01:15:17.900 --> 01:15:20.650
that you're going
to pass into write.

01:15:20.650 --> 01:15:23.190
This is the buffer.

01:15:23.190 --> 01:15:25.080
This is the length
of that buffer.

01:15:27.680 --> 01:15:30.150
This is the syscall number.

01:15:33.970 --> 01:15:35.910
And it is called syscall.

01:15:35.910 --> 01:15:39.150
Right, so if we found
all these gadgets,

01:15:39.150 --> 01:15:42.480
then we can actually
now control the values

01:15:42.480 --> 01:15:44.310
that are put into
those arguments, that

01:15:44.310 --> 01:15:46.435
put in those registers,
because we just pushed them

01:15:46.435 --> 01:15:47.440
on the stack, right.

01:15:47.440 --> 01:15:49.670
And so for example, what's
the socket going to be?

01:15:49.670 --> 01:15:51.560
For once you're going to have
to do a little guessing here,

01:15:51.560 --> 01:15:52.060
right.

01:15:52.060 --> 01:15:54.280
can take advantage of the
fact that Linux restricts

01:15:54.280 --> 01:15:56.960
the number of simultaneous
open file connections,

01:15:56.960 --> 01:15:59.050
for a file that's
going to be 2024.

01:15:59.050 --> 01:16:01.650
And also it's supposed to
be the lowest one available.

01:16:01.650 --> 01:16:03.858
So we do a little bit of
guessing here and figure out

01:16:03.858 --> 01:16:05.690
what that socket
is, put it in there.

01:16:05.690 --> 01:16:07.190
Now interestingly,
what are we going

01:16:07.190 --> 01:16:08.920
to pass into the buff pointer?

01:16:08.920 --> 01:16:10.870
Right, we're actually
going to use the text

01:16:10.870 --> 01:16:12.720
segment of the program.

01:16:12.720 --> 01:16:15.800
We're actually going to pass in
that the pointer to somewhere

01:16:15.800 --> 01:16:17.540
in the code of the program.

01:16:17.540 --> 01:16:19.410
So what's that going
to allow us to do?

01:16:19.410 --> 01:16:23.170
That's going to allows us to
read the binary, out of memory,

01:16:23.170 --> 01:16:26.750
using the right call
to the client socket.

01:16:26.750 --> 01:16:29.740
So that the attacker can
then take that binary,

01:16:29.740 --> 01:16:31.820
analyze it offline, right.

01:16:31.820 --> 01:16:33.670
Just use GDB, or
whatever, to figure out

01:16:33.670 --> 01:16:35.080
where everything is located.

01:16:35.080 --> 01:16:38.280
The attacker knows that now,
every time the server crashes,

01:16:38.280 --> 01:16:41.300
it's going to have the same
randomized set of things in it.

01:16:41.300 --> 01:16:43.950
So now, once the attacker can
find out addresses and offsets

01:16:43.950 --> 01:16:46.350
for stuff, now the
attacker can directly

01:16:46.350 --> 01:16:47.850
attack those gadgets, right.

01:16:47.850 --> 01:16:49.720
Directly attack other
vulnerabilities,

01:16:49.720 --> 01:16:52.330
figure out how to open up a
shell, so on and so forth.

01:16:52.330 --> 01:16:53.850
So in other words,
at the point you

01:16:53.850 --> 01:16:57.880
exfiltrated the binary to the
attacker, you basically lost.

01:16:57.880 --> 01:17:02.454
Right, so this is essentially
how the BROP attack works.

01:17:02.454 --> 01:17:03.870
Like I said, in
the paper, there's

01:17:03.870 --> 01:17:05.882
a bunch of optimization,
but really you

01:17:05.882 --> 01:17:07.840
need to understand this
stuff, the basic stuff,

01:17:07.840 --> 01:17:10.020
before that optimization
will start to make sense.

01:17:10.020 --> 01:17:11.670
And so we can talk about the
optimization with me offline

01:17:11.670 --> 01:17:13.205
if you want, or after class.

01:17:13.205 --> 01:17:14.580
But to suffice it
to say, this is

01:17:14.580 --> 01:17:17.270
the basics of how you
launch that BROP attack.

01:17:17.270 --> 01:17:20.490
You've got to find
the stop gadget,

01:17:20.490 --> 01:17:23.230
find those gadgets
that pop stack entries.

01:17:23.230 --> 01:17:25.260
Figure out which
of those registers

01:17:25.260 --> 01:17:27.440
those gadgets pop
into, and find out

01:17:27.440 --> 01:17:30.330
how to figure out where
syscall is, and then invoke

01:17:30.330 --> 01:17:33.560
write by accumulating
all that knowledge.

01:17:33.560 --> 01:17:35.729
So very quickly, how do
you defend against BROP?

01:17:35.729 --> 01:17:37.270
Well the most obvious
thing is you've

01:17:37.270 --> 01:17:39.270
got to rerandomize, right.

01:17:39.270 --> 01:17:41.810
So the fact that
crashed servers do not

01:17:41.810 --> 01:17:44.490
respawn, rerandomize
versions of themselves,

01:17:44.490 --> 01:17:48.000
that allows the crash to
act as a signal that let's

01:17:48.000 --> 01:17:49.990
the attacker test
various hypotheses

01:17:49.990 --> 01:17:52.010
about how the programs working.

01:17:52.010 --> 01:17:54.990
So one simple defense
is to make sure

01:17:54.990 --> 01:17:58.850
that you do exec when you spawn
your process, instead of fork,

01:17:58.850 --> 01:17:59.350
right.

01:17:59.350 --> 01:18:01.990
Because when you exec the
process, you create totally new

01:18:01.990 --> 01:18:04.676
randomized layout space,
at least on Linux, right.

01:18:04.676 --> 01:18:07.050
So on Linux, when you compile
with this PIE, the Position

01:18:07.050 --> 01:18:09.970
Independent Executable
flag, you only

01:18:09.970 --> 01:18:12.420
get that randomized
address space

01:18:12.420 --> 01:18:14.950
that's new if you use exec.

01:18:14.950 --> 01:18:17.730
So another event you can
use is just use Windows,

01:18:17.730 --> 01:18:20.350
because Windows
basically does not

01:18:20.350 --> 01:18:22.240
have a fork equivalent, right.

01:18:22.240 --> 01:18:23.890
So hooray for us.

01:18:23.890 --> 01:18:26.560
So that means that
on Windows, whenever

01:18:26.560 --> 01:18:28.400
you spawn that new
server, it's always

01:18:28.400 --> 01:18:31.950
going to have a new
randomized address space.

01:18:31.950 --> 01:18:34.440
I think someone over here
mentioned something like,

01:18:34.440 --> 01:18:36.020
what would happen
if for example,

01:18:36.020 --> 01:18:38.340
when the server crashed,
it didn't actually

01:18:38.340 --> 01:18:40.230
close the connection?

01:18:40.230 --> 01:18:41.770
Right, so you can
imagine one thing

01:18:41.770 --> 01:18:45.360
that when a crash takes place,
we somehow catch that fault

01:18:45.360 --> 01:18:48.050
and then we keep that connection
open for a little while

01:18:48.050 --> 01:18:51.310
to confuse the attacker
and remove that signal,

01:18:51.310 --> 01:18:52.540
that something's gone amiss.

01:18:52.540 --> 01:18:54.690
So that's something
you definitely do.

01:18:54.690 --> 01:18:57.720
What's hilarious about that
is, that now your BROP attack

01:18:57.720 --> 01:19:00.980
turns into a denial
of service attack.

01:19:00.980 --> 01:19:03.280
Because now you just got
all the potential zombie

01:19:03.280 --> 01:19:05.660
processes that are sitting
around, they segfaulted.

01:19:05.660 --> 01:19:07.380
They're useless in
society, but you

01:19:07.380 --> 01:19:09.421
can't let them go, because
otherwise you're going

01:19:09.421 --> 01:19:10.905
to delete this information.

01:19:10.905 --> 01:19:12.530
Another thing you
might think about to,

01:19:12.530 --> 01:19:14.155
is you could do bounds
checking, right.

01:19:14.155 --> 01:19:16.040
We just talked a bunch
about that, right.

01:19:16.040 --> 01:19:19.312
But in the paper, they
casually dismiss this

01:19:19.312 --> 01:19:20.770
as saying it has
up to 2x overhead,

01:19:20.770 --> 01:19:24.870
so nobody's going to do that,
but you could in fact do that.

01:19:24.870 --> 01:19:27.100
So that's basically
how BROP works.

01:19:27.100 --> 01:19:29.670
As for the homework
question, the homework

01:19:29.670 --> 01:19:32.140
questions a bit subtle, because
the homework question says,

01:19:32.140 --> 01:19:36.610
what if you use a hash of
the current time, right?

01:19:36.610 --> 01:19:39.060
Get time of day when you
restarted the program.

01:19:39.060 --> 01:19:42.950
Is that sufficient to
prevent this type of attack?

01:19:42.950 --> 01:19:46.780
Well note that, hashing
does not magically

01:19:46.780 --> 01:19:50.010
provide you bits of entropy
if the input to the hash

01:19:50.010 --> 01:19:51.890
is easily guessable, right.

01:19:51.890 --> 01:19:54.860
If I know that you're only
going to hash one or two things,

01:19:54.860 --> 01:19:58.160
it doesn't matter if I have
like some a jillion bit hash.

01:19:58.160 --> 01:19:58.930
Doesn't matter.

01:19:58.930 --> 01:20:01.580
So I can just guess one of those
two values and see what is.

01:20:01.580 --> 01:20:03.580
So the thing to note is
that get time of day,

01:20:03.580 --> 01:20:06.110
actually has much less
entropy than you might think.

01:20:06.110 --> 01:20:09.070
Particularly because the
attacker can actually

01:20:09.070 --> 01:20:12.690
check what time he or she is
launching the attack, right.

01:20:12.690 --> 01:20:15.150
So that's going to actually
remove a bunch of entropy

01:20:15.150 --> 01:20:17.170
from that calculation, right.

01:20:17.170 --> 01:20:18.750
So there's some
subtleties there.

01:20:18.750 --> 01:20:21.860
What's the server skew in
terms of clock or the client

01:20:21.860 --> 01:20:22.900
and so on and so forth.

01:20:22.900 --> 01:20:26.600
The long story short, using
a guessable base value,

01:20:26.600 --> 01:20:28.830
even with guessable
just inside of a range,

01:20:28.830 --> 01:20:30.661
is super useful for
the attacker, right.

01:20:30.661 --> 01:20:32.035
Particularly
because the attack--

01:20:32.035 --> 01:20:35.680
we can start subverting a
bunch of servers in parallel

01:20:35.680 --> 01:20:37.960
and know that all
of them should have

01:20:37.960 --> 01:20:39.320
fairly similar values, right.

01:20:39.320 --> 01:20:41.440
This is a high order
of bits, right.

01:20:41.440 --> 01:20:42.890
So long story
short, the answer is

01:20:42.890 --> 01:20:47.730
that, it's literally better
than nothing to randomize,

01:20:47.730 --> 01:20:50.390
if you use get time of day, but
it doesn't actually provide you

01:20:50.390 --> 01:20:51.870
as much security as you think.

01:20:51.870 --> 01:20:53.953
And the other lesson too
is, that just because you

01:20:53.953 --> 01:20:55.640
hash something
right, that doesn't

01:20:55.640 --> 01:20:59.052
matter if you're not actually
using that hash in a smart way.

01:20:59.052 --> 01:21:00.036
You have a question?

01:21:00.036 --> 01:21:03.480
AUDIENCE: Oh, still when I
did the calculations that some

01:21:03.480 --> 01:21:09.604
[INAUDIBLE] it seems
like maybe to be

01:21:09.604 --> 01:21:13.712
able to get the offset
that the [INAUDIBLE]

01:21:13.712 --> 01:21:17.616
your [INAUDIBLE]
start the process

01:21:17.616 --> 01:21:19.249
to within like 48 milliseconds?

01:21:19.249 --> 01:21:21.040
PROFESSOR: Yes and
getting the timing right

01:21:21.040 --> 01:21:22.780
depends on a bunch of
different things, right.

01:21:22.780 --> 01:21:24.000
But you could take
advantage of the fact

01:21:24.000 --> 01:21:26.166
that the attacker can open
up a bunch of connections

01:21:26.166 --> 01:21:27.640
in parallel, and
leverage the fact

01:21:27.640 --> 01:21:29.640
that even if the initial
guess a little bit off,

01:21:29.640 --> 01:21:31.900
you can still launch
multiple guesses on what

01:21:31.900 --> 01:21:34.209
should be very
similar canary values,

01:21:34.209 --> 01:21:35.500
and do that attack in parallel.

01:21:35.500 --> 01:21:37.650
But you're right, there's
tricky time and issues.