WEBVTT

00:20.700 --> 00:25.560
Quick announcement, I'm gonna use laser pointer and

00:33.170 --> 00:34.870
I'm gonna use this screen.

00:35.250 --> 00:43.050
So those people sitting here, please move either to the center of the room or to the right side.

01:05.620 --> 01:07.440
You prefer to stay there?

01:15.370 --> 01:19.950
Well I think it depends on how close I am to the mic rather than...

01:36.690 --> 01:38.430
Okay, so let's start.

01:38.530 --> 01:40.130
Thank you for coming for my talk.

01:40.130 --> 01:48.830
It's the first talk in the morning, so it might be pretty difficult for you to get up early and come here, so thank you for showing up.

01:50.310 --> 01:58.750
The title of my talk is JIRA, which is a tool for automatic detection, identification and repair of control hijacking attacks.

01:58.990 --> 02:03.490
I am Alexey Smirnov and this is a joint work with Tricker Chair, who is my advisor.

02:03.550 --> 02:05.630
We are from Stony Brook University.

02:07.510 --> 02:09.390
Here is the outline of my talk.

02:09.390 --> 02:14.250
First I'm gonna give a brief introduction on control hijacking attacks.

02:14.450 --> 02:20.170
Then I'm gonna talk about the related work in the areas of attack detection, identification and repair.

02:20.230 --> 02:25.970
Then I'll present our architecture, JIRA, which has these three components.

02:25.970 --> 02:31.250
The attack detection component, the attack identification and attack repair component.

02:31.250 --> 02:36.230
The purpose of attack detection component is to detect a buffer overflow or control hijacking attack.

02:36.230 --> 02:43.150
So it's similar to the goal of the tools like StackGuard and Propolis.

02:43.470 --> 02:52.370
The attack identification component builds up the signature that can be supplied to intrusion detection system so that these attack packets can be filtered out in the future.

02:52.590 --> 03:00.050
The attack repair component repairs the program and allows it to continue its execution as if the attack never happened.

03:00.050 --> 03:08.050
In the performance evaluation part we're gonna talk about the overheads, the runtime overhead and the compile time overheads of our compiler.

03:08.230 --> 03:12.630
And we'll conclude with a summary of research contributions and with the direction of future work.

03:14.290 --> 03:18.150
Buffer overflow attacks are the most common type of attacks.

03:18.870 --> 03:24.370
Computer warms use buffer overflow attacks as a basic building block for the propagation.

03:24.690 --> 03:38.310
So as soon as they arrive to a new host, they perform a buffer overflow attack, hijack control of the underlying program or of the host, and then scan for more vulnerable machines by performing random IP scanning.

03:38.550 --> 03:46.790
Once they find a new vulnerable machine, they send their body to the new machine and perform the control hijacking attack on that new host.

03:47.410 --> 03:51.670
A comprehensive protection strategy should include the following three components.

03:51.670 --> 03:58.870
The attack detection component, which will detect the control hijacking attack when it happens.

03:58.870 --> 04:02.810
That is, when the worm tries to get control of the underlying computer.

04:02.890 --> 04:08.150
The attack identification component is responsible for building the signature of the attack.

04:08.150 --> 04:20.670
That is, for identifying malicious packets and representing them in the most general form so that polymorphic worms or polymorphic attacks can be detected by the same signature.

04:20.990 --> 04:28.510
The attack repair component allows the compromised program to continue its execution as if the attack never happened.

04:28.510 --> 04:43.130
That is, it should restore the memory image or the environment of the program as it was in the pre-attack time so that the program will think that it has never received any attack packets.

04:43.330 --> 04:58.130
We propose a compiler, Jira is a compiler, that instruments programs, source code of a program so that the instrumented program can identify, detect, and repair itself after a control hijacking attack.

04:58.870 --> 05:01.010
What is a buffer overflow attack?

05:01.170 --> 05:14.730
Well, the idea behind control hijacking attacks is to operate a control sensitive data structure such as a return address, function pointer, or any other control sensitive data structure.

05:14.730 --> 05:23.750
By the way, I've got some t-shirts here and books and I'm going to give them away and I'm going to ask you questions and who answers first gets a t-shirt or a book.

05:23.750 --> 05:25.510
So here's the first question.

05:26.150 --> 05:31.330
The return address and the function pointer are two possible types of control sensitive data structure.

05:31.330 --> 05:36.530
What are other data structures that a worm or a virus can override?

05:39.560 --> 05:41.440
That's what I said, function pointer.

05:43.320 --> 05:44.600
What else?

05:45.220 --> 05:46.020
Okay.

05:47.340 --> 05:48.480
What about HIP?

05:49.860 --> 05:51.200
What do you mean by HIP?

05:53.500 --> 05:55.040
Well, okay, I got a t-shirt.

06:01.260 --> 06:02.240
What else?

06:05.600 --> 06:07.460
That's what he said probably, HIP.

06:07.580 --> 06:09.100
Okay , that was what I...

06:19.100 --> 06:24.260
So the name of the control sensitive data structure is...

06:24.940 --> 06:26.080
just word.

06:28.000 --> 06:29.860
Okay, any other ideas?

06:30.360 --> 06:31.200
Okay.

06:35.160 --> 06:38.840
Well, for example, GOT, which is global offsets table.

06:40.380 --> 06:47.640
Anyway, buffer overflows are possible when the length of the destination buffer is shorter than the length of the data that's been written into it.

