WEBVTT

00:03.520 --> 00:08.200
Hello everyone, and welcome back to Mastering Software Exploitation.

00:08.200 --> 00:14.720
I'm excited as we reach to our final section, and in this section we are going to learn about Heap

00:14.720 --> 00:23.600
Exploitations 101, which means that we are going to show a precise example of a step by step exploitation

00:23.760 --> 00:28.000
of an overflow vulnerability in Linux systems.

00:29.000 --> 00:33.280
So let's dive in first as always.

00:33.280 --> 00:34.360
Definitions.

00:34.360 --> 00:42.040
So what is the heap memory heap is a dynamically allocated memory, which means that every time you

00:42.040 --> 00:51.120
use malloc or new or choose your preferred language, this buffer or area is being allocated in the

00:51.120 --> 00:53.760
dynamic memory of the system.

00:54.720 --> 01:02.400
The way that the system actually manages the heap memory is different, uh, and OS specific.

01:02.800 --> 01:11.920
So by management, I mean the mechanisms to track free memory blocks, allocated memory object sizes,

01:11.960 --> 01:18.880
and how I want to arrange different sizes and other types of metadata to actually control and manage

01:19.200 --> 01:26.720
all those different processes, threads that are asking memory to make sure that I can manage that for

01:26.720 --> 01:28.680
them in the heap memory.

01:29.840 --> 01:36.560
We are going to focus on the Linux slab allocator, which is the standard memory allocator in Linux

01:36.560 --> 01:37.160
kernel.

01:38.480 --> 01:46.320
One thing to note about exploiting heap memory or prerequisite of exploiting a heap memory vulnerability,

01:46.920 --> 01:54.000
is that the first critical step is actually thoroughly understand how your target system manages the

01:54.000 --> 01:54.600
memory.

01:55.040 --> 02:00.890
This sounds easy, like you can read some documentation on Google or something like that, but it's

02:00.930 --> 02:09.130
actually not even Linux kernel doesn't have the heap memory management completely documented, um,

02:09.170 --> 02:12.690
in a way that is easy to just read a blog and understand.

02:12.970 --> 02:20.210
Many times there is a need to dive into the code and understand the nuances of what's happening when

02:20.730 --> 02:28.210
all of the cache is full, when specific buckets are full, when a lot of objects are being freed at

02:28.210 --> 02:28.810
the same time.

02:28.850 --> 02:32.770
Is it the same like a few objects being released one by one?

02:33.370 --> 02:40.210
Those sorts of things, especially in sophisticated systems with multiple CPUs and cache per CPU, is

02:40.250 --> 02:43.610
actually crucial to your heap exploitations.

02:44.050 --> 02:51.610
So first advice is really understand the memory manager of the system that you are targeting.

02:54.130 --> 02:56.450
What is the heap memory in Linux kernel then?

02:56.490 --> 03:01.970
So in Linux kernel, we manage the memory in fixed size chunks that are called slabs.

03:02.610 --> 03:12.050
This basically means that if I have a 30 bytes buffer and 28 bytes buffer, they are all going to go

03:12.050 --> 03:14.330
to the cache k malloc 32.

03:14.850 --> 03:19.690
So we have uh the slab maintaining size caches.

03:20.130 --> 03:27.930
And when we call malloc or k malloc if we are in the kernel the memory comes for the corresponding slab.

03:28.810 --> 03:31.890
There is no metadata stored in the object.

03:31.890 --> 03:40.090
And the pointer that we get as a return of the allocation is actually the beginning of the usable memory

03:40.090 --> 03:41.090
that we can use.

03:41.650 --> 03:47.850
So you can see down, uh, in illustration we just have objects one by another.

03:48.330 --> 03:50.570
Some of them are free, some of them are used.

03:50.930 --> 03:56.610
And it's a simple visual of one, uh, slab Cash in the memory.

03:58.410 --> 04:02.450
So let's take it a step even more abstract than that.

04:02.690 --> 04:06.090
Um, and this is basically what we have reused.

04:06.090 --> 04:08.890
Free used, uh, objects.

04:09.010 --> 04:10.450
This, of course, is being changed.

04:10.450 --> 04:14.290
If someone is freeing this use object, it becomes free.

