WEBVTT

00:00.300 --> 00:10.770
In this video let's understand PLT and got PLT stands for procedure linkage table and got stands for

00:10.770 --> 00:12.150
Global Offset Table.

00:13.360 --> 00:20.680
When we call functions like printf from Lipsey, they are dynamically linked to our binary and then

00:20.680 --> 00:21.580
executed.

00:22.240 --> 00:28.960
Remember, this is not true for binaries that are statically linked when functions from shared libraries

00:28.960 --> 00:35.500
like Lipsey are called a call to a piece of code in procedure linkage table is made.

00:36.490 --> 00:43.900
This will in turn take help of dynamic linker, which will search through Lipsey Library for the address

00:43.900 --> 00:52.420
of our print function, and it will add an entry in global offset table with the address of the function

00:52.420 --> 00:53.170
invoked.

00:53.200 --> 00:59.260
Once the address is resolved, it will get executed and the control will be transferred to the saved

00:59.260 --> 01:00.310
return address.

01:00.940 --> 01:08.410
When the same function is called for the next time in the code, the address stored in the global offset

01:08.410 --> 01:15.160
table will be used instead of invoking dynamic linker to resolve the function address again.

01:15.490 --> 01:23.050
So as you can see here on the picture, the PLT stub code is not taking the help of this dynamic linker

01:23.050 --> 01:27.190
anymore to get the address of printf function from Lipsey.

01:27.520 --> 01:33.520
Instead it is directly using the entry that is available in global offset table.

01:33.820 --> 01:42.280
So to summarize, PLT is just a stub code which is going to invoke this dynamic linker to resolve the

01:42.280 --> 01:45.790
addresses of the functions that are being invoked from Lipsey.

01:46.090 --> 01:51.960
Once it resolves the address, the address is going to be updated in Global Offset Table.

01:51.970 --> 01:54.970
If the same function is invoked for the next time.

01:55.060 --> 02:01.570
Instead of resolving the address once again, the address will be picked from the global offset table.

02:01.810 --> 02:06.040
This is how procedure linkage table and Global Offset Table works.

02:06.490 --> 02:12.550
I have left some low level details during this explanation, but I think this should be enough for now

02:12.550 --> 02:15.910
to understand what PLT and got are.

02:16.270 --> 02:22.480
Now let's see a quick demo of how PLT and GT look like in GDB.

02:23.140 --> 02:30.280
Let's navigate to x86 underscore 64 and let's navigate to a red to PLT.

02:31.090 --> 02:33.690
Here we do have two files.

02:33.700 --> 02:37.780
The first one is vulnerable point C and the second file is Makefile.

02:38.170 --> 02:41.940
Let's quickly take a look at the contents of vulnerable point.

02:41.950 --> 02:46.180
See if you notice we have main function.

02:46.180 --> 02:49.140
Inside the main function we have three functions.

02:49.150 --> 02:56.590
The first one is printf, the second one is one in function and get date is the third one.

02:56.890 --> 03:00.820
After invoking this one function, we have a buffer overflow here.

03:00.820 --> 03:06.250
Within the definition and inside the definition of get date, there is nothing much.

03:06.250 --> 03:12.820
There is a system function which is invoked which is actually printing the date and we have another

03:12.820 --> 03:22.300
printf now to understand plt and God, we can use these two function calls as example because to understand

03:22.300 --> 03:27.100
God and PLT, we need a function being called more than once.

03:27.220 --> 03:33.010
So printf here is a very good candidate for us to understand plt and geode.

03:33.400 --> 03:36.790
Now let's take a look at the contents of Makefile.

03:37.900 --> 03:43.310
If you notice, I have added an additional flag here, which is dash no dash p.

03:43.420 --> 03:46.840
This flag must be specified here for this demo to work.

03:46.960 --> 03:52.780
The reason for that is we are going to use the addresses within the binary while writing the exploit.

03:52.900 --> 03:59.290
And if we don't specify this flag, the addresses are going to be changed on each run.

03:59.470 --> 04:02.650
This is something like a slot within the binary.

04:02.770 --> 04:03.340
Right?

04:03.340 --> 04:06.850
So let's use this makefile to compile the program.

04:06.850 --> 04:08.530
So I'm just typing make.

04:09.880 --> 04:15.100
There are some warnings, but seems like we have our vulnerable binary ready.

04:16.120 --> 04:18.550
Now let's load this binary using gdb.

04:22.360 --> 04:26.620
And let's type this as Maine.

04:27.670 --> 04:31.060
If you notice, there is a put call here, which is our printer.

04:31.480 --> 04:35.340
If you remember, there is another printer within get debt.

04:35.350 --> 04:40.720
So let's also type this as get debt.

04:42.550 --> 04:44.950
If you notice, there is another call here.

