Flash and JavaScript are required for this feature.
Download the video from iTunes U or the Internet Archive.
Description: In this lecture, Professor Zeldovich discusses network security, and how TCP/IP has evolved.
Instructor: Nickolai Zeldovich
Lecture 12: Network Security
The following content is provided under a Creative Commons license. Your support will help MIT OpenCourseWare continue to offer high quality educational resources for free. To make a donation or to view additional materials from hundreds of MIT courses, visit MIT OpenCourseWare at ocw.mit.edu.
PROFESSOR: All right, guys, let's get started. So today, we're going to talk about network security. And in particular, we're going to talk about this paper on TCP/IP security by this guy Steve Bellovin, who used to be at AT&T and now is at Columbia. One interesting thing about this paper is it's actually a relatively old paper. It's more than 10 years old. And in fact, it's commentary on a paper that was 10 years before that. And many of you guys actually ask, why are we reading this if many of these problems have been solved in today's TCP protocol stacks?
So one interesting point-- so it's true that some of these problems that Steve describes in this paper have been solved since then. Some of them are still actually problems today. We'll sort of look at that and see what's going on. But you might actually wonder, why didn't people solve all these problems in the first place when they were designing TCP? What were they thinking?
And it's actually not clear. So what do you guys think? Why wasn't TCP designed to be secure with all these considerations up front? Yeah, any guesses? All right, anyone else? Yeah.
AUDIENCE: The internet was a much more trusting place back then.
PROFESSOR: Yeah, this was almost literally a quote from this guy's paper. Yeah, at the time-- the whole internet set of protocols was designed I guess about 40 years ago now. The requirements were totally different. It was to connect a bunch of relatively trusting sites that all knew each other by name.
And I think this is often the case in any system that becomes successful. The requirements change. So it used to be that this was a protocol for a small number of sites. Now it's the entire world. And you don't know all the people connected to the internet by name anymore. You can't call them up on the phone if they do something bad, et cetera.
So I think this is a story for many of the protocols we look at. And many of you guys have questions, like, what the hell were these guys thinking? This is so broken. But in fact, they were designing a totally different system. It got adopted.
Same for the web, like we were looking at in the last couple of weeks. It was designed for a very different goal. And it expanded. And you sort of have these growing pains you have to figure out how to make the protocol adapt to new requirements.
And another thing that somewhat suddenly happened is I think people also in the process gained a much greater appreciation for the kinds of problems you have to worry about in security. And it used to be the case that you didn't really understand all the things that you should worry about an attacker doing to your system.
And I think it's partly for this reason that it's sort of interesting to look at what happened to TCP security, what went wrong, how could we fix it, et cetera, to both figure out what kinds of problems you might want to avoid when designing your own protocols, and also what's the right mindset for thinking about these kinds of attacks. How do you figure out what an attacker might be able to do in your own protocol when you're designing it so you can avoid similar pitfalls?
All right, so with that preamble aside, let's actually start talking about what the paper is about. So how should we think about security in a network? So I guess we could try to start from first principles and try to figure out, what is our threat model? So what do we think the attacker is going to be able to do in our network?
Well, relatively straightforwardly, there's presumably being able to intercept packets, and probably being able to modify them. So if you send a packet over the network, it might be prudent to assume that some bad guy out there is going to see your packet and might be able to change it before it reaches the destination, might be able to drop it, and in fact might be able to inject packets of their own that you never sent with arbitrary contents.
And probably-- so this you can sort of come up with fairly straightforwardly by just thinking, well, if you don't trust the network, some bad guy is going to send arbitrary packets, see yours, modify them, et cetera. Somewhat more worryingly, as this paper talks about, the bad guy can also participate in your protocols. They have their own machine, right?
So the attacker has their own computer that they have full control over. So even if all the computers that you trust are reasonably maintained, they all behave correctly, the bad guy has his own computer that he can make it do whatever he wants. And in fact, he can participate in a protocol or distribute a system.
So if you have a routing protocol, which involves many people talking to each other, at some scale, it's probably going to be impractical to keep the bad guys out. If you're running a routing protocol with 10 participants, then maybe you can just call all them up and say, well, yeah, yeah, I know all you guys.
But at the scale of the internet today, it's unfeasible to have sort of direct knowledge of what everyone else or who everyone else in this protocol is. So probably some bad guy is going to be participating in your protocols or distributed systems. And it's important to design distributed systems that can nonetheless do something reasonable with that.
All right, so what are the implications of all these things? I guess we'll go down the list. So intercepting is-- it's on the whole easy to understand. Well, you shouldn't send any important data over the network if you expect a bad guy to intercept them, or at least not in clear text. Maybe you should encrypt your data.
So that seems relatively straightforward to sort of figure out. Although still you should sort of keep it in mind, of course, when designing protocols. Now, injecting packets turns out to lead to a much wider range of interesting problems that this paper talks about. And in particular, attackers can inject packets that can pretend to be from any other sender. Because the way this works in IP is that the IP packet itself has a header that contains the source of the packet and the destination.
And it's up to whoever creates the packet to fill in the right values for the source and destination. And no one checks that the source is necessarily the correct. There's some filtering going on these days. But it's sort of fairly spotty, and it's hard to rely on. So to a first approximation, an attacker could fill in any IP address as the source, and it will get to the destination correctly. And it's interesting to try to figure out what could an attacker do with such a capability of sending arbitrary packets.
Now, in the several weeks up to this, like in buffer overflows and web security, we looked at, to a large extent, implementation bugs, like, how could you exploit a buffer overflow? And interestingly, the author of this paper is actually not at all interested in implementation bugs. He's really interested in protocol errors or protocol mistakes.
So what's the big deal? Why is he down on implementation bugs, even though we spent several weeks looking at them? Why does it matter? Yeah.
AUDIENCE: Because we have to keep those bugs [INAUDIBLE].
PROFESSOR: Yeah, so this is the really big bummer about a bug in your protocol design. Because it's hard to change. So if you have an implementation bug, well, you had a memcpy or a print-out out of some sort that didn't check the range. OK, well, you had a range check, and it still works, and now it's also secure. So that's great.
But if you have some bug in the protocol specification, in how the protocol has to work, then fixing a bug is going to require fixing a protocol, which means potentially affecting all the systems that are out there speaking this protocol. So if we find some problem in TCP, it's potentially quite devastating. Because every machine that uses TCP is going to have to change. Because it's going to be hard to make it potentially backwards compatible.
We'll see exactly what these bugs are. But this is the real reason he's so excited about looking at protocol bugs. Because they're fairly fundamental to the TCP protocol that everyone agrees to speak.
So let's look at one of these guys. So the first example he points out has to do with how TCP sequence numbers work. So just to re-explain-- yeah, question.
AUDIENCE: I'm just curious. This is a tiny bit off topic. But let's say you do find a bug in TCP. How do you make the change to it? How do you tell all the computers in the world to change that?
PROFESSOR: Yeah, I think it's a huge problem. What if you find a bug in TCP? Well, it's unclear what to do. And I think the authors here struggle a lot with that. And in many ways, if you could redesign TCP, many of these bugs are relatively easy to fix if you knew what to look for ahead of time.
But because TCP is sort of relatively hard to fix or change, what ends up happening is that people or designers try to look for backwards compatible tweaks that either allow old implementations to coexist with the new implementation or to add some optional field that if it's there, then the communication is more secure in some way.
But it is a big problem. If it's some security issue that's deeply ingrained in TCP, then it's going to be a pretty humongous issue for everyone to just pack up and move onto a TCP version whatever, n plus 1. And you can look at IPv6 as one example of this not happening. We've known this problem was going to come up for like 15 years or 20 years.
IPv6 has been around for well over 10 years now. And it's just hard to convince people to move away from IPv4. It's good enough. It sort of works. It's a lot of overhead to move over. And no one else is speaking IPv6, so why should I start speaking this bizarre protocol that no one else is going to speak to me in?
So it's sort of moving along. But I think it takes a long time. And there's going to be really some motivation to migrate. And backwards compatibility helps a lot. Not good enough for, I guess, IPv6-- IPv6 has lots of backwards compatibility plans in it. You can talk to an IPv4 host from IPv6. So they try to engineer all this support. But still, it's hard to convince people to upgrade.
All right, but yeah, looking back at the TCP sequence numbers, we're going to look at actually two problems that have to do with how the TCP handshake works. So let's just spend a little bit of time working out what are the details of how a TCP connection gets initially established.
So there's actually three packets that have to get sent in order for a new TCP connection to be established. So our client generates a packet to connect to a server. And it says, well, here's my IP address, C, client. I'm sending this to the server.
And there's various fields. But the ones that are interesting for the purpose of this discussion is going to be a sequence number. So there's going to be a syn flag saying, I want to synchronize state and establish a new connection. And you include a client sequence number in the initial syn packet.
Then when the server receives this, the server is going to look and say, well, a client wants to connect to me, so I'll send a packet back to whatever this address is, whoever said they're trying to connect to me. So it'll send a packet from the server to the client and include its own synchronization number, SN server. And it'll acknowledge the client's number.
And finally, the client replies back, acknowledging the server synchronization number-- acknowledge SNS. And now the client can actually start sending data. So in order to send data, the client has to include some data in the packet, and also put in the sequence number of the client to indicate that this is actually sort of legitimate client data at the start of the connection. It's not some data from later on, for example, that just happens to arrive now because the server missed some initial parts of the data.
So generally, all these sequence numbers were meant for ensuring in order delivery of packets. So if the client sends two packets, the one that has the initial sequence number, that's the first chunk of data. And the one with the next sequence number is the next chunk of data.
But it turns out to also be useful for providing some security properties. Here's an example of these requirements changing. So initially, no one was thinking TCP provides any security properties. But then applications started using TCP and sort of relying on these TCP connections not being able to be broken by some arbitrary attacker, or an attacker not being able to inject data into your existing TCP connection. And all of a sudden, this mechanism that was initially meant for just packet ordering now gets used to guarantee some semblance of security for these connections.
So in this case, I guess the problem stems from what could a server assume about this TCP connection. So typically, the server assumes-- implicitly, you might imagine-- that this connection is established with the right client at this IP address C. It seems like a natural thing to assume.
Is there any basis for making this assumption? If a server gets this message saying, here's some data on this connection from a client to a server, and it has sequence number C, why might the server conclude that this was actually the real client sending this?
AUDIENCE: Because the sequence number is hard to guess.
PROFESSOR: Right, so that's sort of the implicit thing going on, that it has to have the right sequence number C here. And in order for this connection to get established, the client must have acknowledged the server sequence number S here. And the server sequence number S was only sent by the server to the intended client IP address. Yeah.
AUDIENCE: How many bits are available for the sequence number?
PROFESSOR: So sequence numbers in TCP are 32 bits long. That's not entirely easy to guess. If it was really a random 32 bit number, it would be hard to just guess. And you'd probably waste a lot of bandwidth trying to guess this. Yeah, question.
AUDIENCE: The data frequency number is higher than the initial sequence number?
PROFESSOR: Yeah, so basically, these things get incremented. So every time you send a syn, that counts as one byte against your sequence number. So this is SNC. I think actually what happens is this is SNC plus 1. And then it goes on from there.
So if you send 5 bytes, then the next one is SNC initial plus 6. So this just counts the bytes that you're sending. SYNs count as 1 byte each. Make sense? Other questions about this?
All right, so typically, or at least the way the TCP specification recommended that people choose these sequence numbers, was to increment them at some roughly fixed rate. So the initial RFCs suggested that you increment these things at something like 250,000 units, plus 250,000, per second.
And the reason that it wasn't entirely random is that these sequence numbers are actually used to prevent out of order packets, or packets from previous connections, from interfering with new connections. So if every time you established a new connection you chose a completely random sequence number, then there's some chance if you establish lots of connections over and over that some packet from a previous connection is going to have a similar enough sequence number to your new connection and is going to be accepted as a valid piece of data on that new connection.
So this is something that the TCP designers worried a lot about-- these out of order packets or delayed packets. So as a result, they really wanted these sequence numbers to progress in a roughly monotonic matter over time, even across connections. If I opened one connection, it might have the same source and destination, port numbers, IP addresses, et cetera. But because I established this connection now instead of earlier, packets from earlier hopefully aren't going to match up with the sequence numbers I have for my new connection. So this was a mechanism to prevent confusion across repeated connection establishments. Yeah.
AUDIENCE: So if you don't know exactly how much your other grid that you're talking to is going to improve the sequencing pack, how do you know that the packet you're getting is the next packet if there wasn't [INAUDIBLE] immediate packet that you--
PROFESSOR: So typically you'll remember the last packet that you received. And if the next sequence number is exactly that, then this is the next packet in sequence. So for example, here, the server knows that I've seen exactly SNC plus 1 worth of data. If the next packet has sequence number SNC plus 1, that's the next one.
AUDIENCE: So you're saying that when you establish a sequence number, then even after that you're committing it--
PROFESSOR: Well, absolutely, yeah, yeah. So these sequence numbers, initially when you establish it, they get picked according to some plan. We'll talk about that plan. You can sort of think they might be random. But over time, they have to have some flow for initial sequence numbers for connection.
But within a connection, once they're established, that's it. They're fixed. And they just tick along as the data gets sent on the connection, exactly. Make sense? All right, so there were some plans suggested for how to manage these sequence numbers. And it was actually a reasonable plan for avoiding duplicate packets in the network causing trouble.
But the problem, of course, showed up that attackers were able to sort of guess these sequence numbers. Because there wasn't a lot of randomness being chosen. So the way that the host machine would choose these sequence numbers is they have just a running counter in memory. Every second they bump it by 250,000. And every time a new connection comes in, they also bump it by some constant like 64k or 128k. I forget the exact number. So this was relatively easy to guess, as you can tell. You send them their connection request, and you see what sequence number comes back. And then you know the next one is going to be 64k higher than that. So there wasn't a huge amount of randomness in this protocol.
So we can just sketch out what this looks like. So if I'm an attacker that wants to connect to a server but pretend to be from a particular IP address, then what I might do is send a request to the server, very much like the first step there, include some initial sequence number that I choose. At this point, any sequence number is just as good, because the server shouldn't have any assumptions about what the client's sequence number is.
Now, what does the server do? The server gets the same packet as before. So it performs the same way as before. It sends a packet back to the client with some server sequence number and acknowledges SNC. And now the attacker, if the attacker wants to establish a connection, needs to somehow synthesize a packet that looks exactly like the third packet over there. So it needs to send a packet from the client to the server.
That's easy enough. You just fill in these values in the header. But you have to acknowledge this server sequence number SNS. And this is where sort of the problems start. If the SNS value is relatively easy to guess, then the attacker is good to go. And now the server thinks they have an established connection with a client coming from this IP address.
And now an attacker could inject data into this connection just as before. They just synthesize a packet that looks like this, has the data, and it has the client sequence number that in fact the adversary chose. Maybe it's plus 1 here. But it all hinges on being able to guess this particular server supplied sequence number. All right, does this make sense? Yeah.
AUDIENCE: What's the reason that the server sequence number isn't completely random?
PROFESSOR: So there's two reasons. One, as I was describing earlier, the server wants to make sure that packets from different connections over time don't get confused for one another. So if you establish a connection from one source port to another destination port, and then you close the connection and establish another one of the same source and destination port, you want to make sure the packets from one connection don't appear to be valid in another connection.
AUDIENCE: So the server sequence number is incremented for every one of their packets?
PROFESSOR: Well, so the sequence numbers within a connection, as I was describing, get bumped with all the data in a connection. But there's also the question of, how do you choose the initial sequence number here?
And that gets bumped every time a new connection is established. So the hope is that by the time it wraps around 2 to the 32 and comes back, there's been enough time so that old packets in the network have actually been dropped and will not appear as duplicates anymore. So that's the reason why you don't just choose random points, or they didn't initially choose random points. Yeah.
AUDIENCE: So this is a problem between connections, for a connection between the same guide, the same client, the same server, the same source port, the same destination. And we're worried about old packets--
PROFESSOR: So this is what the original, yeah, TCP designers were worried about, which is why they prescribed this way of picking these initial sequence numbers.
AUDIENCE: If you have different new connections, you could differentiate.
PROFESSOR: That's right, yeah.
AUDIENCE: So then I don't see why the incrementing stuff and not just take randomly.
PROFESSOR: So I think the reason they don't pick randomly is that if you did pick randomly, and you established, I don't know, 1,000 connections within a short amount of time from the same source to the same destination, then, well, every one of them is some random value of module 2 to the 32. And now there's a nontrivial chance that some packet from one connection will be delayed in the network, and eventually show up again, and will get confused for a packet from another connection. This is just sort of nothing to do with security. This is just their design consideration initially for reliable delivery.
AUDIENCE: [INAUDIBLE] some other client to the server, right?
PROFESSOR: Sorry?
AUDIENCE: This is [INAUDIBLE] some other client?
PROFESSOR: That's right, yeah. So we haven't actually said why this is interesting at all for the attacker to do. Why bother? You could just go from his old IP address, right?
AUDIENCE: So what happens for the server [INAUDIBLE]?
PROFESSOR: Yes, this is actually an interesting question. What happens here? So this packet doesn't just get dropped. It actually goes to this computer. And what happens?
AUDIENCE: [INAUDIBLE], they just mentioned you try and do it like they would try and do it when the other computer was updating or rebooting or off, or something.
PROFESSOR: Right, certainly they felt, oh, that computer is offline. The packet will just get dropped, and you don't have to worry about it too much. If a computer is actually listening on that IP address, then in the TCP protocol, you're supposed to send a reset packet resetting the connection. Because this is not a connection that computer C knows about.
And in TCP, this is presumed to be because, oh, this is some old packet that I requested long ago, but I've since forgotten about it. So the machine C here might send a packet to the server saying, I want a reset. I actually forget exactly which sequence number goes in there. But the client C here knows all the sequence numbers and send any sequence number as necessary and reset this connection.
So if this computer C is going to do this, then it might interfere with your plan to establish a connection. Because when S gets this packet, it says, oh, sure, if you don't want it, I'll reset your connection.
There's some implementation-ish bugs that you might exploit, or at least the author talks about, and an potentially exploiting, that would prevent client C from responding. So for example, if you flood C with lots of packets, it's an easy way to get him to drop this one. It turns out there are other more interesting bugs that don't require flooding C with lots of packets that still get C to drop this packet, or at least it used to on some implementations on TCP stacks. Yeah.
AUDIENCE: Presumably, most firewalls would also [INAUDIBLE].
PROFESSOR: This one?
AUDIENCE: No, the SYN.
PROFESSOR: This one.
AUDIENCE: That came into a client, and a client didn't originally send a SYN to that server. And the firewall is going to drop it.
PROFESSOR: It depends, yeah. So certainly if you have a very sophisticated stateful firewall that keeps track of all existing connections, or for example if you have a NAT, then this might happen. On the other hand, a NAT might actually send the RST on behalf of the client.
So it's not clear. I think this is not as common. So for example, on a Comcast network, I certainly don't have anyone intercepting these packets and maintaining state for me and sending RSTs on my behalf or anything like that. Yeah.
AUDIENCE: So why can't the server have independent sequence numbers for each possible source?
PROFESSOR: Right, so this is in fact what TCP stacks do today. This is one example of how you fix this problem in a backwards compatible manner. So we'll get to exactly the formulation of how you arrange this. But yeah, it turns out that if you look at this carefully, as you're doing, you don't need to have this initial sequence number be global. You just scope it to every source/destination pair. And then you have all the duplicate avoidance properties we had before, and you have some security as well.
So just to sort of write this out on the board of how the attacker is getting this initial sequence number, the attacker would probably just send a connection from its own IP address to the server saying, I want to establish a new connection, and the server would send a response back to the attacker containing its own sequence number S. And if the SNS for this connection and the SNS for this connection are related, then this is a problem.
But you're saying, let's make them not related. Because this is from a different address. Then this is not a problem anymore. You can't guess what this SNS is going to be based on this SNS for a different connection. Yeah.
AUDIENCE: So you still have a collision problem, because you could engage the 32 bits by the addresses of your peers. So you have a lot of ports for each one of these. So you still have conflicting sequence numbers for all of these connections that you're getting, right?
PROFESSOR: So these sequence numbers are specific, as it turns out, to an IP address and a port number source/destination duple. So if it's different ports, then they don't interfere with each other at all.
AUDIENCE: Oh, because you're using the port--
PROFESSOR: That's right, yeah, you also use the port in this as well.
AUDIENCE: Because I thought those ports--
PROFESSOR: Yeah, so the ports are sort of below the sequence numbers in some way of thinking about it. Question?
AUDIENCE: If the sequence numbers are global, then doesn't the attacker [INAUDIBLE]?
PROFESSOR: Yeah, good point. So in fact, if the server increments the sequence number by, I don't know, 64k I think it is, or it was, for every connection, then, well, you connect. And then maybe five other people connect. And then you have to do this attack.
So to some extent, you're right, this is a little troublesome. On the other hand, you could probably arrange it for your packet here to be delivered just before this packet. So if you send these guys back to back, then there's a good chance they'll arrive at the server back to back.
The server will get this one, respond with this sequence number. It'll get the next one, this one, respond with the sequence number right afterwards. And then you know exactly what to put in this third packet in your sequence.
So I think this is not a foolproof method of connecting to a server. There's some guessing involved. But if you carefully arrange your packets right, then it's quite easy to make the right guess. Or maybe you try several times, and you'll get lucky. Yeah.
AUDIENCE: So even if it's totally random, and you have to guess it, there are only like 4 billion possibilities. It's not a huge number, right? I feel like in the course of a year, you should be able to probably get through.
PROFESSOR: Right, yeah, so you're absolutely right. You shouldn't really be relying on TCP to provide security very strongly. Because you're right, it's only 4 billion guesses. And you can probably send that many packets certainly within a day if you have a fast enough connection.
So it's sort of an interesting argument we're having here in the sense that at some level, TCP is hopefully insecure. Because it's only 32 bits. There's no way we could make it secure. But I think many applications rely on it enough that not providing any security at all is so much of a nuisance that it really becomes a problem.
But you're absolutely right. In practice, you do want to do some sort of encryption on top of this that will provide stronger guarantees that no one tampered with your data, but where the keys are more than 32 bits long. It still turns out to be useful to prevent people from tampering with TCP connections in most cases.
All right, other questions? All right, so let's see what actually goes wrong. Why is it a bad thing if people are able to spoof TCP connections from arbitrary addresses? So one reason why this is bad is if there is any kind of IP-based authorization. So if some server decides whether an operation is going to be allowed or not based on the IP address it comes from, then this is potentially going to be a problem for an attacker who spoofed connections from an arbitrary source address.
So one example where this was a problem-- and it largely isn't anymore-- is this family of r commands, things like rlogin. So it used to be the case that you could run something like rlogin into a machine, let's say athena.dialup.mit.edu. And if your connection was coming from a host at MIT, then this rlogin command would succeed if you say, oh yeah, I'm user Alice on this machine. Let me log in as user Alice onto this other machine. And it'll just trust that all the machines at mit.edu are trustworthy to make these statements.
I should say I think dial-up never actually had this problem. It was using Cerberus from the very beginning. But other systems certainly did have such problems. And this is an example of using the IP address where the connection is coming from some sort of authentication mechanism for whether the caller or the client is trustworthy or not. So this certainly used to be a problem, isn't a problem anymore. So relying on IP seems like such a clearly bad plan.
Yet, this actually is still the case. So rlogin is gone. It was recently replaced by SSH now, which is good. On the other hand, there are still many other examples of protocols that rely on IP-based authentication.
One of them is SMTP. So when you send email, you use SMTP to talk to some mail server to send a message. And to prevent spam, many SMTP servers will only accept incoming messages from a particular source IP address. So for example, Comcast's mail server will only accept mail from Comcast IP addresses. Same for MIT mail servers-- will only accept mail from MIT IP addresses. Or there was at least one server that ISNT runs that has this property.
So this is the case where it's still using IP-based authentication. Here it's not so bad. Worst case, you'll send some piece of spam through the mail server. So that's probably why they're still using it, whereas things that allow you to log into an arbitrary account stopped using IP-based authentication. So does this make sense, why this is a bad plan?
And just to double check, suppose that some server was using rlogin. What would you do to attack it? What bad thing would happen? Suggestions? Yeah.
AUDIENCE: Just getting into your computer, and then make a user that you want to log into, and then you get into the network.
PROFESSOR: Yeah, so basically you get your computer. You synthesize this data to look like a legitimate set of rlogin commands that say, log in as this user and run this command in my Unix shell there. You sort of synthesize this data and you mount this whole attack and send this data as if a legitimate user was interacting with an rlogin client, and then you're good to go.
OK, so this is one reason why you probably don't want your TCP sequence numbers to be so guessable. Another problem is these reset attacks. So much like we were able to send a SYN packet, if you know someone's sequence number, you could also send a reset packet. We sort of briefly talked about it here as the legitimate client potentially sending a reset to reset the fake connection that the attacker is establishing.
But in a similar vain, the adversary could try to send reset packets for an existing connection if there's some way that the adversary knows what your sequence number is on that connection. So this is actually not clear if this is such a big problem or or.
At some level, maybe you should be assuming that all your TCP connections could be broken at any time anyway. It's not like the network is reliable. So maybe you should be expecting your connections to drop.
But one place where this turned out to be particularly not a good assumption to make is in the case of routers talking to one another. So if you have multiple routers that speak some routing protocol, then they're connected, of course, by some physical links. But over some physical links, they actually speak some network protocol. And that network protocol runs over TCP. So there's actually some TCP session running over each of these physical links that the routers use to exchange routing information.
So this is certainly the case for this protocol called BGP we'll talk about a bit more in a second. And BGP uses the fact that the TCP connection is alive to also infer that the link is alive. So if the TCP connection breaks, then the routers assume the link broke. And they recompute all their routing tables.
So if an adversary wants to mount some sort of a denial of service attack here, they could try to guess the sequence numbers of these routers and reset these sessions. So if the TCP session between two routers goes down, both routers are like, oh, this link is dead. We have to recompute all the routing tables, and the routes change. And then you might shoot down another link, and so on.
So this is a bit of a worrisome attack, not because it violates someone's secrecy, et cetera, or at least not directly, but more because it really causes a lot of availability problems for other users in the system. Yeah.
AUDIENCE: So if you're an attacker, and you wanted to target one particular user, could you just keep sending connection requests to a server on behalf of his IP and make him keep dropping his connections to the servers and so you just [INAUDIBLE]?
PROFESSOR: Well, so it requires you guessing. So you're saying, suppose I'm using Gmail, and you want to stop me from learning something in Gmail, so just send packets to my machine pretending to be from Gmail. Well, you have to guess the right source and destination port numbers.
The destination port number is probably 443, because I'm using HTTPS. But the source port number is going to be some random 16-bit thing. And it's also going to be the case that probably the sequence numbers are going to be different. So unless you guess a sequence number that's within my TCP window, which is in order of probably tens of kilobytes, you're also going to be not successful in that regard.
So you have to guess a fair amount of stuff. There's no sort of oracle access. You can't just query the server and say, well, what is that guy's sequence number? So that's the reason why that doesn't work out as well.
So again, many of these issues were fixed, including this RST-based thing, especially for BGP routers. There was actually two sort of amusing fixes. One really shows you how you can carefully exploit existing things or take advantage of them to fix particular problems. Here, the insight is that these routers only want to talk to each other, not to someone else over the network. And as a result, if the packet is coming not from the immediate router next across the link, but from someone else, I want to drop this packet all together.
And what the designers of these writing protocols realized is that there's this wonderful field in a packet called time to live. It's an 8-bit field that gets decremented by every router to make sure that packets don't go into an infinite loop. So the highest this TTL value could ever be is 255. And then it'll get decremented from there.
So what these writing protocols do-- it's sort of a clever hack-- is they reject any packet with a TTL value that's not 255. Because if a packet has a value of 255, it must have come from the router just on the other side of this link. And if the an adversary tries to inject any packet to tamper with this existing BGP connection, it'll have a TTL value less than 255, because it'll be decremented by some other routers along the path, including this one.
And then it'll just get rejected by the recipient. So this is one example of a clever combination of techniques that's backwards compatible and solves this very specific problem. Yeah.
AUDIENCE: Doesn't the bottom right router also send something with a TTL of 255?
PROFESSOR: Yeah, so these routers are actually-- this is a physical router. And it knows these are separate links. So it looks at the TTL and which link it came on. So if a packet came in on this link, it will not accept it for this TCP connection.
But you're right. For the most part, these routers trust their immediate neighbors. It need not necessarily be the case. But if you keep seeing this problem, and you know you've implemented this hack, then it must be one of your neighbors. You're going to look. TCP dumped these interfaces. Why are you sending me these reset packets?
This problem is not as big. You can manage it by some Auto Pan mechanism. Make sense? All right, there are other fixes for BGP where they implemented some form of header authentication, MD5 header authentication as well. But they're really targeting this particular application where this reset attack is particularly bad.
This is still a problem today. If there's some long-lived connection out there that I really want to shoot down, I just have to send some large number of RST packets, probably on the order of hundreds of thousands or so, but probably not exactly 4 billion. Because the servers are actually somewhat lax in terms of which sequence number they accept for a reset.
It can be any packet within a certain window. And in that case, I could probably, or any attacker, reset an existing connection with a modest but not a huge amount of effort. That's still a problem. And people haven't really found any great solution for that.
All right, and I guess the sort of last bad thing that happens because these sequence numbers are somewhat predictable is just data injection into existing connections. So suppose there is some protocol like rlogin, but maybe rlogin doesn't-- suppose we have some hypothetical protocol that's kind of like rlogin, but actually it doesn't do IP-based authentication. You have to type in your password to log in, all this great stuff.
The problem is once you've typed your password, maybe your TCP connection is just established and can accept arbitrary data. So wait for one of you guys to log into a machine, type in your password. I don't know what that password is. But once you've established TCP connection, I'll just try to guess your sequence number and inject some data into your existing connection. So if I can guess your sequence numbers correctly, then this allows me to make it pretend like you've typed some command after you authenticated correctly with your password.
So this all sort of suggests that you really don't want to rely on these 32-bit sequence numbers for providing security. But let's actually see what modern TCP stacks actually do to try to mitigate this problem. So as we were sort of discussing, I guess one approach that we'll look at in the next two lectures is how to implement some security at the application level. So we'll use cryptography to authenticate and encrypt and sign and verify messages at the application level without really involving TCP so much.
But there are some existing applications that would benefit from making this slightly better, at least not make it so easy to exploit these problems. And the way that I guess people do this in practice today-- for example Linux and Windows-- is they implement the suggestion that John gave earlier, that we maintain different initial sequence numbers for every source destination pair.
So what most TCP SYN implementations do is they still compute this initial sequence number as we were computing before. So this is the old style ISN, let's say. And in order to actually generate the actual ISN for any particular connection, we're going to add a random 32-bit offset. So we're going to include some sort of a function. Think of it like as like a hash function like SHA-1 or something maybe better.
And this is going to be a function of the source IP, the source port number, the destination IP address, destination port, and some sort of a secret key that only the server knows in this case. So this has the nice property that within any particular connection, as identified by a source and destination IP port pair, it still preserves all these nice properties of this old style sequence number algorithm had.
But if you have connections from different source/destination tuples, then there's nothing you can learn about the exact value of another connection tuple's sequence number. And in fact, you'll have to guess this key in order to infer that value. And hopefully the server, presumably the OS kernel, stores this key somewhere in its memory and doesn't give it out to anyone else.
So this is how pretty much most TCP stacks deal with this particular problem today to the extent allowed by the total 32-bit sequence number. It's not great, but sort of works. Yeah.
AUDIENCE: Could you repeat that again? Is the key unique to--
PROFESSOR: So when my machine boots up, or when any machine boots up, it generates a random key. Every time you reboot it it generates a new key. And this means that every time that for a particular source/destination pair, the sequence numbers advance at the same rate as controlled by this.
So for a given source/destination pair, this thing is fixed. So you observe your sequence numbers evolving according to your initial sequence numbers for new connections evolving according to a particular algorithm. So that still provides all these defences against old packets from previous connections being injected into new connections, just like packet reordering problems.
So that still works. And that's the only real thing for which we needed this sequence number choosing algorithms to prevent these duplicate packets from causing problems. However, the thing that we were exploiting before, which is that if you get the sequence number for one connection from A to S, then from that you can infer the sequence number for a different connection.
That's now gone. Because every connection has a different offset in this 32-bit space as implemented by its F function. So this completely decouples the initial sequence numbers seen by every connection. Yeah.
AUDIENCE: What's the point in including the key?
PROFESSOR: Well, if you don't include the key, then I can connect to you. I'll compute the same function F. I'll subtract it out. I'll get this. I'll compute this function F for the connection I actually want to fake. And I'll guess what the initial sequence number for that one is going to be.
AUDIENCE: So can you-- because machines now restart infrequently, can you still [INAUDIBLE] by reversing--
PROFESSOR: I think typically this function F is something like a cryptographically secure hash function, which has a semi-proved property that it's very difficult. It's cryptographically hard to invert it. So even if you were given the literal inputs and outputs of this hash function except for this key part, it would be very hard for you guess what this key is cryptographically, even in an isolated setting.
So hopefully this will be at least as hard in this setting as well. We'll talk a little bit more about what these functions F are a bit later on and how you to use them correctly. Make sense? Other questions of this problem and solution?
All right, so in fact, this was mostly sort of an example of these TCP sequence number attacks that aren't as relevant anymore. Because every operating system basically implements this plan these days. So it's hard to infer what someone's sequence number is going to be.
On the other hand, people keep making the same mistakes. So even after this was implemented for TCP, there was this other protocol called DNS that is hugely vulnerable to similar attacks. And the reason is that DNS actually runs over UDP.
So UDP is a stateless protocol where you actually don't do any connection establishment where you exchange sequence numbers. In UDP, you simply send a request from your source address to the server. And the server figures out what the reply should be and sends it back to whatever source address appeared in the packet.
So it's a single round trip, so there's no time to exchange sequence numbers and to establish that, oh, yeah, you're actually talking to the right guy. So with DNS, as a result, for a while, it was quite easy to fake responses from a DNS server.
So how would a query look like in DNS, typically? Well, you send some queries-- so suppose a client sends a packet from client to some DNS server that knows the DNS server's IP address ahead of time, maybe preconfigured somewhere, say, well, here's my query. Maybe I'm looking for mit.edu. And that's basically it.
And the server's destination port number is always 53 for DNS. And the clients used to also run on the same port number for ease of use or something. So you send this packet from the client on this port to the server on this port. Here's the query. And the server eventually sends back a reply saying, mit.edu has a particular IP address, 18.9 dot something.
The problem is that some adversary could easily send a similar response packet pretending to be from the server. And there's not a whole lot of randomness here. So if I know that you're trying to connect to mit.edu, I'll just send a lot of packets like this to your machine.
I know exactly what DNS server you're going to query. I know exactly what your IP address is. I know the port numbers. I know what you're querying for. I can just supply my own IP address here.
And if my packet gets there after you send this but before you get the real response, your client machine is going to use my packet. So this is another example where insufficient randomness in this protocol makes it very easy to inject responses or inject packets in general.
And this is actually in some ways even worse than the previous attack. Because here you could convince a client to connect to another IP address all together. And it'll probably cache this result, because DNS involves caching. Maybe you can supply a very long time to live in this response saying, this is valid for years. And then your client, again till it reboots, is going to keep using this IP address for mit.edu. Yeah.
AUDIENCE: Could you fix this by having the client include some random value in the query, and the server customer exactly?
PROFESSOR: That's right, yeah, so this is typically what people have done now. The problem, as we were sort of talking about earlier, is backward compatibility. It's very hard to change the DNS server software that everyone runs.
So you basically have to figure out, where can you inject randomness? And people have figured out two places. It's not great. But basically there's a source port number, which is 16 bits of randomness. So if you can choose the source port number randomly, then you get 16 bits. And there's also a query ID inside of the packet, which is also 16 bits. And the server does echo back the query ID.
So combining these two things together, most resolvers these days get 32 bits of randomness out of this protocol. And it, again, makes it noticeably harder, but still not cryptographically perfect, to fake this kind of response and have it be accepted by the client. But these problems keep coming up, unfortunately. So even though it was well understood for TCP, some people I guess suggested that this might be a problem. But it wasn't actually fixed until only a few years ago. Make sense?
All right, so I guess maybe as an aside, there are solutions to this DNS problem as well by enforcing security for DNS at the application level. So instead of relying on these randomness properties of small numbers of bits in the packet, you could try to use encryption in the DNS protocols. So protocols like DNS SEC that the paper briefly talks about try to do this. So instead of relying on any network level security properties, they require that all DNS names have signatures attached to them.
That seems like a sensible plan. But it turns out that working out the details is actually quite difficult. So one example of a problem that showed up is name and origin. Because in DNS, you want to get responses. Well, this name has that IP address.
Or you could get a response saying, no, so sorry, this name doesn't exist. So you want to sign the it doesn't exist response as well. Because otherwise, that adversary could send back a doesn't exist response and pretend that a name doesn't exist, even though it does. So how do you sign responses that certain names don't exist ahead of time? I guess one possibility is you could give your DNS server the key that signs all your records.
That seems like a bad plan. Because then someone who compromises your DNS server could walk away with this key. So instead, the model the DNS SEC operates under is that you sign all your names in your domain ahead of time, and you give the signed blob to your DNS server. And the DNS server can then respond to any queries. But even if it's compromised, there's not much else that that attacker can do. All these things are signed, and the key is not to be found on the DNS server itself.
So the DNS SEC protocol had this clever mechanism called NSEC for signing nonexistent records. And the way you would do this is by signing gaps in the namespace. So an NSEC record might say, well, there's a name called foo.mit.edu, and the next name alphabetically is maybe goo.mit.edu.
And there's nothing alphabetical in between these two names. So if you query for a name between these two names alphabetically sorted, then the server could send back this signed message saying, oh, there's nothing between these two names. You can safely return, doesn't exist.
But then this allows some attacker to completely enumerate your domain name. You can just ask for some domain name and find this record and say, oh, yeah, great. So these two things exist. Let me query for gooa.mit.edu. That'll give me a response saying, what's the next name in your domain, et cetera.
So it's actually a little bit hard to come up with the right protocol that both preserves all the nice properties of DNS and prevents name enumeration and other problems. There's actually a nice thing now called NSEC3 that tries to solve this problem partially-- sort of works, sort of not. We'll see, I guess, what gets it [INAUDIBLE]. Yeah.
AUDIENCE: Is there any kind of signing of nonexistent top level domains?
PROFESSOR: Yeah, I think actually yeah. The dot domain is just another domain. And they similarly have this mechanism implemented as well. So actually dot and dot com now implement DNS SEC, and there's all these records there that say, well, .in is a domain name that exists, and dot something else exists, and there's nothing in between. So there's all these things.
AUDIENCE: So other than denial of service, why do we care so much about repeating domain names within mit.edu?
PROFESSOR: Well, probably we don't. Actually, there's a text file in AFS that lists all these domain names at MIT anyway. But I think in general, some companies feel a little uneasy about revealing this. They often have internal names that sit in DNS that should never be exposed to the outside. I think it's actually this fuzzy area where it was never really formalized what guarantees DNS was providing to you or was not. And people started assuming things like, well, if we stick some name, and it's not really publicized anywhere, then it's probably secure here.
I think this is another place where this system doesn't have a clear spec in terms of what it has and doesn't have to provide. And when you make some changes like this, then people say, oh, yeah, I was sort of relying on that. Yeah.
AUDIENCE: [INAUDIBLE] replay attack where you could send in bold gap signature?
PROFESSOR: Yeah, there's actually time outs on these things. So when you sign this, you actually sign and say, I'm signing that this set of names is valid for, I don't know, a week. And then the clients, if they have a synchronized clock, they can reject old signed messages. Make sense?
All right, so this is on the TCP SYN guessing attacks. Another interesting problem that also comes up in the TCP case is a denial of service attack that exploits the fact that the server has to store some state. So if you look at this handshake that we had on the board before, we'll see that when a client establishes a connection to the server, the server has to actually remember the sequence number SNC. So the server has to maintain some data structure on the side that says, for this connection, here's the sequence number.
And it's going to say, well, my connection from C to S has the sequence number SNC. And the reason the server has to store this table is because the server needs to figure out what SNC value to accept here later. Does this make sense?
AUDIENCE: [INAUDIBLE] SNS?
PROFESSOR: Yeah, the server also needs SNS I guess, yeah. But it turns out that-- well, yeah, you're right. And the problem is that-- actually, yeah, you're right. SNS is actually much more important. Sorry, yeah. [INAUDIBLE] SNS is actually much more important. Because SNS is how you know that you're talking to the right guy.
The problem is that there's no real bound on the size of this table. So you might get packets from some machine. You don't even know who sent it. You just get a packet that looks like this with a source address that claims to be C.
And in order to potentially accept a connection later from this IP address, you have to create this table entry. And these table entries are somewhat long lived. Because maybe someone is connecting to you from a really far away place. There's lots of packet loss. It might be not for maybe a minute until someone finishes this TCP handshake in the worst case.
So you have to store this state in your TCP stack for a relatively long time. And there's no way to guess whether this is a valid connection or not. So one denial of service attack that people discovered against most TCP stacks is to simply send lots of packets like this.
So if I'm an attacker, then I'll just send lots of SYN packets to a particular server and get it to fill up its table. And the problem is that in the best case, maybe the attacker just always uses the same source IP address.
In that case, you can just say, well, every client machine is allowed two entries in my table, or something like this. And then the attacker can use up two table entries but not much more. The problem, of course, is that the attacker can fake these client IP addresses, make them look random. And then for the server, it's going to be very difficult to distinguish whether this is an attacker trying to connect to me or some client I've never heard of before.
So if you're some website that's supposed to accept connections from anywhere in the world, this is going to be a big problem. Because either you deny access to everyone, or you have a store state for all these mostly fake connection attempts. Does that make sense?
So this is a bit of a problem for TCP, and in fact for most protocols that allow some sort of connection initiation, and the server has to store state. So there's some fixes. We'll talk about in a second what workaround TCP implements to try to deal with this problem. This is called SYN flooding in TCP.
But in general, this is a problem that's worth knowing about and trying to avoid in any protocol you design on top as well. So you want to make sure that the server doesn't have to keep state until it can actually authenticate and identify, who is the client?
Because by that time, if you've identified who the client is, you've authenticated them somehow, then you can actually make a decision, well, every client is allowed to only connect once, or something. And then I'm not going to keep more state.
Here, the problem is you're guaranteeing that you're storing state before you have any idea who it is that is connecting to you. So let's look at how you can actually solve this SYN flooding attack where the server accumulates lots of state.
So of course, if you could change TCP again, you could fix this pretty easily by using cryptography or something or changing exactly who's responsible for storing what state. The problem is we have TCP as is. And could we fix this problem without changing the TCP wire protocol? So this is, again, an exercise in trying to figure out, well, what exactly tricks we could play or exactly what assumptions we could relax and still stick to the TCP header format and other things.
And the trick is to in fact figure out a clever way to make the server stateless without having to-- so the server isn't going to have to keep this table around in memory. And the way we're going to do this is by carefully choosing SMS. Instead of using this formula we were looking at before, where we were to add this function, we're instead going to choose this sequence number in a different way.
And I'll give you exactly the formula. And then we'll talk about why this is actually interesting and what nice properties it has. So if the server detects that it's under this kind of attack, it's going to switch into this mode where it chooses SNS using this formula of applying basically the same or similar kind of function F we saw before. And what it's going to apply it to is the source IP, destination IP, the same things as before, source port, destination port, and also timestamp, and also a key in here as well.
And we're going to concatenate it with a timestamp as well. So this timestamp is going to be fairly coarse grained. It's going to go in order of minutes. So every minute, the timestamp ticks off by one. It's a very coarse grained time.
And there's probably some split between this part of the header and this part of the header. This timestamp doesn't need a whole lot of bits. So I forget exactly what this protocol does in real machines. But you could easily imagine maybe using 8 bits. For the timestamp, I'm going to be using 24 bits for this chunk of the sequence number.
All right, so why is this a good plan? What's going on here? Why this weird formula? So I think you have to remember, one was the property that we were trying to achieve of the sequence number. So there's two things going on. One is there's this defense against duplicated packets that we were trying to achieve by-- maybe the formula is still here. Nope-- oh, yeah, yeah, here.
Right, so just to compare these guys-- so when we're not under attack, we were previously maintaining this old style sequence number scheme to prevent duplicate packets from previous connections, all this good stuff. It turns out people couldn't figure out a way to defend against these kinds of SYN flooding attacks without giving up on this property, so basically saying, well, here's one plan that works well in some situations. Here's a different plan where we'll give up on that ISN old style component.
And instead, we'll focus on just ensuring that if someone presents us this sequence number S in response to a packet, like here, then we know it must've been the right client. So remember that in order to prevent IP spoofing attacks, we sort of rely on this SNS value. So if the server sends this SNS value to some client, then hopefully only that client can send us back the correct SNS value, finish establishing the connection.
And this is why you had to store it in this table over here. Because otherwise, how do you know if this is a real response or a fake response? And the reason for using this function F here is that now we can maybe not store this table in memory. And instead, when a connection attempt arrives here, we're going to compute SNS according to this formula over here and just send it back to whatever client pretends to have connected to us.
And then we'll forget all about this connection. And then if this third packet eventually comes through, and its SNS value here matches what we would expect to see, then we'll say, oh yeah, this must've been someone got our response from step two and finally sent it back to us.
And now we finally commit after step three to storing a real entry for this TCP connection in memory. So this is a way to sort of defer the storage of this state at the server by requiring the server, the client, to echo back this exact value. And by constructing it in this careful way, we can actually check whether the client just made up this value, or if it's the real thing we're expecting. Does that make sense?
AUDIENCE: [INAUDIBLE] SNC [INAUDIBLE]?
PROFESSOR: Yeah, so SNC now, we basically don't store it. It's maybe not great. But so it is. So in fact, I guess what really happens is in-- I didn't show it here. But there's probably going to be sort of a null data field here that says this packet has no data. But it still includes the sequence number SNC just because there's a field for it.
So this is how the server can reconstruct what this SNC value is. Because the client is going to include it in this packet anyway. It wasn't relevant before. But it sort of is relevant now. And we weren't going to check it against anything. But it turns out to be pretty much good enough.
It has some unfortunate consequences. Like if this is-- well, there's some complicated things you might abuse here. But it doesn't seem to be that bad. It seems certainly better than the server filling up its memory and swapping serving requests all together.
And then we don't include in this computation. Because the only thing we care about here is offloaded the storage of this table and making sure that the only connections that eventually you do get established are legitimate clients. Because therefore, we can say, well, if this client is establishing a million connections to me, I'll stop accepting connections from him.
That's easy enough, finally. The problem is that all these source addresses, if they're spoofed, are hard to distinguish from legitimate clients. Make sense? Yeah.
AUDIENCE: Would you need to store the timestamp?
PROFESSOR: Ahh, so the clever thing, the reason this timestamp is sort of on the slide here, is that when we receive this SNS value in step three, we need to figure out, how do you compute the input to this function F to check whether it's correct? So actually, we take the timestamp from the end of the packet, and we use that inside of this computation.
Everything else we can reconstruct. We know who just sent us the third step and packet. And we have all these fields. And we have our key, which is, again, still secret. And this timestamp just comes from the end of the sequence, from the last 8 bits. And then it might be that we'll reject timestamps that are too old, just disallow old connections. Yeah.
AUDIENCE: So I'm guessing the reason you only use this when you're under attack is because you lose 8 bits of security, or whatever?
PROFESSOR: Yes, it's not great. It has many bad properties. One is you sort of lose 8 bits of security in some sense. Because now the unguessable part is just 24 bits instead of 32 bits. Another problem is what happens if you lose certain packets? So if this packet is lost-- so it's typically, in TCP, there's someone responsible for retransmitting something if a particular packet is lost. And in TCP, if the third packet is lost, then the client might not be waiting for anything. Or sorry, maybe the protocol we're running on top of this TCP connection is one where the server is supposed to say something initially.
So I connect. I just listen. And in the SMTP, for example, the server is supposed to send me some sort of an initial greeting in the protocol. So OK, suppose I'm connecting to an SMTP server. I send my third packet. I think I'm done. I'm just waiting for the server to tell me, greetings as an SMTP server. Please send mail.
This packet could get lost. And in real TCP, the way this gets handled is that the server from step two remembers that, hey, I sent this response. I never heard back, this third thing. So it's the server that's supposed to resend this packet to trigger the client to resend this third packet.
Of course, if the server isn't storing any state, it has no idea what to resend. So this actually makes connection establishment potentially programmatic where you could enter this weird state where both sides are waiting for each other. Well, the server doesn't even know that it's waiting for anything. And the client is waiting for the server. And the server basically dropped responsibility by not storing state. So this is another reason why you don't run this in production mode all the time. Yeah.
AUDIENCE: Presumably also you could have data commissions if you establish two very short-lived connections right after each other from the same host.
PROFESSOR: Absolutely, yeah, yeah. So another thing is, of course, because we gave up on using this ISN old style part, we now give up protection against these multiple connections in a short time period being independent from one another. So I think there's a number of trade-offs. We just talked about three. There's several more things you worry about.
But it's not great. If we could design a protocol from scratch to be better, we could just have a separate nice 64-bit header for this and a 64-bit value for this. And then we could enable this all the time without giving up the other stuff and all these nice things. Yeah.
AUDIENCE: I just had one quick question on the SNS. In step two, [INAUDIBLE], do they have to be the same?
PROFESSOR: This SNS and this SNS?
AUDIENCE: Mhm.
PROFESSOR: Yeah, because otherwise, the server has no way to conclude that this client got our packet. If the server didn't check that this SNS was the same value as before, then these actually would be even worse.
Because I could fake a connection from some arbitrary IP address, then get this response. Maybe I don't even get it, because it goes to a different IP. Then I establish a connection from some other IP address. And then the server is maintaining a whole live connection. Probably a server crosses another side waiting for me to send data and so on.
AUDIENCE: But the timestamp is going to be different, right? So how can the server recalculate that with a new timestamp and null the one before if it doesn't store any state?
PROFESSOR: So the way this works is these timestamps, as I was saying, are course grained. So they're on a scale of minutes. So if you connect within the same minute, then you're in good shape. And if you connect on the minute boundary, well, too bad.
Yet another problem with the scheme-- it's imperfect in many ways. But most operating systems, including Linux, actually have ways of detecting if there's too many entries building up in this table that aren't being completed. It switches to this other scheme instead to make sure it doesn't overflow this table. Yeah.
AUDIENCE: So if the attacker has control of a lot of IP addresses, and they do this, and even if you switch it the same--
PROFESSOR: Yeah, so then actually there's not much you can do. The reason that we were so worried about this scheme in the first place is because we wanted to filter out or somehow distinguish between the attacker and the good guys. And if the attacker has more IP addresses and just controls more machines than the good guys, then he can just connect to our server and request lots of web pages or maintain connections.
And it's very hard then for the server to distinguish whether these are legitimate clients or just the attacker tying up resources of the server. So you're absolutely right. This only addresses the case where the attacker has a small number of IP addresses and wants to amplify his effect.
But it is a worry. And in fact, today it might be that some attackers control a large number of compromised machines, like just desktop machines of someone that didn't patch their machine correctly. And then they can just mount denial of service attacks from this distributed set of machines all over the world. And that's pretty hard to defend against.
So another actually interesting thing I want to mention is denial of service attacks, but in the particular way that other protocols make them worse. I guess other protocols allow denial of service attacks in the first place. I'm sorry. But there are some that are protocols that are particularly susceptible to abuse. And probably a good example of that is, again, this DNS protocol that we were looking at before.
So the DNS protocol-- we still have it here-- involves the client sending a request to the server and the server sending a response back to the client. And in many cases, the response is larger than the request. The request could be just, tell me about mit.edu. And the response might be all the records the server has about mit.edu-- the email address, the mail server for mit.edu, the assigned record if it's using DNS SEC, and so on.
So the query might be 100 bytes. The response could well be over 1,000 bytes. So suppose that you want to flood some guy with lots of packets or lots of bandwidth. Well, you might only be able to send a small amount of bandwidth.
But what you could do is you could fake queries to DNS servers on behalf of that guy. So you only have to send 100 bytes to some DNS server pretending to be a query from that poor guy. And the DNS server is going to send 1,000 bytes to him on your behalf.
So this is a problematic feature of this protocol. Because it allows you to amplify bandwidth attacks. And partly for the same reason we were talking about with TCP's SYN flooding attacks, it's very hard for the server, for the DNS server, in this case, to know whether this request is valid or not. Because there's no authentication or no sort of sequence number exchanges going on to tell that this is the right guy connecting to you, et cetera.
So in fact this is still a problem in DNS today. And it gets used quite frequently to attack people with bandwidth attacks. So if you have a certain amount of bandwidth, you'll be that much more effective if you reflect your attack off of a DNS server.
And these DNS servers are very well provisioned. And they basically have to respond to every query out there. Because if they stop responding to requests, then probably some legitimate requests are going to get dropped. So this is a big problem in practice. Yeah.
AUDIENCE: So if you can still see it on the DNS server, [INAUDIBLE] requests and never reply to--
PROFESSOR: Right, yeah, so it's possible to maybe modify the DNS server to keep some sort of state like this.
AUDIENCE: That's the reason why this still works now, because they don't store state?
PROFESSOR: Yeah, well I think some people are starting to modify DNS server to try to store state. A lot of times, there's so many DNS servers out there that it doesn't matter. Even if you appear to do 10 queries against every DNS server, that's still every packet gets amplified by some significant factor. And they have to respond. Because maybe that client really is trying to issue this query. So this is a problem. Yeah, so you're right, if this was one DNS server, then this would be maybe not as big of a deal.
The problem is also that the root servers for DNS, for example, aren't a single machine. It's actually racks and racks of servers. Because they're so heavily used. And trying to maintain a state across all these machines is probably nontrivial. So as it gets abused more, probably it will be more worthwhile to maintain this state.
I guess a general principle you want to follow in any protocol-- well, might be a good principle-- is to make the client do at least as much work as the server is doing. So here, the problem is the client isn't doing as much work as the server. That's why the server can help the client amplify this effect.
If you were redesigning DNS from scratch, and this was really your big concern, then it'd probably be fairly straightforward to fix this. The client has to send a request that has extra padding bytes just there just wasting bandwidth. And then the server is going to respond back with a response that's at most as big as that.
And if you want a response that's bigger, maybe the server will say, sorry, your padding wasn't big enough. Send me more padding. And this way, you guarantee that the DNS server cannot be used ever to amplify these kinds of bandwidth attacks.
Actually, these kinds of problems happen also at higher levels as well. So in web applications, you often have web services that do lots and lots of computation on behalf of a single request. And there's often denial of service attacks at that level where adversaries know that a certain operation is very expensive, and they'll just ask for that operation to be done over and over again. And unless you carefully design your protocol and application to allow the client to prove that, oh, I'm burning at least as much work as you, or something like this, then it's hard to defend against these things as well. Make sense?
All right, so I guess the last thing I want to briefly touch on about the paper we talked about as well is these routing attacks. And the reason these attacks are interesting is they're maybe popping up a level above these protocol transport level issues. And look at what goes wrong in an application.
And the routing protocol is a particularly interesting example. Because it's often the place where trust and sort of initial configuration gets bootstrapped in the first place. And it's easy to sort of get that wrong. And even today, there's not great authentication mechanisms for that.
Perhaps the clearest example is the DHCP protocol that all of you guys use when you open a computer or connect to some wireless or wired network. The computer just sends out a packet saying, I want an IP address and other stuff. And some DHCP server at MIT typically receives that packet and sends you back, here's an IP address that you should use. And also here's a DNS server you should use, and other interesting configuration data.
And the problem is that the DHCP request packet is just broadcasting on the local network trying to reach the DHCP server. Because you actually don't know what the DHCP is going to be ahead of time. You're just plugging into the network, the first time you've been here, let's say. And your client doesn't know what else to do or who to trust.
And consequently, any machine on the local network could intercept these DHCP requests and respond back with any IP address that the client could use, and also maybe tell the client, hey you should use my DNS server instead of the real one. And then you could intercept those future DNS requests from the client and so on. That make sense?
So I think these protocols are fairly tricky to get right. And on a global scale, the protocols like BGP allow any participant to announce a particular IP address prefix for the world to sort of know about and route packets toward the attacker. There's certainly been attacks where some router participating in BGP says, oh, I'm a very quick way to reach this particular IP address range. And then all the routers in the world say, OK, sure, we'll send those packets to you.
And probably the most frequent abuse of this is by spammers who want to send spam, but their old IP addresses are blacklisted everywhere, because they are sending spam. So they just pick some random IP address. They announce that, oh yeah, this IP address is now here. And then they sort of announce this IP address, send spam from it, and then disconnect. And it gets abused a fair amount this way.
It's sort of getting less now. But it's kind of hard to fix. Because in order to fix it, you have to know whether someone really owns that IP address or not. And it's hard to do without establishing some global database of, maybe, cryptographic keys for every ISP in the world. And it takes quite a bit of effort by someone to build this database.
The same actually applies to DNS SEC as well. In order to know which signature to look for in DNS, you have to have a cryptographic key associated with every entity in the world. And it's not there now. Maybe it'll get built up slowly. But it's certainly one big problem for adopting DNS SEC.
All right, so I guess the thing to take away from this is maybe just a bunch of lessons about what not to do in general in protocols. But also actually one thing I want to mention is that while probably secrecy and integrity are good properties and driving force of higher levels of abstraction, like in cryptographic protocols in the application-- and we'll look at that in next lectures-- one thing that you really do want from the network is some sort of availability and DOS resistance. Because these properties are much harder to achieve at higher levels in the stack.
So you really want to avoid things like maybe these amplification attacks, maybe these SYN flooding attacks, maybe these RST attacks where you can shoot down an arbitrary person's connection. These are things that are really damaging at the low level and that are hard to fix higher up. But the integrity and confidentiality you can more or less solve with encryption. And we'll talk about how we do that in the next lecture on Cerberus. See you guys then.
Free Downloads
Video
- iTunes U (MP4 - 174MB)
- Internet Archive (MP4 - 174MB)
Subtitle
- English - US (SRT)