04:15.010 --> 04:22.850
If someone is allocating a memory, it can get a pointer to that free space here and so on and so forth.

04:24.170 --> 04:27.890
And now a naive example of a vulnerability in the heap.

04:27.890 --> 04:33.050
So very similar to the Stack Overflow vulnerability we've seen in section one.

04:33.810 --> 04:35.890
We actually have a buffer here.

04:35.930 --> 04:40.050
Only this time the buffer is allocated via malloc.

04:40.490 --> 04:45.290
Malloc actually causes the kernel to allocate a buffer in the heap memory.

04:45.610 --> 04:51.570
And in this case the buffer is 256 56 bytes.

04:51.570 --> 04:56.170
Which means we are going to get into k malloc 256.

04:57.210 --> 05:03.090
Now this buffer is going to be allocated somewhere in the slab before and after.

05:03.090 --> 05:06.290
They are going to be many different types of objects.

05:06.290 --> 05:09.130
We don't know who they are, they are used or not.

05:09.450 --> 05:16.410
But what we do know is if we overflow this buffer on the heap, we are going to corrupt what's next,

05:16.450 --> 05:21.370
what's actually in the memory after our vulnerable buffer?

05:22.010 --> 05:23.370
Do we know what it is?

05:23.690 --> 05:24.570
We don't.

05:24.610 --> 05:30.610
And this is exactly the magic in heap exploitations into Stack Overflow example.

05:30.610 --> 05:35.970
If you remember we know exactly what are we going to overwrite?

05:36.290 --> 05:38.690
The return address is always there for us.

05:38.690 --> 05:45.010
We can count on the return address to be there, and we can count on the return address to be executed

05:45.010 --> 05:46.650
when the function exits.

05:47.090 --> 05:48.330
This is perfect, right?

05:48.330 --> 05:51.610
We have an address that is being executed.

05:51.850 --> 05:56.700
We know where it is and we can overflow it easy in the heap.

05:56.940 --> 05:58.580
It's quite difficult.

05:58.580 --> 06:04.060
We don't know what we are going to overflow, and we don't even know if this memory is being used in

06:04.060 --> 06:05.220
any interesting way.

06:05.620 --> 06:07.100
Remember to exploit.

06:07.100 --> 06:12.420
We have to cause an unintended behavior of the system.

06:13.340 --> 06:19.460
If the memory after our vulnerable buffer is not being used by anything interesting, that can influence

06:19.460 --> 06:22.020
the execution flow of the program.

06:22.860 --> 06:24.020
We are not doing anything.

06:24.020 --> 06:25.580
We didn't exploit anything.

06:26.460 --> 06:33.660
So we understand that we need to somehow control and predict what will be after us in the memory.

06:34.500 --> 06:35.780
But how can we do that?

06:35.780 --> 06:41.420
The memory so sophisticated blocks of memory are being allocated and freed all the time.

06:41.740 --> 06:44.740
The kernel is managing the memory for all of the processes.

06:44.740 --> 06:54.260
This sounds like almost impossible, but I will walk you through a simple steps that makes it very possible.

06:56.460 --> 07:03.340
So our primary goal in exploiting a heap vulnerability is to override some kind of a function pointer

07:03.340 --> 07:05.580
so we can redirect the execution flow.

07:05.820 --> 07:08.700
And this is what we are going to focus on in this section.

07:09.620 --> 07:15.740
The key exploitation strategies in heap are called heap feng shui or heap shaping, which is basically

07:15.780 --> 07:22.140
precisely arranging the heap layout to position vulnerable objects that we think we can use to exploit

07:22.420 --> 07:24.740
next to our target object.

07:26.260 --> 07:32.020
Next, free exploitation techniques are not covered in this section, but it's another thing that you

07:32.020 --> 07:34.780
can explore on your own time.

07:36.180 --> 07:43.300
So successful exploitation basically requires shaping the heap to our desire.

07:45.460 --> 07:55.100
And now let's talk and define target objects in hip exploitations, we must control what memory we overflow

07:55.100 --> 07:55.620
into.

07:56.180 --> 08:02.060
So in the illustration, you can see we have the vulnerable object allocated somewhere we don't know

08:02.060 --> 08:02.460
where.

08:02.980 --> 08:05.420
And we're asking ourselves, who are you?