06:47.680 --> 06:55.100
So whenever you write something that is longer, it can override something that is behind this buffer, such as a return address.

06:55.100 --> 06:57.520
And that's when the buffer overflow happens.

06:57.520 --> 07:04.760
Standard libc functions, such as stringcpy or sprintf, are responsible for most buffer overflow attacks.

07:05.820 --> 07:10.240
So we're going to review related work in the areas of attack detection, identification, and repair.

07:10.240 --> 07:13.800
StackGuard is the first tool for buffer overflow attack detection.

07:13.800 --> 07:21.000
It works by placing a canRevert in the stack frame in the function prologue, and it checks this canRevert at function epilogue.

07:21.000 --> 07:26.500
If the values are different, then the attack has happened, and the application is terminated.

07:26.500 --> 07:31.960
RADint is another tool that protects programs from buffer overflow attacks.

07:31.960 --> 07:42.260
It works by saving the original return address in a special well-protected buffer at function prologue, and compares it with the values stored in the stack at function epilogue.

07:42.260 --> 07:52.700
If the values stored in the protected buffer end in the function frame when the function returns are different, then an attack is dejected.

07:52.700 --> 07:58.040
Can anyone think of any other tools for attack detection?

07:59.800 --> 08:02.340
Nah, Snore is content filter engine.

08:05.000 --> 08:06.720
Okay, I got it.

08:07.380 --> 08:08.720
You got a T-shirt?

08:08.720 --> 08:09.800
Who was that?

08:18.280 --> 08:21.300
So, let's move to attack identification.

08:23.120 --> 08:30.620
We need automatic ways for attack identification, because it's very important to generate signatures fast.

08:30.620 --> 08:34.780
Computer warms infect vulnerable machines very fast.

08:34.780 --> 08:38.620
It's a rate of thousands per minute, or maybe tens of thousands per minute.

08:38.660 --> 08:48.500
Therefore, if we wait for a human expert to come up with a signature, which is going to take a few hours, then the warm is going to hijack the most vulnerable host on the Internet.

08:48.680 --> 08:59.620
Recent epidemics propagate at a very, very high speed, so it's very difficult for a human expert to come up with a signature quickly.

08:59.620 --> 09:13.360
Previous systems for automatic signature generation either produced signatures that consisted of only one packet, or required a large pool of malicious network data to come up with a comprehensive signature.

09:13.360 --> 09:29.160
Signature that consists of one packet is sometimes insufficient, because a complex attack can involve multiple packets, such as, let's say, FTP server attack, it involves sending out authentication packets, and only then sending out the final attack packet.

09:29.160 --> 09:34.140
A comprehensive signature should include all attack packets, not just the last one.

09:34.140 --> 09:36.400
So here are some relevant projects.

09:36.460 --> 09:40.020
TaintCheck is a tool for...

09:40.020 --> 09:53.860
It uses the taint analysis to generate attack signature, and it reports the value of the return address, the form used to hijack control as a signature.

09:53.860 --> 09:55.940
So it's only a four-byte signature.

09:55.940 --> 10:08.000
Autograph uses so-called Rabin fingerprints to find common subsequences in a large pool of malicious network data.

10:08.000 --> 10:15.120
Polygraph and naming also use a large pool of malicious data, and to use machine learning algorithms to construct a multi-packet signature.

10:18.700 --> 10:22.600
AttackRepair relies on checkpointing.

10:22.600 --> 10:31.280
That is, one first checkpoints the program state, and then jumps to a previous point in the past to restore program's execution.

10:32.460 --> 10:38.860
So two approaches here are either keeping complete execution history, or do periodic stack checkpointing.

10:38.860 --> 10:45.020
That is, to take a snapshot of the memory image of the program.

10:45.140 --> 10:51.440
And the second approach relies on a fork system call, which is available under Linux, but might not be available under other operating systems.

10:51.440 --> 11:02.240
And Shadow Honeypot project runs two versions of the application, instrumented, that is protected and non-protected, and switches between them dynamically when it detects an attack.

11:02.240 --> 11:04.580
Now we move on to DIRA architecture.

11:04.580 --> 11:07.660
DIRA is a compiler that provides all these three components.

11:07.960 --> 11:11.840
AttackDetectionComponent, AttackIdentification, and AttackRepairComponent.

11:14.930 --> 11:24.310
As I said, DIRA is an extension to GCC, version 3.4.1 currently, but it can be used with other versions as well.

11:24.310 --> 11:32.730
The idea behind DIRA is memory updates logging, and this approach solves all these three problems at the same time.

11:32.770 --> 11:38.730
So the idea is to maintain a run-time log of all changes that the program performs.

11:40.110 --> 11:49.130
Assignments such as A equals B, or ellipsis functions call, such as memcpy, change memory state of the program, and therefore their effects should be saved.

11:49.130 --> 11:51.150
For example...

11:51.150 --> 11:53.570
Okay, we will see some examples later.

11:53.570 --> 12:00.010
For each memory update, DIRA stores its source address, its destination address, its length, and the preimage.

12:00.290 --> 12:05.790
So in the case of the assignment A equals B...

12:05.790 --> 12:07.150
Where's my pointer?

12:09.270 --> 12:10.030
Here.

12:10.550 --> 12:18.150
The source is the address of variable B, because that's where the new data comes from.

12:18.150 --> 12:23.410
The right address is the address of A, because that's the address that has been written into.

12:23.410 --> 12:27.290
The length of the data is the size of type of variable B.

