Next Previous Contents

15. Networking

15.1 Sender spoofing

Since we create the packets ourselves, it is trivial to fill in the sender/source fields as we like. We can spoof a DNS host name, an IP address, a MAC address, etc.

SNMP walk of a cable modem

I found that SNMP walking my cable modem only worked if I claimed to be someone else.

Given a cable modem, watch the traffic, say with ethereal. I see three MAC addresses: my own (M1), that of the cable modem (M2) and that of the server (M3). Almost all traffic involves M1 and/or M3, but once every few hours there is an ARP request of the cable modem for the address Interesting.

An nmap of the cable modem shows:

# nmap
(The 1643 ports scanned but not shown below are in state: closed)
Port       State       Service
80/tcp     open        http
# nmap -sU
(The 1469 ports scanned but not shown below are in state: closed)
Port       State       Service
68/udp     open        dhcpclient
161/udp    open        snmp

But if I say that I am, then the result is

# nmap -S -e ethkabel
sendto in send_tcp_raw: sendto(3, packet, 40, 0,, 16) => Operation not permitted
(The 1642 ports scanned but not shown below are in state: closed)
Port       State       Service
20/tcp     filtered    ftp-data
80/tcp     filtered    http
# nmap -sU -S -e ethkabel
sendto in send_udp_raw: sendto(3, packet, 28, 0,, 16) => Operation not permitted
(The 1466 ports scanned but not shown below are in state: closed)
Port       State       Service
53/udp     open        domain
68/udp     open        dhcpclient
161/udp    open        snmp
162/udp    open        snmptrap
514/udp    open        syslog

Interesting. So showing the right identity can be important.

Continuing this example, if I try to access the SNMP port, I get

% snmpwalk public 1.3
Timeout: No Response from
If I change my IP sender address to, then again the same timeout happens, but ethereal shows that there is SNMP traffic: the modem sends replies to Aha. So that is also an interesting identity. Changing my identity to shows
% snmpwalk public 1.3
system.sysUpTime.0 = Timeticks: (24973200) 2 days, 6:39:12.00
% snmpwalk public
system.sysDescr.0 = <<HW_REV: 3; VENDOR: Motorola Corporation; BOOTR: 2150; SW_REV: SB5100E-; MODEL: SB5100E>>
system.sysObjectID.0 = OID: enterprises.1166.1.450.12.2
system.sysUpTime.0 = Timeticks: (19688900) 2 days, 6:41:29.00
system.sysContact.0 =
system.sysName.0 = SB5100E
system.sysLocation.0 =
system.sysServices.0 = 79
system.sysORLastChange.0 = Timeticks: (0) 0:00:00.00
system.sysORTable.sysOREntry.sysORID.1 = OID: enterprises.1166.1.20
system.sysORTable.sysOREntry.sysORDescr.1 = Motorola Cable Modem SNMP Agent Capabilities Statement

A complete snmpwalk gives a lot of output, with interesting items like the upload and download speeds, and all IP addresses and ports used.


How does one change identity? In the above, two techniques were used.

One is the ARP spoof:

# while true; do sleep 20; nemesis arp -d ethkabel -S -D; done
(Ask the cable modem every twenty seconds: "We are, and our MAC address is M1, can you tell us the MAC address corresponding to" The cable modem will oblige and answer with M2, and as a side effect will note down that has MAC address M1, that is our address. Now all traffic for goes to us.)

The other is a simple change of routing tables.

# ip addr add dev ethkabel local
# ip addr del dev ethkabel local $myIP

15.2 ARP cache poisoning


When sending an IP packet to some host, the hardware address of the host is needed.

The Address Resolution Protocol (ARP) is used to associate hardware addresses to protocol addresses. It can be used whenever the data link supports broadcast. The most common use is on ethernet. See RFC 826 (and 903, 1293, 1868, ...).

hw type prot type hw addr len IP addr len
op source hw addr source IP addr dest hw addr dest IP addr

An ARP packet is either a request (op = 1) or a reply (op = 2). A request is broadcast ("Who has dest IP? Please tell me") with source hw addr and source IP addr pointing at the submitter of the request, dest IP addr being the topic of the question, and dest hw addr all zero. A reply ("source IP is at source hw addr") is sent to the requester only, and has as dest hw addr and dest IP addr the addresses of the requester, and as source hw addr and source IP addr the addresses that answer the question.

