Packet sniffing is the act of intercepting and reading any or all network traffic that is being transmitted across a shared network communication channel. The Ethernet protocol works by sending packets to all computers on a physical network circuit.
The network interface card (NIC) hardware in a networked computer receives every piece of network traffic that is transmitted across the physical network. Ordinarily the network device driver software will process only incoming traffic which contains the address of its host computer, or broadcast packets which are meant for all computers on a network. However certain network adapter hardware can be configured to operate in an altered state where the network device driver processes all traffic transmitted across the network, whether addressed to the host computer or not.
Monitoring network traffic requires both hardware and software mechanisms working together. The monitoring process begins with the NIC, with the packets being captured by the device driver software. Both the hardware and the software components of the NIC need to provide mechanisms for capturing the raw packets. After the network traffic is processed by the NIC, software mechanisms are needed to filter the captured data. Finally, a mechanism is required to extract and reconstruct the data portion of the captured packets, and to display what you get in a readable format.
The good news is that some TCP/IP protocols transmit user name and password data across the network in clear text. Intercepting this data can compromise the security of the network. Solutions for this problem are readily available. However most sites do not implement these solutions, and are consequently vulnerable to this sort of attack. Authentication schemes such as MD4 and MD5, KERBEROS, DESLOGIN, s/key, and SSH are available to prevent the clear text transmission of user names and passwords across a network. Public key encryption programs such as PGP are available to encrypt electronic mail (E-mail) to prevent the contents from being read. Privtool is a neat tool for reading and sending mail using PGP. Unfortunately many sites fail to take advantage of these mechanisms to safeguard their system's integrity. Even in cases where sites do attempt to safeguard this data, faulty algorithm implementations, such as Windows NT's password hashing algorithm, give the impression of more security than actually exists. TELNET packets bound for an Windows NT server, for example, can be intercepted and decrypted by someone knowing the password hashing weakness or even by some LAMF who downloaded NT crack from the L0pht site.
The bad news is that in order to implement the mechanisms that I'm going to talk about here, you are going to need root access. So why would we want to discuss a technology for compromising security that already requires that the system privileges be compromised? The answer is to compromise the other machines on the network, and to compromise machines on other networks. Also because in many instances it is neither wise nor effective to remain logged onto a root shell account. Accessing the machine as root generates all kinds of nasty log entries that have to be cleaned up as it is, so if information can be acquired in a more subtle manner over time, this is an advantage.
Root shell access is easily acquired. Array, stack, and buffer overflow exploits, as well as physical access to the machine and social engineering are all viable means of surmounting this first obstacle. Array, stack and buffer overflows in xterm, xlock, rlogind, and lpr are some old favorites that still work. The main thing here is to be able to surmount the permissions for some of the later tasks, including modifying programs and possibly building new kernels.
Access to the physical network is required when you set up a sniffer. WARNING:i Some 10baseT hubs can log port activation statistics, so if you punch into a port and somebody reads the logs, you are found out.
A packet is a self-contained unit of data that includes information necessary to route it from its origin to its destination across a network. The term packet sniffing is actually a misnomer, since the data units that are transmitted across the network are called frames.
Packet capture requires that the network interface card support promiscuous mode. Promiscuous mode means that the card indiscriminately accepts all network traffic into it, whether bound for that card's machine or not. Promiscuous mode is easy to implement. Most hardware requires that a register bit be set, and the machine will receive every packet on the physical network. Some hardware requires that you disengage the Ethernet card, reconfigure it, and then re-enable the Ethernet card. It is possible to run a sniffer without setting the NIC to promiscuous mode; however you will only see packets addressed to the machine that the sniffer is running on.
The four layer TCP/IP network model illustrates the different levels of functionality in a network. The TCP/IP model looks like this:
Application layer | End-user program interface |
Transport layer | Communication between programs across a network |
Network layer | Communication addressing and routing |
Link layer | Network hardware and device drivers |
Each layer of the TCP/IP model performs a unique function within the network communication process. Starting at the bottom layer, network traffic travels between computers at the link layer. Address resolution and routing are handled by the network layer. Program to program communication is the function of the transport layer. The interface between man and machine is the application layer.
Outgoing network traffic travels down from the application layer to the link layer and incoming traffic travels up from the link layer to the application layer within each individual computer. Each independent piece of data accumulates data structures as it passes down through the four network model layers and sheds data structures as it is passed back up. The data encapsulation process looks like this:
Application layer | Data | ||||
| | |||||
V | |||||
Transport layer | TCP header | Data | |||
| | |||||
V | |||||
Network layer | IP header | TCP header | Data | ||
| | |||||
V | |||||
Link layer | Ethernet header | IP header | TCP header | Data | Checksum |
The application layer is the interface between the human user and the network. This layer includes the TELNET, FTP, RLOGIN, and RSH TCP/IP protocols. Other potentially vulnerable protocols, including NFS and DNS, are considered part of the application layer. In addition, the Simple Mail Transport Protocol (SMTP), the delivery mechanism for electronic mail, is part of the Application layer.
The transport layer handles the end to end communication between two computers on the network. This layer includes the Transmission Control Protocol (TCP) and the User Datagram Protocol (UDP). TCP provides reliable connections between computers, while UDP provides an unreliable, "send and pray" communication mechanism. TCP constructs and transmits data as discrete packets. A TCP packet looks like this:
Source port | Destination port | |||
Sequence number | ||||
Acknowledgment number | ||||
| Window | |||
Checksum | Urgent data pointer | |||
Options | Padding | |||
Data |
A UDP packet is much simpler and looks like this:
Source port | Destination port |
Length | Checksum |
Data |
The network layer handles the addressing and routing of packets across the network. The network layer is responsible for moving data to and from the protocols above and below it. This layer includes the Internet Protocol (IP) and the Internet Control Message Protocol (ICMP), a support protocol for the Internet Protocol. IP defines a common address space for the entire Internet. IP hides the details of the underlying link layer from the upper layers. IP also divides and reassembles large packets that would not otherwise be transmitted across the physical network. IP constructs and transmits discrete units of data called datagrams. An IP datagram looks like this:
Version | Hlen | Type of Service | Length | ||||
Fragmentation ID | Flags | Fragmentation Offset | |||||
Time To Live | Protocol | Checksum | |||||
IP Source address | |||||||
IP Destination address | |||||||
Options | Padding | ||||||
Data |
The link layer handles the physical interaction of devices connected to the physical network. The link layer includes the Address Resolution Protocol (ARP) which handles the translation of IP address values to physical Medium Access Control (MAC) addresses, and the Reverse ARP (RARP) protocol which performs the reverse translation. The link layer also handles the encapsulation of IP datagrams into frames that can be recognized by the physical network interface. An IP datagram encapsulated in an Ethernet frame looks like this:
Destination address | Source address | Type | IP datagram | Checksum |
There are two groups here, depending upon the operating system. The first is mechanisms that are built into the operating system. The other is software that works directly with the operating system.
Some UNIX vendors supply software devices that can be used to monitor network interfaces. These devices are called Network Taps. Examples of network taps are the BSD Packet Filter (bpf) provided with most BSD distributions, SUN's Network Interface Tap (NIT) available with SUNOS 4.x and HP-UX, the Packet Filter (pf) device provided with the DEC ULTRIX distribution.
Devices | System | Commands |
/dev/bpf (pseudo-device) | BSD systems | |
/dev/nit | ATT, SUNOS, HP-UX | |
/dev/pf | VAX (ULTRIX) |
The other possibility is software that places the machine's Ethernet controller into promiscuous mode directly, without having a specific device associated with it. These include the snoop program supplied with SGI IRIX machines, and the Ethernet Traffic Monitor (ENTM) supplied with DEC/VAX machines. These programs have man pages, nice of them.
Program Name | System | Usage |
tcpdump | BSD systems | |
etherfind | SUNOS | |
Ethernet Traffic Monitor (ENTM) | VAX/VMS | |
snoop | SGI IRIX |
A special exception that I am including here is Microsoft Windows NT. NT doesn't really have a device that you have to work with, it has the registry instead.
1. Run the Registry Editor. |
2. From the HKEY_LOCAL_MACHINE subtree, find the key: |
\SYSTEM\CurrentControlSet\Services\MdgMPort1\Parameters |
3. From the Edit menu, choose Add Value. |
4. Add the following: |
Value Name: PromiscuousModeX |
Data Type: REG_DWORD |
Data: 1 |
Note: To disable promiscuous mode set the data to 0. |
5. Choose OK and quit Registry Editor. |
6. Shut down and restart Windows NT. |
The best possible scenario is that you have gained the ability to compile and execute programs with root permissions. In this case you need to know the programming interface for the device that you want to use to sniff packets. I am going to talk about some kernel structures and some socket ioctls here, so if you want to learn how to program at the device driver level, stay. Otherwise...
The ifnet structure contains common information for every interface. It's a large structure, so I will only touch on a few points. Ifnet structures are chained together in a linked list. Hardware specific information, stuff like the MAC address, lives here. It also contains the flag bits, including the promiscuous mode bit for Ethernet interfaces. Ethernet devices have a field telling how many promiscuous listeners the interface currently has, sort of a reference count. You can also reference the bpf device directly through here, if the device is supported. Ifnet includes a linked list of addresses for the interface.
struct | ifnet { | ||
void | *if_softc; | /* pointer to driver state */ | |
char | *if_name; | /* interface name e.g. ep0 */ | |
struct | ifnet *if_next; | /* forward pointer */ | |
struct | ifaddr *if_addrlist; | /* addresses for this interface */ | |
int | if_pcount; | /* number of promiscuous listeners */ | |
struct | bpf_if *if_bpf; | /* bpf structure */ | |
. | |||
. | |||
. | |||
short | if_flags; | /* up, down, promiscuous, etc */ | |
. | |||
. | |||
. | |||
} |
An ifaddr structure exists for each address that an interface supports. Ifaddr structures are chained in a linked list. The ifaddr structure contains a backward pointer to its parent ifnet structure. Ifaddr also contains a reference count field. If the reference count goes to zero, the structure is freed from memory.
struct | ifaddr { | ||
struct sockaddr | *ifa_addr; | /* address of interface */ | |
struct sockaddr | *ifa_dstaddr; | /* other end of point to point link */ | |
. | |||
. | |||
. | |||
struct ifnet | *ifa_ifp; | /* back pointer to ifnet */ | |
. | |||
. | |||
. | |||
short | ifa_refcnt; | /* references to this structure */ | |
. | |||
. | |||
. | |||
} |
An ifreq structure is the structure that is returned by the kernel when you do an ioctl system command to get the interface flags.
struct | ifreq { | ||
char | ifr_name[IFNAMSIZ]; | /* interface name e.g. ep0 */ | |
union { | |||
struct sockaddr ifru_flags; | /* get-set flags */ | ||
. | |||
. | |||
. | |||
} ifr_ifru; | |||
} |
ioctl stands for I/O conTroL. It is the programming interface for system calls. ioctls have the general form of ...
ioctl(fd, cmd, *ptr) |
where: |
fd is an open file descriptor for the device |
cmd is the command that the driver should perform |
*ptr is a pointer to an optional third argument |
to get the flags for an interface, |
ioctl(fd, SIOCGIFFLAGS, &ifreq); |
to set the flags for an interface, |
ioctl(fd, SIOCSIFFLAGS, &ifreq); |
kernel code for privileged commands like setting flags usually starts with something that looks like this: |
suser(p->p_ucred, &p->p_acflag); |
...which is fancy C code for "check if this program has root credentials." So don't try this from a user space because not only will it fail, but it will almost certainly be logged. More on that later.
System V (ATT, HP-UX, SUNOS) and some BSD systems support streams, which is an alternative to the BSD sockets interface. Accessing devices using streams ioctls works like this: You format a structure and pass it to the stream head, which translates it into a message and passes it down stream.
For streams ioctls, we use a constant I_STR and supply the third argument like this:
ioctl(fd, I_STR, &str) | |||
where: | |||
fd is an open file descriptor for the device | |||
I_STR indicates a streams ioctl system call | |||
&str is a pointer to strioctl structure | |||
struct | strioctl { | ||
int | cmd; | /* command */ | |
int | timeout; | /* timeout value */ | |
int | len; | /* length */ | |
char | *data; | /* pointer to parameter data block */ | |
}; | |||
to set the flags for an interface, | |||
struct | strioctl | str; | |
. | |||
. | |||
. | |||
str->cmd = SIOCGIFFLAGS; | |||
. | |||
. | |||
. | |||
if (ioctl(fd, I_STR, &str) == M_IOCNACK) { | /* failed */ | ||
perror(...); | |||
} else { | /* got it */ | ||
str->cmd &= IFF_PROMISC; | /* toggle flag */ | ||
} |
Strioctl is a representation of the command that streams understands. The stream head converts the structure into a message that gets passed down the stream to each module in line. If a device module recognizes the command, it gets performed and the result gets returned. Otherwise you get a NACK back.
BTW, the data pointed to by the &str structure must reside in the kernel data space. If it lives outside, then the stream head translation will only get the pointer and *NOT* the data pointed to when it converts the message, and your call will always fail.
Okay, now that you know all these kewl ways to sniff, let's talk a bit about how not to get caught.
If you have root access, make sure to clean up all log entries. That includes history files, utmp, wtmp, any hidden logs (check through inetd.conf and syslog.conf while you're at it). Remember that many logs are not human readable, so do your homework.
Now, if you happen to get lucky and have access to the source, there's a few things that can trip you up that you should try to replace. First and foremost is that suser function I showed earlier. It lives in /usr/include/sys/ucred.h (your path may vary). Edit that module and build a new kernel, or wait for the next rebuild and you won't have any problems with root permissions.
Next, certain commands can trip you up. ifconfig displays current interface information. It will indicate that an interface is in promiscuous mode. Netstat will display the network status for network interfaces, and will also display whether an interface is in promiscuous mode. If you can modify the sources for these commands, do it. Otherwise build a modified command off line and replace the existing commands. There are root kits out there for some of this kind of work. All else fails, disable the commands to buy some time, and maybe force a kernel rebuild by the syadmin.
There are programs that will display whether an interface is in promiscuous mode. cpm (check promiscuous mode) and ifstatus will show you up also. Same as above applies. Rebuild or replace, or else disable.
Everything I have told you and some stuff I haven't told you is publicly available in the Request For Comment documents, or RFCs, published by Internic.
RFCs are available via FTP from
nic.ddn.mil and from
www.internic.net.
ARP is described in RFC 826. |
Encapsulation of IP datagrams in Ethernet frames is described in RFC 894. |
Encapsulation of IP datagrams in other low level frames is described in RFC 1042. |
FTP is described in RFC 959. |
ICMP is described in RFC 792. |
IP is described in RFC 791. |
IPv6 is described in RFC 1883. |
RARP is described in RFC 903. |
RLOGIN is described in RFC 1258. |
TCP is described in detail in RFC 793. |
TELNET protocol is described in RFC 854. |
UDP is described in RFC 768. |
Thank you.
Webmaster modified this page on January 1, 2005 |