Sniffer has always been an annoying hacker tool because it is a static attack software and its existence does not leave any trace, therefore, it is difficult for people to pull it out. However, it is quite harmful (it is like a monitor, and your "every action" is under its surveillance, you say it is not very harmful ). Therefore, it is necessary to find a way to check whether there is sniffer in the network. 1. sniffer Principle The so-called "Know Yourself" and "Know Yourself" have no advantages. To understand the method of detecting sniffer, you must first understand the principles of sniffer. First, let's take a look at how data is transmitted in the LAN. When a data packet is destined for a computer in the LAN, the data packet is sent to each computer in the network as a broadcast. The NIC of each computer analyzes the destination MAC address (that is, the ethernet address) in the packet, if this address is the MAC address of this computer or the broadcast address (FF-FF-FF-FF-FF-FF), then, the packet will be received, and if not, the NIC will discard it directly. However, there is a premise that the NIC of the computer on the receiving end works in normal mode. If the NIC is set to the hybrid mode, it can receive all the packets that pass through (including, of course, packets whose destination is not local ). That is to say, as long as the packet is sent to the LAN, it will be received by the NIC in the mixed mode! This is the basic principle of sniffer. As for the specific implementation and some details of Sniffer, I will not talk about it here. If you are interested, please refer to the relevant materials. 2. ARP datagram transmitted over Ethernet Now that we know the basic principles of Sniffer, we need to think about how to pull out the hidden sniffer in the LAN.Article. Here, we need to construct our own ARP data packets. So we will first briefly introduce the structure of ARP requests and response data packets: Typedef struct _ et_header // Ethernet header { Unsigned char eh_dst [6]; Unsigned char eh_src [6]; Unsigned short eh_type; } Et_header; Typedef struct _ arp_header // ARP Header { Unsigned short arp_hdr; Unsigned short arp_pro; Unsigned char arp_hln; Unsigned char arp_pln; Unsigned short arp_opt; Unsigned char arp_sha [6]; Unsigned long arp_spa; Unsigned char arp_tha [6]; Unsigned long arp_tpa; } Arp_header; The above is the structure of the ARP packet transmitted in the network. As for the specific meaning of each field in the structure and how to initialize, beyond the scope of this article, you are interested to see the TCP-IP protocol details book. 3. Detect sniffer in the LAN Finally, the topic is entered. Since sniffer is a static blacklist and does not leave any logs, We need to actively detect it. In view of the principle of sniffer is to set the network card to the mixed mode, we can find a way to detect the network card that is set to the mixed mode in the network, in order to determine whether there is sniffer. Here, let's take a look at the computer's rules for receiving data packets. As mentioned above, in normal mode, the network adapter first determines the destination MAC address of the data packet. If it is a local MAC address or a broadcast address, the data packet will be received into the system core, otherwise, it will be discarded. If the NIC is set to the hybrid mode, all data packets will directly enter the system core. After data packets arrive at the system core, the system further filters data packets: the system only responds to packets whose destination MAC address is the local MAC address or broadcast address. If arp request packets are received, the system returns an ARP response packet. However, the difference is that the core of the system and the NIC have different judgment on the broadcast address: in windows, the NIC determines all the six digits of the MAC address, the system core only determines the first two digits of the MAC address (Win98 or even the first digit). That is to say, for the system core, the correct broadcast address FF-FF-FF-FF-FF-FF and the wrong broadcast address FF-FF-FF-FF-FF-FE are the same, are considered as broadcast addresses, and even the FF-FF-00-00-00-00 will be considered as broadcast addresses by the system's core! Here, smart readers probably know how to do it. If we construct an ARP request packet whose destination MAC address is FF-FF-FF-FF-FF-FE, the packet will be discarded for the NIC in normal working mode, of course, no packet will be returned; for NICs in hybrid mode, data packets are received at the core of the system. The system core considers this MAC address as a broadcast address, so it returns an ARP response packet. In this way, we can determine that sniffer exists on this machine. 4. Main source code analysis According to the above analysis,ProgramIt is divided into two modules: one is the ARP request packet that sends the disguised broadcast address, and the other is the ARP response packet that receives the feedback for analysis. We use two threads respectively. The main thread is responsible for sending and the listening thread is responsible for receiving. |
First, create the structure of the Ethernet header and ARP header:
★
Typedef struct _ et_header // Ethernet header
{
Unsigned char eh_dst [6];
Unsigned char eh_src [6];
Unsigned short eh_type;
} Et_header;
Typedef struct _ arp_header // ARP Header
{
Unsigned short arp_hdr;
Unsigned short arp_pro;
Unsigned char arp_hln;
Unsigned char arp_pln;
Unsigned short arp_opt;
Unsigned char arp_sha [6];
Unsigned long arp_spa;
Unsigned char arp_tha [6];
Unsigned long arp_tpa;
} Arp_header;
★
Then the main thread that sends the ARP request message gets the names of all adapters. "Adapter_name" indicates a buffer for storing the name of the adapter, which is stored in the buffer using Unicode encoding. Unicode encoding is used to store one character in two bytes. In this way, a '\ 0' will naturally appear between each character '. The two adapter names are separated by a word '\ 0. Adapter_length: buffer size:
★
If (packetgetadapternames (char *) adapter_name, & adapter_length) = false)
{
Printf ("packetgetadapternames error: % d \ n", getlasterror ());
Return 0;
}
★
Open the adapter. By default, the first adapter is Enabled:
★
Lpadapter = (lpadapter) packetopenadapter (lptstr) adapter_list [0]);
If (! Lpadapter | (lpadapter-> hfile = invalid_handle_value ))
{
Printf ("unable to open the driver, error code: % lx \ n", getlasterror ());
Return 0;
}
★
Assign values to the structure of the Ethernet header and ARP header. The strtomac function is the function for converting a custom string to a MAC address:
★
Strtomac ("00e06e41508f", s_mac); // "00e06e41508f" is the NIC address of the local machine used by the author to test the program. The tester should change it to the NIC address of the testing machine.
Memcpy (et_header.eh_src, s_mac, 6 );
Strtomac ("fffffffffe", d_mac); // set the destination physical address to fffffffffe.
Memcpy (et_header.eh_dst, d_mac, 6 );
Et_header.eh_type = htons (0x0806); // type 0x0806 indicates this is an ARP packet
Arp_header.arp_hdr = htons (0x0001); // hardware address type ethernet address
Arp_header.arp_pro = htons (0x0800); // The Protocol address type is IP protocol.
Arp_header.arp_hln = 6; // The hardware address length is 6.
Arp_header.arp_pln = 4; // The Protocol address length is 4.
Arp_header.arp_opt = htons (0x0001); // identifies as an ARP request
Arp_header.arp_spa = inet_addr ("172.24.21.10"); // "172.24.21.10" is the IP address of the Local Machine Used by my test program. The tester should change it to the IP address of the testing machine.
Memcpy (arp_header.arp_sha, et_header.eh_src, 6 );
Arp_header.arp_tpa = inet_addr (argv [1]);
Memcpy (arp_header.arp_tha, et_header.eh_dst, 6 );
★
Send data packets:
★
Lppacket = packetallocatepacket (); // allocate memory to the packet structure pointer
Packetinitpacket (lppacket, buffer, 512); // initialize the packet structure pointer
Packetsetnumwrites (lpadapter, 5); // you can specify the number of sent messages.
Packetsendpacket (lpadapter, lppacket, true); // sends an ARP request packet
★
Finally, don't forget to finish the work:
★
Packetfreepacket (lppacket); // release the packet structure pointer
Packetcloseadapter (lpadapter); // close the adapter
★
Finally, the listening thread:
Set the series parameters for receiving data packets:
★
Packetsethwfilter (lpadapter, ndis_packet_type_directed); // set the NIC to the direct mode.
Packetsetbuff (lpadapter, 1024); // sets the buffer size of packets received by the network adapter.
Packetsetreadtimeout (lpadapter, 2); // set the "rest" time after receiving a package
★
Receive data packets:
★Packetreceivepacket (lpadapter, lppacket, true); // receives data packets★
Analyze the data packets to draw a conclusion:
★
Char * Buf;
Bpf_hdr * lpbpfhdr;
Et_header * lpethdr;
In_addr ADDR = {0 };
Buf = (char *) lppacket-> buffer;
Lpbpfhdr = (bpf_hdr *) BUF;
Lpethdr = (et_header *) (BUF + lpbpfhdr-> bh_hdrlen );
If (lpethdr-> eh_type = htons (0x0806) // determines whether the ARP packet is used
{
Arp_header * lparphdr = (arp_header *) (BUF + lpbpfhdr-> bh_hdrlen + sizeof (et_header ));
Char source_ip [20] = {0}, dest_ip [20] = {0 };
ADDR. s_un.s_addr = lparphdr-> arp_spa;
Memcpy (source_ip, inet_ntoa (ADDR), strlen (inet_ntoa (ADDR )));
Memset (& ADDR, 0, sizeof (in_addr ));
ADDR. s_un.s_addr = lparphdr-> arp_tpa;
Memcpy (dest_ip, inet_ntoa (ADDR), strlen (inet_ntoa (ADDR )));
If (! Strcmp (source_ip, ip )&&! Strcmp (dest_ip, "172.24.21.10") // determines whether the source IP address and destination IP address of the received packet are correct (the string variable IP address is the IP address of the probe machine passed from the main thread)
{
If (lparphdr-> arp_opt = htons (0x0002) // determines whether the ARP response is correct.
{
Printf ("there is a sniffer! \ N ");
}
}
}