12:27.290 --> 12:29.270
So if it's integer, it's 4-byte.

12:29.270 --> 12:35.050
The preimage is the old value of A, and it's used to restore memory image to the program.

12:35.410 --> 12:43.250
So the DIRA compiler instruments the source code of the program in compile-time.

12:43.250 --> 12:48.490
It adds the log-in code for variable assignments and for standard library functions.

12:48.530 --> 12:58.950
At run-time, this log-in code, this memory update log, is generated, and it's used at repair time to detect, to identify, and to repair the attack.

12:59.450 --> 13:03.510
So how can we detect, identify, and repair an attack if we have this memory update log?

13:03.510 --> 13:12.210
To detect an attack, we need to compare the current value of the return pointer, or the return address, saved in the stack frame with the value saved in the memory update log.

13:12.210 --> 13:29.770
When we invoke a function, we lay out a new stack frame, we save the old return address, we save any registers that are used in this function, and therefore, this is a changed memory state of the program, which should be saved in the memory update log according to our concept.

13:30.050 --> 13:35.530
Therefore, the old value of the return address will be saved in the memory update log when the function is invoked.

13:35.530 --> 13:42.230
When the function is returning, this saved value should be compared with the value that is currently on the stack.

13:42.230 --> 13:44.750
If these two values are different, then there is an attack.

13:44.890 --> 13:56.910
To identify an attack using the memory update log, we can trace back the data that overrode the control-sensitive data structure to the point where it was first received in the program.

13:57.770 --> 14:00.330
For example, through a receive call.

14:01.390 --> 14:09.270
To repair an attack, we need to restore the memory image of the program by using the pre-images that are also saved in the memory update log.

14:09.270 --> 14:17.810
This idea of keeping the memory update log of program memory state changes is the essential idea behind our tool.

14:17.890 --> 14:24.010
It allows us to solve all these three problems of attack detection, identification, and repair in the same uniform way.

14:25.450 --> 14:27.850
Memory update log is a circle buffer.

14:27.910 --> 14:30.470
Each record of this buffer has four fields.

14:30.470 --> 14:32.670
Read address, write address, length, and data.

14:33.150 --> 14:46.210
Dero saves the effect of each assignment operation, such as x equals y, where x and y are either directly referenced variables, array references, or dereferenced variables.

14:46.430 --> 15:02.690
As I said previously, the read address is set to the address of the right-hand side, the write address is set to the address of the left-hand side, the length is set to the size of the memory update, and the data is set to the pre-image that stores the data that they're going to overwrite,

15:02.690 --> 15:04.690
that is, the old value of x.

15:05.770 --> 15:13.170
If the right-hand side is a complex expression, then a log record is created for each variable in the right-hand side.

15:13.170 --> 15:26.210
To handle memory change performed by standard library functions, Dero proxies a few of them, such as string manipulation functions, format string functions, file network IO functions, and other functions that change memory state of the program.

15:27.490 --> 15:40.450
So the proxy function constructs a new memory update log record that summarizes the changes performed by the corresponding ellipsis function.

15:40.830 --> 15:47.310
And the memory update log is also used to store tags, which are special records that indicate change to memory to the state of the program.

15:47.310 --> 15:53.090
For example, when the function is invoked, function enter tag is inserted, and when the function returns, function exit tag is inserted.

15:53.090 --> 15:59.970
These tags are used at repair and identification time to build up signature and to repair program after an attack.

16:01.870 --> 16:03.730
So here are a few examples.

16:03.730 --> 16:09.830
At compile time, let's say there is a statement x equals y plus z.

16:10.690 --> 16:15.230
So the compiler adds two logging codes.

16:15.310 --> 16:23.130
The first code logs the effect of variable y, sorry, of variable z.

16:23.170 --> 16:25.870
The other of the variable y.

16:26.150 --> 16:28.390
And finally, there is this original statement.

16:28.510 --> 16:37.470
At run time, these two logging codes produce these two log records with the read and write addresses set as I described previously.

16:38.250 --> 16:42.590
Suppose there is the string CPY code in the source code of the program.

16:43.210 --> 16:46.950
The debug compiler replaces this code with a proxy function.

16:47.530 --> 16:59.710
And at run time, this proxy function inserts a log record with the read address of b, because that's where the data is coming from, with the write address of a, because that's where the write data enter.

16:59.750 --> 17:09.250
With the length, strlen of b plus one, because they're going to write strlen of b bytes plus non-terminating character.

17:09.430 --> 17:19.010
And with the preimage is a, which is the old value of a, Now let's talk about attack detection.

17:19.270 --> 17:20.810
Jira uses a RAD-like approach.

17:20.810 --> 17:29.810
That is, it saves the original return address when the function is invoked and compares the saved value with the value that is currently on stack at function epilogue.

17:29.810 --> 17:32.830
If these two values are different, then an attack is detected.

17:33.490 --> 17:40.770
Jira can protect other control-sensitive data structures, such as function pointers, GOT, signal-handling variables, and a similar function, but it's not implemented yet.

17:46.380 --> 17:48.600
Now let's talk about attack identification.

17:48.600 --> 17:52.060
So here are the desired properties of an ideal signature.

17:52.200 --> 17:58.460
A signature should be context-aware, which means that it should include all the attack packets that participate in a given attack.

17:58.880 --> 18:01.360
And this allows to reduce the rate of false positives.

18:01.600 --> 18:06.160
It should be also semantics-aware, that it ideally should incorporate the knowledge about the protocol.