08:05.620 --> 08:08.020
This memory that is after us.

08:08.020 --> 08:08.860
We don't know.

08:09.700 --> 08:13.020
All we can do right now is overflow the vulnerable object.

08:14.020 --> 08:20.540
So we need to control the object that's being placed after sometimes before the vulnerable object.

08:20.540 --> 08:23.340
Depending if we have an underflow or an overflow.

08:23.980 --> 08:28.860
So we can overflow a memory that is strategic to us and not just random memory.

08:29.620 --> 08:38.860
Let's call this desired strategic object that we want to overflow the target object, the thing, the

08:38.860 --> 08:43.660
object that we want to get right here after the vulnerable object.

08:45.900 --> 08:55.860
The target object has very specific characteristics, and I'll divided it to three main critical criterias

08:55.860 --> 08:56.580
to be.

08:56.620 --> 08:59.260
Able to classify as a target object.

08:59.700 --> 09:02.980
The first one is controlled allocations.

09:03.500 --> 09:11.500
This basically means that we, as the attacker that has some kind of outside communication to the system,

09:11.740 --> 09:16.220
is able to trigger allocations of the target objects on the heap.

09:17.260 --> 09:26.260
This means that I can perform certain operations if it's asking something, if it's sending, uh, certain

09:26.260 --> 09:33.980
packets to the system, and in reaction, the system is causing a certain object or target object to

09:33.980 --> 09:35.540
be allocated on the heap.

09:36.220 --> 09:44.940
Put simply, the attacker is able to cause the target object to be allocated on the memory in its own

09:44.940 --> 09:45.860
discretion.

09:46.060 --> 09:49.870
It can do something that will cause target object to be allocated.

09:51.310 --> 09:56.470
The second criteria is that the target object has to contain a function pointer.

09:57.030 --> 10:03.590
If not a function pointer, then some other critical element that we want to control.

10:03.590 --> 10:09.670
But usually, and for the sake of simplicity, in this example, we want the target object to have a

10:09.670 --> 10:16.230
function pointer so that we can overwrite it with our malicious address, which can be a beginning of

10:16.270 --> 10:20.230
a rope chain depending on the system that we exploit.

10:21.550 --> 10:29.110
The third criteria is that this function pointer has to be Triggerable Triggerable.

10:29.150 --> 10:31.510
Sorry Triggerable execution.

10:31.950 --> 10:36.990
So we must be able to trigger the execution of this function pointer that we override.

10:37.030 --> 10:42.590
Otherwise we will have a function pointer that we override and with malicious address.

10:42.590 --> 10:46.510
But that malicious address never gets executed kid, right?

10:47.070 --> 10:54.990
So we need to somehow make sure that we can cause this function pointer to be executed, or just count

10:55.030 --> 11:00.390
on the system to reach to this function pointer at some point, but better to control always.

11:01.870 --> 11:07.830
So let's take a step by step walkthrough of heap Feng Shui.

11:09.070 --> 11:12.070
First step is finding this target object.

11:12.070 --> 11:15.030
We just defined exactly what we are looking for.

11:15.070 --> 11:21.430
Now it's time to go to the system that we want to exploit and actually find the target object that we

11:21.430 --> 11:22.190
can use.

11:22.710 --> 11:30.070
Usually we will take a look at existing objects of the system, like file structs and those sort of

11:30.110 --> 11:36.110
things, and see if some of the objects there can be useful for us as a target object.

11:36.990 --> 11:39.150
Second is spray.

11:39.150 --> 11:40.790
We call it spray the heap.

11:41.430 --> 11:49.750
So what it means is that we are going to make and cause the system to allocate so many of these target

11:49.790 --> 11:57.710
objects, so that eventually the heap will be filled with many, many, many, many, many target objects.

11:58.790 --> 12:02.590
So I jumped a little bit here, but let's stay focused on step number two.

12:03.070 --> 12:08.990
So requirement number one of target objects is that we can control their allocations.

12:09.750 --> 12:15.990
If we can control their allocations we can just decide to allocate 1000 of target objects.

12:17.150 --> 12:17.990
Why not.

12:18.190 --> 12:19.150
We can do that.

12:19.350 --> 12:26.310
And then what will happen is that the heap memory is at some point we're going to be filled with so

