mas-bandwidth / netcode

Secure client/server connections over UDP
BSD 3-Clause "New" or "Revised" License
2.43k stars 191 forks source link

Connect Token Sniffing #84

Closed RandyGaul closed 5 years ago

RandyGaul commented 5 years ago

Say a valid, but malicious, client records their own list of valid dedicated server IP addresses. They then want to DoS another player, or steal another player's session. They sniff the other player's packets and get access to the opaque connect token. They then make an attempt to connect to a dedicated server by using their own personal IP address collection, and send the token to each server to try and connect before the sniffed client.

This causes two problems:

  1. The sniffed player can have their identity stolen, as another player has connected with their token before they do.
  2. The sniffed player might have to retrieve a new token and try to connect to other servers. In the case where no other servers are available, they are in a DoS scenario.

What is the idea for netcode regarding this strategy?

ghost commented 5 years ago

Say a valid, but malicious, client records their own list of valid dedicated server IP addresses. They then want to DoS another player, or steal another player's session. They sniff the other player's packets and get access to the opaque connect token. They then make an attempt to connect to a dedicated server by using their own personal IP address collection, and send the token to each server to try and connect before the sniffed client.

This causes two problems:

  1. The sniffed player can have their identity stolen, as another player has connected with their token before they do.
  2. The sniffed player might have to retrieve a new token and try to connect to other servers. In the case where no other servers are available, they are in a DoS scenario.

What is the idea for netcode regarding this strategy?

You test it ?

RandyGaul commented 5 years ago

It would require a whole lot of work to hack a client to do packet sniffing. But it's trivial to write a test to simulate sniffing: https://gist.github.com/RandyGaul/9387c766ff9279f8fe6a8372795d7f53. The test should be identical to sniffing, since the private section of the connect token is just memcpy'd around in any case.

I'm unable to see how netcode distinguishes between a user attempting to connect with a token twice, between the DoS/identity stealing scenario.

ghost commented 5 years ago

It would require a whole lot of work to hack a client to do packet sniffing. But it's trivial to write a test to simulate sniffing: https://gist.github.com/RandyGaul/9387c766ff9279f8fe6a8372795d7f53. The test should be identical to sniffing, since the private section of the connect token is just memcpy'd around in any case.

I'm unable to see how netcode distinguishes between a user attempting to connect with a token twice, between the DoS/identity stealing scenario.

Do you have a solution to this problem?

Do I understand correctly that if one user hacks the client of a game of another user, he can connect use other token, but this is not terrible, given that he does not know the second user’s login and password for auth in game. By the way, what do you think about this library in general? Should it be used in the MMORPG?

RandyGaul commented 5 years ago

I actually don’t know if this is really a problem. That’s why I’m posting, to find out if it’s really a problem at all.

I’ve never made an MMORPG before, so I’m not really sure if it’s suitable or not.

I’m sure it’s possible to do username and password auth after the connection is established... But I thought the whole idea was to offload this part to the webserver over HTTPS.

ghost commented 5 years ago

From my understanding, the initial communication of a connect token is outside the spec of netcode.io- that being said it's recommended to transfer the connect token over HTTPS with properly implemented TLS.

I believe the challenge token sequence is responsible for ensuring that spoofed IPs can't pass the connection sequence. From my understanding, the challenge token utilizes both a sequence number and data present only in the entire connect token. An attacker who is sniffing the UDP packet stream would not be able to create packets that could pass the challenge sequence.

If an attacker has your full connect token, chances are either that your initial webserver is not properly configured for TLS, or the attacker has access to the client itself, which in that case you have much bigger problems that netcode would not be able to approach.

RandyGaul commented 5 years ago

Thanks you’re right! The nonce part was that piece I missed :)

RandyGaul commented 5 years ago

Actually if we look here: https://github.com/networkprotocol/netcode.io/blob/master/netcode.c#L4293-L4304

The challenge token sequence is just an incrementing number. It does not use a shared-secret between in the initial connect token from the webserver. @stellarLuminant So your response does sound like it would work - if the sequence number was a shared secret like you explained, then I can see how the challenge-response secret would not work for a packet sniffer. However the strategy netcode actually uses is the challenge-response secret is covered using the shared keyset. A sniffer would not have access to the shared keyset and would be unable to respond during the challenge response sequence.

So the best the sniffer could do is to try and DoS the server by filling up encryption mappings by initiating the challenge-response sequence. But they should be unable to connect. So this must be why netcode by default reserves 4x encryption mappings as opposed to client slots, as a way to mitigate this DoS strategy.

ghost commented 5 years ago

Actually if we look here: https://github.com/networkprotocol/netcode.io/blob/master/netcode.c#L4293-L4304

The challenge token sequence is just an incrementing number. It does not use a shared-secret between in the initial connect token from the webserver. @stellarLuminant So your response does sound like it would work - if the sequence number was a shared secret like you explained, then I can see how the challenge-response secret would not work for a packet sniffer. However the strategy netcode actually uses is the challenge-response secret is covered using the shared keyset. A sniffer would not have access to the shared keyset and would be unable to respond during the challenge response sequence.

So the best the sniffer could do is to try and DoS the server by filling up encryption mappings by initiating the challenge-response sequence. But they should be unable to connect.

As far as I know, the client cannot spoof the sequence value to deceive the server.

The sequence number is used as the nonce for packet encryption, so any modification to the sequence number fails the encryption signature check.

But i have other ask about "#define NETCODE_PACKET_SEND_RATE 10.0" I did an analysis of how many packets the client / server sends over a specific time. As it turned out, they send each other about 100 packets per second and about 5000 per minute. This is normal? If you change the value of NETCODE_PACKET_SEND_RATE down, that increase the delay before sending keep-alive packets. I’m wondering why the author set the NETCODE_PACKET_SEND_RATE = 10.0 version and whether I need to change the fact that the client and the server send a lot of packets to each other, even when it is just send keep-alive (more time)

RandyGaul commented 5 years ago

That’s normal yes. Glenn has said he wrote netcode with support for FPS games especially in mind, or games like agar.io. By rapidly sending keepalives, libyojimbo is able to piggy-back the keepalives to send reliable messages in the event the game is not currently sending any other unreliable data. I haven’t looked at the yojimbo source in-depth since 2017, but I imagine it still does the same thing.

ghost commented 5 years ago

That’s normal yes. Glenn has said he wrote netcode with support for FPS games especially in mind. By rapidly sending keepalives, libyojimbo is able to piggy-back the keepalives to send reliable messages in the event the game is not currently sending any other unreliable data. I haven’t looked at the yojimbo source in-depth since 2017, but I imagine it still does the same thing.

So, me need use yojimbo or netcode ??

RandyGaul commented 5 years ago

You probably want to use yojimbo. It uses netcode inside, but had reliability features, and other features too.