18:06.160 --> 18:22.320
For example, if this is an HTTP attack, and the attack request is a GET request, then the signature should specify that this is GET, so that the intrusion detection system can filter out, keep all the requests of other types, of other protocols, and even if it's HTTP,

18:22.320 --> 18:25.740
but not GET, it should also discard those packets.

18:25.740 --> 18:31.940
It should check the signature only against packets that are HTTP GET kind of packets.

18:32.780 --> 18:35.340
And this also allows to reduce the rate of false positives.

18:35.640 --> 18:45.540
And the signature should provide a certain degree of flexibility within each packet, so that polymorphic warnings that change their body as they propagate can be matched using the same signature.

18:46.820 --> 18:55.380
The attack packets should be represented as regular expressions, and that's the desired flexibility that a signature should have.

18:56.760 --> 19:05.480
So, as I said, these three properties are the desired properties, and now let's see how JIRA satisfies all those properties.

19:05.480 --> 19:09.780
JIRA signatures are kind of severe, because they consist of multiple packets.

19:10.100 --> 19:15.420
They consist of all packets that an attack consists of.

19:15.420 --> 19:19.060
And each of those packets is represented as a regular expression.

19:19.780 --> 19:26.380
And there's a feature called length constraint that allows to limit the attack in part of the packet.

19:26.640 --> 19:36.720
That is, it allows to specify that a terminating character, such as null character, should occur between offset A and offset B.

19:36.820 --> 19:41.320
If the terminating sequence occurs within this offset, this is not an attack packet.

19:41.320 --> 19:47.460
If there is no such a terminating character in the packet, then this is an attack packet.

19:48.140 --> 20:00.080
So, in some sense, this is equivalent to semantics awareness, because it allows to narrow down the part of the packet that the intrusion detection system searches.

20:00.080 --> 20:07.320
So it doesn't search the specified sequence in the whole packet, but rather this length constraint allows to limit the...

20:07.320 --> 20:10.380
or narrow down the scope where we search for the...

20:12.720 --> 20:14.420
required terminating constraint.

20:14.420 --> 20:15.880
For example, if this is a...

20:15.880 --> 20:31.160
same example, if this is a GET attack, and there's an overly long URL, which is terminated by a null character, here it allows to specify that this null character should occur between the fourth and, let's say, twentieth-bit byte of the packet.

20:31.180 --> 20:37.620
Because the first three characters are GET characters, and then the remaining part of the packet is the URL.

20:37.720 --> 20:44.720
If the terminating character is found in the first twenty-four bytes of the packet, then this is not an attacking packet.

20:44.780 --> 20:51.700
If the null terminating character is not found in the first twenty-four bytes, then this is an attack packet, because the URL is too long.

20:52.740 --> 21:02.440
Memory update slog allows us to construct signatures that consist of multiple packets, to represent each packet as a regular expression, and to generate a length constraint.

21:02.440 --> 21:10.260
And we're going to give an example, and we will show how all this functionality is implemented.

21:11.920 --> 21:16.920
Two types of dependencies exist in the program, data and control dependency.

21:20.740 --> 21:26.040
Data dependency is created when one variable is assigned to another, for example, A equals B, same example.

21:26.040 --> 21:28.960
In this case, A depends on B.

21:29.180 --> 21:37.700
A control dependency is created whenever variable X and variable Y is used...

21:39.600 --> 21:46.160
I'm sorry, variable X is used in conditional expressions, such as if, and Y is in this conditional body.

21:46.220 --> 21:47.400
So here's an example.

21:47.980 --> 21:58.800
In this case, even though there is no direct assignment between X and Y, Y depends on X, because the value that Y will take depends on the value of X.

21:58.920 --> 22:01.340
This type of dependency is called control dependency.

22:01.340 --> 22:07.380
No direct assignment, but dependency is there, because value of Y depends on value of X.

22:08.700 --> 22:10.320
Why do we need control dependencies?

22:10.740 --> 22:11.780
So here's an example.

22:11.780 --> 22:14.240
FTP server attack involvement authentication.

22:15.000 --> 22:17.700
Here's an example of vulnerable FTP server.

22:18.180 --> 22:20.120
Here's the vulnerable buffer.

22:20.300 --> 22:23.900
The program has two state variables, isAuthentication, isUser.

22:25.540 --> 22:28.640
And here is the main loop of this server.

22:28.640 --> 22:31.140
First, it receives a packet.

22:31.140 --> 22:34.360
Then it compares the four bytes of the packet.

22:34.400 --> 22:36.300
If it's QuickCommand, the loop breaks.

22:36.400 --> 22:40.100
If it's UserCommand, then isUser variable is set to 1.

22:40.100 --> 22:44.160
If it's PasswordCommand, then isUser and isUser has been set.

22:44.160 --> 22:50.220
Then authentication has been completed, and isAuthenticated variable is set to 1.

22:50.480 --> 22:54.740
If authentication was not performed previously, then the program continues.

22:55.180 --> 23:01.660
The client requests are handled only in the case if the authentication has been completed previously.

23:01.740 --> 23:10.060
So if the user is authenticated, then the program checks the first three bytes of the packet.

23:10.060 --> 23:15.320
If it's a GET packet, then there's a GET request, and it returns the file that the user requested.

23:15.540 --> 23:19.040
But this request is only processed if the user has previously authenticated.

23:21.120 --> 23:23.960
So these are the three packets used in the attack.