12:26.310 --> 12:35.790
much target objects that hopefully and actually most likely one of those target objects are going to

12:35.790 --> 12:39.510
be allocated right next to our vulnerable buffer.

12:40.430 --> 12:41.990
Imagine it this way.

12:42.270 --> 12:45.960
You have a function that is exploiting the system.

12:46.640 --> 12:51.160
This function opens two threads.

12:51.360 --> 13:00.760
One of them is spraying the heap with 2000 target objects being allocated one by one, and the other

13:00.760 --> 13:05.640
thread is allocating the vulnerable buffer and overflowing it.

13:06.920 --> 13:08.320
Imagine what will happen.

13:08.320 --> 13:12.360
We have one heap and those threads are running simultaneously.

13:12.760 --> 13:18.920
Most likely the vulnerable buffer will be allocated next to one of those target buffers that the other

13:18.920 --> 13:20.320
threads keep spraying.

13:21.040 --> 13:22.840
This is exactly what we want.

13:24.720 --> 13:27.720
The third step is to trigger the vulnerable code.

13:27.720 --> 13:35.240
Now that we have the target buffer, the target object allocated right next to the vulnerable memory,

13:36.320 --> 13:39.800
we can trigger the vulnerability and overflow the memory.

13:40.440 --> 13:44.680
This will Uh, overflow directly to our target buffer.

13:46.160 --> 13:50.760
At this point, we have a target object with a function pointer.

13:50.800 --> 13:51.160
Right.

13:51.160 --> 13:58.120
Because requirements number three means a number two means the target object has a function pointer.

13:58.680 --> 14:01.320
So the only thing we need to do is to trigger.

14:01.360 --> 14:07.080
Now the use of this now malicious function pointer that we overflow.

14:07.840 --> 14:10.360
We can do that because we took care of it.

14:10.360 --> 14:20.880
In step number one we chose an targets object that contains a function pointer that we can trigger the

14:20.880 --> 14:22.000
execution of.

14:24.240 --> 14:30.640
So at this point we have the heap looking some something like that target object again and again and

14:30.640 --> 14:31.200
again.

14:31.200 --> 14:36.080
At some point the vulnerable object allocated between a few target objects.

14:36.600 --> 14:44.120
In this target object there is a function pointer somewhere Error, and we perform the overflow to cause

14:44.160 --> 14:48.160
this function pointer to point to a malicious address.

14:48.840 --> 14:57.160
And then we trigger the execution of the function pointer to execute malicious code on the system.

15:00.200 --> 15:02.280
To make it even more real.

15:02.720 --> 15:04.600
Let me show you an example.

15:04.640 --> 15:07.840
A real one simple one from Linux systems.

15:08.680 --> 15:16.240
So the struct file in Linux, one of the most used files, uh, most used structs, sorry.

15:16.280 --> 15:17.080
In Linux.

15:17.080 --> 15:23.960
And one of the most known objects as well is actually a great target object.

15:24.280 --> 15:25.560
Let's see why.

15:27.400 --> 15:30.360
First, it has a controlled allocation trigger.

15:30.400 --> 15:41.200
Basically, every system call such as open socket and almost most of the user space operations.

15:41.200 --> 15:44.920
Create a new struct file allocations in the kernel memory space.

15:45.400 --> 15:54.920
This means that from an outsider perspective attacker perspective, almost every interaction that I

15:55.880 --> 16:02.880
do with the with the with the system, with the target system that I I'd like to will probably cause

16:02.880 --> 16:07.600
the system to allocate a file operation, a file structure.

16:07.640 --> 16:14.160
So that's that's great because as you know, in Linux a lot of things happen through Syscalls.

16:14.160 --> 16:17.640
And most of the syscalls use struct file.

16:18.680 --> 16:20.000
So that's good for us.

16:21.040 --> 16:25.120
Second it has many function pointers.

16:25.600 --> 16:29.640
So every struct file contains file operation structure.

16:29.640 --> 16:36.360
And it contains multiple function pointers that can be overwritten to redirect the execution flow as

16:36.360 --> 16:36.920
we need.

16:37.330 --> 16:45.330
Lastly, it is also quite simple to trigger the execution of one of those function pointers at least.