04:45.100 --> 04:50.830
So what I'm going to do is I'm going to set up a breakpoint at these two, puts calls.

04:50.830 --> 04:56.110
So I'm just copying the first address and I'm just setting up a breakpoint there.

04:57.170 --> 05:05.300
And I'm also copying this address associated with the second puts call and I'm setting up a breakpoint

05:05.300 --> 05:05.780
there.

05:06.320 --> 05:06.980
Hit enter.

05:08.210 --> 05:10.460
Now let's run the binary using the command.

05:10.460 --> 05:11.060
Run.

05:13.240 --> 05:19.720
And if you notice the first breakpoint is hit which is at the call to puts function.

05:20.110 --> 05:24.070
Now let's observe where the control is being redirected to.

05:24.460 --> 05:27.040
This is where the control is being redirected to.

05:27.070 --> 05:32.350
We are being redirected to execute some instructions in PLT section.

05:32.680 --> 05:39.890
Immediately after that there is a jump instruction to put it dot, dot, plt.

05:39.910 --> 05:47.470
So after landing in this PLD section, we are making another jump to this section which is dot dot plt.

05:47.950 --> 05:51.100
Now let's keep executing see instruction.

05:54.240 --> 06:01.770
So we have taken a jump and we have taken another jump.

06:01.890 --> 06:06.840
If you notice, our execution now is landed in this section.

06:07.290 --> 06:09.240
Now, we don't know what this section is.

06:09.240 --> 06:10.370
We don't know where we are.

06:10.380 --> 06:19.560
So let's quickly take the output off the map and let's try to understand which program in memory these

06:19.560 --> 06:21.120
addresses belong to.

06:21.510 --> 06:32.430
So if a7a is zero and if you notice this is what the address belongs to, what it means is these addresses

06:32.430 --> 06:38.340
belong to this LD library, which is the dynamic linker loader.

06:38.490 --> 06:45.960
This program is going to find out the address of put function from C and global offset table will be

06:45.960 --> 06:47.610
updated with an entry.

06:47.790 --> 06:51.240
This entire process is called lazy binding.

06:51.630 --> 06:59.490
In a nutshell, this dynamic linker loader does all the heavy lifting in the background and finds the

06:59.490 --> 07:08.460
correct addresses of functions in other shared libraries, even when ASL is on and dynamically links

07:08.460 --> 07:11.580
it to executable via the global offset table.

07:12.000 --> 07:18.360
So when the puts function is executed for the next time, the address will be readily available in the

07:18.360 --> 07:19.590
global offset table.

07:19.980 --> 07:23.760
Now let's type C to continue our execution.

07:27.800 --> 07:29.420
Let's enter something.

07:31.460 --> 07:33.590
Now we hit the second breakpoint.

07:33.770 --> 07:36.980
You can see here we are about to call the function.

07:37.190 --> 07:43.190
And we also have another instruction which is taking the jump to this God dot plot section.

07:43.940 --> 07:50.810
Now let's type C and observe if we land on the dynamic linker section once again, I'm just typing a

07:50.810 --> 07:51.260
sign.

07:57.130 --> 08:03.460
If you observe we are already in the function this time the dynamic linker did not have to do the loading

08:03.460 --> 08:09.250
once again as the address of the function was already available in the global offset table.

08:09.520 --> 08:15.220
Let's quickly confirm that these addresses indeed belong to outputs from the Lipsey Library.

08:15.430 --> 08:18.430
So I'm going to just type via map.

08:18.970 --> 08:22.330
Let's see if you notice this.

08:22.330 --> 08:31.570
This address is ending with seven E 40 5a0, and that should be in between these two addresses.

08:31.810 --> 08:35.920
That means these addresses belong to Lipsey Library.

08:36.070 --> 08:36.460
Right?

08:36.460 --> 08:42.640
So that confirms that we have landed inside the function directly within Lipsey Library.

08:42.640 --> 08:47.200
And the dynamic linker did not have to do the function resolution once again.

08:47.800 --> 08:53.440
So this is how the procedure linkage table and global offset table works.

08:53.980 --> 09:01.360
Just to recap, when a function which is available in Lipsey is called from within the library, a stab

09:01.360 --> 09:08.830
code within PLT is going to be executed, which in turn is going to take help from this dynamic linker,

09:08.860 --> 09:16.090
which is going to go through the Lipsey Library and search for the actual address of this print function.

09:16.090 --> 09:23.800
And it is going to update that in global offset table when the next time the print function is invoked,

09:23.830 --> 09:29.950
instead of going through the dynamic linker, this address will be picked from the global offset table

09:29.950 --> 09:30.730
directly.

09:31.180 --> 09:36.160
So that's how procedure linkage table and the global offset table work.