23:26.820 --> 23:40.120
There is a file name that is too long and that overrides the buffer, that overrides this buffer, which is only 16 characters bytes long.

23:41.020 --> 23:43.720
Let's look at lock records generated at run time.

23:44.020 --> 23:49.660
First, there is a lock record here at receive for the receive function.

23:49.820 --> 23:55.800
For the proxy function, proxy is standard receive call, and it has this tag.

23:55.800 --> 23:57.100
Here's the tag.

23:57.100 --> 23:58.380
This is the write address.

23:58.660 --> 24:05.280
That's the destination, where the network data is written into 11 different things.

24:05.280 --> 24:10.140
And here's also the image of the data that varies from network.

24:10.340 --> 24:18.760
Then there is a proxy function for SDR and CMP, which also has the write address...

24:18.760 --> 24:22.740
I'm sorry, it's read address of the variable.

24:22.740 --> 24:24.560
4 is the length of the argument.

24:24.560 --> 24:27.400
This record specifies...

24:27.400 --> 24:34.560
indicates that we search buffer P and we look at first four bytes of this buffer.

24:34.720 --> 24:40.940
Then this record is created for conditional expression and it means that variable P participates in the if expression.

24:40.940 --> 24:45.560
So for every variable in the if expression, we save this variable into memory and this log.

24:46.060 --> 24:47.840
And this is also...

24:47.840 --> 24:53.920
this is the record for the statement that updates each user variable.

24:53.920 --> 25:01.320
So in this case, the read address is set now because we don't know where the data that is written into isUser comes from.

25:01.320 --> 25:03.340
And it's just a constant.

25:03.720 --> 25:05.240
So the write address is isUser.

25:05.240 --> 25:07.980
The length is 4 and isUser is preimage.

25:07.980 --> 25:12.380
Similarly, for the second packet, we have the receive record here.

25:12.380 --> 25:18.880
We have the string comparison record that checks the first four bytes of the packet.

25:18.880 --> 25:24.520
We have two conditional variables now because two variables are checked, P and isUser.

25:24.560 --> 25:31.380
And finally, this is the record that updates the isAuthentication variable.

25:32.660 --> 25:35.520
So finally, let's look at the third packet.

25:35.760 --> 25:42.040
So we also have a record when the packet is received.

25:42.060 --> 25:46.600
Then we also have the conditional record for variable isAuthenticated.

25:46.600 --> 25:52.820
Then there is the record for string comparison that checks the first three bytes of the packet.

25:52.820 --> 25:56.860
Then there is the conditional record for P.

25:56.860 --> 26:02.240
And finally, this is the record that was created by string.cpyProxy function.

26:02.420 --> 26:12.420
And it describes the fact that the data from buffer here, I'm sorry, the data from buffer P plus 4 was written into buffer.

26:13.180 --> 26:23.920
And the length of the update is the length of P minus 4 plus 1 because all bytes of P except the first four bytes were copied into buffer buff.

26:24.280 --> 26:27.040
And we also save the preimage of P.

26:32.060 --> 26:34.000
So this is the summary.

26:34.000 --> 26:39.200
These are all log records that are generated at runtime when this server attack is executed.

26:39.740 --> 26:46.380
And suppose that the return address is located after the buff variable.

26:46.380 --> 26:50.880
That is, the return address is saved at the offset buff plus 17.

26:50.920 --> 26:53.400
Buffer is a buffer of 16 bytes.

26:53.660 --> 26:56.320
So the return address is saved at the offset 17.

26:57.180 --> 27:02.400
Now let's see how we can detect the control hijacking attack using this memory on this log.

27:07.160 --> 27:12.520
So we start with log record, with the last log record that overrode this buffer.

27:14.100 --> 27:16.360
And here is its write address.

27:16.360 --> 27:19.460
So we look for the source of this data.

27:19.720 --> 27:22.480
That is, we try to find out where the data came from.

27:22.840 --> 27:26.660
And this log record allows us to conclude that this data came from P.

27:27.660 --> 27:30.540
Return address was saved at the offset buff plus 17.

27:30.540 --> 27:37.240
Therefore, the data was read from the offset P plus 4 plus 17, which is P plus 21.

27:37.340 --> 27:44.320
That is, the return address value came from memory address P plus 4 plus 17, which is P plus 21.

27:44.340 --> 27:46.600
So this is the new address that we look for.

27:46.600 --> 27:50.580
Now we search memory on this log for the address P plus 21.

27:50.900 --> 28:05.120
And if we traverse this log record, this memory on this log upward, we can find that there is this receive record that read data from network into buffer P and the length was 62.

28:05.120 --> 28:08.000
And we look for memory...

28:09.320 --> 28:12.260
memory location with the address P plus 21.

28:12.600 --> 28:21.060
And this is the record that has written data from network into that memory location.

28:21.140 --> 28:30.520
So we conclude that here is the read operation that read data from network and wrote it into address P plus 21.

28:31.040 --> 28:38.800
And because this is the operation that reads data from network, we conclude that this is the attack in packet.

28:39.040 --> 28:42.460
So this way we identify the first attack in packet.

28:42.720 --> 28:45.320
Is it the only packet in the attack in packet?

28:45.700 --> 28:51.400
Probably not, because the user is only processed if the user has authenticated.

28:51.400 --> 28:54.780
So we need to continue our search and try to find more attack in packets.

28:56.080 --> 28:56.820
Sure.

