Chapter 2 ■ UDp
23
Promiscuous Clients and Unwelcome Replies
The client program in Listing 2-1 is actually dangerous! If you review its source code, you will see that although
recvfrom() returns the address of the incoming datagram, the code never checks the source address of the datagram
it receives to verify that it is actually a reply from the server.
You can see this problem by delaying the server’s reply and seeing whether someone else can send a response
that this naïve client will trust. On a less capable operating system such as Windows, you will probably have to add a
long time.sleep() call in between the server’s receive and send to simulate a server that takes a long time to answer.
On Mac OS X and Linux, however, you can much more simply suspend the server with Ctrl+Z once it has set up its
socket to simulate a server that takes a long time to reply.
So, start up a fresh server but then suspend it using Ctrl+Z.
$ python udp_local.py server
Listening at ('127.0.0.1', 1060)
^Z
[1] + 9370 suspended python udp_local.py server
$
If you now run the client, it will send its datagram and then hang, waiting to receive a reply.
$ python udp_local.py client
The OS assigned me the address ('0.0.0.0', 39692)
Assume that you are now an attacker who wants to forge a response from the server by jumping in and sending
your datagram before the server has a chance to send its own reply. Since the client has told the operating system that
it is willing to receive any datagram whatsoever and is doing no sanity checks against the result, it should trust that
your fake reply in fact originated at the server. You can send such a packet using a quick session at the Python prompt.
$ python3
Python 3.4.0 (default, Apr 11 2014, 13:05:18)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto('FAKE'.encode('ascii'), ('127.0.0.1', 39692))
4
The client will immediately exit and happily interpret this third-party reply as being the response for which it was
waiting.
The server ('127.0.0.1', 37821) replied 'FAKE'
You can kill the server now by typing fg to unfreeze it and let it keep running (it will now see the client packet
that has been queued and waiting for it and will send its reply to the now-closed client socket). Press Ctrl+C as
usual to kill it.