16:46.010 --> 16:54.490
So simply performing standard operations on the file that was opened like read, write, pipe, and

16:54.490 --> 17:07.010
so on will execute the compromise function pointer from the um, from the file operations inside the

17:07.010 --> 17:08.010
struct file.

17:08.530 --> 17:16.570
So at this point, struct file seems like a great target object to be placed right after the vulnerable

17:16.570 --> 17:17.290
object.

17:18.370 --> 17:24.730
The function pointer that we are going to override is going to be one of the functions in file operations.

17:26.650 --> 17:31.730
We will choose the actual one according to which one we can trigger.

17:31.730 --> 17:35.410
If we can trigger a pipe, a write or read, and so on.

17:35.850 --> 17:44.610
In most cases this can be used as a privilege escalation vulnerability, which means the attacker already

17:44.610 --> 17:47.570
have the ability to run code on the user space.

17:47.690 --> 17:53.330
Let's say you downloaded something from the internet and it has malicious code in it.

17:54.690 --> 18:04.490
This originally is running the user space, but running on the user space gets the attacker the ability

18:04.490 --> 18:10.690
to create a new file and perform operations on the file like read write pipe.

18:12.170 --> 18:20.050
This means that with an additional heap overflow vulnerability and these capabilities to control what

18:20.090 --> 18:27.610
gets what gets allocated on the heap, the attacker on the user space can perform a privilege escalation

18:27.610 --> 18:30.930
to execute code on the kernel.

18:35.130 --> 18:38.290
And a real world example is exactly that.

18:38.530 --> 18:46.250
Uh, this is a pipe overflow is actually a local privilege escalation vulnerability, because a completely

18:46.250 --> 18:53.530
remote attacker that does not have any access to the system cannot really trigger the vulnerability.

18:54.050 --> 19:01.530
So in order to exploit this vulnerability, we assume the attacker already have some user space, uh,

19:01.530 --> 19:02.770
code execution.

19:03.210 --> 19:06.210
This is why it's called local privilege escalation.

19:07.050 --> 19:16.330
But just as a note, there are heap overflows that can be exploited completely remotely and not just

19:16.330 --> 19:18.570
privilege escalation vulnerabilities.

19:19.850 --> 19:30.370
I highly recommend those, uh, further reading, because heap exploitations are getting more and more

19:30.370 --> 19:36.090
complicated, and it depends on the Isn't the vulnerability that we need to exploit.

19:36.530 --> 19:43.330
Remember, an exploitation is always connected to a specific vulnerability, and sometimes it requires

19:43.330 --> 19:46.130
us to get even more sophisticated.

19:46.290 --> 19:50.570
And these examples are good, and there are many more online.

19:50.570 --> 19:57.050
But the basics of what we are trying to achieve, what we need to learn to achieve that and how it works

19:57.530 --> 20:00.010
is being presented here.

20:00.730 --> 20:10.010
Just to give you a head start on getting into the deep waters of hip exploitation, by the way, this

20:10.010 --> 20:15.490
vulnerability, the CVE mentioned here has a publicly available exploit code.

20:15.490 --> 20:20.130
So you can actually take a look of a real vulnerability and exploitation.

20:21.610 --> 20:22.850
What's next?

20:23.090 --> 20:28.130
So first you're going to write your first exploitation exploit.

20:28.650 --> 20:35.220
The lab is going to take you step by step so that everything will be clear and you can practice what

20:35.220 --> 20:36.020
we've learned.

20:36.700 --> 20:45.620
And perhaps in the future I will, uh, present an advanced course covering even more interesting topics

20:45.620 --> 20:52.940
in real world exploitations and how they look like for security engineers, researchers, and just everyone

20:52.940 --> 20:56.980
that want to be more familiar with that subject.

20:57.500 --> 20:58.380
I really enjoy.

20:58.420 --> 21:00.740
I really hope you enjoy the course.

21:01.140 --> 21:04.820
Thank you so much for attending and feel free to contact me.

21:05.420 --> 21:15.340
Always happy to to hear feedback and think about other ideas on additional courses or changes to this

21:15.340 --> 21:15.620
one.

21:15.620 --> 21:21.020
So please feel free to reach out and I hope this has been helpful for you.

21:21.620 --> 21:22.660
Thank you so much.