29:23.870 --> 29:25.350
Well, debugging is not automatic.

29:25.350 --> 29:26.570
Our tool is completely automatic.

29:26.570 --> 29:28.690
It doesn't require any user involvement at all.

29:28.830 --> 29:32.430
So the process that I described here is completely automatic.

29:32.430 --> 29:34.590
It's performed by our program, not by a user.

29:34.590 --> 29:35.690
Not manually.

29:35.830 --> 29:38.190
It's not log analysis performed by a human expert.

29:38.190 --> 29:40.230
It's log analysis performed automatically.

29:51.700 --> 29:55.800
Well, you are right.

30:06.410 --> 30:09.370
Well, that's the question of our performance evaluation.

30:09.370 --> 30:11.410
We will get to this question later.

30:11.890 --> 30:15.450
And if I don't give a clear answer, I'd like to talk to you offline.

30:17.010 --> 30:20.850
So as I said previously, we were able to identify the first attack in packet.

30:20.850 --> 30:22.830
And now we look for more attack in packets.

30:22.830 --> 30:25.390
And here's where we use conditional dependencies.

30:25.390 --> 30:28.850
Let's look at the first memory update statement.

30:28.850 --> 30:34.150
If we go upward, we can see that this statement depends on two conditions.

30:34.150 --> 30:38.170
That is, it's inside two outer if statements.

30:38.170 --> 30:44.850
The first if statement checks p variable, and the second checks is authenticate variable.

30:45.290 --> 30:51.750
Therefore, this memory update was only possible because of these two checks that involve these two variables.

30:52.130 --> 30:55.670
Variable p is, has been found before.

30:55.910 --> 30:58.570
So, this record should be discarded.

30:58.870 --> 31:03.470
Whereas, this variable is authenticated should be used for later search.

31:04.730 --> 31:07.270
So we continue with variable is authenticated.

31:07.270 --> 31:11.350
And we try to find out whether this variable depends on network packet or not.

31:11.530 --> 31:16.690
So, if we continue traversing the block upward, we can see this memory update block operation.

31:16.950 --> 31:22.130
And the read address of this operation is unknown because this variable was assigned to a constant.

31:22.230 --> 31:31.570
Therefore, we should again use condition dependencies to find out what our variable is authenticated depends on.

31:31.830 --> 31:36.350
And we can see two conditional lock records isUser and p here.

31:37.070 --> 31:42.810
Which means that variable is authenticated depends conditionally on isUser and p.

31:43.610 --> 31:46.330
So, we now look for p and isUser.

31:46.330 --> 31:48.070
We can find p here.

31:49.030 --> 31:54.830
Therefore, we conclude that variable isUser depends on network packet that contains password.

31:54.830 --> 32:04.570
And this turns out to be true because variable p is set only if the attacker sends password packet.

32:05.110 --> 32:10.510
That variable isUser also depends sorry, variable isAuthenticated also depends on isUser.

32:10.510 --> 32:14.170
So, we continue with this variable isUser and we can find it here.

32:14.690 --> 32:18.210
This is the memory update long operation that sets variable isUser.

32:18.210 --> 32:21.630
Its readers is also unknown because it's set to constant.

32:21.630 --> 32:29.170
Therefore, we should use control dependencies to find out whether variable isUser depends on any network packets.

32:30.370 --> 32:35.590
And once again, we can see this conditional string expression that uses variable P.

32:35.830 --> 32:41.390
Therefore, we now search for variable P and try to find out whether it depends on any network data.

32:41.690 --> 32:43.650
And it turns out to be true.

32:43.650 --> 32:47.790
Variable P contains the packet payload of the user command.

32:47.790 --> 32:51.390
So what we can see now, we have found three attack packets.

32:52.570 --> 32:56.450
And so the get packet, the pass packet, the user packet.

32:56.990 --> 32:59.730
The first packet was found using direct dependencies.

32:59.730 --> 33:03.090
The remaining two packets were found using control dependencies.

33:03.610 --> 33:11.370
So the control dependencies are really important to link the first attack packet to all the remaining attack packets.

33:12.110 --> 33:16.250
Because of this state variables that are used in network daemons.

33:27.160 --> 33:29.220
Well, this is just our assumption.

33:29.460 --> 33:35.540
Well, the real value of the return errors is returned by the attack detection component.

33:39.300 --> 33:44.820
Well, this attack detection component tells you which data structure was damaged.

33:45.060 --> 33:51.740
So it tells you the return address of the compromised data structure, which in our case is the return address.

33:51.900 --> 33:54.480
So this assumption I just made it up.

33:54.840 --> 33:57.300
But this address is always known at runtime.

34:00.580 --> 34:03.360
Let's now give a precise definition of control dependencies .

34:04.880 --> 34:12.120
We say that whenever a variable x can prevent control flow from reaching variable y , a control dependency is created between x and y .

34:27.040 --> 34:29.620
Let's look at the value of variable cond is.

34:29.620 --> 34:37.940
However, if you look at the right-hand side, then one of these branches here, this branch, has a return .

34:38.900 --> 34:42.100
And therefore , if condition is takes such

34:51.820 --> 34:59.780
a value from x to then value

35:04.040 --> 35:04.980
is returned y.

35:10.180 --> 35:10.860
And

35:16.980 --> 35:22.860
therefore, the value of condition is returned from x to y.

35:25.600 --> 35:28.940
So this the value

35:38.280 --> 35:40.360
of condition.

