Programs written to listen on a port number lower than 1024 must be executed with root privilege (that is, UID 0). This rule protects sensitive system services because these run on ports lower in number than 1024 (that is, the reserved ports). The UNIX kernel enforces this restriction to prevent non-privileged users from launching fake network server processes on idle ports. Without this rule, a local user (that is, a user with an account on the system) could
· Start a fake Telnet server to capture user ids and passwords of unsuspecting Telnet clients logging in to the system. If implemented properly, the victims would never realize their accounts had been compromised.
· Start a fake domain name server (DNS) and supply false IP addressing information to DNS clients. For example, a client system attempting to visit http://www.pottedmeatfoodproducts.com/ could be redirected to an exact clone of the site created by the attacker. Sensitive information could then fall into the wrong hands.
· Start a malicious FTP server. Every time a user connects to the FTP service, the rogue FTP program spits back specially crafted data that exploits a bug in a client FTP program. By exploiting a security weakness in the client side program, the attacker is now able to run code on the user's workstation with the privileges of the remote user!
· ...and many, many more malicious acts.
On the other hand, non-privileged processes are allowed to bind and listen on port numbers higher than 1024. Network-aware application programs make use of these non-privileged ports. The advantage of using ports higher than 1024 is that programs do not need to be executed with root privilege just to bind and listen for client requests.
Unfortunately, this does not stop impersonation attacks. We noted earlier that, when a program makes a call to bind(), it has the option of specifying a single IP address or a wildcard. The wildcard tells the kernel, "Bind to all available interfaces,"—or, in other words—"Listen on every IP address on the system." You can tell which network daemons do this by using the netstat command. A very useful command to learn, netstat shows networking statistics. On most UNIX systems, netstat -a shows all ports that are active or in the LISTEN state. The entries marked LISTEN either have a wildcard (*) source address or a specific IP address.
If a caller to bind() specifies a wildcard address, a subsequent caller (that is, another program) can still impersonate the server by binding "in front" of the original server. This wouldn't be possible if the original call had been made with a specific IP address. For example, a database listener binds to port 1999 and specifies the wildcard IP address. The kernel services the request. A local attacker notices the weak binding (via the netstat command) and runs a rogue database listener (that is, one she made earlier). This bind()s to the primary IP address of the machine, allowing her to perform Man In the Middle Attacks (MITM) or just to snoop on application usernames and passwords.
Some kernels prevent this kind of attack, but, unfortunately, it is still possible on many popular distributions.
A further point to be aware of is the Strong versus Weak End System model, as defined in RFC 1122, "Requirements for Internet Hosts—Communication Layers." If your distribution follows the Weak model, remote attackers might be able to communicate with network services in ways you do not expect. Specifically, a multi-homed system can allow packets coming in on one interface to communicate with network services running on another (including a loopback) interface. So, binding network services to specific IP addresses might not gain you anything at all. See this Bugtraq thread for full details: http://archives.neohapsis.com/archives/bugtraq/2001-03/0009.html