An ARP packet will be sent in an ethernet frame, but there need not be any relation between the hardware (MAC) addresses given in the ethernet frame header, and those given in the ARP packet.

ARP cache

Machines have an ARP cache with recently used addresses. Among the attributes that an IP address in the ARP cache can have are: published: we are willing to reply on behalf of the target ("proxy ARP"); incomplete: we have an IP address but do not know the corresponding MAC address - an ARP request was sent, but no reply has arrived yet; permanent (static): the address was given "by hand" (% arp -s 0:1:2:3:4:5) and is not changed by netword traffic.

The following action is expected when an ARP request is received: If I am the target (or proxy for the target): reply, and also add the sender info to my cache. (That is reasonable: the request comes because someone wants to connect to us, and soon we'll want to reply and need that info.)

The following action is expected when an ARP reply is received: If there is no outstanding request and no cache entry: possibly ignore the reply. Otherwise: update the cache.

ARP spoof

Suppose A wants B to believe that C is at MAC address M. There are two cases.

Case 1 B already has an ARP entry for C. Send an ARP reply to B telling that C is at M.

Case 2 B does not have an ARP entry for C. Maybe B would ignore an unsolicited reply. Let us make sure he has an ARP entry by sending a fake ping (with spoofed sender C).

Injecting fake packets

Various utilities exist to do packet injection. For example, arpoison is especially for sending ARP replies. A more generally useful tool is nemesis. It will send all kinds of hand-crafted packets.

For example (on Linux):

# nemesis arp -d eth3 -r -S -h 0:1:2:3:4:5 -D -m 00:76:12:a2:44:70
(send an ARP packet, to the eth3 interface, a reply, saying " is at 0:1:2:3:4:5", sending it to who is at 00:76:12:a2:44:70).

If we were in Case 2, then first

# nemesis icmp -qE -S -D
(send an ICMP ECHO "ping" packet to with spoofed source

Man in the middle attack

A (with MAC address M) tells B that C is at M, and tells C that B is at M. Now both B and C will send the packets meant for the other via A.

A can read, possibly change, the conversation.

This is better than sniffing: an ssh connection may be intercepted this way, and even though ssh will warn


Someone could be eavesdropping on you right now 
(man-in-the-middle attack)! It is also possible that 
the host-key has just been changed.  Please contact 
your system administrator.
Are you sure you want to continue connecting (yes/no)?
when it finds that B and C suddenly have different public keys, most naive users will just answer "yes" as one always does when some question is asked. This is a practical way to defeat ssh. This man-in-the-middle attack is automated by the sshmitm utility from the dsniff package.

A quote:

The easy availability of dsniff/sshmitm drives home the point that MITM is a real threat, not just a theoretical one. With the dsniff tools, it took this author only a few minutes to spoof DNS replies to a victim host, redirect an SSH connection to an intermediate system, and conduct a successful MITM against it. The sshmitm program obligingly printed out my username and password, and then echoed the contents of the trapped SSH session as I typed. Scary stuff. It should serve to raise user and sysadmin awareness of their responsibility to maintain the SSH known-hosts lists, configure client behavior in accordance with a considered security policy, and think carefully before overriding security warnings about changed or missing host-keys.

Avoiding ARP spoofs

No satisfactory solutions have been proposed. One can be a little bit cautious. Or one can be slow but rigorously secure.

Proxy and Gratuitous ARP

One approach is to always reject unsolicited ARP replies, and to reject all frames with different "outside" and "inside" MAC addresses. But this also rejects some legitimate uses:

Proxy ARP is used to connect two ethernet segments. The gateway in-between will answer ARP requests for machines on one side by machines on the other side.

Gratuitous ARP is an unsolicited broadcast ARP packet. It comes in two flavours. The packet sent by arping -U is the request "Who has my-IP. Please tell me." that has both as source and as dest IP address the IP address of the sender, and the sender's MAC as source MAC address, and ff:ff:ff:ff:ff:ff as dest MAC address. The intention of such a request is to detect possible duplicate IP addresses on the network. One also uses this with as source IP address, in order to avoid that listeners update their ARP cache.

The packet sent by arping -A is the reply "my-IP is at my-MAC" with the same ethernet header (with broadcast dest address), and the same fields as the previous, except (i) that this is a reply, and (ii) the dest MAC address equals my-MAC.

Do not confuse these two variations on Gratuitous ARP with the Reverse ARP broadcast used at boot time to ask for one's own IP address given the ARP address. (RARP uses op = 3 for the reverse request, and op = 4 for the reverse reply.)

Secure ARP

One can use digital signatures to authenticate ARP replies. This S-ARP is secure, but inconvenient, and much slower than the usual ARP.

15.3 TCP sequence numbers

A TCP/IP connection is started by sending SYN, the other side replying SYN ACK, and then sending ACK. After this handshake a connection exists, and data can be sent. What would prevent someone from faking the sender to be some trustred host?

Each TCP packet has two serial numbers: the seqence number and the acknowledgement number. Each packet with the ACK flag acknowledges receipt of all packets preceding the number given as the ack number. So, the conversation start is e.g.: (i) SYN, Seq 4189934627, Ack 0, (ii) SYN ACK, Seq 1370322447, Ack 4189934628, (iii) ACK, Seq 4189934628, Ack 1370322448.


  1   mymachine -> webserver TCP myport > http [SYN] Seq=1861201800 Ack=0
  2   webserver -> mymachine TCP http > myport [SYN, ACK] Seq=1736749861 Ack=1861201801
  3   mymachine -> webserver TCP myport > http [ACK] Seq=1861201801 Ack=1736749862
  4   mymachine -> webserver HTTP GET /foo/index.html HTTP/1.1 (Seq=1861201801 Ack=1736749862 Len=420)
  5   webserver -> mymachine TCP http > myport [ACK] Seq=1736749862 Ack=1861202221
  6   webserver -> mymachine HTTP HTTP/1.1 200 OK (text/html) (Seq=1736749862 1861202221 Len=1408)
  7   mymachine -> webserver TCP myport > http [ACK] Seq=1861202221 Ack=1736751270
  8   webserver -> mymachine HTTP HTTP Continuation (Seq=1736751270 Ack=1861202221 Len=1398)
  9   mymachine -> webserver TCP myport > http [ACK] Seq=1861202221 Ack=1736752668
 10   webserver -> mymachine TCP http > myport [FIN, ACK] Seq=1736752668 Ack=1861202221
 11   mymachine -> webserver TCP myport > http [ACK] Seq=1861202221 Ack=1736752669
One sees that the sequence number is incremented by 1 for a SYN and FIN, by 0 for an ACK, by Len (the data length) for data.

Normally, packets with wrong ack number are ignored and discarded: a low number is probably some old retransmitted packet, and a high number is garbage or perhaps some very old packet from a previous conversation between the same two endpoints.

If the source of the conversation is spoofed, then the SYN ACK of Step (ii) will be sent to the wrong machine (the faked source), and the spoofer does not know what Ack number to use in Step (iii). But this number is the only piece of information preventing a successful impersonation.

(There is a small detail: the faked source will receive an unexpected SYN ACK and reply with RST, resetting the connection. So, for this to work, one must make sure that the faked source is down, or is DoSsed. See, e.g., TCP SYN flood below.)

People have known for a long time that guessing a sequence number sufficed for a remote attack, but the world awoke when the attack was first performed in reality.

On 1994-12-25, Kevin Mitnick broke into the system in the home of Tsutomu Shimomura in order to steal some security related software. Shimomura had left a tcpdump running, so details have been preserved. Mitnick first made some test connections from a different machine to the machine that was going to be spoofed, and found that the initial sequence numbers were 2021824000, 2021952000, 2022080000, 2022208000, ..., 2024256000, each 128000 more than the previous one. So, he knew that the next initial sequence number was going to be 2024384000 so that the Ack had to be 2024384001. That was all.

(A spectacular chase followed. Books have been written and a movie was made. Mitnick was sentenced to 46 months in prison, and 3 years without touching a computer.)

Of course people wondered afterwards how one can avoid such attacks. Basically one can't, but one can pick the initial sequence numbers in a way that is much more difficult to guess. The numbers cannot be chosen at random, since that would leave the possibility of an old and a new conversation between the same two hosts interfering because they used overlapping intervals of sequence numbers. But one can pick the number using a cryptographic hash involving the source and destination IP addresses and ports and a secret on the local system, and adding to that value something that increases over time. Basically, this is what rfc1948 advises.

Linux is even more safe and uses a new secret every five minutes. Here is the code:

In tcp_ipv4.c:

static inline __u32 tcp_v4_init_sequence(...) {
        return secure_tcp_sequence_number(destip, srcip, destport, srcport);

In random.c:

#define COUNT_BITS      8
#define COUNT_MASK      ((1<<8)-1)
#define HASH_BITS       24
#define HASH_MASK       ((1<<24)-1)

static struct keydata {
        time_t rekey_time;
        __u32   count;          // already shifted to the final position
        __u32   secret[12];
} ____cacheline_aligned ip_keydata[2];

static spinlock_t ip_lock = SPIN_LOCK_UNLOCKED;
static unsigned int ip_cnt;

static struct keydata *__check_and_rekey(time_t time) {
        struct keydata *keyptr;
        keyptr = &ip_keydata[ip_cnt & 1];
        if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) {
                keyptr = &ip_keydata[1^(ip_cnt & 1)];
                keyptr->rekey_time = time;
                get_random_bytes(keyptr->secret, sizeof(keyptr->secret));
                keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS;
        return keyptr;

static inline struct keydata *check_and_rekey(time_t time) {
        struct keydata *keyptr = &ip_keydata[ip_cnt & 1];

        if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL)
                keyptr = __check_and_rekey(time);
        return keyptr;

__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
                                 __u16 sport, __u16 dport)
        struct timeval  tv;
        __u32           seq;
        __u32   hash[4];
        struct keydata *keyptr;

        keyptr = check_and_rekey(tv.tv_sec);

        hash[0] = saddr;
        hash[1] = daddr;
        hash[2] = (sport << 16) + dport;
        hash[3] = keyptr->secret[11];

        seq = halfMD4Transform(hash, keyptr->secret) & HASH_MASK;
        seq += keyptr->count;
        seq += tv.tv_usec + tv.tv_sec*1000000;

        return seq;

Comments The pair of structs ip_keydata holds the current and the next keydata, so that one CPU gets consistent values while another CPU is making a change. The pair is protected by the spinlock ip_lock, preventing two CPUs making a change at the same time. The parity of ip_cnt determines the current struct. Once in a REKEY_INTERVAL (300 seconds) the routine get_random_bytes() is called. It gets some bytes from the entropy pool that is fed with timings of keystrokes and mouse moves and network interrupts. The secret value and source and destination IP address and port are hashed by a partial MD4 to give a 24-bit random value. In the leading 8 bits an 8-bit counter (incremented every REKEY_INTERVAL) is stored. Finally, the time (in microseconds) is added. So, every 5 minutes the leading 8 bits of this value are increased by about 18, and values may start repeating after slightly over an hour.

Guessing, or cryptanalysis, seems unfeasible.

Some other operating systems use weaker mechanisms. Just calling a random generator is not good enough. The design criterion of a random generator is that it must produce arbitrary values, evenly distributed over all possibilities, and a linear congruential generator is usually good enough. Here one needs more: a generator that withstands cryptanalysis.

Even when sequence numbers cannot be guessed, it may be possible to determine them. In Phrack 64#14 a possible approach is sketched.

15.4 Hijack a TCP session

If machines B and C are having a TCP/IP conversation, can A take over the session with C, or just inject some stuff? As we saw above this is easy to do provided A can get at the sequence numbers. This is trivial when the packets pass A's local ethernet. Sometimes ARP spoofing or DNS spoofing makes a man-in-the-middle attack possible. Maybe etherleak can provide information on sequence numbers.

Various utilities exist to automate this process. The most popular ones seem to be hunt (with description in hunt.txt), and ettercap. For example, play man-in-the-middle between hosts and

# ettercap -a -i eth3
Press [h] for help. Commands or text can be injected with [i] pwd\r\n or so. (That is, the Enter key finishes the text to enter, and carriage return and linefeed are represented by \r and \n.) There are lots of features, see for example this article.

15.5 DNS cache poisoning

DNS is used to convert a domain name into an IP address or back ("reverse DNS"). A client sends a query to a server, and the server generally does one of the following: (i) return the answer, in case the server is authoritative for the domain or has the information cached from an earlier query, (ii) go out on the net and ask other servers ("recursive lookup"), (iii) do not go out but just tell the client where he should go himself ("referral").

Typically the name server of an ISP will do all the work for its clients, while otherwise servers just refer. A query for would go out to a root server, and that root server will return a list of addresses of com. name servers. A query to a com. server then yields addresses for name servers. Etc.

A reply may contain more information than what was asked. For example, if the reply is a referral to it will generally also contain as "glue" the IP address of that host. The additional data will be accepted as trustworthy when it is "in bailiwick".
Etymology: ME i[baillifwik], fr. i[baillif] + i[wik] dwelling 
   place, village, fr. OE i[w{i-}c]; akin to OHG i[w{i-}ch] 
   dwelling place, town
1) n, the office or jurisdiction of a bailiff
2) n, one's special domain

This means the following: if the com. name server when asked for refers to a name server, then that latter server is regarded as authoritative for that domain. Before the "in bailiwick" requirement was added, it was trivial to poison the DNS cache: force the resolver to query a server under your control and add all the records you want.

Poisoning is still possible. After the resolver has sent out its query, an imposter can send a fake reply, and hope it arrives before the proper reply. The reply of the server is matched to the query by the client using a 16-bit transaction ID (TID) and is discarded if there is no match. If an imposter wants to inject his forged data, he has to guess this TID correctly, and of course the reply must come in on the correct (UDP or TCP) port, and he will not get a chance at all if the information was already present in cache.

Old resolver libraries just increment TID by one for each query, and guessing is easy. Good resolvers use a random value. Old resolver libraries use a fixed port for the queries. Good resolvers use a random port number. (The servers of course use the well-known port 53 for DNS.)

All of this was well-known, but in 2008 Dan Kaminsky came with an attack that was much more effective than earlier attacks. If the resolver is asked to resolve, where the number is chosen at random, then the answer will not be in cache, so that we pass the first hurdle. Keep generating such queries, each followed by a few hundred fake replies. If the port is known then we may hit the right TID within 10 seconds. The fake reply will be a referral, naming a host under the attackers control as name server for the domain and now this domain has been hijacked. This process may be started for example via a URL on some web page that refers to the attacker's machine. If the port is also random then this attack takes more effort - success after ten hours was reported for a fast network. Exploit code is found in the Metasploit framework.

The current conclusion is that DNS is not safe.

15.6 NFS - No File Security

The Network File System NFS (say, v2) is a security disaster. (NFS v4 can be configured to be more secure.)

NFS keeps user state and credentials at the server. With each request the user sends a cookie, the filehandle. Snooping the filehandle suffices to get access.

Even worse, authentication is done on the client. Injecting suitable packets will convince the server about one's credentials.

Usually NFS runs over UDP, and UDP is trivial to spoof. No sequence numbers to worry about.

15.7 Exploiting scanners

Most people are lazy, install the operating system in the default way, or get their machine preinstalled that way, and never upgrade or patch. As soon as some exploit is discovered, one can break in.

On the other hand, there are the very active people, who scan for viruses, net attacks etc. The funny part is that it is often possible to use attacks against these active people that the lazy people are not vulnerable to.

There have been found buffer overflows in virus scanners (both for incoming and outgoing email), and spam scanners like SpamAssassin, ethernet watchers like tcpdump, ethereal and Snort, etc. Thus, local or remote root is sometimes possible by exploiting such vulnerabilities.

15.8 Simple Denial of Service attacks

TCP SYN flood

A TCP connection is setup by the handshake (i) SYN, (ii) SYN-ACK, (iii) ACK. If the attacker sends a SYN, but never sends the ACK, then the receiver has a half-open connection and has to wait for a timeout before the corresponding data can be freed. A flood of such requests, with varying (spoofed) source addresses, is an effective Denial of Service attack. In rfc2267 it is suggested that ISPs should filter spoofed source addresses to combat this and similar attacks. See also CA-96.21.


See above under ping.

Next Previous Contents