35:40.660 --> 35:51.080
therefore, the value of condition is returned from x to y.

35:54.240 --> 35:59.340
And therefore, the value of condition is returned from x to y.

36:03.840 --> 36:08.040
therefore, the of condition is returned from x y.

36:08.300 --> 36:15.440
And therefore, value of condition is returned from x to y.

36:25.120 --> 36:27.980
And therefore, the value of condition

36:31.080 --> 36:31.860
returned from y .

36:38.900 --> 36:47.360
And therefore, the

36:52.760 --> 36:54.080
value is returned from y.

36:54.080 --> 36:57.300
And therefore, the value of is returned from x

37:07.220 --> 37:09.620
And therefore, the

37:13.380 --> 37:25.420
value of condition is returned from x to y.

37:25.420 --> 37:32.540
And therefore, the value of condition is from x to y .

37:45.960 --> 37:53.200
And therefore, the value of condition is returned from x y.

37:53.340 --> 37:56.380
And therefore, the value condition is

38:05.040 --> 38:24.780
returned from And therefore, the is returned from x to y.

38:24.780 --> 38:25.640
And

38:39.540 --> 38:45.420
therefore, value of condition is returned from y .

38:45.420 --> 38:54.900
And therefore, the value of condition is returned from x to y.

38:55.340 --> 38:55.620
And

39:07.140 --> 39:13.960
therefore, the value of condition from y .

39:13.960 --> 39:30.260
And therefore, of condition is returned from x therefore, the value of condition is from x to

39:37.720 --> 39:40.580
And therefore, the value of

39:44.100 --> 39:45.980
condition is y.

39:46.580 --> 39:48.460
And therefore, condition is returned from

39:56.920 --> 40:00.320
x to y.

40:08.440 --> 40:10.800
therefore, the value of condition

40:16.860 --> 40:18.380
is returned from y .

40:18.740 --> 40:23.700
And therefore, the value of condition is returned from x to y.

40:23.700 --> 40:33.200
And therefore, the value of condition is returned x And therefore, the value

40:37.920 --> 40:39.060
of condition

40:44.120 --> 40:46.420
returned from x to y.

40:46.580 --> 40:54.220
And therefore, the of condition is returned from x

41:00.160 --> 41:01.720
to y.

41:01.840 --> 41:08.300
And therefore, value of is returned x to y .

41:09.620 --> 41:11.000
And therefore, the value of is returned

41:15.540 --> 41:16.620
from x to y.

41:20.380 --> 41:24.840
And therefore, the value of from

41:41.900 --> 41:45.300
And therefore,

41:48.680 --> 41:53.240
value of condition is returned from x to y.

42:00.940 --> 42:03.280
And therefore, the value of condition is

42:07.940 --> 42:14.960
returned from x to y .

42:14.960 --> 42:16.220
And therefore , value of

42:20.980 --> 42:23.540
condition is returned from x y.

42:25.700 --> 42:26.720
And therefore , the value

42:31.940 --> 42:35.140
condition is returned from x to y.

42:38.360 --> 42:46.040
And therefore, the value of condition is x

42:51.020 --> 42:55.120
to y.

42:55.120 --> 42:59.600
And therefore, the value of condition is returned from x to y.

42:59.600 --> 43:03.580
And therefore, the value returned from to y .

43:03.580 --> 43:04.120
And

43:08.400 --> 43:10.980
therefore, the

43:21.000 --> 43:22.300
value of condition is returned from x y .

43:22.360 --> 43:29.060
And therefore, the value of condition is returned from

43:36.840 --> 43:38.300
x to y.

43:38.300 --> 43:41.320
And therefore , the value condition is

43:44.960 --> 43:47.080
returned from x to y.

43:47.380 --> 43:54.060
And therefore, the value of is returned from x to y.

43:54.360 --> 43:55.040
And

44:21.740 --> 44:24.080
therefore, condition is y.

44:24.080 --> 44:25.700
And therefore, is returned from x y.

44:25.700 --> 44:30.880
And therefore, the value of condition is

44:35.960 --> 44:44.640
returned x to And therefore, of is returned from x to y.

44:58.040 --> 44:59.860
And therefore, condition

45:06.460 --> 45:08.110
x to

45:16.430 --> 45:17.310
y is

45:22.190 --> 45:23.530
returned to y.

45:24.810 --> 45:25.310
And

45:29.650 --> 45:35.410
therefore, value of condition is returned from x to y.

45:35.410 --> 45:45.310
And therefore, value of condition is returned from x

46:04.150 --> 46:06.850
to y.

46:06.850 --> 46:06.990
And value

46:10.230 --> 46:34.700
of condition returned from x y .

46:34.700 --> 46:37.320
And therefore, returned x to y.

46:37.320 --> 46:37.580
And

46:46.930 --> 46:48.830
therefore, condition is returned from x

47:11.320 --> 47:37.180
to y.

47:37.180 --> 47:37.840
And therefore, value

47:44.540 --> 47:47.580
of condition is returned from y .

47:47.580 --> 47:54.500
And therefore, condition is returned to y.

47:57.620 --> 48:01.340
And therefore, value condition is returned from

48:06.660 --> 48:08.900
x to

48:19.840 --> 48:21.600
y.

48:22.080 --> 48:29.600
And therefore, value is returned x to y.

48:29.600 --> 48:34.460
And therefore, is returned x to y.

48:34.640 --> 48:38.980
And therefore, condition is returned from x

48:55.460 --> 49:09.220
And therefore, value of condition is returned y.

49:09.220 --> 49:10.240
And y.

49:10.240 --> 49:11.120
And

49:44.210 --> 49:48.770
therefore, condition is returned x to y .

49:49.450 --> 49:53.670
And therefore, value returned This is the length of packet, this is the packet that represents the regular expression, this is the length constraint.

49:53.670 --> 49:57.110
This is pretty much the same as the signature that we constructed in our example.

49:57.610 --> 50:01.650
This is the bind signature, signature for DNS daemon.

50:01.910 --> 50:05.550
So one packet, this is the length, this is the length constraint.

50:06.610 --> 50:15.850
Remote cat daemon has a signature that consists of three packets because this cat daemon requires user authentication.

50:16.150 --> 50:27.190
So here we can see user packet, password packet, the length constraint and the, yes, and the last packet.

50:27.850 --> 50:31.730
All the signatures will generate automatically from a single attack instance.

50:33.350 --> 50:35.330
Now let's talk about the recovery.

50:35.330 --> 50:36.550
Is it really useful?

50:36.550 --> 50:38.230
The overhead is pretty high at 70%.

50:38.230 --> 50:41.330
Maybe we can do well without recovery.

50:41.830 --> 50:48.770
And we think that recovery is really useful because many programs are single-thread and they are, like, event-driven.

50:48.770 --> 50:52.790
And if you just terminate the program, then you disconnect all the clients.

50:52.850 --> 50:55.910
So you have only one bad client, you have, let's say, a dozen of good clients.

50:55.910 --> 51:00.830
You disconnect one bad and disconnect a dozen of good, which is very bad for good clients.

51:00.990 --> 51:10.050
And the same attack can be reviewed in the future, and therefore the attacker can implement the denial of service attack if you simply terminate the program instead of recovering.

51:10.050 --> 51:16.030
If you recover it, then repair the effect of the bad guy, but you allow good guys to continue their execution.

51:17.070 --> 51:20.130
And the same trade-off exists in the case of source code analysis tools.

51:20.890 --> 51:34.690
Whenever you have a bug, if you use static code analysis tool, then you first need to find out this bug, and these tools are prone to false positives, so we need to determine whether this is a false positive or a real bug.

51:34.810 --> 51:37.850
If it turns out to be a real bug, then you have to come up with a fix.

51:37.850 --> 51:41.610
You have to upload this patch to the developer's side.

51:41.610 --> 51:43.430
The developer has to verify this patch.

51:43.430 --> 51:47.330
So it's also a lengthy process, and it involves a lot of human experience.

51:48.270 --> 51:49.550
So there is the same trade-off.

51:49.550 --> 51:56.230
You either invest the same amount of runtime as we do, or you invest the same amount of developers' time, which is probably more expensive.

51:57.790 --> 51:59.470
Now we arrive at the conclusion.

52:00.150 --> 52:06.950
DIRA is the first system that solves the problems of attack detection and identification in a unified way using memory on this log.

52:07.070 --> 52:21.630
It can produce accurate multi-packet signatures from a single attack instance, which we believe is a big achievement, because all the previous systems either reported less attack packets, or they required a large pool of network data to generate an accurate multi-packet signature.

52:21.950 --> 52:27.810
Dynamic slicing of the memory on this log is the underlying technique behind our tool.

52:27.810 --> 52:35.370
And this is a well-known technique from programming languages, but I think we just found some cool applications for this programming languages technique.

52:35.870 --> 52:41.890
And we plan to apply the same technique in the future to generate patches for buffer overflow attacks.

52:42.570 --> 52:43.790
This is what we're working on.

52:43.790 --> 52:45.870
We plan to work in the next few months.

52:46.590 --> 52:48.150
Our tool is available for download.

52:48.150 --> 52:52.130
Please visit our website and download it and play with it.

52:52.130 --> 52:59.810
So if you find bugs or if you have any experiences to share, please mail me and I'll be happy to answer you.

52:59.810 --> 53:00.890
Thank you.

53:08.450 --> 53:11.230
I have one book, one question.

53:12.950 --> 53:13.850
Yes.

53:40.770 --> 53:42.110
I'm sorry.

53:51.160 --> 53:55.540
Well, our program generates a signature whenever an attack happens.

53:55.540 --> 53:58.120
It doesn't use history.

53:58.120 --> 54:00.820
It doesn't look for previous packets.

54:00.820 --> 54:02.280
It doesn't analyze them.

54:02.280 --> 54:04.740
So whenever you perform an attack, a signature will be generated.

54:04.740 --> 54:08.460
So the question is whether the signature will be different from previously generated signatures or not.

54:08.660 --> 54:16.220
And I think the answer is yes, because if the length is different, then the regular expressions will also be different.

54:43.590 --> 54:57.850
Yes, this is the kind of denial-of-service attack that we think is like more lightweight than complete program restart, because a complete program restart disconnects all clients, all benign clients, and recovery doesn't disconnect anybody except attacker.

54:57.950 --> 55:08.770
And therefore, the benign clients will be able to perform their requests slower than when the program runs normally, but at least they won't be disconnected, which we believe is pretty good.

55:16.770 --> 55:18.230
Remember, AtlasLocker is a circular buffer.

55:18.230 --> 55:26.050
Yes, the log records are used constantly and previous records are freed up when the record is about to be used.

55:28.870 --> 55:29.750
Yes.

55:31.130 --> 55:32.850
Okay, thank you very much.

